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 if (aTgCirc.size() + aTgLine.size() != 3)
217 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
218 switch (aTgLine.size()) {
220 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
221 *aTgCirc[0], *aTgCirc[1], *aTgCirc[2], Precision::Confusion()));
224 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
225 *aTgCirc[0], *aTgCirc[1], *aTgLine[0], Precision::Confusion()));
228 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
229 *aTgCirc[0], *aTgLine[0], *aTgLine[1], Precision::Confusion()));
232 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
233 *aTgLine[0], *aTgLine[1], *aTgLine[0], Precision::Confusion()));
239 return getProperCircle(aCircleBuilder);
242 Circ2dPtr circleByPointAndTwoTangentCurves()
244 const gp_Pnt2d& aPoint = myPassingPoints[0];
245 CurveAdaptorPtr aCurve1 = myTangentShapes[0];
246 CurveAdaptorPtr aCurve2 = myTangentShapes[1];
247 if (!aCurve1 || !aCurve2)
250 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
251 if (aCurve1->GetType() == GeomAbs_Line) {
252 if (aCurve2->GetType() == GeomAbs_Line) {
253 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
254 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve1->Line()),
255 GccEnt::Unqualified(aCurve2->Line()),
256 aPoint, Precision::Confusion()));
257 } else if (aCurve2->GetType() == GeomAbs_Circle) {
258 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
259 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve2->Circle()),
260 GccEnt::Unqualified(aCurve1->Line()),
261 aPoint, Precision::Confusion()));
263 } else if (aCurve1->GetType() == GeomAbs_Circle) {
264 if (aCurve2->GetType() == GeomAbs_Line) {
265 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
266 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve1->Circle()),
267 GccEnt::Unqualified(aCurve2->Line()),
268 aPoint, Precision::Confusion()));
269 } else if (aCurve2->GetType() == GeomAbs_Circle) {
270 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
271 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve2->Circle()),
272 GccEnt::Unqualified(aCurve1->Circle()),
273 aPoint, Precision::Confusion()));
277 return getProperCircle(aCircleBuilder);
280 Circ2dPtr circleByTwoPointsAndTangentCurve()
282 const gp_Pnt2d& aPoint1 = myPassingPoints[0];
283 const gp_Pnt2d& aPoint2 = myPassingPoints[1];
284 CurveAdaptorPtr aCurve = myTangentShapes[0];
288 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
289 if (aCurve->GetType() == GeomAbs_Line) {
290 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
291 GccEnt::Unqualified(aCurve->Line()), aPoint1, aPoint2, Precision::Confusion()));
292 } else if (aCurve->GetType() == GeomAbs_Circle) {
293 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
294 GccEnt::Unqualified(aCurve->Circle()), aPoint1, aPoint2, Precision::Confusion()));
297 return getProperCircle(aCircleBuilder);
300 Circ2dPtr circleByThreePassingPoints()
302 GccAna_Circ2d3Tan aCircleBuilder(myPassingPoints[0],
305 Precision::Confusion());
306 if (aCircleBuilder.NbSolutions() > 0)
307 return Circ2dPtr(new gp_Circ2d(aCircleBuilder.ThisSolution(1)));
311 Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2d3Tan>& theBuilder) const
316 int aNbSol = theBuilder->NbSolutions();
320 int anAppropriateSolution = 1;
321 double aMinDist = Precision::Infinite();
323 double aParSol, aPonTgCurve;
325 for (int i = 1; i <= aNbSol && aNbSol > 1; ++i) {
326 bool isApplicable = false;
327 if (myTangentShapes.size() >= 1) {
328 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
329 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[0]);
331 if (myTangentShapes.size() >= 2 && isApplicable) {
332 theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
333 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[1]);
335 if (myTangentShapes.size() >= 3 && isApplicable) {
336 theBuilder->Tangency3(i, aParSol, aPonTgCurve, aTgPnt);
337 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[2]);
341 double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
342 if (aDist < aMinDist) {
343 anAppropriateSolution = i;
349 return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
353 Circ2dPtr circleByRadiusAndTwoTangentCurves()
355 VectorOfGccCirc aTgCirc;
356 VectorOfGccLine aTgLine;
357 convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
359 if (aTgCirc.size() + aTgLine.size() != 2)
362 std::shared_ptr<GccAna_Circ2d2TanRad> aCircleBuilder;
363 switch (aTgLine.size()) {
365 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
366 *aTgCirc[0], *aTgCirc[1], myRadius, Precision::Confusion()));
369 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
370 *aTgCirc[0], *aTgLine[0], myRadius, Precision::Confusion()));
373 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
374 *aTgLine[0], *aTgLine[1], myRadius, Precision::Confusion()));
380 return getProperCircle(aCircleBuilder);
383 Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2d2TanRad>& theBuilder) const
388 int aNbSol = theBuilder->NbSolutions();
392 int anAppropriateSolution = 1;
393 double aMinDist = Precision::Infinite();
395 double aParSol, aPonTgCurve;
397 for (int i = 1; i <= aNbSol && aNbSol > 1; ++i) {
398 bool isApplicable = false;
399 if (myTangentShapes.size() >= 1) {
400 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
401 isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[0]);
403 if (myTangentShapes.size() >= 2 && isApplicable) {
404 theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
405 isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[1]);
409 double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
410 if (aDist < aMinDist) {
411 anAppropriateSolution = i;
417 return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
421 void convertTangentCurvesToGccEnt(VectorOfGccCirc& theTangentCircles,
422 VectorOfGccLine& theTangentLines)
424 theTangentCircles.reserve(3);
425 theTangentLines.reserve(3);
427 std::vector<CurveAdaptorPtr>::iterator anIt = myTangentShapes.begin();
428 for (; anIt != myTangentShapes.end(); ++anIt) {
429 switch ((*anIt)->GetType()) {
431 theTangentLines.push_back(
432 std::shared_ptr<GccEnt_QualifiedLin>(
433 new GccEnt_QualifiedLin((*anIt)->Line(), GccEnt_unqualified))
437 theTangentCircles.push_back(
438 std::shared_ptr<GccEnt_QualifiedCirc>(
439 new GccEnt_QualifiedCirc((*anIt)->Circle(), GccEnt_unqualified))
449 static void adjustPeriod(double& theParameter, const CurveAdaptorPtr& theCurve)
451 if (theCurve->Curve()->IsPeriodic()) {
452 theParameter = ElCLib::InPeriod(theParameter,
453 theCurve->FirstParameter(),
454 theCurve->FirstParameter() + theCurve->Period());
458 // boundary parameters of curve are NOT applied
459 static bool isParamInCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
461 adjustPeriod(theParameter, theCurve);
462 return theParameter > theCurve->FirstParameter() &&
463 theParameter < theCurve->LastParameter();
466 // boundary parameters of curve are applied too
467 static bool isParamOnCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
469 adjustPeriod(theParameter, theCurve);
470 return theParameter >= theCurve->FirstParameter() &&
471 theParameter <= theCurve->LastParameter();
475 Handle(Geom_Plane) myPlane;
476 std::shared_ptr<GeomAPI_Pnt2d> myCenter;
477 std::vector<gp_Pnt2d> myPassingPoints;
478 std::vector<CurveAdaptorPtr> myTangentShapes;
480 std::shared_ptr<GeomAPI_Pnt2d> myClosestPoint;
487 GeomAlgoAPI_Circ2dBuilder::GeomAlgoAPI_Circ2dBuilder(const std::shared_ptr<GeomAPI_Ax3>& thePlane)
493 void GeomAlgoAPI_Circ2dBuilder::setRadius(const double theRadius)
495 myRadius = theRadius;
498 void GeomAlgoAPI_Circ2dBuilder::setCenter(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter)
500 myCenter = theCenter;
503 void GeomAlgoAPI_Circ2dBuilder::addTangentCurve(const std::shared_ptr<GeomAPI_Shape>& theEdge)
505 if (theEdge->isEdge())
506 myTangentShapes.push_back(theEdge);
509 void GeomAlgoAPI_Circ2dBuilder::addPassingPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
511 myPassingPoints.push_back(thePoint);
514 void GeomAlgoAPI_Circ2dBuilder::setClosestPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
516 myClosestPoint = thePoint;
519 std::shared_ptr<GeomAPI_Circ2d> GeomAlgoAPI_Circ2dBuilder::circle(
520 const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
521 const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint,
522 const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPoint)
524 std::shared_ptr<GeomAPI_Ax3> aPlane(new GeomAPI_Ax3);
526 GeomAlgoAPI_Circ2dBuilder aBuilder(aPlane);
527 aBuilder.addPassingPoint(theFirstPoint);
528 aBuilder.addPassingPoint(theSecondPoint);
529 aBuilder.addPassingPoint(theThirdPoint);
530 return aBuilder.circle();
533 std::shared_ptr<GeomAPI_Circ2d> GeomAlgoAPI_Circ2dBuilder::circle()
535 CircleBuilder aCircleBuilder(myPlane);
536 aCircleBuilder.setCenter(myCenter);
537 aCircleBuilder.setTangentCurves(myTangentShapes);
538 aCircleBuilder.setPassingPoints(myPassingPoints);
539 aCircleBuilder.setClosestPoint(myClosestPoint);
540 aCircleBuilder.setRadius(myRadius);
541 Circ2dPtr aCirc2d = aCircleBuilder.circle();
543 std::shared_ptr<GeomAPI_Circ2d> aCircle;
545 const gp_Pnt2d& aCenter = aCirc2d->Location();
546 const gp_Dir2d& aXAxis = aCirc2d->Position().XDirection();
548 std::shared_ptr<GeomAPI_Pnt2d> aCircleCenter(new GeomAPI_Pnt2d(aCenter.X(), aCenter.Y()));
549 std::shared_ptr<GeomAPI_Dir2d> aCircleDir(new GeomAPI_Dir2d(aXAxis.X(), aXAxis.Y()));
551 aCircle = std::shared_ptr<GeomAPI_Circ2d>(
552 new GeomAPI_Circ2d(aCircleCenter, aCircleDir, aCirc2d->Radius()));