1 // Copyright (C) 2014-2020 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include <GeomAlgoAPI_Circ2dBuilder.h>
21 #include <GeomAPI_Ax3.h>
22 #include <GeomAPI_Circ2d.h>
23 #include <GeomAPI_Pnt2d.h>
24 #include <GeomAPI_Dir2d.h>
25 #include <GeomAPI_Shape.h>
27 #include <BRep_Tool.hxx>
29 #include <GccAna_Circ2d2TanOn.hxx>
30 #include <GccAna_Circ2d2TanRad.hxx>
31 #include <GccAna_Circ2d3Tan.hxx>
32 #include <GccAna_Circ2dTanCen.hxx>
34 #include <GccEnt_QualifiedCirc.hxx>
35 #include <GccEnt_QualifiedLin.hxx>
36 #include <Geom2dAdaptor_Curve.hxx>
37 #include <Geom_Plane.hxx>
39 #include <TopoDS_Edge.hxx>
43 typedef std::shared_ptr<gp_Circ2d> Circ2dPtr;
44 typedef std::shared_ptr<Geom2dAdaptor_Curve> CurveAdaptorPtr;
45 typedef std::vector< std::shared_ptr<GccEnt_QualifiedCirc> > VectorOfGccCirc;
46 typedef std::vector< std::shared_ptr<GccEnt_QualifiedLin> > VectorOfGccLine;
49 // Provide different mechanisms to create circle:
50 // * by passing points
52 // * by transversal line
53 // * with specified radius
58 CircleBuilder(const std::shared_ptr<GeomAPI_Ax3>& theBasePlane)
59 : myPlane(new Geom_Plane(theBasePlane->impl<gp_Ax3>())),
63 void setRadius(const double theRadius)
64 { myRadius = theRadius; }
66 void setCenter(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter)
67 { myCenter = theCenter; }
69 void setTangentCurves(const std::vector< std::shared_ptr<GeomAPI_Shape> >& theEdges)
71 std::vector< std::shared_ptr<GeomAPI_Shape> >::const_iterator anEdgeIt;
72 for (anEdgeIt = theEdges.begin(); anEdgeIt != theEdges.end(); ++anEdgeIt) {
73 const TopoDS_Edge& anEdge = TopoDS::Edge((*anEdgeIt)->impl<TopoDS_Shape>());
77 Handle(Geom2d_Curve) aCurve = BRep_Tool::CurveOnSurface(anEdge, myPlane, aLoc, aFirst, aLast);
78 CurveAdaptorPtr aCurveAdaptor(new Geom2dAdaptor_Curve(aCurve, aFirst, aLast));
80 // sort curves (circles should become first)
81 if (aCurveAdaptor->GetType() == GeomAbs_Circle)
82 myTangentShapes.insert(myTangentShapes.begin(), aCurveAdaptor);
84 myTangentShapes.push_back(aCurveAdaptor);
88 void setTransversalLine(const std::shared_ptr<GeomAPI_Shape>& theLine)
93 const TopoDS_Edge& anEdge = TopoDS::Edge(theLine->impl<TopoDS_Shape>());
97 Handle(Geom2d_Curve) aCurve = BRep_Tool::CurveOnSurface(anEdge, myPlane, aLoc, aFirst, aLast);
98 myTransversalLine = CurveAdaptorPtr(new Geom2dAdaptor_Curve(aCurve, aFirst, aLast));
101 void setPassingPoints(const std::vector< std::shared_ptr<GeomAPI_Pnt2d> >& thePoints)
103 std::vector< std::shared_ptr<GeomAPI_Pnt2d> >::const_iterator aPIt;
104 for (aPIt = thePoints.begin(); aPIt != thePoints.end(); ++aPIt)
105 myPassingPoints.push_back((*aPIt)->impl<gp_Pnt2d>());
108 void setClosestPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
109 { myClosestPoint = thePoint; }
116 if (myPassingPoints.size() == 1)
117 aResult = circleByCenterAndPassingPoint();
118 else if (myTangentShapes.size() == 1)
119 aResult = circleByCenterAndTangent();
120 else if (myRadius > 0.0)
121 aResult = circleByCenterAndRadius();
122 } else if (myRadius > 0.0) {
123 if (myTangentShapes.size() == 2)
124 aResult = circleByRadiusAndTwoTangentCurves();
126 switch (myPassingPoints.size()) {
128 aResult = circleByThreeTangentCurves();
131 aResult = circleByPointAndTwoTangentCurves();
134 if (myTransversalLine)
135 aResult = circleByTwoPointsAndTransversalLine();
137 aResult = circleByTwoPointsAndTangentCurve();
141 aResult = circleByThreePassingPoints();
151 Circ2dPtr circleByCenterAndRadius()
153 const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
154 return Circ2dPtr(new gp_Circ2d(gp_Ax2d(aCenter, gp::DX2d()), myRadius));
157 Circ2dPtr circleByCenterAndPassingPoint()
159 const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
160 if (aCenter.SquareDistance(myPassingPoints[0]) > Precision::SquareConfusion()) {
161 GccAna_Circ2dTanCen aBuilder(myPassingPoints[0], aCenter);
162 if (aBuilder.NbSolutions() > 0)
163 return Circ2dPtr(new gp_Circ2d(aBuilder.ThisSolution(1)));
168 Circ2dPtr circleByCenterAndTangent()
170 const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
171 CurveAdaptorPtr aCurve = myTangentShapes[0];
173 std::shared_ptr<GccAna_Circ2dTanCen> aCircleBuilder;
174 if (aCurve->GetType() == GeomAbs_Line &&
175 aCurve->Line().Distance(aCenter) > Precision::Confusion()) {
176 aCircleBuilder = std::shared_ptr<GccAna_Circ2dTanCen>(
177 new GccAna_Circ2dTanCen(aCurve->Line(), aCenter));
178 } else if (aCurve->GetType() == GeomAbs_Circle) {
179 aCircleBuilder = std::shared_ptr<GccAna_Circ2dTanCen>(new GccAna_Circ2dTanCen(
180 GccEnt::Unqualified(aCurve->Circle()), aCenter, Precision::Confusion()));
183 return getProperCircle(aCircleBuilder);
186 Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2dTanCen>& theBuilder) const
191 CurveAdaptorPtr aCurve = myTangentShapes[0];
193 int aNbSol = theBuilder->NbSolutions();
197 int anAppropriateSolution = 1;
198 double aMinDist = Precision::Infinite();
200 double aParSol, aPonTgCurve;
202 for (int i = 1; i <= aNbSol && aNbSol > 1 && aCurve; ++i) {
203 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
204 if (isParamOnCurve(aPonTgCurve, aCurve)) {
205 double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
206 if (aDist < aMinDist) {
207 anAppropriateSolution = i;
213 return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
216 double distanceToClosestPoint(const gp_Circ2d& theCirc) const
218 if (myClosestPoint) {
219 double aDist = myClosestPoint->impl<gp_Pnt2d>().Distance(theCirc.Location());
220 return fabs(aDist - theCirc.Radius());
226 Circ2dPtr circleByThreeTangentCurves()
228 VectorOfGccCirc aTgCirc;
229 VectorOfGccLine aTgLine;
230 convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
232 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
233 if (aTgCirc.size() + aTgLine.size() == 3) {
234 switch (aTgLine.size()) {
236 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
237 *aTgCirc[0], *aTgCirc[1], *aTgCirc[2], Precision::Confusion()));
240 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
241 *aTgCirc[0], *aTgCirc[1], *aTgLine[0], Precision::Confusion()));
244 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
245 *aTgCirc[0], *aTgLine[0], *aTgLine[1], Precision::Confusion()));
248 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
249 *aTgLine[0], *aTgLine[1], *aTgLine[2], Precision::Confusion()));
256 return getProperCircle(aCircleBuilder);
259 Circ2dPtr circleByPointAndTwoTangentCurves()
261 const gp_Pnt2d& aPoint = myPassingPoints[0];
263 VectorOfGccCirc aTgCirc;
264 VectorOfGccLine aTgLine;
265 convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
267 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
268 if (aTgCirc.size() + aTgLine.size() == 2) {
269 switch (aTgLine.size()) {
271 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
272 *aTgCirc[0], *aTgCirc[1], aPoint, Precision::Confusion()));
275 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
276 *aTgCirc[0], *aTgLine[0], aPoint, Precision::Confusion()));
279 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
280 *aTgLine[0], *aTgLine[1], aPoint, Precision::Confusion()));
287 return getProperCircle(aCircleBuilder);
290 Circ2dPtr circleByTwoPointsAndTangentCurve()
292 const gp_Pnt2d& aPoint1 = myPassingPoints[0];
293 const gp_Pnt2d& aPoint2 = myPassingPoints[1];
294 CurveAdaptorPtr aCurve = myTangentShapes[0];
296 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
298 if (aCurve->GetType() == GeomAbs_Line) {
299 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
300 GccEnt::Unqualified(aCurve->Line()), aPoint1, aPoint2, Precision::Confusion()));
302 else if (aCurve->GetType() == GeomAbs_Circle) {
303 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
304 GccEnt::Unqualified(aCurve->Circle()), aPoint1, aPoint2, Precision::Confusion()));
308 return getProperCircle(aCircleBuilder);
311 Circ2dPtr circleByThreePassingPoints()
313 GccAna_Circ2d3Tan aCircleBuilder(myPassingPoints[0],
316 Precision::Confusion());
317 if (aCircleBuilder.NbSolutions() > 0)
318 return Circ2dPtr(new gp_Circ2d(aCircleBuilder.ThisSolution(1)));
322 Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2d3Tan>& theBuilder) const
327 int aNbSol = theBuilder->NbSolutions();
331 int anAppropriateSolution = 1;
332 double aMinDist = Precision::Infinite();
334 double aParSol, aPonTgCurve;
336 for (int i = 1; i <= aNbSol && aNbSol > 1; ++i) {
337 bool isApplicable = false;
338 if (myTangentShapes.size() >= 1) {
339 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
340 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[0]);
342 if (myTangentShapes.size() >= 2 && isApplicable) {
343 theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
344 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[1]);
346 if (myTangentShapes.size() >= 3 && isApplicable) {
347 theBuilder->Tangency3(i, aParSol, aPonTgCurve, aTgPnt);
348 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[2]);
352 double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
353 if (aDist < aMinDist) {
354 anAppropriateSolution = i;
360 return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
364 Circ2dPtr circleByTwoPointsAndTransversalLine()
366 const gp_Pnt2d& aPoint1 = myPassingPoints[0];
367 const gp_Pnt2d& aPoint2 = myPassingPoints[1];
369 if (myTransversalLine && myTransversalLine->GetType() == GeomAbs_Line) {
370 GccAna_Circ2d2TanOn aCircleBuilder(aPoint1, aPoint2, myTransversalLine->Line(),
371 Precision::Confusion());
372 if (aCircleBuilder.NbSolutions() > 0)
373 return Circ2dPtr(new gp_Circ2d(aCircleBuilder.ThisSolution(1)));
380 Circ2dPtr circleByRadiusAndTwoTangentCurves()
382 VectorOfGccCirc aTgCirc;
383 VectorOfGccLine aTgLine;
384 convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
386 std::shared_ptr<GccAna_Circ2d2TanRad> aCircleBuilder;
387 if (aTgCirc.size() + aTgLine.size() == 2) {
388 switch (aTgLine.size()) {
390 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
391 *aTgCirc[0], *aTgCirc[1], myRadius, Precision::Confusion()));
394 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
395 *aTgCirc[0], *aTgLine[0], myRadius, Precision::Confusion()));
398 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
399 *aTgLine[0], *aTgLine[1], myRadius, Precision::Confusion()));
406 return getProperCircle(aCircleBuilder);
409 Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2d2TanRad>& theBuilder) const
414 int aNbSol = theBuilder->NbSolutions();
418 int anAppropriateSolution = 1;
419 double aMinDist = Precision::Infinite();
421 double aParSol, aPonTgCurve;
423 for (int i = 1; i <= aNbSol && aNbSol > 1; ++i) {
424 bool isApplicable = false;
425 if (myTangentShapes.size() >= 1) {
426 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
427 isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[0]);
429 if (myTangentShapes.size() >= 2 && isApplicable) {
430 theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
431 isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[1]);
435 double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
436 if (aDist < aMinDist) {
437 anAppropriateSolution = i;
443 return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
447 void convertTangentCurvesToGccEnt(VectorOfGccCirc& theTangentCircles,
448 VectorOfGccLine& theTangentLines)
450 theTangentCircles.reserve(3);
451 theTangentLines.reserve(3);
453 std::vector<CurveAdaptorPtr>::iterator anIt = myTangentShapes.begin();
454 for (; anIt != myTangentShapes.end(); ++anIt) {
455 switch ((*anIt)->GetType()) {
457 theTangentLines.push_back(
458 std::shared_ptr<GccEnt_QualifiedLin>(
459 new GccEnt_QualifiedLin((*anIt)->Line(), GccEnt_unqualified))
463 theTangentCircles.push_back(
464 std::shared_ptr<GccEnt_QualifiedCirc>(
465 new GccEnt_QualifiedCirc((*anIt)->Circle(), GccEnt_unqualified))
475 static void adjustPeriod(double& theParameter, const CurveAdaptorPtr& theCurve)
477 if (theCurve->Curve()->IsPeriodic()) {
478 theParameter = ElCLib::InPeriod(theParameter,
479 theCurve->FirstParameter(),
480 theCurve->FirstParameter() + theCurve->Period());
484 // boundary parameters of curve are NOT applied
485 static bool isParamInCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
487 adjustPeriod(theParameter, theCurve);
488 return theParameter > theCurve->FirstParameter() &&
489 theParameter < theCurve->LastParameter();
492 // boundary parameters of curve are applied too
493 static bool isParamOnCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
495 adjustPeriod(theParameter, theCurve);
496 return theParameter >= theCurve->FirstParameter() &&
497 theParameter <= theCurve->LastParameter();
501 Handle(Geom_Plane) myPlane;
502 std::shared_ptr<GeomAPI_Pnt2d> myCenter;
503 std::vector<gp_Pnt2d> myPassingPoints;
504 std::vector<CurveAdaptorPtr> myTangentShapes;
505 CurveAdaptorPtr myTransversalLine;
507 std::shared_ptr<GeomAPI_Pnt2d> myClosestPoint;
514 GeomAlgoAPI_Circ2dBuilder::GeomAlgoAPI_Circ2dBuilder(const std::shared_ptr<GeomAPI_Ax3>& thePlane)
520 void GeomAlgoAPI_Circ2dBuilder::setRadius(const double theRadius)
522 myRadius = theRadius;
525 void GeomAlgoAPI_Circ2dBuilder::setCenter(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter)
527 myCenter = theCenter;
530 void GeomAlgoAPI_Circ2dBuilder::addTangentCurve(const std::shared_ptr<GeomAPI_Shape>& theEdge)
532 if (theEdge->isEdge())
533 myTangentShapes.push_back(theEdge);
536 void GeomAlgoAPI_Circ2dBuilder::setTransversalLine(const std::shared_ptr<GeomAPI_Shape>& theEdge)
538 if (theEdge->isEdge())
539 myTransversalLine = theEdge;
542 void GeomAlgoAPI_Circ2dBuilder::addPassingPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
544 myPassingPoints.push_back(thePoint);
547 void GeomAlgoAPI_Circ2dBuilder::setClosestPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
549 myClosestPoint = thePoint;
552 std::shared_ptr<GeomAPI_Circ2d> GeomAlgoAPI_Circ2dBuilder::circle(
553 const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
554 const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint,
555 const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPoint)
557 std::shared_ptr<GeomAPI_Ax3> aPlane(new GeomAPI_Ax3);
559 GeomAlgoAPI_Circ2dBuilder aBuilder(aPlane);
560 aBuilder.addPassingPoint(theFirstPoint);
561 aBuilder.addPassingPoint(theSecondPoint);
562 aBuilder.addPassingPoint(theThirdPoint);
563 return aBuilder.circle();
566 std::shared_ptr<GeomAPI_Circ2d> GeomAlgoAPI_Circ2dBuilder::circle()
568 CircleBuilder aCircleBuilder(myPlane);
569 aCircleBuilder.setCenter(myCenter);
570 aCircleBuilder.setTangentCurves(myTangentShapes);
571 aCircleBuilder.setTransversalLine(myTransversalLine);
572 aCircleBuilder.setPassingPoints(myPassingPoints);
573 aCircleBuilder.setClosestPoint(myClosestPoint);
574 aCircleBuilder.setRadius(myRadius);
575 Circ2dPtr aCirc2d = aCircleBuilder.circle();
577 std::shared_ptr<GeomAPI_Circ2d> aCircle;
579 const gp_Pnt2d& aCenter = aCirc2d->Location();
580 const gp_Dir2d& aXAxis = aCirc2d->Position().XDirection();
582 std::shared_ptr<GeomAPI_Pnt2d> aCircleCenter(new GeomAPI_Pnt2d(aCenter.X(), aCenter.Y()));
583 std::shared_ptr<GeomAPI_Dir2d> aCircleDir(new GeomAPI_Dir2d(aXAxis.X(), aXAxis.Y()));
585 aCircle = std::shared_ptr<GeomAPI_Circ2d>(
586 new GeomAPI_Circ2d(aCircleCenter, aCircleDir, aCirc2d->Radius()));