// Author: Artem ZHIDKOV
#include <GeomAPI_Circ2d.h>
-#include <GeomAPI_Ax3.h>
#include <GeomAPI_Pnt2d.h>
#include <GeomAPI_Dir2d.h>
-#include <GeomAPI_Shape.h>
-#include <BRep_Tool.hxx>
-#include <ElCLib.hxx>
-#include <gp_Dir2d.hxx>
#include <gp_Circ2d.hxx>
-#include <gp_Lin2d.hxx>
#include <gp_Pnt2d.hxx>
-#include <gp_Ax2d.hxx>
-#include <GccAna_Circ2d2TanRad.hxx>
-#include <GccAna_Circ2d3Tan.hxx>
-#include <GccAna_Circ2dTanCen.hxx>
-#include <GccEnt.hxx>
-#include <GccEnt_QualifiedCirc.hxx>
-#include <GccEnt_QualifiedLin.hxx>
#include <GeomLib_Tool.hxx>
#include <Geom2d_Circle.hxx>
-#include <Geom2dAPI_ProjectPointOnCurve.hxx>
-#include <Geom_Plane.hxx>
-#include <IntAna2d_AnaIntersection.hxx>
#include <Precision.hxx>
-#include <TopoDS.hxx>
-#include <TopoDS_Edge.hxx>
-
-#include <vector>
#define MY_CIRC2D implPtr<gp_Circ2d>()
-typedef std::shared_ptr<Geom2dAdaptor_Curve> CurveAdaptorPtr;
-typedef std::vector< std::shared_ptr<GccEnt_QualifiedCirc> > VectorOfGccCirc;
-typedef std::vector< std::shared_ptr<GccEnt_QualifiedLin> > VectorOfGccLine;
-
-// Provide different mechanisms to create circle:
-// * by passing points
-// * by tangent edges
-// * with specified radius
-// * etc.
-class CircleBuilder
-{
-public:
- CircleBuilder(const std::shared_ptr<GeomAPI_Ax3>& theBasePlane)
- : myPlane(new Geom_Plane(theBasePlane->impl<gp_Ax3>())),
- myRadius(0.0)
- {}
-
- void setRadius(const double theRadius)
- { myRadius = theRadius; }
-
- void addCenter(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter)
- { myCenter = theCenter; }
-
- void addPassingEntity(const std::shared_ptr<GeomAPI_Interface>& theEntity)
- {
- std::shared_ptr<GeomAPI_Pnt2d> aPoint = std::dynamic_pointer_cast<GeomAPI_Pnt2d>(theEntity);
- if (aPoint)
- addPassingPoint(aPoint);
- else {
- std::shared_ptr<GeomAPI_Shape> aShape = std::dynamic_pointer_cast<GeomAPI_Shape>(theEntity);
- if (aShape)
- addTangentCurve(aShape);
- }
- }
-
- void addTangentCurve(const std::shared_ptr<GeomAPI_Shape>& theEdge)
- {
- if (!theEdge->isEdge())
- return;
-
- const TopoDS_Edge& anEdge = TopoDS::Edge(theEdge->impl<TopoDS_Shape>());
-
- double aFirst, aLast;
- TopLoc_Location aLoc;
- Handle(Geom2d_Curve) aCurve = BRep_Tool::CurveOnSurface(anEdge, myPlane, aLoc, aFirst, aLast);
- CurveAdaptorPtr aCurveAdaptor(new Geom2dAdaptor_Curve(aCurve, aFirst, aLast));
-
- myTangentShapes.push_back(aCurveAdaptor);
- }
-
- void addPassingPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
- {
- myPassingPoints.push_back(thePoint->impl<gp_Pnt2d>());
- }
-
- gp_Circ2d* circle()
- {
- if (myTangentShapes.size() > 1)
- sortTangentShapes();
-
- gp_Circ2d* aResult = 0;
- if (myCenter) {
- if (myPassingPoints.size() == 1)
- aResult = circleByCenterAndPassingPoint();
- else if (myTangentShapes.size() == 1)
- aResult = circleByCenterAndTangent();
- else if (myRadius > 0.0)
- aResult = circleByCenterAndRadius();
- } else if (myRadius > 0.0) {
- if (myTangentShapes.size() == 2)
- aResult = circleByRadiusAndTwoTangentCurves();
- } else {
- switch (myPassingPoints.size()) {
- case 0:
- aResult = circleByThreeTangentCurves();
- break;
- case 1:
- aResult = circleByPointAndTwoTangentCurves();
- break;
- case 2:
- aResult = circleByTwoPointsAndTangentCurve();
- break;
- case 3:
- aResult = circleByThreePassingPoints();
- break;
- default:
- break;
- }
- }
- return aResult;
- }
-
-private:
- void sortTangentShapes()
- {
- // sort tangent shapes, so circles go before lines
- int aSize = (int)myTangentShapes.size();
- for (int i = 1; i < aSize; ++i) {
- if (myTangentShapes[i]->GetType() != GeomAbs_Circle)
- continue;
-
- for (int j = i - 1; j >= 0 && myTangentShapes[j]->GetType() == GeomAbs_Line; --j)
- std::swap(myTangentShapes[j], myTangentShapes[j+1]);
- }
- }
-
- gp_Circ2d* circleByCenterAndRadius()
- {
- const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
- return new gp_Circ2d(gp_Ax2d(aCenter, gp::DX2d()), myRadius);
- }
-
- gp_Circ2d* circleByCenterAndPassingPoint()
- {
- const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
- GccAna_Circ2dTanCen aBuilder(myPassingPoints[0], aCenter);
- if (aBuilder.NbSolutions() > 0)
- return new gp_Circ2d(aBuilder.ThisSolution(1));
- return 0;
- }
-
- gp_Circ2d* circleByCenterAndTangent()
- {
- const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
- CurveAdaptorPtr aCurve = myTangentShapes[0];
-
- std::shared_ptr<GccAna_Circ2dTanCen> aCircleBuilder;
- if (aCurve->GetType() == GeomAbs_Line) {
- aCircleBuilder = std::shared_ptr<GccAna_Circ2dTanCen>(
- new GccAna_Circ2dTanCen(aCurve->Line(), aCenter));
- } else if (aCurve->GetType() == GeomAbs_Circle) {
- aCircleBuilder = std::shared_ptr<GccAna_Circ2dTanCen>(new GccAna_Circ2dTanCen(
- GccEnt::Unqualified(aCurve->Circle()), aCenter, Precision::Confusion()));
- }
-
- return getProperCircle(aCircleBuilder);
- }
-
- gp_Circ2d* getProperCircle(const std::shared_ptr<GccAna_Circ2dTanCen>& theBuilder) const
- {
- if (!theBuilder)
- return 0;
-
- CurveAdaptorPtr aCurve = myTangentShapes[0];
-
- gp_Circ2d* aResult = 0;
- int aNbSol = theBuilder->NbSolutions();
- double aParSol, aPonTgCurve;
- gp_Pnt2d aTgPnt;
- for (int i = 1; i <= aNbSol && aCurve; ++i) {
- theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
- if (isParamOnCurve(aPonTgCurve, aCurve)) {
- aResult = new gp_Circ2d(theBuilder->ThisSolution(i));
- break;
- }
- }
- // unable to build circle passing through the tangent curve,
- // so get a circle passing any tangent point
- if (!aResult && aNbSol > 0)
- aResult = new gp_Circ2d(theBuilder->ThisSolution(1));
- return aResult;
- }
-
-
- gp_Circ2d* circleByThreeTangentCurves()
- {
- VectorOfGccCirc aTgCirc;
- VectorOfGccLine aTgLine;
- convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
-
- if (aTgCirc.size() + aTgLine.size() != 3)
- return 0;
-
- std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
- switch (aTgLine.size()) {
- case 0:
- aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
- *aTgCirc[0], *aTgCirc[1], *aTgCirc[2], Precision::Confusion()));
- break;
- case 1:
- aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
- *aTgCirc[0], *aTgCirc[1], *aTgLine[0], Precision::Confusion()));
- break;
- case 2:
- aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
- *aTgCirc[0], *aTgLine[0], *aTgLine[1], Precision::Confusion()));
- break;
- case 3:
- aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
- *aTgLine[0], *aTgLine[1], *aTgLine[0], Precision::Confusion()));
- break;
- default:
- break;
- }
-
- return getProperCircle(aCircleBuilder);
- }
-
- gp_Circ2d* circleByPointAndTwoTangentCurves()
- {
- const gp_Pnt2d& aPoint = myPassingPoints[0];
- CurveAdaptorPtr aCurve1 = myTangentShapes[0];
- CurveAdaptorPtr aCurve2 = myTangentShapes[1];
- if (!aCurve1 || !aCurve2)
- return 0;
-
- std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
- if (aCurve1->GetType() == GeomAbs_Line) {
- if (aCurve2->GetType() == GeomAbs_Line) {
- aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
- new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve1->Line()),
- GccEnt::Unqualified(aCurve2->Line()),
- aPoint, Precision::Confusion()));
- } else if (aCurve2->GetType() == GeomAbs_Circle) {
- aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
- new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve2->Circle()),
- GccEnt::Unqualified(aCurve1->Line()),
- aPoint, Precision::Confusion()));
- }
- } else if (aCurve1->GetType() == GeomAbs_Circle) {
- if (aCurve2->GetType() == GeomAbs_Line) {
- aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
- new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve1->Circle()),
- GccEnt::Unqualified(aCurve2->Line()),
- aPoint, Precision::Confusion()));
- } else if (aCurve2->GetType() == GeomAbs_Circle) {
- aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(
- new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve2->Circle()),
- GccEnt::Unqualified(aCurve1->Circle()),
- aPoint, Precision::Confusion()));
- }
- }
-
- return getProperCircle(aCircleBuilder);
- }
-
- gp_Circ2d* circleByTwoPointsAndTangentCurve()
- {
- const gp_Pnt2d& aPoint1 = myPassingPoints[0];
- const gp_Pnt2d& aPoint2 = myPassingPoints[1];
- CurveAdaptorPtr aCurve = myTangentShapes[0];
- if (!aCurve)
- return 0;
-
- std::shared_ptr<GccAna_Circ2d3Tan> aCircleBuilder;
- if (aCurve->GetType() == GeomAbs_Line) {
- aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
- GccEnt::Unqualified(aCurve->Line()), aPoint1, aPoint2, Precision::Confusion()));
- } else if (aCurve->GetType() == GeomAbs_Circle) {
- aCircleBuilder = std::shared_ptr<GccAna_Circ2d3Tan>(new GccAna_Circ2d3Tan(
- GccEnt::Unqualified(aCurve->Circle()), aPoint1, aPoint2, Precision::Confusion()));
- }
-
- return getProperCircle(aCircleBuilder);
- }
-
- gp_Circ2d* circleByThreePassingPoints()
- {
- GccAna_Circ2d3Tan aCircleBuilder(myPassingPoints[0],
- myPassingPoints[1],
- myPassingPoints[2],
- Precision::Confusion());
- if (aCircleBuilder.NbSolutions() > 0)
- return new gp_Circ2d(aCircleBuilder.ThisSolution(1));
- return 0;
- }
-
- gp_Circ2d* getProperCircle(const std::shared_ptr<GccAna_Circ2d3Tan>& theBuilder) const
- {
- if (!theBuilder)
- return 0;
-
- gp_Circ2d* aResult = 0;
- int aNbSol = theBuilder->NbSolutions();
- double aParSol, aPonTgCurve;
- gp_Pnt2d aTgPnt;
- for (int i = 1; i <= aNbSol; ++i) {
- bool isApplicable = false;
- if (myTangentShapes.size() >= 1) {
- theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
- isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[0]);
- }
- if (myTangentShapes.size() >= 2 && isApplicable) {
- theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
- isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[1]);
- }
- if (myTangentShapes.size() >= 3 && isApplicable) {
- theBuilder->Tangency3(i, aParSol, aPonTgCurve, aTgPnt);
- isApplicable = isParamOnCurve(aPonTgCurve, myTangentShapes[2]);
- }
-
- if (isApplicable) {
- aResult = new gp_Circ2d(theBuilder->ThisSolution(i));
- break;
- }
- }
- // unable to build circle passing through the tangent curve => get any tangent point
- if (!aResult && aNbSol > 0)
- aResult = new gp_Circ2d(theBuilder->ThisSolution(1));
- return aResult;
- }
-
-
- gp_Circ2d* circleByRadiusAndTwoTangentCurves()
- {
- VectorOfGccCirc aTgCirc;
- VectorOfGccLine aTgLine;
- convertTangentCurvesToGccEnt(aTgCirc, aTgLine);
-
- if (aTgCirc.size() + aTgLine.size() != 2)
- return 0;
-
- std::shared_ptr<GccAna_Circ2d2TanRad> aCircleBuilder;
- switch (aTgLine.size()) {
- case 0:
- aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
- *aTgCirc[0], *aTgCirc[1], myRadius, Precision::Confusion()));
- break;
- case 1:
- aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
- *aTgCirc[0], *aTgLine[0], myRadius, Precision::Confusion()));
- break;
- case 2:
- aCircleBuilder = std::shared_ptr<GccAna_Circ2d2TanRad>(new GccAna_Circ2d2TanRad(
- *aTgLine[0], *aTgLine[1], myRadius, Precision::Confusion()));
- break;
- default:
- break;
- }
-
- return getProperCircle(aCircleBuilder);
- }
-
- gp_Circ2d* getProperCircle(const std::shared_ptr<GccAna_Circ2d2TanRad>& theBuilder) const
- {
- if (!theBuilder)
- return 0;
-
- gp_Circ2d* aResult = 0;
- int aNbSol = theBuilder->NbSolutions();
- double aParSol, aPonTgCurve;
- gp_Pnt2d aTgPnt;
- for (int i = 1; i <= aNbSol; ++i) {
- bool isApplicable = false;
- if (myTangentShapes.size() >= 1) {
- theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
- isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[0]);
- }
- if (myTangentShapes.size() >= 2 && isApplicable) {
- theBuilder->Tangency2(i, aParSol, aPonTgCurve, aTgPnt);
- isApplicable = isParamInCurve(aPonTgCurve, myTangentShapes[1]);
- }
-
- if (isApplicable) {
- aResult = new gp_Circ2d(theBuilder->ThisSolution(i));
- break;
- }
- }
- // unable to build circle passing through the tangent curve => get any tangent point
- if (!aResult && aNbSol > 0)
- aResult = new gp_Circ2d(theBuilder->ThisSolution(1));
- return aResult;
- }
-
-
- void convertTangentCurvesToGccEnt(VectorOfGccCirc& theTangentCircles,
- VectorOfGccLine& theTangentLines)
- {
- theTangentCircles.reserve(3);
- theTangentLines.reserve(3);
-
- std::vector<CurveAdaptorPtr>::iterator anIt = myTangentShapes.begin();
- for (; anIt != myTangentShapes.end(); ++anIt) {
- switch ((*anIt)->GetType()) {
- case GeomAbs_Line:
- theTangentLines.push_back(
- std::shared_ptr<GccEnt_QualifiedLin>(
- new GccEnt_QualifiedLin((*anIt)->Line(), GccEnt_unqualified))
- );
- break;
- case GeomAbs_Circle:
- theTangentCircles.push_back(
- std::shared_ptr<GccEnt_QualifiedCirc>(
- new GccEnt_QualifiedCirc((*anIt)->Circle(), GccEnt_unqualified))
- );
- break;
- default:
- break;
- }
- }
- }
-
-
- // boundary parameters of curve are NOT applied
- static bool isParamInCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
- {
- if (theCurve->Curve()->IsPeriodic()) {
- theParameter = ElCLib::InPeriod(theParameter,
- theCurve->FirstParameter(),
- theCurve->FirstParameter() + theCurve->Period());
- }
- return theParameter > theCurve->FirstParameter() &&
- theParameter < theCurve->LastParameter();
- }
-
- // boundary parameters of curve are applied too
- static bool isParamOnCurve(double& theParameter, const CurveAdaptorPtr& theCurve)
- {
- if (theCurve->IsPeriodic()) {
- theParameter = ElCLib::InPeriod(theParameter,
- theCurve->FirstParameter(),
- theCurve->FirstParameter() + theCurve->Period());
- }
- return theParameter >= theCurve->FirstParameter() &&
- theParameter <= theCurve->LastParameter();
- }
-
-private:
- Handle(Geom_Plane) myPlane;
- std::shared_ptr<GeomAPI_Pnt2d> myCenter;
- std::vector<gp_Pnt2d> myPassingPoints;
- std::vector<CurveAdaptorPtr> myTangentShapes;
- double myRadius;
-};
-
-typedef std::shared_ptr<CircleBuilder> CircleBuilderPtr;
-
static gp_Circ2d* newCirc2d(const double theCenterX, const double theCenterY, const gp_Dir2d theDir,
const double theRadius)
return newCirc2d(theCenterX, theCenterY, aDir, aRadius);
}
-static gp_Circ2d* newCirc2d(const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
- const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint,
- const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPoint)
-{
- gp_XY aFirstPnt(theFirstPoint->x(), theFirstPoint->y());
- gp_XY aSecondPnt(theSecondPoint->x(), theSecondPoint->y());
- gp_XY aThirdPnt(theThirdPoint->x(), theThirdPoint->y());
-
- gp_XY aVec12 = aSecondPnt - aFirstPnt;
- gp_XY aVec23 = aThirdPnt - aSecondPnt;
- gp_XY aVec31 = aFirstPnt - aThirdPnt;
-
- // coefficients to calculate center
- double aCoeff1, aCoeff2, aCoeff3;
-
- // square of parallelogram
- double aSquare2 = aVec12.Crossed(aVec23);
- aSquare2 *= aSquare2 * 2.0;
- if (aSquare2 < 1.e-20) {
- // if two points are equal, build a circle on two different points as on diameter
- double aSqLen12 = aVec12.SquareModulus();
- double aSqLen23 = aVec23.SquareModulus();
- double aSqLen31 = aVec31.SquareModulus();
- if (aSqLen12 < Precision::SquareConfusion() &&
- aSqLen23 < Precision::SquareConfusion() &&
- aSqLen31 < Precision::SquareConfusion())
- return NULL;
- aCoeff1 = aCoeff2 = aCoeff3 = 1.0 / 3.0;
- }
- else {
- aCoeff1 = aVec23.Dot(aVec23) / aSquare2 * aVec12.Dot(aVec31.Reversed());
- aCoeff2 = aVec31.Dot(aVec31) / aSquare2 * aVec23.Dot(aVec12.Reversed());
- aCoeff3 = aVec12.Dot(aVec12) / aSquare2 * aVec31.Dot(aVec23.Reversed());
- }
- // center
- gp_XY aCenter = aFirstPnt * aCoeff1 + aSecondPnt * aCoeff2 + aThirdPnt * aCoeff3;
- // radius
- double aRadius = (aFirstPnt - aCenter).Modulus();
-
- gp_Dir2d aDir(aFirstPnt - aCenter);
- return newCirc2d(aCenter.X(), aCenter.Y(), aDir, aRadius);
-}
-
GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
{
}
-GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
- const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint,
- const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPoint)
- : GeomAPI_Interface(newCirc2d(theFirstPoint, theSecondPoint, theThirdPoint))
-{
-}
-
-GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
- const std::shared_ptr<GeomAPI_Shape>& theTangent,
- const std::shared_ptr<GeomAPI_Ax3>& thePlane)
-{
- CircleBuilderPtr aBuilder(new CircleBuilder(thePlane));
- aBuilder->addCenter(theCenter);
- aBuilder->addTangentCurve(theTangent);
- setImpl(aBuilder->circle());
-}
-
-GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Interface>& theEntity1,
- const std::shared_ptr<GeomAPI_Interface>& theEntity2,
- const std::shared_ptr<GeomAPI_Interface>& theEntity3,
- const std::shared_ptr<GeomAPI_Ax3>& thePlane)
-{
- CircleBuilderPtr aBuilder(new CircleBuilder(thePlane));
- aBuilder->addPassingEntity(theEntity1);
- aBuilder->addPassingEntity(theEntity2);
- aBuilder->addPassingEntity(theEntity3);
- setImpl(aBuilder->circle());
-}
-
-GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Interface>& theEntity1,
- const std::shared_ptr<GeomAPI_Interface>& theEntity2,
- const double theRadius,
- const std::shared_ptr<GeomAPI_Ax3>& thePlane)
-{
- CircleBuilderPtr aBuilder(new CircleBuilder(thePlane));
- aBuilder->addPassingEntity(theEntity1);
- aBuilder->addPassingEntity(theEntity2);
- aBuilder->setRadius(theRadius);
- setImpl(aBuilder->circle());
-}
-
-
-
const std::shared_ptr<GeomAPI_Pnt2d> GeomAPI_Circ2d::project(
const std::shared_ptr<GeomAPI_Pnt2d>& thePoint) const
{