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 GccAna_Circ2dTanCen aBuilder(myPassingPoints[0], aCenter);
129 if (aBuilder.NbSolutions() > 0)
130 return Circ2dPtr(new gp_Circ2d(aBuilder.ThisSolution(1)));
134 Circ2dPtr circleByCenterAndTangent()
136 const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
137 CurveAdaptorPtr aCurve = myTangentShapes[0];
139 std::shared_ptr<GccAna_Circ2dTanCen> aCircleBuilder;
140 if (aCurve->GetType() == GeomAbs_Line) {
141 aCircleBuilder = std::shared_ptr<GccAna_Circ2dTanCen>(
142 new GccAna_Circ2dTanCen(aCurve->Line(), aCenter));
143 } else if (aCurve->GetType() == GeomAbs_Circle) {
144 aCircleBuilder = std::shared_ptr<GccAna_Circ2dTanCen>(new GccAna_Circ2dTanCen(
145 GccEnt::Unqualified(aCurve->Circle()), aCenter, Precision::Confusion()));
148 return getProperCircle(aCircleBuilder);
151 Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2dTanCen>& theBuilder) const
156 CurveAdaptorPtr aCurve = myTangentShapes[0];
158 int aNbSol = theBuilder->NbSolutions();
162 int anAppropriateSolution = 1;
163 double aMinDist = Precision::Infinite();
165 double aParSol, aPonTgCurve;
167 for (int i = 1; i <= aNbSol && aCurve; ++i) {
168 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
169 if (isParamOnCurve(aPonTgCurve, aCurve)) {
170 double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
171 if (aDist < aMinDist) {
172 anAppropriateSolution = i;
178 return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
181 double distanceToClosestPoint(const gp_Circ2d& theCirc) const
183 if (myClosestPoint) {
184 double aDist = myClosestPoint->impl<gp_Pnt2d>().Distance(theCirc.Location());
185 return fabs(aDist - theCirc.Radius());
191 Circ2dPtr circleByThreeTangentCurves()
193 VectorOfGccCirc aTgCirc;
194 VectorOfGccLine aTgLine;
195 convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
197 if (aTgCirc.size() + aTgLine.size() != 3)
200 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
201 switch (aTgLine.size()) {
203 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
204 *aTgCirc[0], *aTgCirc[1], *aTgCirc[2], Precision::Confusion()));
207 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
208 *aTgCirc[0], *aTgCirc[1], *aTgLine[0], Precision::Confusion()));
211 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
212 *aTgCirc[0], *aTgLine[0], *aTgLine[1], Precision::Confusion()));
215 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
216 *aTgLine[0], *aTgLine[1], *aTgLine[0], Precision::Confusion()));
222 return getProperCircle(aCircleBuilder);
225 Circ2dPtr circleByPointAndTwoTangentCurves()
227 const gp_Pnt2d& aPoint = myPassingPoints[0];
228 CurveAdaptorPtr aCurve1 = myTangentShapes[0];
229 CurveAdaptorPtr aCurve2 = myTangentShapes[1];
230 if (!aCurve1 || !aCurve2)
233 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
234 if (aCurve1->GetType() == GeomAbs_Line) {
235 if (aCurve2->GetType() == GeomAbs_Line) {
236 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
237 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve1->Line()),
238 GccEnt::Unqualified(aCurve2->Line()),
239 aPoint, Precision::Confusion()));
240 } else if (aCurve2->GetType() == GeomAbs_Circle) {
241 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
242 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve2->Circle()),
243 GccEnt::Unqualified(aCurve1->Line()),
244 aPoint, Precision::Confusion()));
246 } else if (aCurve1->GetType() == GeomAbs_Circle) {
247 if (aCurve2->GetType() == GeomAbs_Line) {
248 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
249 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve1->Circle()),
250 GccEnt::Unqualified(aCurve2->Line()),
251 aPoint, Precision::Confusion()));
252 } else if (aCurve2->GetType() == GeomAbs_Circle) {
253 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
254 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve2->Circle()),
255 GccEnt::Unqualified(aCurve1->Circle()),
256 aPoint, Precision::Confusion()));
260 return getProperCircle(aCircleBuilder);
263 Circ2dPtr circleByTwoPointsAndTangentCurve()
265 const gp_Pnt2d& aPoint1 = myPassingPoints[0];
266 const gp_Pnt2d& aPoint2 = myPassingPoints[1];
267 CurveAdaptorPtr aCurve = myTangentShapes[0];
271 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
272 if (aCurve->GetType() == GeomAbs_Line) {
273 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
274 GccEnt::Unqualified(aCurve->Line()), aPoint1, aPoint2, Precision::Confusion()));
275 } else if (aCurve->GetType() == GeomAbs_Circle) {
276 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
277 GccEnt::Unqualified(aCurve->Circle()), aPoint1, aPoint2, Precision::Confusion()));
280 return getProperCircle(aCircleBuilder);
283 Circ2dPtr circleByThreePassingPoints()
285 GccAna_Circ2d3Tan aCircleBuilder(myPassingPoints[0],
288 Precision::Confusion());
289 if (aCircleBuilder.NbSolutions() > 0)
290 return Circ2dPtr(new gp_Circ2d(aCircleBuilder.ThisSolution(1)));
294 Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2d3Tan>& theBuilder) const
299 int aNbSol = theBuilder->NbSolutions();
303 int anAppropriateSolution = 1;
304 double aMinDist = Precision::Infinite();
306 double aParSol, aPonTgCurve;
308 for (int i = 1; i <= aNbSol; ++i) {
309 bool isApplicable = false;
310 if (myTangentShapes.size() >= 1) {
311 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
312 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[0]);
314 if (myTangentShapes.size() >= 2 && isApplicable) {
315 theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
316 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[1]);
318 if (myTangentShapes.size() >= 3 && isApplicable) {
319 theBuilder->Tangency3(i, aParSol, aPonTgCurve, aTgPnt);
320 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[2]);
324 double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
325 if (aDist < aMinDist) {
326 anAppropriateSolution = i;
332 return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
336 Circ2dPtr circleByRadiusAndTwoTangentCurves()
338 VectorOfGccCirc aTgCirc;
339 VectorOfGccLine aTgLine;
340 convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
342 if (aTgCirc.size() + aTgLine.size() != 2)
345 std::shared_ptr<GccAna_Circ2d2TanRad> aCircleBuilder;
346 switch (aTgLine.size()) {
348 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
349 *aTgCirc[0], *aTgCirc[1], myRadius, Precision::Confusion()));
352 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
353 *aTgCirc[0], *aTgLine[0], myRadius, Precision::Confusion()));
356 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
357 *aTgLine[0], *aTgLine[1], myRadius, Precision::Confusion()));
363 return getProperCircle(aCircleBuilder);
366 Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2d2TanRad>& theBuilder) const
371 int aNbSol = theBuilder->NbSolutions();
375 int anAppropriateSolution = 1;
376 double aMinDist = Precision::Infinite();
378 double aParSol, aPonTgCurve;
380 for (int i = 1; i <= aNbSol; ++i) {
381 bool isApplicable = false;
382 if (myTangentShapes.size() >= 1) {
383 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
384 isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[0]);
386 if (myTangentShapes.size() >= 2 && isApplicable) {
387 theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
388 isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[1]);
392 double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
393 if (aDist < aMinDist) {
394 anAppropriateSolution = i;
400 return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
404 void convertTangentCurvesToGccEnt(VectorOfGccCirc& theTangentCircles,
405 VectorOfGccLine& theTangentLines)
407 theTangentCircles.reserve(3);
408 theTangentLines.reserve(3);
410 std::vector<CurveAdaptorPtr>::iterator anIt = myTangentShapes.begin();
411 for (; anIt != myTangentShapes.end(); ++anIt) {
412 switch ((*anIt)->GetType()) {
414 theTangentLines.push_back(
415 std::shared_ptr<GccEnt_QualifiedLin>(
416 new GccEnt_QualifiedLin((*anIt)->Line(), GccEnt_unqualified))
420 theTangentCircles.push_back(
421 std::shared_ptr<GccEnt_QualifiedCirc>(
422 new GccEnt_QualifiedCirc((*anIt)->Circle(), GccEnt_unqualified))
432 // boundary parameters of curve are NOT applied
433 static bool isParamInCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
435 if (theCurve->Curve()->IsPeriodic()) {
436 theParameter = ElCLib::InPeriod(theParameter,
437 theCurve->FirstParameter(),
438 theCurve->FirstParameter() + theCurve->Period());
440 return theParameter > theCurve->FirstParameter() &&
441 theParameter < theCurve->LastParameter();
444 // boundary parameters of curve are applied too
445 static bool isParamOnCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
447 if (theCurve->IsPeriodic()) {
448 theParameter = ElCLib::InPeriod(theParameter,
449 theCurve->FirstParameter(),
450 theCurve->FirstParameter() + theCurve->Period());
452 return theParameter >= theCurve->FirstParameter() &&
453 theParameter <= theCurve->LastParameter();
457 Handle(Geom_Plane) myPlane;
458 std::shared_ptr<GeomAPI_Pnt2d> myCenter;
459 std::vector<gp_Pnt2d> myPassingPoints;
460 std::vector<CurveAdaptorPtr> myTangentShapes;
462 std::shared_ptr<GeomAPI_Pnt2d> myClosestPoint;
469 GeomAlgoAPI_Circ2dBuilder::GeomAlgoAPI_Circ2dBuilder(const std::shared_ptr<GeomAPI_Ax3>& thePlane)
475 void GeomAlgoAPI_Circ2dBuilder::setRadius(const double theRadius)
477 myRadius = theRadius;
480 void GeomAlgoAPI_Circ2dBuilder::setCenter(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter)
482 myCenter = theCenter;
485 void GeomAlgoAPI_Circ2dBuilder::addTangentCurve(const std::shared_ptr<GeomAPI_Shape>& theEdge)
487 if (theEdge->isEdge())
488 myTangentShapes.push_back(theEdge);
491 void GeomAlgoAPI_Circ2dBuilder::addPassingPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
493 myPassingPoints.push_back(thePoint);
496 void GeomAlgoAPI_Circ2dBuilder::setClosestPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
498 myClosestPoint = thePoint;
501 std::shared_ptr<GeomAPI_Circ2d> GeomAlgoAPI_Circ2dBuilder::circle(
502 const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
503 const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint,
504 const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPoint)
506 std::shared_ptr<GeomAPI_Ax3> aPlane(new GeomAPI_Ax3);
508 GeomAlgoAPI_Circ2dBuilder aBuilder(aPlane);
509 aBuilder.addPassingPoint(theFirstPoint);
510 aBuilder.addPassingPoint(theSecondPoint);
511 aBuilder.addPassingPoint(theThirdPoint);
512 return aBuilder.circle();
515 std::shared_ptr<GeomAPI_Circ2d> GeomAlgoAPI_Circ2dBuilder::circle()
517 CircleBuilder aCircleBuilder(myPlane);
518 aCircleBuilder.setCenter(myCenter);
519 aCircleBuilder.setTangentCurves(myTangentShapes);
520 aCircleBuilder.setPassingPoints(myPassingPoints);
521 aCircleBuilder.setClosestPoint(myClosestPoint);
522 aCircleBuilder.setRadius(myRadius);
523 Circ2dPtr aCirc2d = aCircleBuilder.circle();
525 std::shared_ptr<GeomAPI_Circ2d> aCircle;
527 const gp_Pnt2d& aCenter = aCirc2d->Location();
528 const gp_Dir2d& aXAxis = aCirc2d->XAxis().Direction();
530 std::shared_ptr<GeomAPI_Pnt2d> aCircleCenter(new GeomAPI_Pnt2d(aCenter.X(), aCenter.Y()));
531 std::shared_ptr<GeomAPI_Dir2d> aCircleDir(new GeomAPI_Dir2d(aXAxis.X(), aXAxis.Y()));
533 aCircle = std::shared_ptr<GeomAPI_Circ2d>(
534 new GeomAPI_Circ2d(aCircleCenter, aCircleDir, aCirc2d->Radius()));