From 4a56d705d8a85c486ad4d0ab903112339bb74684 Mon Sep 17 00:00:00 2001 From: azv Date: Sat, 1 Apr 2017 11:33:13 +0300 Subject: [PATCH] Cleanup code of SketchPlugin_Fillet feature. Move calculation of tangent circle to GeomAPI_Circ2d. --- src/GeomAPI/GeomAPI_Circ2d.cpp | 200 +++++++++-- src/GeomAPI/GeomAPI_Circ2d.h | 8 + src/SketchPlugin/SketchPlugin_Fillet.cpp | 417 ++++------------------- src/SketchPlugin/SketchPlugin_Fillet.h | 6 +- 4 files changed, 256 insertions(+), 375 deletions(-) diff --git a/src/GeomAPI/GeomAPI_Circ2d.cpp b/src/GeomAPI/GeomAPI_Circ2d.cpp index a50e343ca..ca6be46f3 100644 --- a/src/GeomAPI/GeomAPI_Circ2d.cpp +++ b/src/GeomAPI/GeomAPI_Circ2d.cpp @@ -11,11 +11,13 @@ #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -35,14 +37,25 @@ #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())) + : 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; } @@ -80,12 +93,20 @@ public: 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: @@ -108,6 +129,25 @@ public: } 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(); @@ -162,31 +202,15 @@ private: gp_Circ2d* circleByThreeTangentCurves() { - std::shared_ptr aTgCirc[3]; - std::shared_ptr aTgLine[3]; - int aNbTgCirc = 0; - int aNbTgLine = 0; + VectorOfGccCirc aTgCirc; + VectorOfGccLine aTgLine; + convertTangentCurvesToGccEnt(aTgCirc, aTgLine); - std::vector::iterator anIt = myTangentShapes.begin(); - for (; anIt != myTangentShapes.end(); ++anIt) { - switch ((*anIt)->GetType()) { - case GeomAbs_Line: - aTgLine[aNbTgLine++] = std::shared_ptr( - new GccEnt_QualifiedLin((*anIt)->Line(), GccEnt_unqualified)); - break; - case GeomAbs_Circle: - aTgCirc[aNbTgCirc++] = std::shared_ptr( - new GccEnt_QualifiedCirc((*anIt)->Circle(), GccEnt_unqualified)); - break; - default: - break; - } - } - if (aNbTgCirc + aNbTgLine != 3) + if (aTgCirc.size() + aTgLine.size() != 3) return 0; std::shared_ptr aCircleBuilder; - switch (aNbTgLine) { + switch (aTgLine.size()) { case 0: aCircleBuilder = std::shared_ptr(new GccAna_Circ2d3Tan( *aTgCirc[0], *aTgCirc[1], *aTgCirc[2], Precision::Confusion())); @@ -279,7 +303,6 @@ private: return 0; } - gp_Circ2d* getProperCircle(const std::shared_ptr& theBuilder) const { if (!theBuilder) @@ -318,11 +341,127 @@ private: 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; @@ -439,6 +578,19 @@ GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr& theEnti 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 0777ad354..427197a84 100644 --- a/src/GeomAPI/GeomAPI_Circ2d.h +++ b/src/GeomAPI/GeomAPI_Circ2d.h @@ -53,6 +53,14 @@ class GeomAPI_Circ2d : public GeomAPI_Interface 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/SketchPlugin/SketchPlugin_Fillet.cpp b/src/SketchPlugin/SketchPlugin_Fillet.cpp index 6456d7b8c..89b2c6df8 100644 --- a/src/SketchPlugin/SketchPlugin_Fillet.cpp +++ b/src/SketchPlugin/SketchPlugin_Fillet.cpp @@ -46,22 +46,19 @@ const double PI = 3.141592653589793238463; static void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute, FeaturePtr theFeature, const std::string& theFeatureAttribute); + +/// \brief Calculate radius of a fillet. +/// It should not be greater than 1/3 of shortest edge length. +static double calculateFilletRadius(FeaturePtr theFilletFeatures[2]); + /// \brief Calculates center of fillet arc and coordinates of tangency points -static void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB, - double theRadius, bool theNotInversed[2], +static void calculateFilletCenter(FeaturePtr theFilletFeatures[2], + double theFilletRadius, + const std::shared_ptr& theSketchPlane, std::shared_ptr& theCenter, std::shared_ptr& theTangentA, std::shared_ptr& theTangentB); -/// Get point on 1/3 length of edge from fillet point -static void getPointOnEdge(const FeaturePtr theFeature, - const std::shared_ptr theFilletPoint, - std::shared_ptr& thePoint); - -/// Get distance from point to feature -static double getProjectionDistance(const FeaturePtr theFeature, - const std::shared_ptr thePoint); - /// Get coincide edges for fillet static std::set getCoincides(const FeaturePtr& theConstraintCoincidence); @@ -233,18 +230,8 @@ bool SketchPlugin_Fillet::calculateFilletParameters() return false; } - // Getting points located at 1/3 of edge length from fillet point. std::shared_ptr aFilletPnt2d = aFilletPoint2D->pnt(); - std::shared_ptr aPnt1, aPnt2; - getPointOnEdge(myBaseFeatures[0], aFilletPnt2d, aPnt1); - getPointOnEdge(myBaseFeatures[1], aFilletPnt2d, aPnt2); - - /// Getting distances. - double aDistance1 = getProjectionDistance(myBaseFeatures[1], aPnt1); - double aDistance2 = getProjectionDistance(myBaseFeatures[0], aPnt2); - - // Calculate radius value for fillet. - double aRadius = aDistance1 < aDistance2 ? aDistance1 / 2.0 : aDistance2 / 2.0; + double aRadius = calculateFilletRadius(myBaseFeatures); // Calculate arc attributes. static const int aNbFeatures = 2; @@ -277,8 +264,9 @@ bool SketchPlugin_Fillet::calculateFilletParameters() } } - calculateFilletCenter(myBaseFeatures[0], myBaseFeatures[1], aRadius, - myIsNotInversed, myCenterXY, myTangentXY1, myTangentXY2); + std::shared_ptr aSketchPlane = SketchPlugin_Sketch::plane(sketch()); + calculateFilletCenter(myBaseFeatures, aRadius, aSketchPlane, + myCenterXY, myTangentXY1, myTangentXY2); // Tangent directions of the features in coincident point. std::shared_ptr aTangentDir[aNbFeatures]; @@ -376,351 +364,84 @@ void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAt theFeature->attribute(theFeatureAttribute))->setValue(anArcPoint->x(), anArcPoint->y()); } -/// \brief Find intersections of lines shifted along normal direction -void possibleFilletCenterLineLine( - std::shared_ptr thePointA, std::shared_ptr theDirA, - std::shared_ptr thePointB, std::shared_ptr theDirB, - double theRadius, std::list< std::shared_ptr >& theCenters) +static std::shared_ptr toPoint(const AttributePtr& theAttribute) { - std::shared_ptr aDirAT(new GeomAPI_Dir2d(-theDirA->y(), theDirA->x())); - std::shared_ptr aDirBT(new GeomAPI_Dir2d(-theDirB->y(), theDirB->x())); - std::shared_ptr aPntA, aPntB; - double aDet = theDirA->cross(theDirB); - for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) { - aPntA = thePointA->added(aDirAT->xy()->multiplied(aStepA * theRadius)); - for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) { - aPntB = thePointB->added(aDirBT->xy()->multiplied(aStepB * theRadius)); - double aVX = aDirAT->xy()->dot(aPntA); - double aVY = aDirBT->xy()->dot(aPntB); - std::shared_ptr aPoint(new GeomAPI_XY( - (theDirB->x() * aVX - theDirA->x() * aVY) / aDet, - (theDirB->y() * aVX - theDirA->y() * aVY) / aDet)); - theCenters.push_back(aPoint); - } - } + std::shared_ptr aPoint; + AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast(theAttribute); + if (aPointAttr) + aPoint = aPointAttr->pnt(); + return aPoint; } -/// \brief Find intersections of line shifted along normal direction in both sides -/// and a circle with extended radius -void possibleFilletCenterLineArc( - std::shared_ptr theStartLine, std::shared_ptr theDirLine, - std::shared_ptr theCenterArc, double theRadiusArc, - double theRadius, std::list< std::shared_ptr >& theCenters) +static std::shared_ptr toLine(const FeaturePtr& theFeature) { - std::shared_ptr aDirT(new GeomAPI_Dir2d(-theDirLine->y(), theDirLine->x())); - std::shared_ptr aPnt; - double aDirNorm2 = theDirLine->dot(theDirLine); - double aRad = 0.0; - double aDirX = theDirLine->x(); - double aDirX2 = theDirLine->x() * theDirLine->x(); - double aDirY2 = theDirLine->y() * theDirLine->y(); - double aDirXY = theDirLine->x() * theDirLine->y(); - for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) { - aPnt = theStartLine->added(aDirT->xy()->multiplied(aStepA * theRadius)); - double aCoeff = aDirT->xy()->dot(aPnt->decreased(theCenterArc)); - double aCoeff2 = aCoeff * aCoeff; - for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) { - aRad = theRadiusArc + aStepB * theRadius; - double aD = aRad * aRad * aDirNorm2 - aCoeff2; - if (aD < 0.0) - continue; - double aDs = sqrt(aD); - double x1 = theCenterArc->x() + (aCoeff * aDirT->x() - aDirT->y() * aDs) / aDirNorm2; - double x2 = theCenterArc->x() + (aCoeff * aDirT->x() + aDirT->y() * aDs) / aDirNorm2; - double y1 = (aDirX2 * aPnt->y() + aDirY2 * theCenterArc->y() - - aDirXY * (aPnt->x() - theCenterArc->x()) - theDirLine->y() * aDs) / aDirNorm2; - double y2 = (aDirX2 * aPnt->y() + aDirY2 * theCenterArc->y() - - aDirXY * (aPnt->x() - theCenterArc->x()) + theDirLine->y() * aDs) / aDirNorm2; - - std::shared_ptr aPoint1(new GeomAPI_XY(x1, y1)); - theCenters.push_back(aPoint1); - std::shared_ptr aPoint2(new GeomAPI_XY(x2, y2)); - theCenters.push_back(aPoint2); - } + std::shared_ptr aLine; + if (theFeature->getKind() == SketchPlugin_Line::ID()) { + std::shared_ptr aStart = + toPoint( theFeature->attribute(SketchPlugin_Line::START_ID()) ); + std::shared_ptr aEnd = + toPoint( theFeature->attribute(SketchPlugin_Line::END_ID()) ); + aLine = std::shared_ptr(new GeomAPI_Lin2d(aStart, aEnd)); } + return aLine; } -/// \brief Find intersections of two circles with extended radii -void possibleFilletCenterArcArc( - std::shared_ptr theCenterA, double theRadiusA, - std::shared_ptr theCenterB, double theRadiusB, - double theRadius, std::list< std::shared_ptr >& theCenters) +static std::shared_ptr toCircle(const FeaturePtr& theFeature) { - std::shared_ptr aCenterDir = theCenterB->decreased(theCenterA); - double aCenterDist2 = aCenterDir->dot(aCenterDir); - double aCenterDist = sqrt(aCenterDist2); - - double aRadA, aRadB; - for (double aStepA = -1.0; aStepA <= 1.0; aStepA += 2.0) { - aRadA = theRadiusA + aStepA * theRadius; - for (double aStepB = -1.0; aStepB <= 1.0; aStepB += 2.0) { - aRadB = theRadiusB + aStepB * theRadius; - if (aRadA + aRadB < aCenterDist || fabs(aRadA - aRadB) > aCenterDist) - continue; // there is no intersections - - double aMedDist = (aRadA * aRadA - aRadB * aRadB + aCenterDist2) / (2.0 * aCenterDist); - double aHeight = sqrt(aRadA * aRadA - aMedDist * aMedDist); - - double x1 = theCenterA->x() + - (aMedDist * aCenterDir->x() + aCenterDir->y() * aHeight) / aCenterDist; - double y1 = theCenterA->y() + - (aMedDist * aCenterDir->y() - aCenterDir->x() * aHeight) / aCenterDist; - - double x2 = theCenterA->x() + - (aMedDist * aCenterDir->x() - aCenterDir->y() * aHeight) / aCenterDist; - double y2 = theCenterA->y() + - (aMedDist * aCenterDir->y() + aCenterDir->x() * aHeight) / aCenterDist; - - std::shared_ptr aPoint1(new GeomAPI_XY(x1, y1)); - theCenters.push_back(aPoint1); - std::shared_ptr aPoint2(new GeomAPI_XY(x2, y2)); - theCenters.push_back(aPoint2); - } + std::shared_ptr aCircle; + if (theFeature->getKind() == SketchPlugin_Arc::ID()) { + std::shared_ptr aCenter = + toPoint( theFeature->attribute(SketchPlugin_Arc::CENTER_ID()) ); + std::shared_ptr aStart = + toPoint( theFeature->attribute(SketchPlugin_Arc::START_ID()) ); + aCircle = std::shared_ptr(new GeomAPI_Circ2d(aCenter, aStart)); } + return aCircle; } -void calculateFilletCenter(FeaturePtr theFeatureA, FeaturePtr theFeatureB, - double theRadius, bool theNotInversed[2], + +void calculateFilletCenter(FeaturePtr theFilletFeatures[2], + double theFilletRadius, + const std::shared_ptr& theSketchPlane, std::shared_ptr& theCenter, std::shared_ptr& theTangentA, std::shared_ptr& theTangentB) { - static const int aNbFeatures = 2; - FeaturePtr aFeature[aNbFeatures] = {theFeatureA, theFeatureB}; - std::shared_ptr aStart[aNbFeatures], aEnd[aNbFeatures], aCenter[aNbFeatures]; - std::shared_ptr aStartPoint, aEndPoint; - - for (int i = 0; i < aNbFeatures; i++) { - if (aFeature[i]->getKind() == SketchPlugin_Line::ID()) { - aStartPoint = std::dynamic_pointer_cast( - aFeature[i]->attribute(SketchPlugin_Line::START_ID())); - aEndPoint = std::dynamic_pointer_cast( - aFeature[i]->attribute(SketchPlugin_Line::END_ID())); - } else if (aFeature[i]->getKind() == SketchPlugin_Arc::ID()) { - aStartPoint = std::dynamic_pointer_cast( - aFeature[i]->attribute(SketchPlugin_Arc::START_ID())); - aEndPoint = std::dynamic_pointer_cast( - aFeature[i]->attribute(SketchPlugin_Arc::END_ID())); - aCenter[i] = std::dynamic_pointer_cast( - aFeature[i]->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt()->xy(); - } else - return; - aStart[i] = std::shared_ptr(theNotInversed[i] ? - new GeomAPI_XY(aStartPoint->x(), aStartPoint->y()) : - new GeomAPI_XY(aEndPoint->x(), aEndPoint->y())); - aEnd[i] = std::shared_ptr(theNotInversed[i] ? - new GeomAPI_XY(aEndPoint->x(), aEndPoint->y()) : - new GeomAPI_XY(aStartPoint->x(), aStartPoint->y())); - } - - if (theFeatureA->getKind() == SketchPlugin_Line::ID() && - theFeatureB->getKind() == SketchPlugin_Line::ID()) { - std::shared_ptr aDir[2]; - std::shared_ptr aDirT[2]; - for (int i = 0; i < aNbFeatures; i++) { - aDir[i] = std::shared_ptr(new GeomAPI_Dir2d(aEnd[i]->decreased(aStart[i]))); - aDirT[i] = std::shared_ptr(new GeomAPI_Dir2d(-aDir[i]->y(), aDir[i]->x())); + 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()) + return; + + theCenter = aFilletCircle->center()->xy(); + // tangent points + std::shared_ptr aTgPoints[2]; + for (int i = 0; i < 2; ++i) { + std::shared_ptr aCircle = toCircle(theFilletFeatures[i]); + if (aCircle) + aTgPoints[i] = aCircle->project(aFilletCircle->center()); + else { + std::shared_ptr aLine = toLine(theFilletFeatures[i]); + if (aLine) + aTgPoints[i] = aLine->project(aFilletCircle->center()); } - - // get and filter possible centers - std::list< std::shared_ptr > aSuspectCenters; - possibleFilletCenterLineLine(aStart[0], aDir[0], aStart[1], aDir[1], - theRadius, aSuspectCenters); - double aDot = 0.0; - std::list< std::shared_ptr >::iterator anIt = aSuspectCenters.begin(); - for (; anIt != aSuspectCenters.end(); anIt++) { - aDot = aDirT[0]->xy()->dot(aStart[0]->decreased(*anIt)); - theTangentA = (*anIt)->added(aDirT[0]->xy()->multiplied(aDot)); - if (theTangentA->decreased(aStart[0])->dot(aDir[0]->xy()) < 0.0) - continue; // incorrect position - aDot = aDirT[1]->xy()->dot(aStart[1]->decreased(*anIt)); - theTangentB = (*anIt)->added(aDirT[1]->xy()->multiplied(aDot)); - if (theTangentB->decreased(aStart[1])->dot(aDir[1]->xy()) < 0.0) - continue; // incorrect position - // the center is found, stop searching - theCenter = *anIt; - return; - } - } else if ((theFeatureA->getKind() == SketchPlugin_Arc::ID() && - theFeatureB->getKind() == SketchPlugin_Line::ID()) || - (theFeatureA->getKind() == SketchPlugin_Line::ID() && - theFeatureB->getKind() == SketchPlugin_Arc::ID())) { - int aLineInd = theFeatureA->getKind() == SketchPlugin_Line::ID() ? 0 : 1; - double anArcRadius = aStart[1-aLineInd]->distance(aCenter[1-aLineInd]); - std::shared_ptr aDirLine = std::shared_ptr( - new GeomAPI_Dir2d(aEnd[aLineInd]->decreased(aStart[aLineInd]))); - std::shared_ptr aDirT = std::shared_ptr( - new GeomAPI_Dir2d(-aDirLine->y(), aDirLine->x())); - - std::shared_ptr aStartArcDir = std::shared_ptr( - new GeomAPI_Dir2d(aStart[1-aLineInd]->decreased(aCenter[1-aLineInd]))); - std::shared_ptr aEndArcDir = std::shared_ptr( - new GeomAPI_Dir2d(aEnd[1-aLineInd]->decreased(aCenter[1-aLineInd]))); - double anArcAngle = aStartArcDir->angle(aEndArcDir); - if (anArcAngle < 0.0) - anArcAngle += 2.0 * PI; - - // get possible centers and filter them - std::list< std::shared_ptr > aSuspectCenters; - possibleFilletCenterLineArc(aStart[aLineInd], aDirLine, aCenter[1-aLineInd], - anArcRadius, theRadius, aSuspectCenters); - double aDot = 0.0; - // the line is forward into the arc - double innerArc = aCenter[1-aLineInd]->decreased(aStart[aLineInd])->dot(aDirLine->xy()); - std::shared_ptr aLineTgPoint, anArcTgPoint; - // The possible centers are ranged by their positions. - // If the point is not satisfy one of criteria, the weight is decreased with penalty. - int aBestWeight = 0; - std::list< std::shared_ptr >::iterator anIt = aSuspectCenters.begin(); - for (; anIt != aSuspectCenters.end(); anIt++) { - int aWeight = 2; - aDot = aDirT->xy()->dot(aStart[aLineInd]->decreased(*anIt)); - aLineTgPoint = (*anIt)->added(aDirT->xy()->multiplied(aDot)); - // Check the point is placed on the correct arc (penalty if false) - if (aCenter[1-aLineInd]->distance(*anIt) * innerArc > anArcRadius * innerArc) - aWeight -= 1; - std::shared_ptr aCurDir = std::shared_ptr( - new GeomAPI_Dir2d((*anIt)->decreased(aCenter[1-aLineInd]))); - double aCurAngle = aStartArcDir->angle(aCurDir); - if (aCurAngle < 0.0) - aCurAngle += 2.0 * PI; - if (aCurAngle < 0.0 || aCurAngle > anArcAngle) - continue; - if (aWeight > aBestWeight) - aBestWeight = aWeight; - else if (aWeight < aBestWeight || - aStart[aLineInd]->distance(*anIt) > - aStart[aLineInd]->distance(theCenter)) // <-- take closer point - continue; - // the center is found, stop searching - theCenter = *anIt; - anArcTgPoint = aCenter[1-aLineInd]->added(aCurDir->xy()->multiplied(anArcRadius)); - if (theFeatureA->getKind() == SketchPlugin_Line::ID()) { - theTangentA = aLineTgPoint; - theTangentB = anArcTgPoint; - } else { - theTangentA = anArcTgPoint; - theTangentB = aLineTgPoint; - } - //return; - } - } else if (theFeatureA->getKind() == SketchPlugin_Arc::ID() && - theFeatureB->getKind() == SketchPlugin_Arc::ID()) { - double anArcRadius[aNbFeatures]; - double anArcAngle[aNbFeatures]; - std::shared_ptr aStartArcDir[aNbFeatures]; - for (int i = 0; i < aNbFeatures; i++) { - anArcRadius[i] = aStart[i]->distance(aCenter[i]); - aStartArcDir[i] = std::shared_ptr( - new GeomAPI_Dir2d(aStart[i]->decreased(aCenter[i]))); - std::shared_ptr aEndArcDir = std::shared_ptr( - new GeomAPI_Dir2d(aEnd[i]->decreased(aCenter[i]))); - anArcAngle[i] = aStartArcDir[i]->angle(aEndArcDir); - if (anArcAngle[i] < 0.0) - anArcAngle[i] += 2.0 * PI; - } - - // get and filter possible centers - std::list< std::shared_ptr > aSuspectCenters; - possibleFilletCenterArcArc(aCenter[0], anArcRadius[0], aCenter[1], - anArcRadius[1], theRadius, aSuspectCenters); - double aDot = 0.0; - std::shared_ptr aLineTgPoint, anArcTgPoint; - std::list< std::shared_ptr >::iterator anIt = aSuspectCenters.begin(); - for (; anIt != aSuspectCenters.end(); anIt++) { - std::shared_ptr aCurDir = std::shared_ptr( - new GeomAPI_Dir2d((*anIt)->decreased(aCenter[0]))); - double aCurAngle = aStartArcDir[0]->angle(aCurDir); - if (aCurAngle < 0.0) - aCurAngle += 2.0 * PI; - if (aCurAngle < 0.0 || aCurAngle > anArcAngle[0]) - continue; // incorrect position - theTangentA = aCenter[0]->added(aCurDir->xy()->multiplied(anArcRadius[0])); - - aCurDir = std::shared_ptr(new GeomAPI_Dir2d((*anIt)->decreased(aCenter[1]))); - aCurAngle = aStartArcDir[1]->angle(aCurDir); - if (aCurAngle < 0.0) - aCurAngle += 2.0 * PI; - if (aCurAngle < 0.0 || aCurAngle > anArcAngle[1]) - continue; // incorrect position - theTangentB = aCenter[1]->added(aCurDir->xy()->multiplied(anArcRadius[1])); - - // the center is found, stop searching - theCenter = *anIt; - return; - } - } -} - -void getPointOnEdge(const FeaturePtr theFeature, - const std::shared_ptr theFilletPoint, - std::shared_ptr& thePoint) { - if(theFeature->getKind() == SketchPlugin_Line::ID()) { - std::shared_ptr aPntStart = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt(); - std::shared_ptr aPntEnd = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt(); - if(aPntStart->distance(theFilletPoint) > 1.e-7) { - aPntStart = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt(); - aPntEnd = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt(); - } - thePoint.reset( - new GeomAPI_Pnt2d(aPntStart->xy()->added( - aPntEnd->xy()->decreased( aPntStart->xy() )->multiplied(1.0 / 3.0) ) ) ); - } else { - std::shared_ptr aPntTemp; - std::shared_ptr aPntStart = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt(); - std::shared_ptr aPntEnd = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt(); - if(theFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->value()) { - aPntTemp = aPntStart; - aPntStart = aPntEnd; - aPntEnd = aPntTemp; - } - std::shared_ptr aCenterPnt = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt(); - std::shared_ptr aCirc(new GeomAPI_Circ2d(aCenterPnt, aPntStart)); - double aStartParameter(0), anEndParameter(0); - aCirc->parameter(aPntStart, paramTolerance, aStartParameter); - aCirc->parameter(aPntEnd, paramTolerance, anEndParameter); - if(aPntStart->distance(theFilletPoint) > tolerance) { - double aTmpParameter = aStartParameter; - aStartParameter = anEndParameter; - anEndParameter = aTmpParameter; - } - double aPntParameter = aStartParameter + (anEndParameter - aStartParameter) / 3.0; - aCirc->D0(aPntParameter, thePoint); } + theTangentA = aTgPoints[0]->xy(); + theTangentB = aTgPoints[1]->xy(); } -double getProjectionDistance(const FeaturePtr theFeature, - const std::shared_ptr thePoint) +double calculateFilletRadius(FeaturePtr theFilletFeatures[2]) { - std::shared_ptr aProjectPnt; - if(theFeature->getKind() == SketchPlugin_Line::ID()) { - std::shared_ptr aPntStart = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt(); - std::shared_ptr aPntEnd = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt(); - std::shared_ptr aLin(new GeomAPI_Lin2d(aPntStart, aPntEnd)); - aProjectPnt = aLin->project(thePoint); - } else { - std::shared_ptr aPntStart = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt(); - std::shared_ptr aPntEnd = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt(); - std::shared_ptr aCenterPnt = std::dynamic_pointer_cast( - theFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt(); - std::shared_ptr aCirc(new GeomAPI_Circ2d(aCenterPnt, aPntStart)); - aProjectPnt = aCirc->project(thePoint); - } - if(aProjectPnt.get()) { - return aProjectPnt->distance(thePoint); + double aLengths[2] = { 0, 0 }; + for (int i = 0; i < 2; ++i) { + GeomShapePtr aShape = theFilletFeatures[i]->lastResult()->shape(); + std::shared_ptr anEdge = std::dynamic_pointer_cast(aShape); + if (anEdge) + aLengths[i] = anEdge->length(); } - return -1; + return std::min(aLengths[0], aLengths[1]) / 6.0; } std::set getCoincides(const FeaturePtr& theConstraintCoincidence) diff --git a/src/SketchPlugin/SketchPlugin_Fillet.h b/src/SketchPlugin/SketchPlugin_Fillet.h index 49388f26a..7cee33ca4 100644 --- a/src/SketchPlugin/SketchPlugin_Fillet.h +++ b/src/SketchPlugin/SketchPlugin_Fillet.h @@ -55,13 +55,13 @@ class SketchPlugin_Fillet: public SketchPlugin_SketchEntity, public GeomAPI_IPre /// Reimplemented from ModelAPI_Feature::isMacro(). /// \returns true - SKETCHPLUGIN_EXPORT virtual bool isMacro() const {return true;}; + SKETCHPLUGIN_EXPORT virtual bool isMacro() const {return true;} - SKETCHPLUGIN_EXPORT virtual bool isPreviewNeeded() const {return false;}; + SKETCHPLUGIN_EXPORT virtual bool isPreviewNeeded() const {return false;} /// Reimplemented from SketchPlugin_Feature::move(). /// Do nothing. - SKETCHPLUGIN_EXPORT virtual void move(const double theDeltaX, const double theDeltaY) {}; + SKETCHPLUGIN_EXPORT virtual void move(const double, const double) {} /// \brief Use plugin manager for features creation SketchPlugin_Fillet(); -- 2.39.2