From 5ca6ed762aa2c369cdb0e2b7bc4106d635be6d1a Mon Sep 17 00:00:00 2001 From: azv Date: Mon, 3 Apr 2017 12:45:17 +0300 Subject: [PATCH] Issue #2068: change of arc is by jump even due to smooth mouse movement Improve building of tangent arc by taking into account a point, selected by user. --- src/GeomAPI/GeomAPI_Circ2d.cpp | 533 ----------------- src/GeomAPI/GeomAPI_Circ2d.h | 28 - src/GeomAlgoAPI/CMakeLists.txt | 2 + src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.cpp | 537 ++++++++++++++++++ src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.h | 76 +++ src/SketchPlugin/SketchPlugin_Fillet.cpp | 11 +- src/SketchPlugin/SketchPlugin_MacroArc.cpp | 44 +- src/SketchPlugin/SketchPlugin_MacroCircle.cpp | 62 +- 8 files changed, 688 insertions(+), 605 deletions(-) create mode 100644 src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.cpp create mode 100644 src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.h diff --git a/src/GeomAPI/GeomAPI_Circ2d.cpp b/src/GeomAPI/GeomAPI_Circ2d.cpp index 9061473b0..7cb9f20ba 100644 --- a/src/GeomAPI/GeomAPI_Circ2d.cpp +++ b/src/GeomAPI/GeomAPI_Circ2d.cpp @@ -5,464 +5,17 @@ // Author: Artem ZHIDKOV #include -#include #include #include -#include -#include -#include -#include #include -#include #include -#include -#include -#include -#include -#include -#include -#include #include #include -#include -#include -#include #include -#include -#include - -#include #define MY_CIRC2D implPtr() -typedef std::shared_ptr CurveAdaptorPtr; -typedef std::vector< std::shared_ptr > VectorOfGccCirc; -typedef std::vector< std::shared_ptr > 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& theBasePlane) - : myPlane(new Geom_Plane(theBasePlane->impl())), - myRadius(0.0) - {} - - void setRadius(const double theRadius) - { myRadius = theRadius; } - - void addCenter(const std::shared_ptr& theCenter) - { myCenter = theCenter; } - - void addPassingEntity(const std::shared_ptr& theEntity) - { - std::shared_ptr aPoint = std::dynamic_pointer_cast(theEntity); - if (aPoint) - addPassingPoint(aPoint); - else { - std::shared_ptr aShape = std::dynamic_pointer_cast(theEntity); - if (aShape) - addTangentCurve(aShape); - } - } - - void addTangentCurve(const std::shared_ptr& theEdge) - { - if (!theEdge->isEdge()) - return; - - const TopoDS_Edge& anEdge = TopoDS::Edge(theEdge->impl()); - - 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& thePoint) - { - myPassingPoints.push_back(thePoint->impl()); - } - - 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(); - return new gp_Circ2d(gp_Ax2d(aCenter, gp::DX2d()), myRadius); - } - - gp_Circ2d* circleByCenterAndPassingPoint() - { - const gp_Pnt2d& aCenter = myCenter->impl(); - 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(); - CurveAdaptorPtr aCurve = myTangentShapes[0]; - - std::shared_ptr aCircleBuilder; - if (aCurve->GetType() == GeomAbs_Line) { - aCircleBuilder = std::shared_ptr( - new GccAna_Circ2dTanCen(aCurve->Line(), aCenter)); - } else if (aCurve->GetType() == GeomAbs_Circle) { - aCircleBuilder = std::shared_ptr(new GccAna_Circ2dTanCen( - GccEnt::Unqualified(aCurve->Circle()), aCenter, Precision::Confusion())); - } - - return getProperCircle(aCircleBuilder); - } - - gp_Circ2d* getProperCircle(const std::shared_ptr& 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 aCircleBuilder; - switch (aTgLine.size()) { - case 0: - aCircleBuilder = std::shared_ptr(new GccAna_Circ2d3Tan( - *aTgCirc[0], *aTgCirc[1], *aTgCirc[2], Precision::Confusion())); - break; - case 1: - aCircleBuilder = std::shared_ptr(new GccAna_Circ2d3Tan( - *aTgCirc[0], *aTgCirc[1], *aTgLine[0], Precision::Confusion())); - break; - case 2: - aCircleBuilder = std::shared_ptr(new GccAna_Circ2d3Tan( - *aTgCirc[0], *aTgLine[0], *aTgLine[1], Precision::Confusion())); - break; - case 3: - aCircleBuilder = std::shared_ptr(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 aCircleBuilder; - if (aCurve1->GetType() == GeomAbs_Line) { - if (aCurve2->GetType() == GeomAbs_Line) { - aCircleBuilder = std::shared_ptr( - new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve1->Line()), - GccEnt::Unqualified(aCurve2->Line()), - aPoint, Precision::Confusion())); - } else if (aCurve2->GetType() == GeomAbs_Circle) { - aCircleBuilder = std::shared_ptr( - 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( - new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve1->Circle()), - GccEnt::Unqualified(aCurve2->Line()), - aPoint, Precision::Confusion())); - } else if (aCurve2->GetType() == GeomAbs_Circle) { - aCircleBuilder = std::shared_ptr( - 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 aCircleBuilder; - if (aCurve->GetType() == GeomAbs_Line) { - aCircleBuilder = std::shared_ptr(new GccAna_Circ2d3Tan( - GccEnt::Unqualified(aCurve->Line()), aPoint1, aPoint2, Precision::Confusion())); - } else if (aCurve->GetType() == GeomAbs_Circle) { - aCircleBuilder = std::shared_ptr(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& 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 aCircleBuilder; - switch (aTgLine.size()) { - case 0: - aCircleBuilder = std::shared_ptr(new GccAna_Circ2d2TanRad( - *aTgCirc[0], *aTgCirc[1], myRadius, Precision::Confusion())); - break; - case 1: - aCircleBuilder = std::shared_ptr(new GccAna_Circ2d2TanRad( - *aTgCirc[0], *aTgLine[0], myRadius, Precision::Confusion())); - break; - case 2: - aCircleBuilder = std::shared_ptr(new GccAna_Circ2d2TanRad( - *aTgLine[0], *aTgLine[1], myRadius, Precision::Confusion())); - break; - default: - break; - } - - return getProperCircle(aCircleBuilder); - } - - gp_Circ2d* getProperCircle(const std::shared_ptr& 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::iterator anIt = myTangentShapes.begin(); - for (; anIt != myTangentShapes.end(); ++anIt) { - switch ((*anIt)->GetType()) { - case GeomAbs_Line: - theTangentLines.push_back( - std::shared_ptr( - new GccEnt_QualifiedLin((*anIt)->Line(), GccEnt_unqualified)) - ); - break; - case GeomAbs_Circle: - theTangentCircles.push_back( - std::shared_ptr( - 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 myCenter; - std::vector myPassingPoints; - std::vector myTangentShapes; - double myRadius; -}; - -typedef std::shared_ptr CircleBuilderPtr; - static gp_Circ2d* newCirc2d(const double theCenterX, const double theCenterY, const gp_Dir2d theDir, const double theRadius) @@ -487,49 +40,6 @@ static gp_Circ2d* newCirc2d(const double theCenterX, const double theCenterY, return newCirc2d(theCenterX, theCenterY, aDir, aRadius); } -static gp_Circ2d* newCirc2d(const std::shared_ptr& theFirstPoint, - const std::shared_ptr& theSecondPoint, - const std::shared_ptr& 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& theCenter, @@ -546,49 +56,6 @@ GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr& theCenter, { } -GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr& theFirstPoint, - const std::shared_ptr& theSecondPoint, - const std::shared_ptr& theThirdPoint) - : GeomAPI_Interface(newCirc2d(theFirstPoint, theSecondPoint, theThirdPoint)) -{ -} - -GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr& theCenter, - const std::shared_ptr& theTangent, - const std::shared_ptr& thePlane) -{ - CircleBuilderPtr aBuilder(new CircleBuilder(thePlane)); - aBuilder->addCenter(theCenter); - aBuilder->addTangentCurve(theTangent); - setImpl(aBuilder->circle()); -} - -GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr& theEntity1, - const std::shared_ptr& theEntity2, - const std::shared_ptr& theEntity3, - const std::shared_ptr& 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& theEntity1, - const std::shared_ptr& theEntity2, - const double theRadius, - const std::shared_ptr& thePlane) -{ - CircleBuilderPtr aBuilder(new CircleBuilder(thePlane)); - aBuilder->addPassingEntity(theEntity1); - aBuilder->addPassingEntity(theEntity2); - aBuilder->setRadius(theRadius); - setImpl(aBuilder->circle()); -} - - - const std::shared_ptr GeomAPI_Circ2d::project( const std::shared_ptr& thePoint) const { diff --git a/src/GeomAPI/GeomAPI_Circ2d.h b/src/GeomAPI/GeomAPI_Circ2d.h index 427197a84..42e47defa 100644 --- a/src/GeomAPI/GeomAPI_Circ2d.h +++ b/src/GeomAPI/GeomAPI_Circ2d.h @@ -33,34 +33,6 @@ class GeomAPI_Circ2d : public GeomAPI_Interface GeomAPI_Circ2d(const std::shared_ptr& theCenter, const std::shared_ptr& theDir, double theRadius); - /// Creation of circle defined by three points lying on it - GEOMAPI_EXPORT - GeomAPI_Circ2d(const std::shared_ptr& theFirstPoint, - const std::shared_ptr& theSecondPoint, - const std::shared_ptr& theThirdPoint); - - /// Creation of a circle defined by center and a tangent curve on the given plane - GEOMAPI_EXPORT - GeomAPI_Circ2d(const std::shared_ptr& theCenter, - const std::shared_ptr& theTangent, - const std::shared_ptr& 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& theEntity1, - const std::shared_ptr& theEntity2, - const std::shared_ptr& theEntity3, - const std::shared_ptr& 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& theEntity1, - const std::shared_ptr& theEntity2, - const double theRadius, - const std::shared_ptr& thePlane); - /// Return center of the circle GEOMAPI_EXPORT const std::shared_ptr center() const; diff --git a/src/GeomAlgoAPI/CMakeLists.txt b/src/GeomAlgoAPI/CMakeLists.txt index 2b5d6a2c6..920d67d6d 100644 --- a/src/GeomAlgoAPI/CMakeLists.txt +++ b/src/GeomAlgoAPI/CMakeLists.txt @@ -49,6 +49,7 @@ SET(PROJECT_HEADERS GeomAlgoAPI_ConeSegment.h GeomAlgoAPI_Symmetry.h GeomAlgoAPI_Scale.h + GeomAlgoAPI_Circ2dBuilder.h ) SET(PROJECT_SOURCES @@ -94,6 +95,7 @@ SET(PROJECT_SOURCES GeomAlgoAPI_ConeSegment.cpp GeomAlgoAPI_Symmetry.cpp GeomAlgoAPI_Scale.cpp + GeomAlgoAPI_Circ2dBuilder.cpp ) SET(PROJECT_LIBRARIES diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.cpp new file mode 100644 index 000000000..793ec3f57 --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.cpp @@ -0,0 +1,537 @@ +// Copyright (C) 2017-20xx CEA/DEN, EDF R&D + +// File: GeomAlgoAPI_Circ2dBuilder.cpp +// Created: 3 April 2017 +// Author: Artem ZHIDKOV + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +typedef std::shared_ptr Circ2dPtr; +typedef std::shared_ptr CurveAdaptorPtr; +typedef std::vector< std::shared_ptr > VectorOfGccCirc; +typedef std::vector< std::shared_ptr > 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& theBasePlane) + : myPlane(new Geom_Plane(theBasePlane->impl())), + myRadius(0.0) + {} + + void setRadius(const double theRadius) + { myRadius = theRadius; } + + void setCenter(const std::shared_ptr& theCenter) + { myCenter = theCenter; } + + void setTangentCurves(const std::vector< std::shared_ptr >& theEdges) + { + std::vector< std::shared_ptr >::const_iterator anEdgeIt; + for (anEdgeIt = theEdges.begin(); anEdgeIt != theEdges.end(); ++anEdgeIt) { + const TopoDS_Edge& anEdge = TopoDS::Edge((*anEdgeIt)->impl()); + + 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 >& thePoints) + { + std::vector< std::shared_ptr >::const_iterator aPIt; + for (aPIt = thePoints.begin(); aPIt != thePoints.end(); ++aPIt) + myPassingPoints.push_back((*aPIt)->impl()); + } + + void setClosestPoint(const std::shared_ptr& 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(); + return Circ2dPtr(new gp_Circ2d(gp_Ax2d(aCenter, gp::DX2d()), myRadius)); + } + + Circ2dPtr circleByCenterAndPassingPoint() + { + const gp_Pnt2d& aCenter = myCenter->impl(); + 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(); + CurveAdaptorPtr aCurve = myTangentShapes[0]; + + std::shared_ptr aCircleBuilder; + if (aCurve->GetType() == GeomAbs_Line) { + aCircleBuilder = std::shared_ptr( + new GccAna_Circ2dTanCen(aCurve->Line(), aCenter)); + } else if (aCurve->GetType() == GeomAbs_Circle) { + aCircleBuilder = std::shared_ptr(new GccAna_Circ2dTanCen( + GccEnt::Unqualified(aCurve->Circle()), aCenter, Precision::Confusion())); + } + + return getProperCircle(aCircleBuilder); + } + + Circ2dPtr getProperCircle(const std::shared_ptr& 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().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 aCircleBuilder; + switch (aTgLine.size()) { + case 0: + aCircleBuilder = std::shared_ptr(new GccAna_Circ2d3Tan( + *aTgCirc[0], *aTgCirc[1], *aTgCirc[2], Precision::Confusion())); + break; + case 1: + aCircleBuilder = std::shared_ptr(new GccAna_Circ2d3Tan( + *aTgCirc[0], *aTgCirc[1], *aTgLine[0], Precision::Confusion())); + break; + case 2: + aCircleBuilder = std::shared_ptr(new GccAna_Circ2d3Tan( + *aTgCirc[0], *aTgLine[0], *aTgLine[1], Precision::Confusion())); + break; + case 3: + aCircleBuilder = std::shared_ptr(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 aCircleBuilder; + if (aCurve1->GetType() == GeomAbs_Line) { + if (aCurve2->GetType() == GeomAbs_Line) { + aCircleBuilder = std::shared_ptr( + new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve1->Line()), + GccEnt::Unqualified(aCurve2->Line()), + aPoint, Precision::Confusion())); + } else if (aCurve2->GetType() == GeomAbs_Circle) { + aCircleBuilder = std::shared_ptr( + 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( + new GccAna_Circ2d3Tan(GccEnt::Unqualified(aCurve1->Circle()), + GccEnt::Unqualified(aCurve2->Line()), + aPoint, Precision::Confusion())); + } else if (aCurve2->GetType() == GeomAbs_Circle) { + aCircleBuilder = std::shared_ptr( + 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 aCircleBuilder; + if (aCurve->GetType() == GeomAbs_Line) { + aCircleBuilder = std::shared_ptr(new GccAna_Circ2d3Tan( + GccEnt::Unqualified(aCurve->Line()), aPoint1, aPoint2, Precision::Confusion())); + } else if (aCurve->GetType() == GeomAbs_Circle) { + aCircleBuilder = std::shared_ptr(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& 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 aCircleBuilder; + switch (aTgLine.size()) { + case 0: + aCircleBuilder = std::shared_ptr(new GccAna_Circ2d2TanRad( + *aTgCirc[0], *aTgCirc[1], myRadius, Precision::Confusion())); + break; + case 1: + aCircleBuilder = std::shared_ptr(new GccAna_Circ2d2TanRad( + *aTgCirc[0], *aTgLine[0], myRadius, Precision::Confusion())); + break; + case 2: + aCircleBuilder = std::shared_ptr(new GccAna_Circ2d2TanRad( + *aTgLine[0], *aTgLine[1], myRadius, Precision::Confusion())); + break; + default: + break; + } + + return getProperCircle(aCircleBuilder); + } + + Circ2dPtr getProperCircle(const std::shared_ptr& 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::iterator anIt = myTangentShapes.begin(); + for (; anIt != myTangentShapes.end(); ++anIt) { + switch ((*anIt)->GetType()) { + case GeomAbs_Line: + theTangentLines.push_back( + std::shared_ptr( + new GccEnt_QualifiedLin((*anIt)->Line(), GccEnt_unqualified)) + ); + break; + case GeomAbs_Circle: + theTangentCircles.push_back( + std::shared_ptr( + 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 myCenter; + std::vector myPassingPoints; + std::vector myTangentShapes; + double myRadius; + std::shared_ptr myClosestPoint; +}; + + + + + +GeomAlgoAPI_Circ2dBuilder::GeomAlgoAPI_Circ2dBuilder(const std::shared_ptr& thePlane) + : myPlane(thePlane), + myRadius(0.) +{ +} + +void GeomAlgoAPI_Circ2dBuilder::setRadius(const double theRadius) +{ + myRadius = theRadius; +} + +void GeomAlgoAPI_Circ2dBuilder::setCenter(const std::shared_ptr& theCenter) +{ + myCenter = theCenter; +} + +void GeomAlgoAPI_Circ2dBuilder::addTangentCurve(const std::shared_ptr& theEdge) +{ + if (theEdge->isEdge()) + myTangentShapes.push_back(theEdge); +} + +void GeomAlgoAPI_Circ2dBuilder::addPassingPoint(const std::shared_ptr& thePoint) +{ + myPassingPoints.push_back(thePoint); +} + +void GeomAlgoAPI_Circ2dBuilder::setClosestPoint(const std::shared_ptr& thePoint) +{ + myClosestPoint = thePoint; +} + +std::shared_ptr GeomAlgoAPI_Circ2dBuilder::circle( + const std::shared_ptr& theFirstPoint, + const std::shared_ptr& theSecondPoint, + const std::shared_ptr& theThirdPoint) +{ + std::shared_ptr aPlane(new GeomAPI_Ax3); + + GeomAlgoAPI_Circ2dBuilder aBuilder(aPlane); + aBuilder.addPassingPoint(theFirstPoint); + aBuilder.addPassingPoint(theSecondPoint); + aBuilder.addPassingPoint(theThirdPoint); + return aBuilder.circle(); +} + +std::shared_ptr 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 aCircle; + if (aCirc2d) { + const gp_Pnt2d& aCenter = aCirc2d->Location(); + const gp_Dir2d& aXAxis = aCirc2d->XAxis().Direction(); + + std::shared_ptr aCircleCenter(new GeomAPI_Pnt2d(aCenter.X(), aCenter.Y())); + std::shared_ptr aCircleDir(new GeomAPI_Dir2d(aXAxis.X(), aXAxis.Y())); + + aCircle = std::shared_ptr( + new GeomAPI_Circ2d(aCircleCenter, aCircleDir, aCirc2d->Radius())); + } + return aCircle; +} diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.h b/src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.h new file mode 100644 index 000000000..6aad6126f --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Circ2dBuilder.h @@ -0,0 +1,76 @@ +// 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 + +#include +#include + +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& 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& theCenter); + + /// \brief Constrain circle to be tangent to the given edge + GEOMALGOAPI_EXPORT + void addTangentCurve(const std::shared_ptr& theEdge); + + /// \brief Constrain circle to pass through the given point + GEOMALGOAPI_EXPORT + void addPassingPoint(const std::shared_ptr& thePoint); + + /// \brief Optional constraint to find circle closest to the given point + GEOMALGOAPI_EXPORT + void setClosestPoint(const std::shared_ptr& thePoint); + + /// \brief Build circle + GEOMALGOAPI_EXPORT + std::shared_ptr circle(); + + /// \brief Create a circle passing through three points + GEOMALGOAPI_EXPORT + static std::shared_ptr + circle(const std::shared_ptr& theFirstPoint, + const std::shared_ptr& theSecondPoint, + const std::shared_ptr& theThirdPoint); + +private: + std::shared_ptr myPlane; + std::shared_ptr myCenter; + std::vector< std::shared_ptr > myPassingPoints; + std::vector< std::shared_ptr > myTangentShapes; + std::shared_ptr myClosestPoint; + double myRadius; +}; + +#endif diff --git a/src/SketchPlugin/SketchPlugin_Fillet.cpp b/src/SketchPlugin/SketchPlugin_Fillet.cpp index 89b2c6df8..2a9acd4b1 100644 --- a/src/SketchPlugin/SketchPlugin_Fillet.cpp +++ b/src/SketchPlugin/SketchPlugin_Fillet.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -410,9 +411,13 @@ void calculateFilletCenter(FeaturePtr theFilletFeatures[2], GeomShapePtr aShapeA = theFilletFeatures[0]->lastResult()->shape(); GeomShapePtr aShapeB = theFilletFeatures[1]->lastResult()->shape(); - std::shared_ptr aFilletCircle( - new GeomAPI_Circ2d(aShapeA, aShapeB, theFilletRadius, theSketchPlane)); - if (!aFilletCircle->implPtr()) + GeomAlgoAPI_Circ2dBuilder aCircBuilder(theSketchPlane); + aCircBuilder.addTangentCurve(aShapeA); + aCircBuilder.addTangentCurve(aShapeB); + aCircBuilder.setRadius(theFilletRadius); + + std::shared_ptr aFilletCircle = aCircBuilder.circle(); + if (!aFilletCircle) return; theCenter = aFilletCircle->center()->xy(); diff --git a/src/SketchPlugin/SketchPlugin_MacroArc.cpp b/src/SketchPlugin/SketchPlugin_MacroArc.cpp index 42e3b1cd5..1c8371853 100644 --- a/src/SketchPlugin/SketchPlugin_MacroArc.cpp +++ b/src/SketchPlugin/SketchPlugin_MacroArc.cpp @@ -32,9 +32,11 @@ #include #include -#include + +#include #include #include +#include // for sqrt on Linux #include @@ -437,18 +439,22 @@ void SketchPlugin_MacroArc::fillByThreePassedPoints() SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve( refattr(PASSED_POINT_REF_ID()), aPassedPointAttr, aTangentCurve, aPassedPnt); - std::shared_ptr aPassed; - if (aTangentCurve) - aPassed = aTangentCurve; - else - aPassed = aPassedPnt; - - std::shared_ptr 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 aCircle = aCircBuilder.circle(); + if (!aCircle) + return; + myCenter = aCircle->center(); - recalculateReversedFlagByPassed(aCircle); + aCircle = std::shared_ptr(new GeomAPI_Circ2d(myCenter, myStart)); + recalculateReversedFlagByPassed(*aCircle); } else myCenter.reset(new GeomAPI_Pnt2d(myStart->xy()->added(myEnd->xy())->multiplied(0.5))); } @@ -497,11 +503,15 @@ void SketchPlugin_MacroArc::fillByTangentEdge() FeaturePtr aTangentFeature = ModelAPI_Feature::feature(aTangentPointAttr->owner()); std::shared_ptr aTangentShape = aTangentFeature->lastResult()->shape(); - std::shared_ptr 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 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(new GeomAPI_Circ2d(myCenter, myStart)); + recalculateReversedFlagByEnd(*aCircle); } diff --git a/src/SketchPlugin/SketchPlugin_MacroCircle.cpp b/src/SketchPlugin/SketchPlugin_MacroCircle.cpp index 0310207db..078543b7d 100644 --- a/src/SketchPlugin/SketchPlugin_MacroCircle.cpp +++ b/src/SketchPlugin/SketchPlugin_MacroCircle.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -211,13 +212,20 @@ void SketchPlugin_MacroCircle::fillByCenterAndPassed() aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint); // Build a circle - std::shared_ptr aCircle; + GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch())); + aCircBuilder.setCenter(aCenter); if (aTangentCurve) { - std::shared_ptr anAxis = SketchPlugin_Sketch::plane(sketch()); - aCircle = std::shared_ptr(new GeomAPI_Circ2d(aCenter, aTangentCurve, anAxis)); + aCircBuilder.addTangentCurve(aTangentCurve); + + AttributePoint2DPtr aPassedPntAttr = + std::dynamic_pointer_cast(aPassedAttr); + if (aPassedPntAttr) + aCircBuilder.setClosestPoint(aPassedPntAttr->pnt()); } else - aCircle = std::shared_ptr(new GeomAPI_Circ2d(aCenter, aPassedPoint)); - if (aCircle->implPtr()) { + aCircBuilder.addPassingPoint(aPassedPoint); + + std::shared_ptr aCircle = aCircBuilder.circle(); + if (aCircle) { myCenter = aCircle->center(); myRadius = aCircle->radius(); } @@ -231,7 +239,9 @@ void SketchPlugin_MacroCircle::fillByThreePoints() std::string aPointRef[3] = { FIRST_POINT_REF_ID(), SECOND_POINT_REF_ID(), THIRD_POINT_REF_ID() }; - std::shared_ptr aPassedEntities[3]; + + GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch())); + for (int aPntIndex = 0; aPntIndex < 3; ++aPntIndex) { AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]); if (!aPassedAttr->isInitialized()) @@ -245,15 +255,18 @@ void SketchPlugin_MacroCircle::fillByThreePoints() aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint); if (aPassedPoint) - aPassedEntities[aPntIndex] = aPassedPoint; + aCircBuilder.addPassingPoint(aPassedPoint); else - aPassedEntities[aPntIndex] = aTangentCurve; + aCircBuilder.addTangentCurve(aTangentCurve); } - std::shared_ptr anAxis = SketchPlugin_Sketch::plane(sketch()); - std::shared_ptr aCircle = std::shared_ptr( - new GeomAPI_Circ2d(aPassedEntities[0], aPassedEntities[1], aPassedEntities[2], anAxis)); - if (aCircle->implPtr()) { + AttributePoint2DPtr aThirdPoint = + std::dynamic_pointer_cast(attribute(THIRD_POINT_ID())); + if (aThirdPoint) + aCircBuilder.setClosestPoint(aThirdPoint->pnt()); + + std::shared_ptr aCircle = aCircBuilder.circle(); + if (aCircle) { myCenter = aCircle->center(); myRadius = aCircle->radius(); } @@ -265,8 +278,10 @@ void SketchPlugin_MacroCircle::fillByTwoPassedPoints() 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 aPassedPoints[2]; // there is possible only two passed points - std::shared_ptr aPassedEntities[3]; int aPntIndex = 0; for (; aPntIndex < 2; ++aPntIndex) { AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]); @@ -281,31 +296,30 @@ void SketchPlugin_MacroCircle::fillByTwoPassedPoints() 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(aPassedAttr)->pnt(); + aCircBuilder.addPassingPoint( + std::dynamic_pointer_cast(aPassedAttr)->pnt()); } } - if (aPntIndex <= 1) - return; std::shared_ptr aCircle; - if (aPassedEntities[2]) { - std::shared_ptr anAxis = SketchPlugin_Sketch::plane(sketch()); - aCircle = std::shared_ptr( - 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 aCenter(new GeomAPI_Pnt2d( (aPassedPoints[0]->x() + aPassedPoints[1]->x()) * 0.5, (aPassedPoints[0]->y() + aPassedPoints[1]->y()) * 0.5)); aCircle = std::shared_ptr(new GeomAPI_Circ2d(aCenter, aPassedPoints[0])); } - if (aCircle->implPtr()) { + + if (aCircle) { myCenter = aCircle->center(); myRadius = aCircle->radius(); } -- 2.39.2