1 // Copyright (C) 2017-20xx CEA/DEN, EDF R&D
3 // File: GeomAlgoAPI_Circ2dBuilder.cpp
4 // Created: 3 April 2017
5 // Author: Artem ZHIDKOV
7 #include <GeomAlgoAPI_Circ2dBuilder.h>
8 #include <GeomAPI_Ax3.h>
9 #include <GeomAPI_Circ2d.h>
10 #include <GeomAPI_Pnt2d.h>
11 #include <GeomAPI_Dir2d.h>
12 #include <GeomAPI_Shape.h>
14 #include <BRep_Tool.hxx>
16 #include <GccAna_Circ2d2TanRad.hxx>
17 #include <GccAna_Circ2d3Tan.hxx>
18 #include <GccAna_Circ2dTanCen.hxx>
20 #include <GccEnt_QualifiedCirc.hxx>
21 #include <GccEnt_QualifiedLin.hxx>
22 #include <Geom2dAdaptor_Curve.hxx>
23 #include <Geom_Plane.hxx>
25 #include <TopoDS_Edge.hxx>
29 typedef std::shared_ptr<gp_Circ2d> Circ2dPtr;
30 typedef std::shared_ptr<Geom2dAdaptor_Curve> CurveAdaptorPtr;
31 typedef std::vector< std::shared_ptr<GccEnt_QualifiedCirc> > VectorOfGccCirc;
32 typedef std::vector< std::shared_ptr<GccEnt_QualifiedLin> > VectorOfGccLine;
35 // Provide different mechanisms to create circle:
36 // * by passing points
38 // * with specified radius
43 CircleBuilder(const std::shared_ptr<GeomAPI_Ax3>& theBasePlane)
44 : myPlane(new Geom_Plane(theBasePlane->impl<gp_Ax3>())),
48 void setRadius(const double theRadius)
49 { myRadius = theRadius; }
51 void setCenter(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter)
52 { myCenter = theCenter; }
54 void setTangentCurves(const std::vector< std::shared_ptr<GeomAPI_Shape> >& theEdges)
56 std::vector< std::shared_ptr<GeomAPI_Shape> >::const_iterator anEdgeIt;
57 for (anEdgeIt = theEdges.begin(); anEdgeIt != theEdges.end(); ++anEdgeIt) {
58 const TopoDS_Edge& anEdge = TopoDS::Edge((*anEdgeIt)->impl<TopoDS_Shape>());
62 Handle(Geom2d_Curve) aCurve = BRep_Tool::CurveOnSurface(anEdge, myPlane, aLoc, aFirst, aLast);
63 CurveAdaptorPtr aCurveAdaptor(new Geom2dAdaptor_Curve(aCurve, aFirst, aLast));
65 // sort curves (circles should become first)
66 if (aCurveAdaptor->GetType() == GeomAbs_Circle)
67 myTangentShapes.insert(myTangentShapes.begin(), aCurveAdaptor);
69 myTangentShapes.push_back(aCurveAdaptor);
73 void setPassingPoints(const std::vector< std::shared_ptr<GeomAPI_Pnt2d> >& thePoints)
75 std::vector< std::shared_ptr<GeomAPI_Pnt2d> >::const_iterator aPIt;
76 for (aPIt = thePoints.begin(); aPIt != thePoints.end(); ++aPIt)
77 myPassingPoints.push_back((*aPIt)->impl<gp_Pnt2d>());
80 void setClosestPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
81 { myClosestPoint = thePoint; }
88 if (myPassingPoints.size() == 1)
89 aResult = circleByCenterAndPassingPoint();
90 else if (myTangentShapes.size() == 1)
91 aResult = circleByCenterAndTangent();
92 else if (myRadius > 0.0)
93 aResult = circleByCenterAndRadius();
94 } else if (myRadius > 0.0) {
95 if (myTangentShapes.size() == 2)
96 aResult = circleByRadiusAndTwoTangentCurves();
98 switch (myPassingPoints.size()) {
100 aResult = circleByThreeTangentCurves();
103 aResult = circleByPointAndTwoTangentCurves();
106 aResult = circleByTwoPointsAndTangentCurve();
109 aResult = circleByThreePassingPoints();
119 Circ2dPtr circleByCenterAndRadius()
121 const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
122 return Circ2dPtr(new gp_Circ2d(gp_Ax2d(aCenter, gp::DX2d()), myRadius));
125 Circ2dPtr circleByCenterAndPassingPoint()
127 const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
128 if (aCenter.SquareDistance(myPassingPoints[0]) > Precision::SquareConfusion()) {
129 GccAna_Circ2dTanCen aBuilder(myPassingPoints[0], aCenter);
130 if (aBuilder.NbSolutions() > 0)
131 return Circ2dPtr(new gp_Circ2d(aBuilder.ThisSolution(1)));
136 Circ2dPtr circleByCenterAndTangent()
138 const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
139 CurveAdaptorPtr aCurve = myTangentShapes[0];
141 std::shared_ptr<GccAna_Circ2dTanCen> aCircleBuilder;
142 if (aCurve->GetType() == GeomAbs_Line) {
143 aCircleBuilder = std::shared_ptr<GccAna_Circ2dTanCen>(
144 new GccAna_Circ2dTanCen(aCurve->Line(), aCenter));
145 } else if (aCurve->GetType() == GeomAbs_Circle) {
146 aCircleBuilder = std::shared_ptr<GccAna_Circ2dTanCen>(new GccAna_Circ2dTanCen(
147 GccEnt::Unqualified(aCurve->Circle()), aCenter, Precision::Confusion()));
150 return getProperCircle(aCircleBuilder);
153 Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2dTanCen>& theBuilder) const
158 CurveAdaptorPtr aCurve = myTangentShapes[0];
160 int aNbSol = theBuilder->NbSolutions();
164 int anAppropriateSolution = 1;
165 double aMinDist = Precision::Infinite();
167 double aParSol, aPonTgCurve;
169 for (int i = 1; i <= aNbSol && aCurve; ++i) {
170 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
171 if (isParamOnCurve(aPonTgCurve, aCurve)) {
172 double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
173 if (aDist < aMinDist) {
174 anAppropriateSolution = i;
180 return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
183 double distanceToClosestPoint(const gp_Circ2d& theCirc) const
185 if (myClosestPoint) {
186 double aDist = myClosestPoint->impl<gp_Pnt2d>().Distance(theCirc.Location());
187 return fabs(aDist - theCirc.Radius());
193 Circ2dPtr circleByThreeTangentCurves()
195 VectorOfGccCirc aTgCirc;
196 VectorOfGccLine aTgLine;
197 convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
199 if (aTgCirc.size() + aTgLine.size() != 3)
202 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
203 switch (aTgLine.size()) {
205 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
206 *aTgCirc[0], *aTgCirc[1], *aTgCirc[2], Precision::Confusion()));
209 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
210 *aTgCirc[0], *aTgCirc[1], *aTgLine[0], Precision::Confusion()));
213 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
214 *aTgCirc[0], *aTgLine[0], *aTgLine[1], Precision::Confusion()));
217 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
218 *aTgLine[0], *aTgLine[1], *aTgLine[0], Precision::Confusion()));
224 return getProperCircle(aCircleBuilder);
227 Circ2dPtr circleByPointAndTwoTangentCurves()
229 const gp_Pnt2d& aPoint = myPassingPoints[0];
230 CurveAdaptorPtr aCurve1 = myTangentShapes[0];
231 CurveAdaptorPtr aCurve2 = myTangentShapes[1];
232 if (!aCurve1 || !aCurve2)
235 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
236 if (aCurve1->GetType() == GeomAbs_Line) {
237 if (aCurve2->GetType() == GeomAbs_Line) {
238 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
239 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve1->Line()),
240 GccEnt::Unqualified(aCurve2->Line()),
241 aPoint, Precision::Confusion()));
242 } else if (aCurve2->GetType() == GeomAbs_Circle) {
243 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
244 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve2->Circle()),
245 GccEnt::Unqualified(aCurve1->Line()),
246 aPoint, Precision::Confusion()));
248 } else if (aCurve1->GetType() == GeomAbs_Circle) {
249 if (aCurve2->GetType() == GeomAbs_Line) {
250 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
251 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve1->Circle()),
252 GccEnt::Unqualified(aCurve2->Line()),
253 aPoint, Precision::Confusion()));
254 } else if (aCurve2->GetType() == GeomAbs_Circle) {
255 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
256 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve2->Circle()),
257 GccEnt::Unqualified(aCurve1->Circle()),
258 aPoint, Precision::Confusion()));
262 return getProperCircle(aCircleBuilder);
265 Circ2dPtr circleByTwoPointsAndTangentCurve()
267 const gp_Pnt2d& aPoint1 = myPassingPoints[0];
268 const gp_Pnt2d& aPoint2 = myPassingPoints[1];
269 CurveAdaptorPtr aCurve = myTangentShapes[0];
273 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
274 if (aCurve->GetType() == GeomAbs_Line) {
275 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
276 GccEnt::Unqualified(aCurve->Line()), aPoint1, aPoint2, Precision::Confusion()));
277 } else if (aCurve->GetType() == GeomAbs_Circle) {
278 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
279 GccEnt::Unqualified(aCurve->Circle()), aPoint1, aPoint2, Precision::Confusion()));
282 return getProperCircle(aCircleBuilder);
285 Circ2dPtr circleByThreePassingPoints()
287 GccAna_Circ2d3Tan aCircleBuilder(myPassingPoints[0],
290 Precision::Confusion());
291 if (aCircleBuilder.NbSolutions() > 0)
292 return Circ2dPtr(new gp_Circ2d(aCircleBuilder.ThisSolution(1)));
296 Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2d3Tan>& theBuilder) const
301 int aNbSol = theBuilder->NbSolutions();
305 int anAppropriateSolution = 1;
306 double aMinDist = Precision::Infinite();
308 double aParSol, aPonTgCurve;
310 for (int i = 1; i <= aNbSol; ++i) {
311 bool isApplicable = false;
312 if (myTangentShapes.size() >= 1) {
313 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
314 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[0]);
316 if (myTangentShapes.size() >= 2 && isApplicable) {
317 theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
318 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[1]);
320 if (myTangentShapes.size() >= 3 && isApplicable) {
321 theBuilder->Tangency3(i, aParSol, aPonTgCurve, aTgPnt);
322 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[2]);
326 double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
327 if (aDist < aMinDist) {
328 anAppropriateSolution = i;
334 return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
338 Circ2dPtr circleByRadiusAndTwoTangentCurves()
340 VectorOfGccCirc aTgCirc;
341 VectorOfGccLine aTgLine;
342 convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
344 if (aTgCirc.size() + aTgLine.size() != 2)
347 std::shared_ptr<GccAna_Circ2d2TanRad> aCircleBuilder;
348 switch (aTgLine.size()) {
350 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
351 *aTgCirc[0], *aTgCirc[1], myRadius, Precision::Confusion()));
354 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
355 *aTgCirc[0], *aTgLine[0], myRadius, Precision::Confusion()));
358 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
359 *aTgLine[0], *aTgLine[1], myRadius, Precision::Confusion()));
365 return getProperCircle(aCircleBuilder);
368 Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2d2TanRad>& theBuilder) const
373 int aNbSol = theBuilder->NbSolutions();
377 int anAppropriateSolution = 1;
378 double aMinDist = Precision::Infinite();
380 double aParSol, aPonTgCurve;
382 for (int i = 1; i <= aNbSol; ++i) {
383 bool isApplicable = false;
384 if (myTangentShapes.size() >= 1) {
385 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
386 isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[0]);
388 if (myTangentShapes.size() >= 2 && isApplicable) {
389 theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
390 isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[1]);
394 double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
395 if (aDist < aMinDist) {
396 anAppropriateSolution = i;
402 return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
406 void convertTangentCurvesToGccEnt(VectorOfGccCirc& theTangentCircles,
407 VectorOfGccLine& theTangentLines)
409 theTangentCircles.reserve(3);
410 theTangentLines.reserve(3);
412 std::vector<CurveAdaptorPtr>::iterator anIt = myTangentShapes.begin();
413 for (; anIt != myTangentShapes.end(); ++anIt) {
414 switch ((*anIt)->GetType()) {
416 theTangentLines.push_back(
417 std::shared_ptr<GccEnt_QualifiedLin>(
418 new GccEnt_QualifiedLin((*anIt)->Line(), GccEnt_unqualified))
422 theTangentCircles.push_back(
423 std::shared_ptr<GccEnt_QualifiedCirc>(
424 new GccEnt_QualifiedCirc((*anIt)->Circle(), GccEnt_unqualified))
434 // boundary parameters of curve are NOT applied
435 static bool isParamInCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
437 if (theCurve->Curve()->IsPeriodic()) {
438 theParameter = ElCLib::InPeriod(theParameter,
439 theCurve->FirstParameter(),
440 theCurve->FirstParameter() + theCurve->Period());
442 return theParameter > theCurve->FirstParameter() &&
443 theParameter < theCurve->LastParameter();
446 // boundary parameters of curve are applied too
447 static bool isParamOnCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
449 if (theCurve->IsPeriodic()) {
450 theParameter = ElCLib::InPeriod(theParameter,
451 theCurve->FirstParameter(),
452 theCurve->FirstParameter() + theCurve->Period());
454 return theParameter >= theCurve->FirstParameter() &&
455 theParameter <= theCurve->LastParameter();
459 Handle(Geom_Plane) myPlane;
460 std::shared_ptr<GeomAPI_Pnt2d> myCenter;
461 std::vector<gp_Pnt2d> myPassingPoints;
462 std::vector<CurveAdaptorPtr> myTangentShapes;
464 std::shared_ptr<GeomAPI_Pnt2d> myClosestPoint;
471 GeomAlgoAPI_Circ2dBuilder::GeomAlgoAPI_Circ2dBuilder(const std::shared_ptr<GeomAPI_Ax3>& thePlane)
477 void GeomAlgoAPI_Circ2dBuilder::setRadius(const double theRadius)
479 myRadius = theRadius;
482 void GeomAlgoAPI_Circ2dBuilder::setCenter(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter)
484 myCenter = theCenter;
487 void GeomAlgoAPI_Circ2dBuilder::addTangentCurve(const std::shared_ptr<GeomAPI_Shape>& theEdge)
489 if (theEdge->isEdge())
490 myTangentShapes.push_back(theEdge);
493 void GeomAlgoAPI_Circ2dBuilder::addPassingPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
495 myPassingPoints.push_back(thePoint);
498 void GeomAlgoAPI_Circ2dBuilder::setClosestPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
500 myClosestPoint = thePoint;
503 std::shared_ptr<GeomAPI_Circ2d> GeomAlgoAPI_Circ2dBuilder::circle(
504 const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
505 const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint,
506 const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPoint)
508 std::shared_ptr<GeomAPI_Ax3> aPlane(new GeomAPI_Ax3);
510 GeomAlgoAPI_Circ2dBuilder aBuilder(aPlane);
511 aBuilder.addPassingPoint(theFirstPoint);
512 aBuilder.addPassingPoint(theSecondPoint);
513 aBuilder.addPassingPoint(theThirdPoint);
514 return aBuilder.circle();
517 std::shared_ptr<GeomAPI_Circ2d> GeomAlgoAPI_Circ2dBuilder::circle()
519 CircleBuilder aCircleBuilder(myPlane);
520 aCircleBuilder.setCenter(myCenter);
521 aCircleBuilder.setTangentCurves(myTangentShapes);
522 aCircleBuilder.setPassingPoints(myPassingPoints);
523 aCircleBuilder.setClosestPoint(myClosestPoint);
524 aCircleBuilder.setRadius(myRadius);
525 Circ2dPtr aCirc2d = aCircleBuilder.circle();
527 std::shared_ptr<GeomAPI_Circ2d> aCircle;
529 const gp_Pnt2d& aCenter = aCirc2d->Location();
530 const gp_Dir2d& aXAxis = aCirc2d->Position().XDirection();
532 std::shared_ptr<GeomAPI_Pnt2d> aCircleCenter(new GeomAPI_Pnt2d(aCenter.X(), aCenter.Y()));
533 std::shared_ptr<GeomAPI_Dir2d> aCircleDir(new GeomAPI_Dir2d(aXAxis.X(), aXAxis.Y()));
535 aCircle = std::shared_ptr<GeomAPI_Circ2d>(
536 new GeomAPI_Circ2d(aCircleCenter, aCircleDir, aCirc2d->Radius()));