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 email : webmaster.salome@opencascade.com<mailto: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 if (aTgCirc.size() + aTgLine.size() != 3)
216 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
217 switch (aTgLine.size()) {
219 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
220 *aTgCirc[0], *aTgCirc[1], *aTgCirc[2], Precision::Confusion()));
223 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
224 *aTgCirc[0], *aTgCirc[1], *aTgLine[0], Precision::Confusion()));
227 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
228 *aTgCirc[0], *aTgLine[0], *aTgLine[1], Precision::Confusion()));
231 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
232 *aTgLine[0], *aTgLine[1], *aTgLine[0], Precision::Confusion()));
238 return getProperCircle(aCircleBuilder);
241 Circ2dPtr circleByPointAndTwoTangentCurves()
243 const gp_Pnt2d& aPoint = myPassingPoints[0];
244 CurveAdaptorPtr aCurve1 = myTangentShapes[0];
245 CurveAdaptorPtr aCurve2 = myTangentShapes[1];
246 if (!aCurve1 || !aCurve2)
249 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
250 if (aCurve1->GetType() == GeomAbs_Line) {
251 if (aCurve2->GetType() == GeomAbs_Line) {
252 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
253 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve1->Line()),
254 GccEnt::Unqualified(aCurve2->Line()),
255 aPoint, Precision::Confusion()));
256 } else if (aCurve2->GetType() == GeomAbs_Circle) {
257 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
258 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve2->Circle()),
259 GccEnt::Unqualified(aCurve1->Line()),
260 aPoint, Precision::Confusion()));
262 } else if (aCurve1->GetType() == GeomAbs_Circle) {
263 if (aCurve2->GetType() == GeomAbs_Line) {
264 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
265 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve1->Circle()),
266 GccEnt::Unqualified(aCurve2->Line()),
267 aPoint, Precision::Confusion()));
268 } else if (aCurve2->GetType() == GeomAbs_Circle) {
269 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
270 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve2->Circle()),
271 GccEnt::Unqualified(aCurve1->Circle()),
272 aPoint, Precision::Confusion()));
276 return getProperCircle(aCircleBuilder);
279 Circ2dPtr circleByTwoPointsAndTangentCurve()
281 const gp_Pnt2d& aPoint1 = myPassingPoints[0];
282 const gp_Pnt2d& aPoint2 = myPassingPoints[1];
283 CurveAdaptorPtr aCurve = myTangentShapes[0];
287 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
288 if (aCurve->GetType() == GeomAbs_Line) {
289 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
290 GccEnt::Unqualified(aCurve->Line()), aPoint1, aPoint2, Precision::Confusion()));
291 } else if (aCurve->GetType() == GeomAbs_Circle) {
292 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
293 GccEnt::Unqualified(aCurve->Circle()), aPoint1, aPoint2, Precision::Confusion()));
296 return getProperCircle(aCircleBuilder);
299 Circ2dPtr circleByThreePassingPoints()
301 GccAna_Circ2d3Tan aCircleBuilder(myPassingPoints[0],
304 Precision::Confusion());
305 if (aCircleBuilder.NbSolutions() > 0)
306 return Circ2dPtr(new gp_Circ2d(aCircleBuilder.ThisSolution(1)));
310 Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2d3Tan>& theBuilder) const
315 int aNbSol = theBuilder->NbSolutions();
319 int anAppropriateSolution = 1;
320 double aMinDist = Precision::Infinite();
322 double aParSol, aPonTgCurve;
324 for (int i = 1; i <= aNbSol && aNbSol > 1; ++i) {
325 bool isApplicable = false;
326 if (myTangentShapes.size() >= 1) {
327 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
328 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[0]);
330 if (myTangentShapes.size() >= 2 && isApplicable) {
331 theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
332 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[1]);
334 if (myTangentShapes.size() >= 3 && isApplicable) {
335 theBuilder->Tangency3(i, aParSol, aPonTgCurve, aTgPnt);
336 isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[2]);
340 double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
341 if (aDist < aMinDist) {
342 anAppropriateSolution = i;
348 return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
352 Circ2dPtr circleByRadiusAndTwoTangentCurves()
354 VectorOfGccCirc aTgCirc;
355 VectorOfGccLine aTgLine;
356 convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
358 if (aTgCirc.size() + aTgLine.size() != 2)
361 std::shared_ptr<GccAna_Circ2d2TanRad> aCircleBuilder;
362 switch (aTgLine.size()) {
364 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
365 *aTgCirc[0], *aTgCirc[1], myRadius, Precision::Confusion()));
368 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
369 *aTgCirc[0], *aTgLine[0], myRadius, Precision::Confusion()));
372 aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
373 *aTgLine[0], *aTgLine[1], myRadius, Precision::Confusion()));
379 return getProperCircle(aCircleBuilder);
382 Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2d2TanRad>& theBuilder) const
387 int aNbSol = theBuilder->NbSolutions();
391 int anAppropriateSolution = 1;
392 double aMinDist = Precision::Infinite();
394 double aParSol, aPonTgCurve;
396 for (int i = 1; i <= aNbSol && aNbSol > 1; ++i) {
397 bool isApplicable = false;
398 if (myTangentShapes.size() >= 1) {
399 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
400 isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[0]);
402 if (myTangentShapes.size() >= 2 && isApplicable) {
403 theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
404 isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[1]);
408 double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
409 if (aDist < aMinDist) {
410 anAppropriateSolution = i;
416 return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
420 void convertTangentCurvesToGccEnt(VectorOfGccCirc& theTangentCircles,
421 VectorOfGccLine& theTangentLines)
423 theTangentCircles.reserve(3);
424 theTangentLines.reserve(3);
426 std::vector<CurveAdaptorPtr>::iterator anIt = myTangentShapes.begin();
427 for (; anIt != myTangentShapes.end(); ++anIt) {
428 switch ((*anIt)->GetType()) {
430 theTangentLines.push_back(
431 std::shared_ptr<GccEnt_QualifiedLin>(
432 new GccEnt_QualifiedLin((*anIt)->Line(), GccEnt_unqualified))
436 theTangentCircles.push_back(
437 std::shared_ptr<GccEnt_QualifiedCirc>(
438 new GccEnt_QualifiedCirc((*anIt)->Circle(), GccEnt_unqualified))
448 static void adjustPeriod(double& theParameter, const CurveAdaptorPtr& theCurve)
450 if (theCurve->Curve()->IsPeriodic()) {
451 theParameter = ElCLib::InPeriod(theParameter,
452 theCurve->FirstParameter(),
453 theCurve->FirstParameter() + theCurve->Period());
457 // boundary parameters of curve are NOT applied
458 static bool isParamInCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
460 adjustPeriod(theParameter, theCurve);
461 return theParameter > theCurve->FirstParameter() &&
462 theParameter < theCurve->LastParameter();
465 // boundary parameters of curve are applied too
466 static bool isParamOnCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
468 adjustPeriod(theParameter, theCurve);
469 return theParameter >= theCurve->FirstParameter() &&
470 theParameter <= theCurve->LastParameter();
474 Handle(Geom_Plane) myPlane;
475 std::shared_ptr<GeomAPI_Pnt2d> myCenter;
476 std::vector<gp_Pnt2d> myPassingPoints;
477 std::vector<CurveAdaptorPtr> myTangentShapes;
479 std::shared_ptr<GeomAPI_Pnt2d> myClosestPoint;
486 GeomAlgoAPI_Circ2dBuilder::GeomAlgoAPI_Circ2dBuilder(const std::shared_ptr<GeomAPI_Ax3>& thePlane)
492 void GeomAlgoAPI_Circ2dBuilder::setRadius(const double theRadius)
494 myRadius = theRadius;
497 void GeomAlgoAPI_Circ2dBuilder::setCenter(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter)
499 myCenter = theCenter;
502 void GeomAlgoAPI_Circ2dBuilder::addTangentCurve(const std::shared_ptr<GeomAPI_Shape>& theEdge)
504 if (theEdge->isEdge())
505 myTangentShapes.push_back(theEdge);
508 void GeomAlgoAPI_Circ2dBuilder::addPassingPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
510 myPassingPoints.push_back(thePoint);
513 void GeomAlgoAPI_Circ2dBuilder::setClosestPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
515 myClosestPoint = thePoint;
518 std::shared_ptr<GeomAPI_Circ2d> GeomAlgoAPI_Circ2dBuilder::circle(
519 const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
520 const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint,
521 const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPoint)
523 std::shared_ptr<GeomAPI_Ax3> aPlane(new GeomAPI_Ax3);
525 GeomAlgoAPI_Circ2dBuilder aBuilder(aPlane);
526 aBuilder.addPassingPoint(theFirstPoint);
527 aBuilder.addPassingPoint(theSecondPoint);
528 aBuilder.addPassingPoint(theThirdPoint);
529 return aBuilder.circle();
532 std::shared_ptr<GeomAPI_Circ2d> GeomAlgoAPI_Circ2dBuilder::circle()
534 CircleBuilder aCircleBuilder(myPlane);
535 aCircleBuilder.setCenter(myCenter);
536 aCircleBuilder.setTangentCurves(myTangentShapes);
537 aCircleBuilder.setPassingPoints(myPassingPoints);
538 aCircleBuilder.setClosestPoint(myClosestPoint);
539 aCircleBuilder.setRadius(myRadius);
540 Circ2dPtr aCirc2d = aCircleBuilder.circle();
542 std::shared_ptr<GeomAPI_Circ2d> aCircle;
544 const gp_Pnt2d& aCenter = aCirc2d->Location();
545 const gp_Dir2d& aXAxis = aCirc2d->Position().XDirection();
547 std::shared_ptr<GeomAPI_Pnt2d> aCircleCenter(new GeomAPI_Pnt2d(aCenter.X(), aCenter.Y()));
548 std::shared_ptr<GeomAPI_Dir2d> aCircleDir(new GeomAPI_Dir2d(aXAxis.X(), aXAxis.Y()));
550 aCircle = std::shared_ptr<GeomAPI_Circ2d>(
551 new GeomAPI_Circ2d(aCircleCenter, aCircleDir, aCirc2d->Radius()));