X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchPlugin%2FSketchPlugin_Fillet.cpp;h=10a6a781c9cd7ee9b04168b45a5a1dd17afb5b66;hb=0de6abc2ba4932e6c5b52009f62774c68791ccde;hp=9a163403fdd93b9249d2deae0ae5839fddb2cce4;hpb=c92ed07b94514f5fa8f6c6cdd27d661e2f893c3e;p=modules%2Fshaper.git diff --git a/src/SketchPlugin/SketchPlugin_Fillet.cpp b/src/SketchPlugin/SketchPlugin_Fillet.cpp index 9a163403f..10a6a781c 100644 --- a/src/SketchPlugin/SketchPlugin_Fillet.cpp +++ b/src/SketchPlugin/SketchPlugin_Fillet.cpp @@ -1,8 +1,22 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> - -// File: SketchPlugin_Fillet.cpp -// Created: 19 Mar 2015 -// Author: Artem ZHIDKOV +// Copyright (C) 2014-2017 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or +// email : webmaster.salome@opencascade.com +// #include "SketchPlugin_Fillet.h" @@ -13,6 +27,7 @@ #include "SketchPlugin_ConstraintEqual.h" #include "SketchPlugin_ConstraintCoincidence.h" #include "SketchPlugin_ConstraintLength.h" +#include "SketchPlugin_ConstraintMiddle.h" #include "SketchPlugin_ConstraintTangent.h" #include "SketchPlugin_ConstraintRadius.h" #include "SketchPlugin_Tools.h" @@ -24,6 +39,7 @@ #include #include +#include #include #include @@ -40,27 +56,25 @@ const double tolerance = 1.e-7; const double paramTolerance = 1.e-4; +const double PI = 3.141592653589793238463; /// \brief Attract specified point on theNewArc to the attribute of theFeature 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); @@ -85,6 +99,13 @@ void SketchPlugin_Fillet::execute() if (isUpdateFlushed) Events_Loop::loop()->setFlushed(anUpdateEvent, false); + // set flag here to avoid building Fillet presentation if "Redisplay" event appears + myFilletCreated = true; + + // Calculate Fillet parameters if does not yet + if (!myBaseFeatures[0] || !myBaseFeatures[1]) + calculateFilletParameters(); + // Create arc feature. FeaturePtr aFilletArc = sketch()->addFeature(SketchPlugin_Arc::ID()); @@ -128,6 +149,7 @@ void SketchPlugin_Fillet::execute() aFeaturesToBeRemoved1.insert(aFeaturesToBeRemoved2.begin(), aFeaturesToBeRemoved2.end()); ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToBeRemoved1); + Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED)); // Update fillet edges. recalculateAttributes(aFilletArc, SketchPlugin_Arc::START_ID(), @@ -174,8 +196,6 @@ void SketchPlugin_Fillet::execute() if(isUpdateFlushed) { Events_Loop::loop()->setFlushed(anUpdateEvent, true); } - - myFilletCreated = true; } AISObjectPtr SketchPlugin_Fillet::getAISObject(AISObjectPtr thePrevious) @@ -189,81 +209,49 @@ AISObjectPtr SketchPlugin_Fillet::getAISObject(AISObjectPtr thePrevious) return AISObjectPtr(); } - // Get fillet point. - AttributeRefAttrPtr aPointRefAttr = refattr(FILLET_POINT_ID()); - if (!aPointRefAttr->isInitialized() || aPointRefAttr->isObject()) { + if (!calculateFilletParameters()) return AISObjectPtr(); - } - std::shared_ptr aFilletPoint2D = - std::dynamic_pointer_cast(aPointRefAttr->attr()); - if (!aFilletPoint2D.get()) { - return AISObjectPtr(); - } - // Obtain constraint coincidence for the fillet point. - FeaturePtr aConstraintCoincidence; - const std::set& aRefsList = aFilletPoint2D->owner()->data()->refsToMe(); - for(std::set::const_iterator anIt = aRefsList.cbegin(); - anIt != aRefsList.cend(); - ++anIt) { - std::shared_ptr anAttr = (*anIt); - FeaturePtr aFeature = std::dynamic_pointer_cast(anAttr->owner()); - if(aFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { - AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast( - aFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A())); - AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast( - aFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B())); - if(anAttrRefA.get() && !anAttrRefA->isObject()) { - AttributePtr anAttrA = anAttrRefA->attr(); - if(aFilletPoint2D == anAttrA) { - aConstraintCoincidence = aFeature; - break; - } - } - if(anAttrRefB.get() && !anAttrRefB->isObject()) { - AttributePtr anAttrB = anAttrRefB->attr(); - if(aFilletPoint2D == anAttrB) { - aConstraintCoincidence = aFeature; - break; - } - } - } - } + // Create arc for presentation. + std::shared_ptr aCenterPnt(aSketch->to3D(myCenterXY->x(), myCenterXY->y())); + std::shared_ptr aTangentPnt1(aSketch->to3D(myTangentXY1->x(), + myTangentXY1->y())); + std::shared_ptr aTangentPnt2(aSketch->to3D(myTangentXY2->x(), + myTangentXY2->y())); + std::shared_ptr aNDir = std::dynamic_pointer_cast( + aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID())); + std::shared_ptr anArcShape = + GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenterPnt, aTangentPnt1, aTangentPnt2, aNDir->dir()); - if(!aConstraintCoincidence.get()) { - setError("Error: No coincident edges at selected point."); - return AISObjectPtr(); + AISObjectPtr anAISObject = thePrevious; + if(!anAISObject.get()) { + anAISObject = AISObjectPtr(new GeomAPI_AISObject); } + anAISObject->createShape(anArcShape); + return anAISObject; +} - // Get coincide edges. - std::set anEdgeFeatures = getCoincides(aConstraintCoincidence); - if(anEdgeFeatures.size() != 2) { +bool SketchPlugin_Fillet::calculateFilletParameters() +{ + // Get fillet point. + AttributeRefAttrPtr aPointRefAttr = refattr(FILLET_POINT_ID()); + if (!aPointRefAttr->isInitialized() || aPointRefAttr->isObject()) + return false; + std::shared_ptr aFilletPoint2D = + std::dynamic_pointer_cast(aPointRefAttr->attr()); + if (!aFilletPoint2D.get()) + return false; + + if (!findFeaturesContainingFilletPoint(aFilletPoint2D)) { setError("Error: Selected point does not have two suitable edges for fillet."); - return AISObjectPtr(); + return false; } - FeaturePtr anEdgeFeature1, anEdgeFeature2; - std::set::iterator aLinesIt = anEdgeFeatures.begin(); - anEdgeFeature1 = *aLinesIt++; - anEdgeFeature2 = *aLinesIt; - - // Getting points located at 1/3 of edge length from fillet point. std::shared_ptr aFilletPnt2d = aFilletPoint2D->pnt(); - std::shared_ptr aPnt1, aPnt2; - getPointOnEdge(anEdgeFeature1, aFilletPnt2d, aPnt1); - getPointOnEdge(anEdgeFeature2, aFilletPnt2d, aPnt2); - - /// Getting distances. - double aDistance1 = getProjectionDistance(anEdgeFeature2, aPnt1); - double aDistance2 = getProjectionDistance(anEdgeFeature1, 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; - myBaseFeatures[0] = anEdgeFeature1; - myBaseFeatures[1] = anEdgeFeature2; // First pair of points relate to first feature, second pair - to second. std::shared_ptr aStartEndPnt[aNbFeatures * 2]; for (int i = 0; i < aNbFeatures; i++) { @@ -276,7 +264,7 @@ AISObjectPtr SketchPlugin_Fillet::getAISObject(AISObjectPtr thePrevious) aEndAttr = SketchPlugin_Arc::END_ID(); } else { // Wrong argument. setError("Error: One of the points has wrong coincide feature"); - return AISObjectPtr(); + return false; } myFeatAttributes[2*i] = aStartAttr; aStartEndPnt[2*i] = std::dynamic_pointer_cast( @@ -293,8 +281,9 @@ AISObjectPtr SketchPlugin_Fillet::getAISObject(AISObjectPtr thePrevious) } } - calculateFilletCenter(anEdgeFeature1, anEdgeFeature2, 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]; @@ -334,24 +323,52 @@ AISObjectPtr SketchPlugin_Fillet::getAISObject(AISObjectPtr thePrevious) myTangentXY1 = myTangentXY2; myTangentXY2 = aTmp; } + return true; +} - // Create arc for presentation. - std::shared_ptr aCenterPnt(aSketch->to3D(myCenterXY->x(), myCenterXY->y())); - std::shared_ptr aTangentPnt1(aSketch->to3D(myTangentXY1->x(), - myTangentXY1->y())); - std::shared_ptr aTangentPnt2(aSketch->to3D(myTangentXY2->x(), - myTangentXY2->y())); - std::shared_ptr aNDir = std::dynamic_pointer_cast( - aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID())); - std::shared_ptr anArcShape = - GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenterPnt, aTangentPnt1, aTangentPnt2, aNDir->dir()); - - AISObjectPtr anAISObject = thePrevious; - if(!anAISObject.get()) { - anAISObject = AISObjectPtr(new GeomAPI_AISObject); +bool SketchPlugin_Fillet::findFeaturesContainingFilletPoint( + std::shared_ptr theFilletPoint) +{ + // Obtain constraint coincidence for the fillet point. + FeaturePtr aConstraintCoincidence; + const std::set& aRefsList = theFilletPoint->owner()->data()->refsToMe(); + for(std::set::const_iterator anIt = aRefsList.cbegin(); + anIt != aRefsList.cend(); + ++anIt) { + std::shared_ptr anAttr = (*anIt); + FeaturePtr aFeature = std::dynamic_pointer_cast(anAttr->owner()); + if(aFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { + AttributeRefAttrPtr anAttrRefA = + aFeature->refattr(SketchPlugin_ConstraintCoincidence::ENTITY_A()); + AttributeRefAttrPtr anAttrRefB = + aFeature->refattr(SketchPlugin_ConstraintCoincidence::ENTITY_B()); + if(anAttrRefA.get() && !anAttrRefA->isObject()) { + AttributePtr anAttrA = anAttrRefA->attr(); + if(theFilletPoint == anAttrA) { + aConstraintCoincidence = aFeature; + break; + } + } + if(anAttrRefB.get() && !anAttrRefB->isObject()) { + AttributePtr anAttrB = anAttrRefB->attr(); + if(theFilletPoint == anAttrB) { + aConstraintCoincidence = aFeature; + break; + } + } + } } - anAISObject->createShape(anArcShape); - return anAISObject; + + if(!aConstraintCoincidence.get()) + return false; + + // Get coincide edges. + std::set anEdgeFeatures = getCoincides(aConstraintCoincidence); + std::set::iterator aLinesIt = anEdgeFeatures.begin(); + for (int i = 0; aLinesIt != anEdgeFeatures.end() && i < 2; ++aLinesIt, ++i) + myBaseFeatures[i] = *aLinesIt; + + return myBaseFeatures[0] && myBaseFeatures[1]; } // ========= Auxiliary functions ================= @@ -364,344 +381,88 @@ 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())); - } - - // 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; + GeomShapePtr aShapeA = theFilletFeatures[0]->lastResult()->shape(); + GeomShapePtr aShapeB = theFilletFeatures[1]->lastResult()->shape(); + + 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(); + // 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()); } - } 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 = aEndArcDir->angle(aStartArcDir); - - // 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 = aCurDir->angle(aStartArcDir); - if (anArcAngle < 0.0) aCurAngle *= -1.0; - if (aCurAngle < 0.0 || aCurAngle > fabs(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] = aEndArcDir->angle(aStartArcDir[i]); - } - - // 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 = aCurDir->angle(aStartArcDir[0]); - if (anArcAngle[0] < 0.0) aCurAngle *= -1.0; - if (aCurAngle < 0.0 || aCurAngle > fabs(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 = aCurDir->angle(aStartArcDir[1]); - if (anArcAngle[1] < 0.0) aCurAngle *= -1.0; - if (aCurAngle < 0.0 || aCurAngle > fabs(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->attribute(SketchPlugin_Arc::INVERSED_ID())) { - 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) @@ -776,7 +537,8 @@ std::set findFeaturesToRemove(const FeaturePtr theFeature, continue; } if(aFeature->getKind() == SketchPlugin_ConstraintLength::ID() - || aFeature->getKind() == SketchPlugin_ConstraintEqual::ID()) { + || aFeature->getKind() == SketchPlugin_ConstraintEqual::ID() + || aFeature->getKind() == SketchPlugin_ConstraintMiddle::ID()) { aFeaturesToBeRemoved.insert(aFeature); } else { std::list anAttrs =