1 // Copyright (C) 2014-2017 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
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
21 #include <GeomAlgoAPI_Circ2dBuilder.h>
22 #include <GeomAPI_Ax3.h>
23 #include <GeomAPI_Circ2d.h>
24 #include <GeomAPI_Pnt2d.h>
25 #include <GeomAPI_Dir2d.h>
26 #include <GeomAPI_Shape.h>
28 #include <BRep_Tool.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 // * with specified radius
57 CircleBuilder(const std::shared_ptr<GeomAPI_Ax3>& theBasePlane)
58 : myPlane(new Geom_Plane(theBasePlane->impl<gp_Ax3>())),
62 void setRadius(const double theRadius)
63 { myRadius = theRadius; }
65 void setCenter(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter)
66 { myCenter = theCenter; }
68 void setTangentCurves(const std::vector< std::shared_ptr<GeomAPI_Shape> >& theEdges)
70 std::vector< std::shared_ptr<GeomAPI_Shape> >::const_iterator anEdgeIt;
71 for (anEdgeIt = theEdges.begin(); anEdgeIt != theEdges.end(); ++anEdgeIt) {
72 const TopoDS_Edge& anEdge = TopoDS::Edge((*anEdgeIt)->impl<TopoDS_Shape>());
76 Handle(Geom2d_Curve) aCurve = BRep_Tool::CurveOnSurface(anEdge, myPlane, aLoc, aFirst, aLast);
77 CurveAdaptorPtr aCurveAdaptor(new Geom2dAdaptor_Curve(aCurve, aFirst, aLast));
79 // sort curves (circles should become first)
80 if (aCurveAdaptor->GetType() == GeomAbs_Circle)
81 myTangentShapes.insert(myTangentShapes.begin(), aCurveAdaptor);
83 myTangentShapes.push_back(aCurveAdaptor);
87 void setPassingPoints(const std::vector< std::shared_ptr<GeomAPI_Pnt2d> >& thePoints)
89 std::vector< std::shared_ptr<GeomAPI_Pnt2d> >::const_iterator aPIt;
90 for (aPIt = thePoints.begin(); aPIt != thePoints.end(); ++aPIt)
91 myPassingPoints.push_back((*aPIt)->impl<gp_Pnt2d>());
94 void setClosestPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
95 { myClosestPoint = thePoint; }
102 if (myPassingPoints.size() == 1)
103 aResult = circleByCenterAndPassingPoint();
104 else if (myTangentShapes.size() == 1)
105 aResult = circleByCenterAndTangent();
106 else if (myRadius > 0.0)
107 aResult = circleByCenterAndRadius();
108 } else if (myRadius > 0.0) {
109 if (myTangentShapes.size() == 2)
110 aResult = circleByRadiusAndTwoTangentCurves();
112 switch (myPassingPoints.size()) {
114 aResult = circleByThreeTangentCurves();
117 aResult = circleByPointAndTwoTangentCurves();
120 aResult = circleByTwoPointsAndTangentCurve();
123 aResult = circleByThreePassingPoints();
133 Circ2dPtr circleByCenterAndRadius()
135 const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
136 return Circ2dPtr(new gp_Circ2d(gp_Ax2d(aCenter, gp::DX2d()), myRadius));
139 Circ2dPtr circleByCenterAndPassingPoint()
141 const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
142 if (aCenter.SquareDistance(myPassingPoints[0]) > Precision::SquareConfusion()) {
143 GccAna_Circ2dTanCen aBuilder(myPassingPoints[0], aCenter);
144 if (aBuilder.NbSolutions() > 0)
145 return Circ2dPtr(new gp_Circ2d(aBuilder.ThisSolution(1)));
150 Circ2dPtr circleByCenterAndTangent()
152 const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
153 CurveAdaptorPtr aCurve = myTangentShapes[0];
155 std::shared_ptr<GccAna_Circ2dTanCen> aCircleBuilder;
156 if (aCurve->GetType() == GeomAbs_Line &&
157 aCurve->Line().Distance(aCenter) > Precision::Confusion()) {
158 aCircleBuilder = std::shared_ptr<GccAna_Circ2dTanCen>(
159 new GccAna_Circ2dTanCen(aCurve->Line(), aCenter));
160 } else if (aCurve->GetType() == GeomAbs_Circle) {
161 aCircleBuilder = std::shared_ptr<GccAna_Circ2dTanCen>(new GccAna_Circ2dTanCen(
162 GccEnt::Unqualified(aCurve->Circle()), aCenter, Precision::Confusion()));
165 return getProperCircle(aCircleBuilder);
168 Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2dTanCen>& theBuilder) const
173 CurveAdaptorPtr aCurve = myTangentShapes[0];
175 int aNbSol = theBuilder->NbSolutions();
179 int anAppropriateSolution = 1;
180 double aMinDist = Precision::Infinite();
182 double aParSol, aPonTgCurve;
184 for (int i = 1; i <= aNbSol && aNbSol > 1 && aCurve; ++i) {
185 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
186 if (isParamOnCurve(aPonTgCurve, aCurve)) {
187 double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
188 if (aDist < aMinDist) {
189 anAppropriateSolution = i;
195 return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
198 double distanceToClosestPoint(const gp_Circ2d& theCirc) const
200 if (myClosestPoint) {
201 double aDist = myClosestPoint->impl<gp_Pnt2d>().Distance(theCirc.Location());
202 return fabs(aDist - theCirc.Radius());
208 Circ2dPtr circleByThreeTangentCurves()
210 VectorOfGccCirc aTgCirc;
211 VectorOfGccLine aTgLine;
212 convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
214 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
215 if (aTgCirc.size() + aTgLine.size() == 3) {
216 switch (aTgLine.size()) {
218 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
219 *aTgCirc[0], *aTgCirc[1], *aTgCirc[2], Precision::Confusion()));
222 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
223 *aTgCirc[0], *aTgCirc[1], *aTgLine[0], Precision::Confusion()));
226 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
227 *aTgCirc[0], *aTgLine[0], *aTgLine[1], Precision::Confusion()));
230 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
231 *aTgLine[0], *aTgLine[1], *aTgLine[2], Precision::Confusion()));
238 return getProperCircle(aCircleBuilder);
241 Circ2dPtr circleByPointAndTwoTangentCurves()
243 const gp_Pnt2d& aPoint = myPassingPoints[0];
245 VectorOfGccCirc aTgCirc;
246 VectorOfGccLine aTgLine;
247 convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
249 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
250 if (aTgCirc.size() + aTgLine.size() == 2) {
251 switch (aTgLine.size()) {
253 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
254 *aTgCirc[0], *aTgCirc[1], aPoint, Precision::Confusion()));
257 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
258 *aTgCirc[0], *aTgLine[0], aPoint, Precision::Confusion()));
261 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
262 *aTgLine[0], *aTgLine[1], aPoint, Precision::Confusion()));
269 return getProperCircle(aCircleBuilder);
272 Circ2dPtr circleByTwoPointsAndTangentCurve()
274 const gp_Pnt2d& aPoint1 = myPassingPoints[0];
275 const gp_Pnt2d& aPoint2 = myPassingPoints[1];
276 CurveAdaptorPtr aCurve = myTangentShapes[0];
278 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
280 if (aCurve->GetType() == GeomAbs_Line) {
281 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
282 GccEnt::Unqualified(aCurve->Line()), aPoint1, aPoint2, Precision::Confusion()));
284 else if (aCurve->GetType() == GeomAbs_Circle) {
285 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
286 GccEnt::Unqualified(aCurve->Circle()), aPoint1, aPoint2, Precision::Confusion()));
290 return getProperCircle(aCircleBuilder);
293 Circ2dPtr circleByThreePassingPoints()
295 GccAna_Circ2d3Tan aCircleBuilder(myPassingPoints[0],
298 Precision::Confusion());
299 if (aCircleBuilder.NbSolutions() > 0)
300 return Circ2dPtr(new gp_Circ2d(aCircleBuilder.ThisSolution(1)));
304 Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2d3Tan>& theBuilder) const
309 int aNbSol = theBuilder->NbSolutions();
313 int anAppropriateSolution = 1;
314 double aMinDist = Precision::Infinite();
316 double aParSol, aPonTgCurve;
318 for (int i = 1; i <= aNbSol && aNbSol > 1; ++i) {
319 bool isApplicable = false;
320 if (myTangentShapes.size() >= 1) {
321 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
322 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[0]);
324 if (myTangentShapes.size() >= 2 && isApplicable) {
325 theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
326 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[1]);
328 if (myTangentShapes.size() >= 3 && isApplicable) {
329 theBuilder->Tangency3(i, aParSol, aPonTgCurve, aTgPnt);
330 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[2]);
334 double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
335 if (aDist < aMinDist) {
336 anAppropriateSolution = i;
342 return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
346 Circ2dPtr circleByRadiusAndTwoTangentCurves()
348 VectorOfGccCirc aTgCirc;
349 VectorOfGccLine aTgLine;
350 convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
352 std::shared_ptr<GccAna_Circ2d2TanRad> aCircleBuilder;
353 if (aTgCirc.size() + aTgLine.size() == 2) {
354 switch (aTgLine.size()) {
356 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
357 *aTgCirc[0], *aTgCirc[1], myRadius, Precision::Confusion()));
360 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
361 *aTgCirc[0], *aTgLine[0], myRadius, Precision::Confusion()));
364 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
365 *aTgLine[0], *aTgLine[1], myRadius, Precision::Confusion()));
372 return getProperCircle(aCircleBuilder);
375 Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2d2TanRad>& theBuilder) const
380 int aNbSol = theBuilder->NbSolutions();
384 int anAppropriateSolution = 1;
385 double aMinDist = Precision::Infinite();
387 double aParSol, aPonTgCurve;
389 for (int i = 1; i <= aNbSol && aNbSol > 1; ++i) {
390 bool isApplicable = false;
391 if (myTangentShapes.size() >= 1) {
392 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
393 isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[0]);
395 if (myTangentShapes.size() >= 2 && isApplicable) {
396 theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
397 isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[1]);
401 double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
402 if (aDist < aMinDist) {
403 anAppropriateSolution = i;
409 return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
413 void convertTangentCurvesToGccEnt(VectorOfGccCirc& theTangentCircles,
414 VectorOfGccLine& theTangentLines)
416 theTangentCircles.reserve(3);
417 theTangentLines.reserve(3);
419 std::vector<CurveAdaptorPtr>::iterator anIt = myTangentShapes.begin();
420 for (; anIt != myTangentShapes.end(); ++anIt) {
421 switch ((*anIt)->GetType()) {
423 theTangentLines.push_back(
424 std::shared_ptr<GccEnt_QualifiedLin>(
425 new GccEnt_QualifiedLin((*anIt)->Line(), GccEnt_unqualified))
429 theTangentCircles.push_back(
430 std::shared_ptr<GccEnt_QualifiedCirc>(
431 new GccEnt_QualifiedCirc((*anIt)->Circle(), GccEnt_unqualified))
441 static void adjustPeriod(double& theParameter, const CurveAdaptorPtr& theCurve)
443 if (theCurve->Curve()->IsPeriodic()) {
444 theParameter = ElCLib::InPeriod(theParameter,
445 theCurve->FirstParameter(),
446 theCurve->FirstParameter() + theCurve->Period());
450 // boundary parameters of curve are NOT applied
451 static bool isParamInCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
453 adjustPeriod(theParameter, theCurve);
454 return theParameter > theCurve->FirstParameter() &&
455 theParameter < theCurve->LastParameter();
458 // boundary parameters of curve are applied too
459 static bool isParamOnCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
461 adjustPeriod(theParameter, theCurve);
462 return theParameter >= theCurve->FirstParameter() &&
463 theParameter <= theCurve->LastParameter();
467 Handle(Geom_Plane) myPlane;
468 std::shared_ptr<GeomAPI_Pnt2d> myCenter;
469 std::vector<gp_Pnt2d> myPassingPoints;
470 std::vector<CurveAdaptorPtr> myTangentShapes;
472 std::shared_ptr<GeomAPI_Pnt2d> myClosestPoint;
479 GeomAlgoAPI_Circ2dBuilder::GeomAlgoAPI_Circ2dBuilder(const std::shared_ptr<GeomAPI_Ax3>& thePlane)
485 void GeomAlgoAPI_Circ2dBuilder::setRadius(const double theRadius)
487 myRadius = theRadius;
490 void GeomAlgoAPI_Circ2dBuilder::setCenter(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter)
492 myCenter = theCenter;
495 void GeomAlgoAPI_Circ2dBuilder::addTangentCurve(const std::shared_ptr<GeomAPI_Shape>& theEdge)
497 if (theEdge->isEdge())
498 myTangentShapes.push_back(theEdge);
501 void GeomAlgoAPI_Circ2dBuilder::addPassingPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
503 myPassingPoints.push_back(thePoint);
506 void GeomAlgoAPI_Circ2dBuilder::setClosestPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
508 myClosestPoint = thePoint;
511 std::shared_ptr<GeomAPI_Circ2d> GeomAlgoAPI_Circ2dBuilder::circle(
512 const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
513 const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint,
514 const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPoint)
516 std::shared_ptr<GeomAPI_Ax3> aPlane(new GeomAPI_Ax3);
518 GeomAlgoAPI_Circ2dBuilder aBuilder(aPlane);
519 aBuilder.addPassingPoint(theFirstPoint);
520 aBuilder.addPassingPoint(theSecondPoint);
521 aBuilder.addPassingPoint(theThirdPoint);
522 return aBuilder.circle();
525 std::shared_ptr<GeomAPI_Circ2d> GeomAlgoAPI_Circ2dBuilder::circle()
527 CircleBuilder aCircleBuilder(myPlane);
528 aCircleBuilder.setCenter(myCenter);
529 aCircleBuilder.setTangentCurves(myTangentShapes);
530 aCircleBuilder.setPassingPoints(myPassingPoints);
531 aCircleBuilder.setClosestPoint(myClosestPoint);
532 aCircleBuilder.setRadius(myRadius);
533 Circ2dPtr aCirc2d = aCircleBuilder.circle();
535 std::shared_ptr<GeomAPI_Circ2d> aCircle;
537 const gp_Pnt2d& aCenter = aCirc2d->Location();
538 const gp_Dir2d& aXAxis = aCirc2d->Position().XDirection();
540 std::shared_ptr<GeomAPI_Pnt2d> aCircleCenter(new GeomAPI_Pnt2d(aCenter.X(), aCenter.Y()));
541 std::shared_ptr<GeomAPI_Dir2d> aCircleDir(new GeomAPI_Dir2d(aXAxis.X(), aXAxis.Y()));
543 aCircle = std::shared_ptr<GeomAPI_Circ2d>(
544 new GeomAPI_Circ2d(aCircleCenter, aCircleDir, aCirc2d->Radius()));