Improve building of tangent arc by taking into account a point, selected by user.
// 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
{
GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
const std::shared_ptr<GeomAPI_Dir2d>& theDir, double theRadius);
- /// Creation of circle defined by three points lying on it
- GEOMAPI_EXPORT
- GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
- const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint,
- const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPoint);
-
- /// Creation of a circle defined by center and a tangent curve on the given plane
- GEOMAPI_EXPORT
- GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
- const std::shared_ptr<GeomAPI_Shape>& theTangent,
- const std::shared_ptr<GeomAPI_Ax3>& thePlane);
-
- /// Creation of a circle passing through or tangent to given entities.
- /// Supported items are GeomAPI_Pnt2d or GeomAPI_Shape
- GEOMAPI_EXPORT
- 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);
-
- /// Creation of a circle with given radius passing through or tangent to two entities.
- /// Supported items are GeomAPI_Pnt2d or GeomAPI_Shape
- GEOMAPI_EXPORT
- 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);
-
/// Return center of the circle
GEOMAPI_EXPORT
const std::shared_ptr<GeomAPI_Pnt2d> center() const;
GeomAlgoAPI_ConeSegment.h
GeomAlgoAPI_Symmetry.h
GeomAlgoAPI_Scale.h
+ GeomAlgoAPI_Circ2dBuilder.h
)
SET(PROJECT_SOURCES
GeomAlgoAPI_ConeSegment.cpp
GeomAlgoAPI_Symmetry.cpp
GeomAlgoAPI_Scale.cpp
+ GeomAlgoAPI_Circ2dBuilder.cpp
)
SET(PROJECT_LIBRARIES
--- /dev/null
+// Copyright (C) 2017-20xx CEA/DEN, EDF R&D
+
+// File: GeomAlgoAPI_Circ2dBuilder.cpp
+// Created: 3 April 2017
+// Author: Artem ZHIDKOV
+
+#include <GeomAlgoAPI_Circ2dBuilder.h>
+#include <GeomAPI_Ax3.h>
+#include <GeomAPI_Circ2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Shape.h>
+
+#include <BRep_Tool.hxx>
+#include <ElCLib.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 <Geom2dAdaptor_Curve.hxx>
+#include <Geom_Plane.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Edge.hxx>
+
+#include <cmath>
+
+typedef std::shared_ptr<gp_Circ2d> Circ2dPtr;
+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 setCenter(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter)
+ { myCenter = theCenter; }
+
+ void setTangentCurves(const std::vector< std::shared_ptr<GeomAPI_Shape> >& theEdges)
+ {
+ std::vector< std::shared_ptr<GeomAPI_Shape> >::const_iterator anEdgeIt;
+ for (anEdgeIt = theEdges.begin(); anEdgeIt != theEdges.end(); ++anEdgeIt) {
+ const TopoDS_Edge& anEdge = TopoDS::Edge((*anEdgeIt)->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));
+
+ // sort curves (circles should become first)
+ if (aCurveAdaptor->GetType() == GeomAbs_Circle)
+ myTangentShapes.insert(myTangentShapes.begin(), aCurveAdaptor);
+ else
+ myTangentShapes.push_back(aCurveAdaptor);
+ }
+ }
+
+ void setPassingPoints(const std::vector< std::shared_ptr<GeomAPI_Pnt2d> >& thePoints)
+ {
+ std::vector< std::shared_ptr<GeomAPI_Pnt2d> >::const_iterator aPIt;
+ for (aPIt = thePoints.begin(); aPIt != thePoints.end(); ++aPIt)
+ myPassingPoints.push_back((*aPIt)->impl<gp_Pnt2d>());
+ }
+
+ void setClosestPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
+ { myClosestPoint = thePoint; }
+
+
+ Circ2dPtr circle()
+ {
+ Circ2dPtr aResult;
+ 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:
+ Circ2dPtr circleByCenterAndRadius()
+ {
+ const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
+ return Circ2dPtr(new gp_Circ2d(gp_Ax2d(aCenter, gp::DX2d()), myRadius));
+ }
+
+ Circ2dPtr circleByCenterAndPassingPoint()
+ {
+ const gp_Pnt2d& aCenter = myCenter->impl<gp_Pnt2d>();
+ GccAna_Circ2dTanCen aBuilder(myPassingPoints[0], aCenter);
+ if (aBuilder.NbSolutions() > 0)
+ return Circ2dPtr(new gp_Circ2d(aBuilder.ThisSolution(1)));
+ return Circ2dPtr();
+ }
+
+ Circ2dPtr 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);
+ }
+
+ Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2dTanCen>& theBuilder) const
+ {
+ if (!theBuilder)
+ return Circ2dPtr();
+
+ CurveAdaptorPtr aCurve = myTangentShapes[0];
+
+ int aNbSol = theBuilder->NbSolutions();
+ if (aNbSol == 0)
+ return Circ2dPtr();
+
+ int anAppropriateSolution = 1;
+ double aMinDist = Precision::Infinite();
+
+ double aParSol, aPonTgCurve;
+ gp_Pnt2d aTgPnt;
+ for (int i = 1; i <= aNbSol && aCurve; ++i) {
+ theBuilder->Tangency1(i, aParSol, aPonTgCurve, aTgPnt);
+ if (isParamOnCurve(aPonTgCurve, aCurve)) {
+ double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
+ if (aDist < aMinDist) {
+ anAppropriateSolution = i;
+ aMinDist = aDist;
+ }
+ }
+ }
+
+ return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
+ }
+
+ double distanceToClosestPoint(const gp_Circ2d& theCirc) const
+ {
+ if (myClosestPoint) {
+ double aDist = myClosestPoint->impl<gp_Pnt2d>().Distance(theCirc.Location());
+ return fabs(aDist - theCirc.Radius());
+ }
+ return 0.0;
+ }
+
+
+ Circ2dPtr 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);
+ }
+
+ Circ2dPtr 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);
+ }
+
+ Circ2dPtr 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);
+ }
+
+ Circ2dPtr circleByThreePassingPoints()
+ {
+ GccAna_Circ2d3Tan aCircleBuilder(myPassingPoints[0],
+ myPassingPoints[1],
+ myPassingPoints[2],
+ Precision::Confusion());
+ if (aCircleBuilder.NbSolutions() > 0)
+ return Circ2dPtr(new gp_Circ2d(aCircleBuilder.ThisSolution(1)));
+ return Circ2dPtr();
+ }
+
+ Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2d3Tan>& theBuilder) const
+ {
+ if (!theBuilder)
+ return Circ2dPtr();
+
+ int aNbSol = theBuilder->NbSolutions();
+ if (aNbSol == 0)
+ return Circ2dPtr();
+
+ int anAppropriateSolution = 1;
+ double aMinDist = Precision::Infinite();
+
+ 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) {
+ double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
+ if (aDist < aMinDist) {
+ anAppropriateSolution = i;
+ aMinDist = aDist;
+ }
+ }
+ }
+
+ return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
+ }
+
+
+ Circ2dPtr 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);
+ }
+
+ Circ2dPtr getProperCircle(const std::shared_ptr<GccAna_Circ2d2TanRad>& theBuilder) const
+ {
+ if (!theBuilder)
+ return Circ2dPtr();
+
+ int aNbSol = theBuilder->NbSolutions();
+ if (aNbSol == 0)
+ return Circ2dPtr();
+
+ int anAppropriateSolution = 1;
+ double aMinDist = Precision::Infinite();
+
+ 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) {
+ double aDist = distanceToClosestPoint(theBuilder->ThisSolution(i));
+ if (aDist < aMinDist) {
+ anAppropriateSolution = i;
+ aMinDist = aDist;
+ }
+ }
+ }
+
+ return Circ2dPtr(new gp_Circ2d(theBuilder->ThisSolution(anAppropriateSolution)));
+ }
+
+
+ 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;
+ std::shared_ptr<GeomAPI_Pnt2d> myClosestPoint;
+};
+
+
+
+
+
+GeomAlgoAPI_Circ2dBuilder::GeomAlgoAPI_Circ2dBuilder(const std::shared_ptr<GeomAPI_Ax3>& thePlane)
+ : myPlane(thePlane),
+ myRadius(0.)
+{
+}
+
+void GeomAlgoAPI_Circ2dBuilder::setRadius(const double theRadius)
+{
+ myRadius = theRadius;
+}
+
+void GeomAlgoAPI_Circ2dBuilder::setCenter(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter)
+{
+ myCenter = theCenter;
+}
+
+void GeomAlgoAPI_Circ2dBuilder::addTangentCurve(const std::shared_ptr<GeomAPI_Shape>& theEdge)
+{
+ if (theEdge->isEdge())
+ myTangentShapes.push_back(theEdge);
+}
+
+void GeomAlgoAPI_Circ2dBuilder::addPassingPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
+{
+ myPassingPoints.push_back(thePoint);
+}
+
+void GeomAlgoAPI_Circ2dBuilder::setClosestPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
+{
+ myClosestPoint = thePoint;
+}
+
+std::shared_ptr<GeomAPI_Circ2d> GeomAlgoAPI_Circ2dBuilder::circle(
+ const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
+ const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint,
+ const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPoint)
+{
+ std::shared_ptr<GeomAPI_Ax3> aPlane(new GeomAPI_Ax3);
+
+ GeomAlgoAPI_Circ2dBuilder aBuilder(aPlane);
+ aBuilder.addPassingPoint(theFirstPoint);
+ aBuilder.addPassingPoint(theSecondPoint);
+ aBuilder.addPassingPoint(theThirdPoint);
+ return aBuilder.circle();
+}
+
+std::shared_ptr<GeomAPI_Circ2d> GeomAlgoAPI_Circ2dBuilder::circle()
+{
+ CircleBuilder aCircleBuilder(myPlane);
+ aCircleBuilder.setCenter(myCenter);
+ aCircleBuilder.setTangentCurves(myTangentShapes);
+ aCircleBuilder.setPassingPoints(myPassingPoints);
+ aCircleBuilder.setClosestPoint(myClosestPoint);
+ aCircleBuilder.setRadius(myRadius);
+ Circ2dPtr aCirc2d = aCircleBuilder.circle();
+
+ std::shared_ptr<GeomAPI_Circ2d> aCircle;
+ if (aCirc2d) {
+ const gp_Pnt2d& aCenter = aCirc2d->Location();
+ const gp_Dir2d& aXAxis = aCirc2d->XAxis().Direction();
+
+ std::shared_ptr<GeomAPI_Pnt2d> aCircleCenter(new GeomAPI_Pnt2d(aCenter.X(), aCenter.Y()));
+ std::shared_ptr<GeomAPI_Dir2d> aCircleDir(new GeomAPI_Dir2d(aXAxis.X(), aXAxis.Y()));
+
+ aCircle = std::shared_ptr<GeomAPI_Circ2d>(
+ new GeomAPI_Circ2d(aCircleCenter, aCircleDir, aCirc2d->Radius()));
+ }
+ return aCircle;
+}
--- /dev/null
+// Copyright (C) 2017-20xx CEA/DEN, EDF R&D
+
+// File: GeomAlgoAPI_Circ2dBuilder.h
+// Created: 3 April 2017
+// Author: Artem ZHIDKOV
+
+#ifndef GeomAlgoAPI_Circ2dBuilder_H_
+#define GeomAlgoAPI_Circ2dBuilder_H_
+
+#include <GeomAlgoAPI.h>
+
+#include <memory>
+#include <vector>
+
+class GeomAPI_Ax3;
+class GeomAPI_Circ2d;
+class GeomAPI_Pnt2d;
+class GeomAPI_Shape;
+
+/// \class GeomAlgoAPI_Circ2dBuilder
+/// \ingroup DataAlgo
+/// \brief Creates circle in 2D space satisfying combination of the following constraints:
+/// * center of a circle
+/// * passing through the point
+/// * tangent to a curve
+/// * fixed radius
+class GeomAlgoAPI_Circ2dBuilder
+{
+public:
+ /// \brief Create a builder object.
+ /// Constraints should be applied separately.
+ /// \param thePlane [in] plane to project tangent curves
+ GEOMALGOAPI_EXPORT
+ GeomAlgoAPI_Circ2dBuilder(const std::shared_ptr<GeomAPI_Ax3>& thePlane);
+
+ /// \brief Set fixed radius of the circle
+ GEOMALGOAPI_EXPORT
+ void setRadius(const double theRadius);
+
+ /// \brief Set fixed center of the circle
+ GEOMALGOAPI_EXPORT
+ void setCenter(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter);
+
+ /// \brief Constrain circle to be tangent to the given edge
+ GEOMALGOAPI_EXPORT
+ void addTangentCurve(const std::shared_ptr<GeomAPI_Shape>& theEdge);
+
+ /// \brief Constrain circle to pass through the given point
+ GEOMALGOAPI_EXPORT
+ void addPassingPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
+
+ /// \brief Optional constraint to find circle closest to the given point
+ GEOMALGOAPI_EXPORT
+ void setClosestPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
+
+ /// \brief Build circle
+ GEOMALGOAPI_EXPORT
+ std::shared_ptr<GeomAPI_Circ2d> circle();
+
+ /// \brief Create a circle passing through three points
+ GEOMALGOAPI_EXPORT
+ static std::shared_ptr<GeomAPI_Circ2d>
+ circle(const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
+ const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint,
+ const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPoint);
+
+private:
+ std::shared_ptr<GeomAPI_Ax3> myPlane;
+ std::shared_ptr<GeomAPI_Pnt2d> myCenter;
+ std::vector< std::shared_ptr<GeomAPI_Pnt2d> > myPassingPoints;
+ std::vector< std::shared_ptr<GeomAPI_Shape> > myTangentShapes;
+ std::shared_ptr<GeomAPI_Pnt2d> myClosestPoint;
+ double myRadius;
+};
+
+#endif
#include <ModelAPI_Tools.h>
#include <ModelAPI_Validator.h>
+#include <GeomAlgoAPI_Circ2dBuilder.h>
#include <GeomAlgoAPI_EdgeBuilder.h>
#include <GeomAPI_Circ2d.h>
GeomShapePtr aShapeA = theFilletFeatures[0]->lastResult()->shape();
GeomShapePtr aShapeB = theFilletFeatures[1]->lastResult()->shape();
- std::shared_ptr<GeomAPI_Circ2d> aFilletCircle(
- new GeomAPI_Circ2d(aShapeA, aShapeB, theFilletRadius, theSketchPlane));
- if (!aFilletCircle->implPtr<char>())
+ GeomAlgoAPI_Circ2dBuilder aCircBuilder(theSketchPlane);
+ aCircBuilder.addTangentCurve(aShapeA);
+ aCircBuilder.addTangentCurve(aShapeB);
+ aCircBuilder.setRadius(theFilletRadius);
+
+ std::shared_ptr<GeomAPI_Circ2d> aFilletCircle = aCircBuilder.circle();
+ if (!aFilletCircle)
return;
theCenter = aFilletCircle->center()->xy();
#include <GeomDataAPI_Point2D.h>
#include <GeomDataAPI_Dir.h>
-#include <GeomAlgoAPI_PointBuilder.h>
+
+#include <GeomAlgoAPI_Circ2dBuilder.h>
#include <GeomAlgoAPI_EdgeBuilder.h>
#include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_PointBuilder.h>
// for sqrt on Linux
#include <math.h>
SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
refattr(PASSED_POINT_REF_ID()), aPassedPointAttr, aTangentCurve, aPassedPnt);
- std::shared_ptr<GeomAPI_Interface> aPassed;
- if (aTangentCurve)
- aPassed = aTangentCurve;
- else
- aPassed = aPassedPnt;
-
- std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
- GeomAPI_Circ2d aCircle(myStart, myEnd, aPassed, anAxis);
- myCenter = aCircle.center();
- aCircle = GeomAPI_Circ2d(myCenter, myStart);
+ GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
+ aCircBuilder.addPassingPoint(myStart);
+ aCircBuilder.addPassingPoint(myEnd);
+ if (aTangentCurve) {
+ aCircBuilder.addTangentCurve(aTangentCurve);
+ aCircBuilder.setClosestPoint(aPassedPointAttr->pnt());
+ } else
+ aCircBuilder.addPassingPoint(aPassedPnt);
+
+ std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
+ if (!aCircle)
+ return;
+ myCenter = aCircle->center();
- recalculateReversedFlagByPassed(aCircle);
+ aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(myCenter, myStart));
+ recalculateReversedFlagByPassed(*aCircle);
} else
myCenter.reset(new GeomAPI_Pnt2d(myStart->xy()->added(myEnd->xy())->multiplied(0.5)));
}
FeaturePtr aTangentFeature = ModelAPI_Feature::feature(aTangentPointAttr->owner());
std::shared_ptr<GeomAPI_Shape> aTangentShape = aTangentFeature->lastResult()->shape();
- std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
- GeomAPI_Circ2d aCircle(myStart, myEnd, aTangentShape, anAxis);
- myCenter = aCircle.center();
+ GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
+ aCircBuilder.addPassingPoint(myStart);
+ aCircBuilder.addPassingPoint(myEnd);
+ aCircBuilder.addTangentCurve(aTangentShape);
+
+ std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
+ myCenter = aCircle->center();
// rebuild circle to set start point equal to zero parameter
- aCircle = GeomAPI_Circ2d(myCenter, myStart);
- recalculateReversedFlagByEnd(aCircle);
+ aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(myCenter, myStart));
+ recalculateReversedFlagByEnd(*aCircle);
}
#include <GeomAPI_Pnt2d.h>
#include <GeomAPI_Vertex.h>
+#include <GeomAlgoAPI_Circ2dBuilder.h>
#include <GeomAlgoAPI_CompoundBuilder.h>
#include <GeomAlgoAPI_EdgeBuilder.h>
#include <GeomAlgoAPI_PointBuilder.h>
aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
// Build a circle
- std::shared_ptr<GeomAPI_Circ2d> aCircle;
+ GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
+ aCircBuilder.setCenter(aCenter);
if (aTangentCurve) {
- std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
- aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aTangentCurve, anAxis));
+ aCircBuilder.addTangentCurve(aTangentCurve);
+
+ AttributePoint2DPtr aPassedPntAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPassedAttr);
+ if (aPassedPntAttr)
+ aCircBuilder.setClosestPoint(aPassedPntAttr->pnt());
} else
- aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aPassedPoint));
- if (aCircle->implPtr<char>()) {
+ aCircBuilder.addPassingPoint(aPassedPoint);
+
+ std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
+ if (aCircle) {
myCenter = aCircle->center();
myRadius = aCircle->radius();
}
std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
SECOND_POINT_REF_ID(),
THIRD_POINT_REF_ID() };
- std::shared_ptr<GeomAPI_Interface> aPassedEntities[3];
+
+ GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
+
for (int aPntIndex = 0; aPntIndex < 3; ++aPntIndex) {
AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
if (!aPassedAttr->isInitialized())
aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
if (aPassedPoint)
- aPassedEntities[aPntIndex] = aPassedPoint;
+ aCircBuilder.addPassingPoint(aPassedPoint);
else
- aPassedEntities[aPntIndex] = aTangentCurve;
+ aCircBuilder.addTangentCurve(aTangentCurve);
}
- std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
- std::shared_ptr<GeomAPI_Circ2d> aCircle = std::shared_ptr<GeomAPI_Circ2d>(
- new GeomAPI_Circ2d(aPassedEntities[0], aPassedEntities[1], aPassedEntities[2], anAxis));
- if (aCircle->implPtr<char>()) {
+ AttributePoint2DPtr aThirdPoint =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(THIRD_POINT_ID()));
+ if (aThirdPoint)
+ aCircBuilder.setClosestPoint(aThirdPoint->pnt());
+
+ std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
+ if (aCircle) {
myCenter = aCircle->center();
myRadius = aCircle->radius();
}
SECOND_POINT_ID() };
std::string aPointRef[2] = { FIRST_POINT_REF_ID(),
SECOND_POINT_REF_ID() };
+
+ GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
+
std::shared_ptr<GeomAPI_Pnt2d> aPassedPoints[2]; // there is possible only two passed points
- std::shared_ptr<GeomAPI_Interface> aPassedEntities[3];
int aPntIndex = 0;
for (; aPntIndex < 2; ++aPntIndex) {
AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
if (aPassedPoint) {
- aPassedEntities[aPntIndex] = aPassedPoint;
+ aCircBuilder.addPassingPoint(aPassedPoint);
aPassedPoints[aPntIndex] = aPassedPoint;
} else {
- aPassedEntities[aPntIndex] = aTangentCurve;
+ aCircBuilder.addTangentCurve(aTangentCurve);
// if the circle is tangent to any curve,
// the third point will be initialized by the tangent point
- aPassedEntities[2] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPassedAttr)->pnt();
+ aCircBuilder.addPassingPoint(
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPassedAttr)->pnt());
}
}
- if (aPntIndex <= 1)
- return;
std::shared_ptr<GeomAPI_Circ2d> aCircle;
- if (aPassedEntities[2]) {
- std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
- aCircle = std::shared_ptr<GeomAPI_Circ2d>(
- new GeomAPI_Circ2d(aPassedEntities[0], aPassedEntities[1], aPassedEntities[2], anAxis));
- } else {
+
+ if (aPntIndex == 3)
+ aCircle = aCircBuilder.circle();
+ else if (aPntIndex == 2) {
// the circle is defined by two points, calculate its parameters manually
std::shared_ptr<GeomAPI_Pnt2d> aCenter(new GeomAPI_Pnt2d(
(aPassedPoints[0]->x() + aPassedPoints[1]->x()) * 0.5,
(aPassedPoints[0]->y() + aPassedPoints[1]->y()) * 0.5));
aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aPassedPoints[0]));
}
- if (aCircle->implPtr<char>()) {
+
+ if (aCircle) {
myCenter = aCircle->center();
myRadius = aCircle->radius();
}