1 // Copyright (C) 2014-2019 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_Circ2d2TanRad.hxx>
30 #include <GccAna_Circ2d3Tan.hxx>
31 #include <GccAna_Circ2dTanCen.hxx>
33 #include <GccEnt_QualifiedCirc.hxx>
34 #include <GccEnt_QualifiedLin.hxx>
35 #include <Geom2dAdaptor_Curve.hxx>
36 #include <Geom_Plane.hxx>
38 #include <TopoDS_Edge.hxx>
42 typedef std::shared_ptr<gp_Circ2d> Circ2dPtr;
43 typedef std::shared_ptr<Geom2dAdaptor_Curve> CurveAdaptorPtr;
44 typedef std::vector< std::shared_ptr<GccEnt_QualifiedCirc> > VectorOfGccCirc;
45 typedef std::vector< std::shared_ptr<GccEnt_QualifiedLin> > VectorOfGccLine;
48 // Provide different mechanisms to create circle:
49 // * by passing points
51 // * with specified radius
56 CircleBuilder(const std::shared_ptr<GeomAPI_Ax3>& theBasePlane)
57 : myPlane(new Geom_Plane(theBasePlane->impl<gp_Ax3>())),
61 void setRadius(const double theRadius)
62 { myRadius = theRadius; }
64 void setCenter(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter)
65 { myCenter = theCenter; }
67 void setTangentCurves(const std::vector< std::shared_ptr<GeomAPI_Shape> >& theEdges)
69 std::vector< std::shared_ptr<GeomAPI_Shape> >::const_iterator anEdgeIt;
70 for (anEdgeIt = theEdges.begin(); anEdgeIt != theEdges.end(); ++anEdgeIt) {
71 const TopoDS_Edge& anEdge = TopoDS::Edge((*anEdgeIt)->impl<TopoDS_Shape>());
75 Handle(Geom2d_Curve) aCurve = BRep_Tool::CurveOnSurface(anEdge, myPlane, aLoc, aFirst, aLast);
76 CurveAdaptorPtr aCurveAdaptor(new Geom2dAdaptor_Curve(aCurve, aFirst, aLast));
78 // sort curves (circles should become first)
79 if (aCurveAdaptor->GetType() == GeomAbs_Circle)
80 myTangentShapes.insert(myTangentShapes.begin(), aCurveAdaptor);
82 myTangentShapes.push_back(aCurveAdaptor);
86 void setPassingPoints(const std::vector< std::shared_ptr<GeomAPI_Pnt2d> >& thePoints)
88 std::vector< std::shared_ptr<GeomAPI_Pnt2d> >::const_iterator aPIt;
89 for (aPIt = thePoints.begin(); aPIt != thePoints.end(); ++aPIt)
90 myPassingPoints.push_back((*aPIt)->impl<gp_Pnt2d>());
93 void setClosestPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
94 { myClosestPoint = thePoint; }
101 if (myPassingPoints.size() == 1)
102 aResult = circleByCenterAndPassingPoint();
103 else if (myTangentShapes.size() == 1)
104 aResult = circleByCenterAndTangent();
105 else if (myRadius > 0.0)
106 aResult = circleByCenterAndRadius();
107 } else if (myRadius > 0.0) {
108 if (myTangentShapes.size() == 2)
109 aResult = circleByRadiusAndTwoTangentCurves();
111 switch (myPassingPoints.size()) {
113 aResult = circleByThreeTangentCurves();
116 aResult = circleByPointAndTwoTangentCurves();
119 aResult = circleByTwoPointsAndTangentCurve();
122 aResult = circleByThreePassingPoints();
132 Circ2dPtr circleByCenterAndRadius()
134 const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
135 return Circ2dPtr(new gp_Circ2d(gp_Ax2d(aCenter, gp::DX2d()), myRadius));
138 Circ2dPtr circleByCenterAndPassingPoint()
140 const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
141 if (aCenter.SquareDistance(myPassingPoints[0]) > Precision::SquareConfusion()) {
142 GccAna_Circ2dTanCen aBuilder(myPassingPoints[0], aCenter);
143 if (aBuilder.NbSolutions() > 0)
144 return Circ2dPtr(new gp_Circ2d(aBuilder.ThisSolution(1)));
149 Circ2dPtr circleByCenterAndTangent()
151 const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
152 CurveAdaptorPtr aCurve = myTangentShapes[0];
154 std::shared_ptr<GccAna_Circ2dTanCen> aCircleBuilder;
155 if (aCurve->GetType() == GeomAbs_Line &&
156 aCurve->Line().Distance(aCenter) > Precision::Confusion()) {
157 aCircleBuilder = std::shared_ptr<GccAna_Circ2dTanCen>(
158 new GccAna_Circ2dTanCen(aCurve->Line(), aCenter));
159 } else if (aCurve->GetType() == GeomAbs_Circle) {
160 aCircleBuilder = std::shared_ptr<GccAna_Circ2dTanCen>(new GccAna_Circ2dTanCen(
161 GccEnt::Unqualified(aCurve->Circle()), aCenter, Precision::Confusion()));
164 return getProperCircle(aCircleBuilder);
167 Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2dTanCen>& theBuilder) const
172 CurveAdaptorPtr aCurve = myTangentShapes[0];
174 int aNbSol = theBuilder->NbSolutions();
178 int anAppropriateSolution = 1;
179 double aMinDist = Precision::Infinite();
181 double aParSol, aPonTgCurve;
183 for (int i = 1; i <= aNbSol && aNbSol > 1 && aCurve; ++i) {
184 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
185 if (isParamOnCurve(aPonTgCurve, aCurve)) {
186 double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
187 if (aDist < aMinDist) {
188 anAppropriateSolution = i;
194 return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
197 double distanceToClosestPoint(const gp_Circ2d& theCirc) const
199 if (myClosestPoint) {
200 double aDist = myClosestPoint->impl<gp_Pnt2d>().Distance(theCirc.Location());
201 return fabs(aDist - theCirc.Radius());
207 Circ2dPtr circleByThreeTangentCurves()
209 VectorOfGccCirc aTgCirc;
210 VectorOfGccLine aTgLine;
211 convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
213 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
214 if (aTgCirc.size() + aTgLine.size() == 3) {
215 switch (aTgLine.size()) {
217 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
218 *aTgCirc[0], *aTgCirc[1], *aTgCirc[2], Precision::Confusion()));
221 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
222 *aTgCirc[0], *aTgCirc[1], *aTgLine[0], Precision::Confusion()));
225 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
226 *aTgCirc[0], *aTgLine[0], *aTgLine[1], Precision::Confusion()));
229 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
230 *aTgLine[0], *aTgLine[1], *aTgLine[2], Precision::Confusion()));
237 return getProperCircle(aCircleBuilder);
240 Circ2dPtr circleByPointAndTwoTangentCurves()
242 const gp_Pnt2d& aPoint = myPassingPoints[0];
244 VectorOfGccCirc aTgCirc;
245 VectorOfGccLine aTgLine;
246 convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
248 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
249 if (aTgCirc.size() + aTgLine.size() == 2) {
250 switch (aTgLine.size()) {
252 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
253 *aTgCirc[0], *aTgCirc[1], aPoint, Precision::Confusion()));
256 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
257 *aTgCirc[0], *aTgLine[0], aPoint, Precision::Confusion()));
260 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
261 *aTgLine[0], *aTgLine[1], aPoint, Precision::Confusion()));
268 return getProperCircle(aCircleBuilder);
271 Circ2dPtr circleByTwoPointsAndTangentCurve()
273 const gp_Pnt2d& aPoint1 = myPassingPoints[0];
274 const gp_Pnt2d& aPoint2 = myPassingPoints[1];
275 CurveAdaptorPtr aCurve = myTangentShapes[0];
277 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
279 if (aCurve->GetType() == GeomAbs_Line) {
280 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
281 GccEnt::Unqualified(aCurve->Line()), aPoint1, aPoint2, Precision::Confusion()));
283 else if (aCurve->GetType() == GeomAbs_Circle) {
284 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
285 GccEnt::Unqualified(aCurve->Circle()), aPoint1, aPoint2, Precision::Confusion()));
289 return getProperCircle(aCircleBuilder);
292 Circ2dPtr circleByThreePassingPoints()
294 GccAna_Circ2d3Tan aCircleBuilder(myPassingPoints[0],
297 Precision::Confusion());
298 if (aCircleBuilder.NbSolutions() > 0)
299 return Circ2dPtr(new gp_Circ2d(aCircleBuilder.ThisSolution(1)));
303 Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2d3Tan>& theBuilder) const
308 int aNbSol = theBuilder->NbSolutions();
312 int anAppropriateSolution = 1;
313 double aMinDist = Precision::Infinite();
315 double aParSol, aPonTgCurve;
317 for (int i = 1; i <= aNbSol && aNbSol > 1; ++i) {
318 bool isApplicable = false;
319 if (myTangentShapes.size() >= 1) {
320 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
321 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[0]);
323 if (myTangentShapes.size() >= 2 && isApplicable) {
324 theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
325 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[1]);
327 if (myTangentShapes.size() >= 3 && isApplicable) {
328 theBuilder->Tangency3(i, aParSol, aPonTgCurve, aTgPnt);
329 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[2]);
333 double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
334 if (aDist < aMinDist) {
335 anAppropriateSolution = i;
341 return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
345 Circ2dPtr circleByRadiusAndTwoTangentCurves()
347 VectorOfGccCirc aTgCirc;
348 VectorOfGccLine aTgLine;
349 convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
351 std::shared_ptr<GccAna_Circ2d2TanRad> aCircleBuilder;
352 if (aTgCirc.size() + aTgLine.size() == 2) {
353 switch (aTgLine.size()) {
355 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
356 *aTgCirc[0], *aTgCirc[1], myRadius, Precision::Confusion()));
359 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
360 *aTgCirc[0], *aTgLine[0], myRadius, Precision::Confusion()));
363 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
364 *aTgLine[0], *aTgLine[1], myRadius, Precision::Confusion()));
371 return getProperCircle(aCircleBuilder);
374 Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2d2TanRad>& theBuilder) const
379 int aNbSol = theBuilder->NbSolutions();
383 int anAppropriateSolution = 1;
384 double aMinDist = Precision::Infinite();
386 double aParSol, aPonTgCurve;
388 for (int i = 1; i <= aNbSol && aNbSol > 1; ++i) {
389 bool isApplicable = false;
390 if (myTangentShapes.size() >= 1) {
391 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
392 isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[0]);
394 if (myTangentShapes.size() >= 2 && isApplicable) {
395 theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
396 isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[1]);
400 double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
401 if (aDist < aMinDist) {
402 anAppropriateSolution = i;
408 return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
412 void convertTangentCurvesToGccEnt(VectorOfGccCirc& theTangentCircles,
413 VectorOfGccLine& theTangentLines)
415 theTangentCircles.reserve(3);
416 theTangentLines.reserve(3);
418 std::vector<CurveAdaptorPtr>::iterator anIt = myTangentShapes.begin();
419 for (; anIt != myTangentShapes.end(); ++anIt) {
420 switch ((*anIt)->GetType()) {
422 theTangentLines.push_back(
423 std::shared_ptr<GccEnt_QualifiedLin>(
424 new GccEnt_QualifiedLin((*anIt)->Line(), GccEnt_unqualified))
428 theTangentCircles.push_back(
429 std::shared_ptr<GccEnt_QualifiedCirc>(
430 new GccEnt_QualifiedCirc((*anIt)->Circle(), GccEnt_unqualified))
440 static void adjustPeriod(double& theParameter, const CurveAdaptorPtr& theCurve)
442 if (theCurve->Curve()->IsPeriodic()) {
443 theParameter = ElCLib::InPeriod(theParameter,
444 theCurve->FirstParameter(),
445 theCurve->FirstParameter() + theCurve->Period());
449 // boundary parameters of curve are NOT applied
450 static bool isParamInCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
452 adjustPeriod(theParameter, theCurve);
453 return theParameter > theCurve->FirstParameter() &&
454 theParameter < theCurve->LastParameter();
457 // boundary parameters of curve are applied too
458 static bool isParamOnCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
460 adjustPeriod(theParameter, theCurve);
461 return theParameter >= theCurve->FirstParameter() &&
462 theParameter <= theCurve->LastParameter();
466 Handle(Geom_Plane) myPlane;
467 std::shared_ptr<GeomAPI_Pnt2d> myCenter;
468 std::vector<gp_Pnt2d> myPassingPoints;
469 std::vector<CurveAdaptorPtr> myTangentShapes;
471 std::shared_ptr<GeomAPI_Pnt2d> myClosestPoint;
478 GeomAlgoAPI_Circ2dBuilder::GeomAlgoAPI_Circ2dBuilder(const std::shared_ptr<GeomAPI_Ax3>& thePlane)
484 void GeomAlgoAPI_Circ2dBuilder::setRadius(const double theRadius)
486 myRadius = theRadius;
489 void GeomAlgoAPI_Circ2dBuilder::setCenter(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter)
491 myCenter = theCenter;
494 void GeomAlgoAPI_Circ2dBuilder::addTangentCurve(const std::shared_ptr<GeomAPI_Shape>& theEdge)
496 if (theEdge->isEdge())
497 myTangentShapes.push_back(theEdge);
500 void GeomAlgoAPI_Circ2dBuilder::addPassingPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
502 myPassingPoints.push_back(thePoint);
505 void GeomAlgoAPI_Circ2dBuilder::setClosestPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
507 myClosestPoint = thePoint;
510 std::shared_ptr<GeomAPI_Circ2d> GeomAlgoAPI_Circ2dBuilder::circle(
511 const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
512 const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint,
513 const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPoint)
515 std::shared_ptr<GeomAPI_Ax3> aPlane(new GeomAPI_Ax3);
517 GeomAlgoAPI_Circ2dBuilder aBuilder(aPlane);
518 aBuilder.addPassingPoint(theFirstPoint);
519 aBuilder.addPassingPoint(theSecondPoint);
520 aBuilder.addPassingPoint(theThirdPoint);
521 return aBuilder.circle();
524 std::shared_ptr<GeomAPI_Circ2d> GeomAlgoAPI_Circ2dBuilder::circle()
526 CircleBuilder aCircleBuilder(myPlane);
527 aCircleBuilder.setCenter(myCenter);
528 aCircleBuilder.setTangentCurves(myTangentShapes);
529 aCircleBuilder.setPassingPoints(myPassingPoints);
530 aCircleBuilder.setClosestPoint(myClosestPoint);
531 aCircleBuilder.setRadius(myRadius);
532 Circ2dPtr aCirc2d = aCircleBuilder.circle();
534 std::shared_ptr<GeomAPI_Circ2d> aCircle;
536 const gp_Pnt2d& aCenter = aCirc2d->Location();
537 const gp_Dir2d& aXAxis = aCirc2d->Position().XDirection();
539 std::shared_ptr<GeomAPI_Pnt2d> aCircleCenter(new GeomAPI_Pnt2d(aCenter.X(), aCenter.Y()));
540 std::shared_ptr<GeomAPI_Dir2d> aCircleDir(new GeomAPI_Dir2d(aXAxis.X(), aXAxis.Y()));
542 aCircle = std::shared_ptr<GeomAPI_Circ2d>(
543 new GeomAPI_Circ2d(aCircleCenter, aCircleDir, aCirc2d->Radius()));