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 aCurve->Line().Distance(aCenter) > Precision::Confusion()) {
144 aCircleBuilder = std::shared_ptr<GccAna_Circ2dTanCen>(
145 new GccAna_Circ2dTanCen(aCurve->Line(), aCenter));
146 } else if (aCurve->GetType() == GeomAbs_Circle) {
147 aCircleBuilder = std::shared_ptr<GccAna_Circ2dTanCen>(new GccAna_Circ2dTanCen(
148 GccEnt::Unqualified(aCurve->Circle()), aCenter, Precision::Confusion()));
151 return getProperCircle(aCircleBuilder);
154 Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2dTanCen>& theBuilder) const
159 CurveAdaptorPtr aCurve = myTangentShapes[0];
161 int aNbSol = theBuilder->NbSolutions();
165 int anAppropriateSolution = 1;
166 double aMinDist = Precision::Infinite();
168 double aParSol, aPonTgCurve;
170 for (int i = 1; i <= aNbSol && aNbSol > 1 && aCurve; ++i) {
171 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
172 if (isParamOnCurve(aPonTgCurve, aCurve)) {
173 double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
174 if (aDist < aMinDist) {
175 anAppropriateSolution = i;
181 return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
184 double distanceToClosestPoint(const gp_Circ2d& theCirc) const
186 if (myClosestPoint) {
187 double aDist = myClosestPoint->impl<gp_Pnt2d>().Distance(theCirc.Location());
188 return fabs(aDist - theCirc.Radius());
194 Circ2dPtr circleByThreeTangentCurves()
196 VectorOfGccCirc aTgCirc;
197 VectorOfGccLine aTgLine;
198 convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
200 if (aTgCirc.size() + aTgLine.size() != 3)
203 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
204 switch (aTgLine.size()) {
206 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
207 *aTgCirc[0], *aTgCirc[1], *aTgCirc[2], Precision::Confusion()));
210 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
211 *aTgCirc[0], *aTgCirc[1], *aTgLine[0], Precision::Confusion()));
214 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
215 *aTgCirc[0], *aTgLine[0], *aTgLine[1], Precision::Confusion()));
218 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
219 *aTgLine[0], *aTgLine[1], *aTgLine[0], Precision::Confusion()));
225 return getProperCircle(aCircleBuilder);
228 Circ2dPtr circleByPointAndTwoTangentCurves()
230 const gp_Pnt2d& aPoint = myPassingPoints[0];
231 CurveAdaptorPtr aCurve1 = myTangentShapes[0];
232 CurveAdaptorPtr aCurve2 = myTangentShapes[1];
233 if (!aCurve1 || !aCurve2)
236 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
237 if (aCurve1->GetType() == GeomAbs_Line) {
238 if (aCurve2->GetType() == GeomAbs_Line) {
239 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
240 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve1->Line()),
241 GccEnt::Unqualified(aCurve2->Line()),
242 aPoint, Precision::Confusion()));
243 } else if (aCurve2->GetType() == GeomAbs_Circle) {
244 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
245 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve2->Circle()),
246 GccEnt::Unqualified(aCurve1->Line()),
247 aPoint, Precision::Confusion()));
249 } else if (aCurve1->GetType() == GeomAbs_Circle) {
250 if (aCurve2->GetType() == GeomAbs_Line) {
251 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
252 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve1->Circle()),
253 GccEnt::Unqualified(aCurve2->Line()),
254 aPoint, Precision::Confusion()));
255 } else if (aCurve2->GetType() == GeomAbs_Circle) {
256 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
257 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve2->Circle()),
258 GccEnt::Unqualified(aCurve1->Circle()),
259 aPoint, Precision::Confusion()));
263 return getProperCircle(aCircleBuilder);
266 Circ2dPtr circleByTwoPointsAndTangentCurve()
268 const gp_Pnt2d& aPoint1 = myPassingPoints[0];
269 const gp_Pnt2d& aPoint2 = myPassingPoints[1];
270 CurveAdaptorPtr aCurve = myTangentShapes[0];
274 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
275 if (aCurve->GetType() == GeomAbs_Line) {
276 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
277 GccEnt::Unqualified(aCurve->Line()), aPoint1, aPoint2, Precision::Confusion()));
278 } else if (aCurve->GetType() == GeomAbs_Circle) {
279 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
280 GccEnt::Unqualified(aCurve->Circle()), aPoint1, aPoint2, Precision::Confusion()));
283 return getProperCircle(aCircleBuilder);
286 Circ2dPtr circleByThreePassingPoints()
288 GccAna_Circ2d3Tan aCircleBuilder(myPassingPoints[0],
291 Precision::Confusion());
292 if (aCircleBuilder.NbSolutions() > 0)
293 return Circ2dPtr(new gp_Circ2d(aCircleBuilder.ThisSolution(1)));
297 Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2d3Tan>& theBuilder) const
302 int aNbSol = theBuilder->NbSolutions();
306 int anAppropriateSolution = 1;
307 double aMinDist = Precision::Infinite();
309 double aParSol, aPonTgCurve;
311 for (int i = 1; i <= aNbSol && aNbSol > 1; ++i) {
312 bool isApplicable = false;
313 if (myTangentShapes.size() >= 1) {
314 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
315 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[0]);
317 if (myTangentShapes.size() >= 2 && isApplicable) {
318 theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
319 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[1]);
321 if (myTangentShapes.size() >= 3 && isApplicable) {
322 theBuilder->Tangency3(i, aParSol, aPonTgCurve, aTgPnt);
323 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[2]);
327 double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
328 if (aDist < aMinDist) {
329 anAppropriateSolution = i;
335 return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
339 Circ2dPtr circleByRadiusAndTwoTangentCurves()
341 VectorOfGccCirc aTgCirc;
342 VectorOfGccLine aTgLine;
343 convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
345 if (aTgCirc.size() + aTgLine.size() != 2)
348 std::shared_ptr<GccAna_Circ2d2TanRad> aCircleBuilder;
349 switch (aTgLine.size()) {
351 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
352 *aTgCirc[0], *aTgCirc[1], myRadius, Precision::Confusion()));
355 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
356 *aTgCirc[0], *aTgLine[0], myRadius, Precision::Confusion()));
359 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
360 *aTgLine[0], *aTgLine[1], myRadius, Precision::Confusion()));
366 return getProperCircle(aCircleBuilder);
369 Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2d2TanRad>& theBuilder) const
374 int aNbSol = theBuilder->NbSolutions();
378 int anAppropriateSolution = 1;
379 double aMinDist = Precision::Infinite();
381 double aParSol, aPonTgCurve;
383 for (int i = 1; i <= aNbSol && aNbSol > 1; ++i) {
384 bool isApplicable = false;
385 if (myTangentShapes.size() >= 1) {
386 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
387 isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[0]);
389 if (myTangentShapes.size() >= 2 && isApplicable) {
390 theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
391 isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[1]);
395 double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
396 if (aDist < aMinDist) {
397 anAppropriateSolution = i;
403 return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
407 void convertTangentCurvesToGccEnt(VectorOfGccCirc& theTangentCircles,
408 VectorOfGccLine& theTangentLines)
410 theTangentCircles.reserve(3);
411 theTangentLines.reserve(3);
413 std::vector<CurveAdaptorPtr>::iterator anIt = myTangentShapes.begin();
414 for (; anIt != myTangentShapes.end(); ++anIt) {
415 switch ((*anIt)->GetType()) {
417 theTangentLines.push_back(
418 std::shared_ptr<GccEnt_QualifiedLin>(
419 new GccEnt_QualifiedLin((*anIt)->Line(), GccEnt_unqualified))
423 theTangentCircles.push_back(
424 std::shared_ptr<GccEnt_QualifiedCirc>(
425 new GccEnt_QualifiedCirc((*anIt)->Circle(), GccEnt_unqualified))
435 static void adjustPeriod(double& theParameter, const CurveAdaptorPtr& theCurve)
437 if (theCurve->Curve()->IsPeriodic()) {
438 theParameter = ElCLib::InPeriod(theParameter,
439 theCurve->FirstParameter(),
440 theCurve->FirstParameter() + theCurve->Period());
444 // boundary parameters of curve are NOT applied
445 static bool isParamInCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
447 adjustPeriod(theParameter, theCurve);
448 return theParameter > theCurve->FirstParameter() &&
449 theParameter < theCurve->LastParameter();
452 // boundary parameters of curve are applied too
453 static bool isParamOnCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
455 adjustPeriod(theParameter, theCurve);
456 return theParameter >= theCurve->FirstParameter() &&
457 theParameter <= theCurve->LastParameter();
461 Handle(Geom_Plane) myPlane;
462 std::shared_ptr<GeomAPI_Pnt2d> myCenter;
463 std::vector<gp_Pnt2d> myPassingPoints;
464 std::vector<CurveAdaptorPtr> myTangentShapes;
466 std::shared_ptr<GeomAPI_Pnt2d> myClosestPoint;
473 GeomAlgoAPI_Circ2dBuilder::GeomAlgoAPI_Circ2dBuilder(const std::shared_ptr<GeomAPI_Ax3>& thePlane)
479 void GeomAlgoAPI_Circ2dBuilder::setRadius(const double theRadius)
481 myRadius = theRadius;
484 void GeomAlgoAPI_Circ2dBuilder::setCenter(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter)
486 myCenter = theCenter;
489 void GeomAlgoAPI_Circ2dBuilder::addTangentCurve(const std::shared_ptr<GeomAPI_Shape>& theEdge)
491 if (theEdge->isEdge())
492 myTangentShapes.push_back(theEdge);
495 void GeomAlgoAPI_Circ2dBuilder::addPassingPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
497 myPassingPoints.push_back(thePoint);
500 void GeomAlgoAPI_Circ2dBuilder::setClosestPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
502 myClosestPoint = thePoint;
505 std::shared_ptr<GeomAPI_Circ2d> GeomAlgoAPI_Circ2dBuilder::circle(
506 const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
507 const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint,
508 const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPoint)
510 std::shared_ptr<GeomAPI_Ax3> aPlane(new GeomAPI_Ax3);
512 GeomAlgoAPI_Circ2dBuilder aBuilder(aPlane);
513 aBuilder.addPassingPoint(theFirstPoint);
514 aBuilder.addPassingPoint(theSecondPoint);
515 aBuilder.addPassingPoint(theThirdPoint);
516 return aBuilder.circle();
519 std::shared_ptr<GeomAPI_Circ2d> GeomAlgoAPI_Circ2dBuilder::circle()
521 CircleBuilder aCircleBuilder(myPlane);
522 aCircleBuilder.setCenter(myCenter);
523 aCircleBuilder.setTangentCurves(myTangentShapes);
524 aCircleBuilder.setPassingPoints(myPassingPoints);
525 aCircleBuilder.setClosestPoint(myClosestPoint);
526 aCircleBuilder.setRadius(myRadius);
527 Circ2dPtr aCirc2d = aCircleBuilder.circle();
529 std::shared_ptr<GeomAPI_Circ2d> aCircle;
531 const gp_Pnt2d& aCenter = aCirc2d->Location();
532 const gp_Dir2d& aXAxis = aCirc2d->Position().XDirection();
534 std::shared_ptr<GeomAPI_Pnt2d> aCircleCenter(new GeomAPI_Pnt2d(aCenter.X(), aCenter.Y()));
535 std::shared_ptr<GeomAPI_Dir2d> aCircleDir(new GeomAPI_Dir2d(aXAxis.X(), aXAxis.Y()));
537 aCircle = std::shared_ptr<GeomAPI_Circ2d>(
538 new GeomAPI_Circ2d(aCircleCenter, aCircleDir, aCirc2d->Radius()));