1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
3 // File: GeomAPI_Circ2d.cpp
4 // Created: 29 May 2014
5 // Author: Artem ZHIDKOV
7 #include <GeomAPI_Circ2d.h>
8 #include <GeomAPI_Ax3.h>
9 #include <GeomAPI_Pnt2d.h>
10 #include <GeomAPI_Dir2d.h>
11 #include <GeomAPI_Shape.h>
13 #include <BRep_Tool.hxx>
14 #include <gp_Dir2d.hxx>
15 #include <gp_Circ2d.hxx>
16 #include <gp_Lin2d.hxx>
17 #include <gp_Pnt2d.hxx>
18 #include <gp_Ax2d.hxx>
19 #include <GccAna_Circ2d3Tan.hxx>
20 #include <GccAna_Circ2dTanCen.hxx>
22 #include <GccEnt_QualifiedCirc.hxx>
23 #include <GccEnt_QualifiedLin.hxx>
24 #include <GeomLib_Tool.hxx>
25 #include <Geom2d_Circle.hxx>
26 #include <Geom2dAPI_ProjectPointOnCurve.hxx>
27 #include <Geom_Plane.hxx>
28 #include <IntAna2d_AnaIntersection.hxx>
29 #include <Precision.hxx>
31 #include <TopoDS_Edge.hxx>
35 #define MY_CIRC2D implPtr<gp_Circ2d>()
37 typedef std::shared_ptr<Geom2dAdaptor_Curve> CurveAdaptorPtr;
42 CircleBuilder(const std::shared_ptr<GeomAPI_Ax3>& theBasePlane)
43 : myPlane(new Geom_Plane(theBasePlane->impl<gp_Ax3>()))
46 void addCenter(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter)
47 { myCenter = theCenter; }
49 void addPassingEntity(const std::shared_ptr<GeomAPI_Interface>& theEntity)
51 std::shared_ptr<GeomAPI_Pnt2d> aPoint = std::dynamic_pointer_cast<GeomAPI_Pnt2d>(theEntity);
53 addPassingPoint(aPoint);
55 std::shared_ptr<GeomAPI_Shape> aShape = std::dynamic_pointer_cast<GeomAPI_Shape>(theEntity);
57 addTangentCurve(aShape);
61 void addTangentCurve(const std::shared_ptr<GeomAPI_Shape>& theEdge)
63 if (!theEdge->isEdge())
66 const TopoDS_Edge& anEdge = TopoDS::Edge(theEdge->impl<TopoDS_Shape>());
70 Handle(Geom2d_Curve) aCurve = BRep_Tool::CurveOnSurface(anEdge, myPlane, aLoc, aFirst, aLast);
71 CurveAdaptorPtr aCurveAdaptor(new Geom2dAdaptor_Curve(aCurve, aFirst, aLast));
73 myTangentShapes.push_back(aCurveAdaptor);
76 void addPassingPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
78 myPassingPoints.push_back(thePoint->impl<gp_Pnt2d>());
83 gp_Circ2d* aResult = 0;
85 if (myPassingPoints.size() == 1)
86 aResult = circleByCenterAndPassingPoint();
87 else if (myTangentShapes.size() == 1)
88 aResult = circleByCenterAndTangent();
90 switch (myPassingPoints.size()) {
92 aResult = circleByThreeTangentCurves();
95 aResult = circleByPointAndTwoTangentCurves();
98 aResult = circleByTwoPointsAndTangentCurve();
101 aResult = circleByThreePassingPoints();
111 gp_Circ2d* circleByCenterAndPassingPoint()
113 const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
114 GccAna_Circ2dTanCen aBuilder(myPassingPoints[0], aCenter);
115 if (aBuilder.NbSolutions() > 0)
116 return new gp_Circ2d(aBuilder.ThisSolution(1));
120 gp_Circ2d* circleByCenterAndTangent()
122 const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
123 CurveAdaptorPtr aCurve = myTangentShapes[0];
125 std::shared_ptr<GccAna_Circ2dTanCen> aCircleBuilder;
126 if (aCurve->GetType() == GeomAbs_Line) {
127 aCircleBuilder = std::shared_ptr<GccAna_Circ2dTanCen>(
128 new GccAna_Circ2dTanCen(aCurve->Line(), aCenter));
129 } else if (aCurve->GetType() == GeomAbs_Circle) {
130 aCircleBuilder = std::shared_ptr<GccAna_Circ2dTanCen>(new GccAna_Circ2dTanCen(
131 GccEnt::Unqualified(aCurve->Circle()), aCenter, Precision::Confusion()));
134 return getProperCircle(aCircleBuilder);
137 gp_Circ2d* getProperCircle(const std::shared_ptr<GccAna_Circ2dTanCen>& theBuilder) const
142 CurveAdaptorPtr aCurve = myTangentShapes[0];
144 gp_Circ2d* aResult = 0;
145 int aNbSol = theBuilder->NbSolutions();
146 double aParSol, aPonTgCurve;
148 for (int i = 1; i <= aNbSol && aCurve; ++i) {
149 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
150 if (aPonTgCurve >= aCurve->FirstParameter() && aPonTgCurve <= aCurve->LastParameter()) {
151 aResult = new gp_Circ2d(theBuilder->ThisSolution(i));
155 // unable to build circle passing through the tangent curve,
156 // so get a circle passing any tangent point
157 if (!aResult && aNbSol > 0)
158 aResult = new gp_Circ2d(theBuilder->ThisSolution(1));
163 gp_Circ2d* circleByThreeTangentCurves()
165 std::shared_ptr<GccEnt_QualifiedCirc> aTgCirc[3];
166 std::shared_ptr<GccEnt_QualifiedLin> aTgLine[3];
170 std::vector<CurveAdaptorPtr>::iterator anIt = myTangentShapes.begin();
171 for (; anIt != myTangentShapes.end(); ++anIt) {
172 switch ((*anIt)->GetType()) {
174 aTgLine[aNbTgLine++] = std::shared_ptr<GccEnt_QualifiedLin>(
175 new GccEnt_QualifiedLin((*anIt)->Line(), GccEnt_unqualified));
178 aTgCirc[aNbTgCirc++] = std::shared_ptr<GccEnt_QualifiedCirc>(
179 new GccEnt_QualifiedCirc((*anIt)->Circle(), GccEnt_unqualified));
185 if (aNbTgCirc + aNbTgLine != 3)
188 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
191 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
192 *aTgCirc[0], *aTgCirc[1], *aTgCirc[2], Precision::Confusion()));
195 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
196 *aTgCirc[0], *aTgCirc[1], *aTgLine[0], Precision::Confusion()));
199 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
200 *aTgCirc[0], *aTgLine[0], *aTgLine[1], Precision::Confusion()));
203 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
204 *aTgLine[0], *aTgLine[1], *aTgLine[0], Precision::Confusion()));
210 return getProperCircle(aCircleBuilder);
213 gp_Circ2d* circleByPointAndTwoTangentCurves()
215 const gp_Pnt2d& aPoint = myPassingPoints[0];
216 CurveAdaptorPtr aCurve1 = myTangentShapes[0];
217 CurveAdaptorPtr aCurve2 = myTangentShapes[1];
218 if (!aCurve1 || !aCurve2)
221 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
222 if (aCurve1->GetType() == GeomAbs_Line) {
223 if (aCurve2->GetType() == GeomAbs_Line) {
224 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
225 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve1->Line()),
226 GccEnt::Unqualified(aCurve2->Line()),
227 aPoint, Precision::Confusion()));
228 } else if (aCurve2->GetType() == GeomAbs_Circle) {
229 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
230 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve2->Circle()),
231 GccEnt::Unqualified(aCurve1->Line()),
232 aPoint, Precision::Confusion()));
234 } else if (aCurve1->GetType() == GeomAbs_Circle) {
235 if (aCurve2->GetType() == GeomAbs_Line) {
236 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
237 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve1->Circle()),
238 GccEnt::Unqualified(aCurve2->Line()),
239 aPoint, Precision::Confusion()));
240 } else if (aCurve2->GetType() == GeomAbs_Circle) {
241 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
242 new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve2->Circle()),
243 GccEnt::Unqualified(aCurve1->Circle()),
244 aPoint, Precision::Confusion()));
248 return getProperCircle(aCircleBuilder);
251 gp_Circ2d* circleByTwoPointsAndTangentCurve()
253 const gp_Pnt2d& aPoint1 = myPassingPoints[0];
254 const gp_Pnt2d& aPoint2 = myPassingPoints[1];
255 CurveAdaptorPtr aCurve = myTangentShapes[0];
259 std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
260 if (aCurve->GetType() == GeomAbs_Line) {
261 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
262 GccEnt::Unqualified(aCurve->Line()), aPoint1, aPoint2, Precision::Confusion()));
263 } else if (aCurve->GetType() == GeomAbs_Circle) {
264 aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
265 GccEnt::Unqualified(aCurve->Circle()), aPoint1, aPoint2, Precision::Confusion()));
268 return getProperCircle(aCircleBuilder);
271 gp_Circ2d* circleByThreePassingPoints()
273 GccAna_Circ2d3Tan aCircleBuilder(myPassingPoints[0],
276 Precision::Confusion());
277 if (aCircleBuilder.NbSolutions() > 0)
278 return new gp_Circ2d(aCircleBuilder.ThisSolution(1));
283 gp_Circ2d* getProperCircle(const std::shared_ptr<GccAna_Circ2d3Tan>& theBuilder) const
288 gp_Circ2d* aResult = 0;
289 int aNbSol = theBuilder->NbSolutions();
290 double aParSol, aPonTgCurve;
292 for (int i = 1; i <= aNbSol; ++i) {
293 bool isApplicable = false;
294 if (myTangentShapes.size() >= 1) {
295 theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
296 isApplicable = aPonTgCurve >= myTangentShapes[0]->FirstParameter() &&
297 aPonTgCurve <= myTangentShapes[0]->LastParameter();
299 if (myTangentShapes.size() >= 2 && isApplicable) {
300 theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
301 isApplicable = aPonTgCurve >= myTangentShapes[1]->FirstParameter() &&
302 aPonTgCurve <= myTangentShapes[1]->LastParameter();
304 if (myTangentShapes.size() >= 3 && isApplicable) {
305 theBuilder->Tangency3(i, aParSol, aPonTgCurve, aTgPnt);
306 isApplicable = aPonTgCurve >= myTangentShapes[2]->FirstParameter() &&
307 aPonTgCurve <= myTangentShapes[2]->LastParameter();
311 aResult = new gp_Circ2d(theBuilder->ThisSolution(i));
315 // unable to build circle passing through the tangent curve => get any tangent point
316 if (!aResult && aNbSol > 0)
317 aResult = new gp_Circ2d(theBuilder->ThisSolution(1));
322 Handle(Geom_Plane) myPlane;
323 std::shared_ptr<GeomAPI_Pnt2d> myCenter;
324 std::vector<gp_Pnt2d> myPassingPoints;
325 std::vector<CurveAdaptorPtr> myTangentShapes;
328 typedef std::shared_ptr<CircleBuilder> CircleBuilderPtr;
331 static gp_Circ2d* newCirc2d(const double theCenterX, const double theCenterY, const gp_Dir2d theDir,
332 const double theRadius)
334 gp_Pnt2d aCenter(theCenterX, theCenterY);
335 return new gp_Circ2d(gp_Ax2d(aCenter, theDir), theRadius);
338 static gp_Circ2d* newCirc2d(const double theCenterX, const double theCenterY,
339 const double thePointX, const double thePointY)
341 gp_Pnt2d aCenter(theCenterX, theCenterY);
342 gp_Pnt2d aPoint(thePointX, thePointY);
344 double aRadius = aCenter.Distance(aPoint);
346 if (aCenter.IsEqual(aPoint, Precision::Confusion()))
349 gp_Dir2d aDir(thePointX - theCenterX, thePointY - theCenterY);
351 return newCirc2d(theCenterX, theCenterY, aDir, aRadius);
354 static gp_Circ2d* newCirc2d(const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
355 const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint,
356 const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPoint)
358 gp_XY aFirstPnt(theFirstPoint->x(), theFirstPoint->y());
359 gp_XY aSecondPnt(theSecondPoint->x(), theSecondPoint->y());
360 gp_XY aThirdPnt(theThirdPoint->x(), theThirdPoint->y());
362 gp_XY aVec12 = aSecondPnt - aFirstPnt;
363 gp_XY aVec23 = aThirdPnt - aSecondPnt;
364 gp_XY aVec31 = aFirstPnt - aThirdPnt;
366 // coefficients to calculate center
367 double aCoeff1, aCoeff2, aCoeff3;
369 // square of parallelogram
370 double aSquare2 = aVec12.Crossed(aVec23);
371 aSquare2 *= aSquare2 * 2.0;
372 if (aSquare2 < 1.e-20) {
373 // if two points are equal, build a circle on two different points as on diameter
374 double aSqLen12 = aVec12.SquareModulus();
375 double aSqLen23 = aVec23.SquareModulus();
376 double aSqLen31 = aVec31.SquareModulus();
377 if (aSqLen12 < Precision::SquareConfusion() &&
378 aSqLen23 < Precision::SquareConfusion() &&
379 aSqLen31 < Precision::SquareConfusion())
381 aCoeff1 = aCoeff2 = aCoeff3 = 1.0 / 3.0;
384 aCoeff1 = aVec23.Dot(aVec23) / aSquare2 * aVec12.Dot(aVec31.Reversed());
385 aCoeff2 = aVec31.Dot(aVec31) / aSquare2 * aVec23.Dot(aVec12.Reversed());
386 aCoeff3 = aVec12.Dot(aVec12) / aSquare2 * aVec31.Dot(aVec23.Reversed());
389 gp_XY aCenter = aFirstPnt * aCoeff1 + aSecondPnt * aCoeff2 + aThirdPnt * aCoeff3;
391 double aRadius = (aFirstPnt - aCenter).Modulus();
393 gp_Dir2d aDir(aFirstPnt - aCenter);
394 return newCirc2d(aCenter.X(), aCenter.Y(), aDir, aRadius);
399 GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
400 const std::shared_ptr<GeomAPI_Pnt2d>& theCirclePoint)
402 newCirc2d(theCenter->x(), theCenter->y(), theCirclePoint->x(), theCirclePoint->y()))
406 GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
407 const std::shared_ptr<GeomAPI_Dir2d>& theDir, double theRadius)
409 newCirc2d(theCenter->x(), theCenter->y(), theDir->impl<gp_Dir2d>(), theRadius))
413 GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
414 const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint,
415 const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPoint)
416 : GeomAPI_Interface(newCirc2d(theFirstPoint, theSecondPoint, theThirdPoint))
420 GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
421 const std::shared_ptr<GeomAPI_Shape>& theTangent,
422 const std::shared_ptr<GeomAPI_Ax3>& thePlane)
424 CircleBuilderPtr aBuilder(new CircleBuilder(thePlane));
425 aBuilder->addCenter(theCenter);
426 aBuilder->addTangentCurve(theTangent);
427 setImpl(aBuilder->circle());
430 GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Interface>& theEntity1,
431 const std::shared_ptr<GeomAPI_Interface>& theEntity2,
432 const std::shared_ptr<GeomAPI_Interface>& theEntity3,
433 const std::shared_ptr<GeomAPI_Ax3>& thePlane)
435 CircleBuilderPtr aBuilder(new CircleBuilder(thePlane));
436 aBuilder->addPassingEntity(theEntity1);
437 aBuilder->addPassingEntity(theEntity2);
438 aBuilder->addPassingEntity(theEntity3);
439 setImpl(aBuilder->circle());
443 const std::shared_ptr<GeomAPI_Pnt2d> GeomAPI_Circ2d::project(
444 const std::shared_ptr<GeomAPI_Pnt2d>& thePoint) const
446 std::shared_ptr<GeomAPI_Pnt2d> aResult;
450 const gp_Pnt2d& aCenter = MY_CIRC2D->Location();
451 const gp_Pnt2d& aPoint = thePoint->impl<gp_Pnt2d>();
453 double aDist = aCenter.Distance(aPoint);
454 if (aDist < Precision::Confusion())
457 if (Abs(aDist - MY_CIRC2D->Radius()) < Precision::Confusion()) {
458 // Point on the circle
459 aResult = std::shared_ptr<GeomAPI_Pnt2d>(
460 new GeomAPI_Pnt2d(thePoint->x(), thePoint->y()));
462 gp_Dir2d aDir(aPoint.XY() - aCenter.XY());
463 gp_XY aNewPoint = aCenter.XY() + aDir.XY() * MY_CIRC2D->Radius();
464 aResult = std::shared_ptr<GeomAPI_Pnt2d>(
465 new GeomAPI_Pnt2d(aNewPoint.X(), aNewPoint.Y()));
471 const std::shared_ptr<GeomAPI_Pnt2d> GeomAPI_Circ2d::center() const
474 return std::shared_ptr<GeomAPI_Pnt2d>();
475 const gp_Pnt2d& aCenter = MY_CIRC2D->Location();
476 return std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aCenter.X(), aCenter.Y()));
479 double GeomAPI_Circ2d::radius() const
483 return MY_CIRC2D->Radius();
486 //=================================================================================================
487 const bool GeomAPI_Circ2d::parameter(const std::shared_ptr<GeomAPI_Pnt2d> thePoint,
488 const double theTolerance,
489 double& theParameter) const
491 Handle(Geom2d_Circle) aCurve = new Geom2d_Circle(*MY_CIRC2D);
492 return GeomLib_Tool::Parameter(aCurve, thePoint->impl<gp_Pnt2d>(),
493 theTolerance, theParameter) == Standard_True;
496 //=================================================================================================
497 void GeomAPI_Circ2d::D0(const double theU, std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
499 Handle(Geom2d_Circle) aCurve = new Geom2d_Circle(*MY_CIRC2D);
501 aCurve->D0(theU, aPnt);
502 thePoint.reset(new GeomAPI_Pnt2d(aPnt.X(), aPnt.Y()));