From 7470f1b70a31ce0483e168395a43db9c9c93589e Mon Sep 17 00:00:00 2001 From: azv Date: Fri, 10 Mar 2017 17:28:40 +0300 Subject: [PATCH] Update test cases according to new Fillet API. Fix several problems with fillet and tangent constraint --- src/PythonAPI/Test/TestSketcherSetFillet.py | 13 +- src/PythonAPI/examples/Platine.py | 2 +- src/SketchAPI/SketchAPI_Sketch.cpp | 27 +- src/SketchAPI/SketchAPI_Sketch.h | 7 +- src/SketchPlugin/CMakeLists.txt | 1 + src/SketchPlugin/SketchPlugin_Fillet.cpp | 159 ++++++------ src/SketchPlugin/SketchPlugin_Fillet.h | 6 + src/SketchPlugin/Test/TestFillet.py | 231 +++++++----------- src/SketchPlugin/plugin-Sketch.xml | 2 +- .../PlaneGCSSolver/PlaneGCSSolver_Solver.cpp | 7 +- .../PlaneGCSSolver/PlaneGCSSolver_Tools.cpp | 13 +- .../SketchSolver_ConstraintTangent.cpp | 11 +- 12 files changed, 236 insertions(+), 243 deletions(-) diff --git a/src/PythonAPI/Test/TestSketcherSetFillet.py b/src/PythonAPI/Test/TestSketcherSetFillet.py index f7e8260f0..f121be4db 100644 --- a/src/PythonAPI/Test/TestSketcherSetFillet.py +++ b/src/PythonAPI/Test/TestSketcherSetFillet.py @@ -3,12 +3,19 @@ from salome.shaper import model from TestSketcher import SketcherTestCase class SketcherSetFillet(SketcherTestCase): - def runTest(self): + def test_fillet(self): l1 = self.sketch.addLine(0, 0, 0, 1) l2 = self.sketch.addLine(0, 1, 1, 1) self.sketch.setCoincident(l1.endPoint(), l2.startPoint()) - self.sketch.setFillet([l1.endPoint()], 10.0) + self.sketch.setFillet(l1.endPoint()) + model.do() + + def test_fillet_with_radius(self): + l1 = self.sketch.addLine(10, 10, 30, 10) + l2 = self.sketch.addLine(10, 10, 30, 30) + self.sketch.setCoincident(l1.startPoint(), l2.startPoint()) + self.sketch.setFilletWithRadius(l1.startPoint(), 10.0) model.do() if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main(verbosity=2) \ No newline at end of file diff --git a/src/PythonAPI/examples/Platine.py b/src/PythonAPI/examples/Platine.py index c2b01fa0c..bd40881fc 100644 --- a/src/PythonAPI/examples/Platine.py +++ b/src/PythonAPI/examples/Platine.py @@ -47,7 +47,7 @@ def vertical_body(): sketch.setLength(top, "L") sketch.setLength(left, "L") - sketch.setFillet([left.endPoint()], 32) + sketch.setFilletWithRadius(left.endPoint(), 32) model.do() #!!! diff --git a/src/SketchAPI/SketchAPI_Sketch.cpp b/src/SketchAPI/SketchAPI_Sketch.cpp index e9953784c..ec05c1377 100644 --- a/src/SketchAPI/SketchAPI_Sketch.cpp +++ b/src/SketchAPI/SketchAPI_Sketch.cpp @@ -31,6 +31,7 @@ //-------------------------------------------------------------------------------------- #include #include +#include #include #include #include @@ -603,17 +604,33 @@ std::shared_ptr SketchAPI_Sketch::setEqual( } std::shared_ptr SketchAPI_Sketch::setFillet( - const std::list & thePoints, - const ModelHighAPI_Double & theRadius) + const ModelHighAPI_RefAttr & thePoint) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_Fillet::ID()); - fillAttribute(thePoints, aFeature->data()->refattrlist(SketchPlugin_Constraint::ENTITY_A())); - fillAttribute(theRadius, aFeature->real(SketchPlugin_Constraint::VALUE())); - aFeature->execute(); + fillAttribute(thePoint, aFeature->data()->refattr(SketchPlugin_Fillet::FILLET_POINT_ID())); + apply(); // finish operation to remove Fillet feature correcly return InterfacePtr(new ModelHighAPI_Interface(aFeature)); } +std::shared_ptr SketchAPI_Sketch::setFilletWithRadius( + const ModelHighAPI_RefAttr & thePoint, + const ModelHighAPI_Double & theRadius) +{ + CompositeFeaturePtr aSketch = compositeFeature(); + int aNbSubs = aSketch->numberOfSubs(); + + // create fillet + InterfacePtr aFilletFeature = setFillet(thePoint); + + // set radius for just created arc + FeaturePtr anArc = aSketch->subFeature(aNbSubs - 1); + if (anArc->getKind() == SketchPlugin_Arc::ID()) + setRadius(ModelHighAPI_RefAttr(anArc->lastResult()), ModelHighAPI_Double(theRadius)); + + return aFilletFeature; +} + std::shared_ptr SketchAPI_Sketch::setFixed( const ModelHighAPI_RefAttr & theObject) { diff --git a/src/SketchAPI/SketchAPI_Sketch.h b/src/SketchAPI/SketchAPI_Sketch.h index 216474474..792a8ee79 100644 --- a/src/SketchAPI/SketchAPI_Sketch.h +++ b/src/SketchAPI/SketchAPI_Sketch.h @@ -318,7 +318,12 @@ public: /// Set fillet SKETCHAPI_EXPORT std::shared_ptr setFillet( - const std::list & thePoints, + const ModelHighAPI_RefAttr & thePoint); + + /// Set fillet with additional radius constraint + SKETCHAPI_EXPORT + std::shared_ptr setFilletWithRadius( + const ModelHighAPI_RefAttr & thePoint, const ModelHighAPI_Double & theRadius); /// Set fixed diff --git a/src/SketchPlugin/CMakeLists.txt b/src/SketchPlugin/CMakeLists.txt index 46448c8a4..f1d18eea2 100644 --- a/src/SketchPlugin/CMakeLists.txt +++ b/src/SketchPlugin/CMakeLists.txt @@ -139,6 +139,7 @@ ADD_UNIT_TESTS(TestSketchPointLine.py TestConstraintMiddlePoint.py TestMultiRotation.py TestMultiTranslation.py + TestFillet.py TestRectangle.py TestProjection.py TestSplit.py diff --git a/src/SketchPlugin/SketchPlugin_Fillet.cpp b/src/SketchPlugin/SketchPlugin_Fillet.cpp index 9a163403f..f56b27d73 100644 --- a/src/SketchPlugin/SketchPlugin_Fillet.cpp +++ b/src/SketchPlugin/SketchPlugin_Fillet.cpp @@ -85,6 +85,10 @@ void SketchPlugin_Fillet::execute() if (isUpdateFlushed) Events_Loop::loop()->setFlushed(anUpdateEvent, false); + // 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 +132,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(), @@ -189,81 +194,59 @@ AISObjectPtr SketchPlugin_Fillet::getAISObject(AISObjectPtr thePrevious) return AISObjectPtr(); } - // Get fillet point. - AttributeRefAttrPtr aPointRefAttr = refattr(FILLET_POINT_ID()); - if (!aPointRefAttr->isInitialized() || aPointRefAttr->isObject()) { - return AISObjectPtr(); - } - std::shared_ptr aFilletPoint2D = - std::dynamic_pointer_cast(aPointRefAttr->attr()); - if (!aFilletPoint2D.get()) { + if (!calculateFilletParameters()) 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); + getPointOnEdge(myBaseFeatures[0], aFilletPnt2d, aPnt1); + getPointOnEdge(myBaseFeatures[1], aFilletPnt2d, aPnt2); /// Getting distances. - double aDistance1 = getProjectionDistance(anEdgeFeature2, aPnt1); - double aDistance2 = getProjectionDistance(anEdgeFeature1, aPnt2); + 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; // 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 +259,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,7 +276,7 @@ AISObjectPtr SketchPlugin_Fillet::getAISObject(AISObjectPtr thePrevious) } } - calculateFilletCenter(anEdgeFeature1, anEdgeFeature2, aRadius, + calculateFilletCenter(myBaseFeatures[0], myBaseFeatures[1], aRadius, myIsNotInversed, myCenterXY, myTangentXY1, myTangentXY2); // Tangent directions of the features in coincident point. @@ -334,24 +317,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 ================= diff --git a/src/SketchPlugin/SketchPlugin_Fillet.h b/src/SketchPlugin/SketchPlugin_Fillet.h index b25e0257d..49388f26a 100644 --- a/src/SketchPlugin/SketchPlugin_Fillet.h +++ b/src/SketchPlugin/SketchPlugin_Fillet.h @@ -12,6 +12,7 @@ #include "SketchPlugin_SketchEntity.h" #include +#include class GeomAPI_XY; @@ -65,6 +66,11 @@ class SketchPlugin_Fillet: public SketchPlugin_SketchEntity, public GeomAPI_IPre /// \brief Use plugin manager for features creation SketchPlugin_Fillet(); +private: + bool calculateFilletParameters(); + + bool findFeaturesContainingFilletPoint(std::shared_ptr theFilletPoint); + private: FeaturePtr myBaseFeatures[2]; std::string myFeatAttributes[4]; // attributes of features diff --git a/src/SketchPlugin/Test/TestFillet.py b/src/SketchPlugin/Test/TestFillet.py index 79a82b7b6..fd5ce78bf 100644 --- a/src/SketchPlugin/Test/TestFillet.py +++ b/src/SketchPlugin/Test/TestFillet.py @@ -1,9 +1,9 @@ """ TestFillet.py - Unit test of SketchPlugin_ConstraintFillet class + Unit test of SketchPlugin_Fillet class - SketchPlugin_ConstraintFillet - static const std::string MY_CONSTRAINT_FILLET_ID("SketchConstraintFillet"); + SketchPlugin_Fillet + static const std::string MY_CONSTRAINT_FILLET_ID("SketchFillet"); data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeDouble::typeId()); data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttrList::typeId()); data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefList::typeId()); @@ -18,12 +18,14 @@ from salome.shaper import model #========================================================================= # Auxiliary functions #========================================================================= -aStartPoint1 = [] +TOLERANCE = 1.e-7 def createSketch1(theSketch): global aEndPoint1, aEndPoint2 # Initialize sketch by three lines with coincident boundaries allFeatures = [] + + aSession.startOperation() # Line1 aSketchLine1 = theSketch.addFeature("SketchLine") aStartPoint1 = geomDataAPI_Point2D(aSketchLine1.attribute("StartPoint")) @@ -54,7 +56,7 @@ def createSketch1(theSketch): aCoincidence2.refattr("ConstraintEntityA").setAttr(aEndPoint2) aCoincidence2.refattr("ConstraintEntityB").setAttr(aStartPoint3) - theSketch.execute() + aSession.finishOperation() return allFeatures @@ -62,6 +64,8 @@ def createSketch2(theSketch): global aStartPoint1 # Initialize sketch by line and arc with coincident boundary allFeatures = [] + + aSession.startOperation() # Line aSketchLine = theSketch.addFeature("SketchLine") aStartPoint1 = geomDataAPI_Point2D(aSketchLine.attribute("StartPoint")) @@ -83,78 +87,71 @@ def createSketch2(theSketch): aCoincidence.refattr("ConstraintEntityA").setAttr(aStartPoint1) aCoincidence.refattr("ConstraintEntityB").setAttr(aStartPoint2) - theSketch.execute() + aSession.finishOperation() return allFeatures -def checkFillet(theObjects, theRadius): - # Verify the arc and lines are connected smoothly - print "Check Fillet" - aLine = [] - anArc = [] - aSize = len(theObjects) - for feat in theObjects: - assert(feat is not None) - if (feat.getKind() == "SketchLine"): - aLine.append(feat) - elif (feat.getKind() == "SketchArc"): - anArc.append(feat) - aFilletArc = anArc[-1] - assert(aFilletArc is not None) - anArc.pop() - - anArcPoints = [] - aPoint = geomDataAPI_Point2D(aFilletArc.attribute("ArcStartPoint")) - #print "ArcStartPoint " + repr(aPoint.x()) + " " + repr(aPoint.y()) - anArcPoints.append((aPoint.x(), aPoint.y())) - aPoint = geomDataAPI_Point2D(aFilletArc.attribute("ArcEndPoint")) - #print "ArcEndPoint " + repr(aPoint.x()) + " " + repr(aPoint.y()) - anArcPoints.append((aPoint.x(), aPoint.y())) - aPoint = geomDataAPI_Point2D(aFilletArc.attribute("ArcCenter")) - #print "ArcCenter " + repr(aPoint.x()) + " " + repr(aPoint.y()) - aCenterX = aPoint.x() - aCenterY = aPoint.y() - aFilletRadius = math.hypot(anArcPoints[0][0]-aCenterX, anArcPoints[0][1]-aCenterY) - - for line in aLine: - aStartPoint = geomDataAPI_Point2D(line.attribute("StartPoint")) - aEndPoint = geomDataAPI_Point2D(line.attribute("EndPoint")) - - aLinePoints = [] - aLinePoints.append((aStartPoint.x(), aStartPoint.y())) - #print "aLineStartPoint " + repr(aStartPoint.x()) + " " + repr(aStartPoint.y()) - aLinePoints.append((aEndPoint.x(), aEndPoint.y())) - #print "aLineEndPoint " + repr(aEndPoint.x()) + " " + repr(aEndPoint.y()) - - aLineDirX = aEndPoint.x() - aStartPoint.x() - aLineDirY = aEndPoint.y() - aStartPoint.y() - - for arcPt in anArcPoints: - for linePt in aLinePoints: - if (math.hypot(linePt[0]-arcPt[0], linePt[1]-arcPt[1]) < 1.e-10): - aDirX = linePt[0] - aCenterX - aDirY = linePt[1] - aCenterY - assert(math.fabs(math.hypot(aDirX, aDirY) - theRadius) < 1.e-7) - aDot = aDirX * aLineDirX + aDirY * aLineDirY - - break; - - if (aSize == 3): - for arc in anArc: - aStartPoint = geomDataAPI_Point2D(arc.attribute("ArcStartPoint")) - aEndPoint = geomDataAPI_Point2D(arc.attribute("ArcEndPoint")) - aCenterPoint = geomDataAPI_Point2D(arc.attribute("ArcCenter")) - - aBaseArcPoints = [] - aBaseArcPoints.append((aStartPoint.x(), aStartPoint.y())) - #print "anArcStartPoint " + repr(aStartPoint.x()) + " " + repr(aStartPoint.y()) - aBaseArcPoints.append((aEndPoint.x(), aEndPoint.y())) - #print "anArcEndPoint " + repr(aEndPoint.x()) + " " + repr(aEndPoint.y()) - #print "anArcCenter " + repr(aCenterPoint.x()) + " " + repr(aCenterPoint.y()) - - aRadius = math.hypot(aStartPoint.x()-aCenterPoint.x(), aStartPoint.y()-aCenterPoint.y()) - aDist = math.hypot(aCenterPoint.x() - aCenterX, aCenterPoint.y() - aCenterY) - assert math.fabs(aFilletRadius + aRadius - aDist) < 1.e-7 or math.fabs(math.fabs(aFilletRadius - aRadius) - aDist) < 1.e-7, \ - "Fillet radius = {0}, Base arc radius = {1}, distance between centers = {2}".format(aFilletRadius, aRadius, aDist) +def checkSmoothness(theSketch): + aPtPtCoincidences = getCoincidences(theSketch) + for coinc in aPtPtCoincidences: + aConnectedFeatures = connectedFeatures(coinc) + assert(len(aConnectedFeatures) == 2) + if aConnectedFeatures[0].getKind() == "SketchArc": + if aConnectedFeatures[1].getKind() == "SketchArc": + checkArcArcSmoothness(aConnectedFeatures[0], aConnectedFeatures[1]) + elif aConnectedFeatures[1].getKind() == "SketchLine": + checkArcLineSmoothness(aConnectedFeatures[0], aConnectedFeatures[1]) + elif aConnectedFeatures[0].getKind() == "SketchLine" and aConnectedFeatures[1].getKind() == "SketchArc": + checkArcLineSmoothness(aConnectedFeatures[1], aConnectedFeatures[0]) + +def checkArcLineSmoothness(theArc, theLine): + aCenter = geomDataAPI_Point2D(theArc.attribute("ArcCenter")) + aDistance = distancePointLine(aCenter, theLine) + aRadius = arcRadius(theArc) + assert(math.fabs(aRadius - aDistance) < TOLERANCE) + +def checkArcArcSmoothness(theArc1, theArc2): + aCenter1 = geomDataAPI_Point2D(theArc1.attribute("ArcCenter")) + aCenter2 = geomDataAPI_Point2D(theArc2.attribute("ArcCenter")) + aDistance = distancePointPoint(aCenter1, aCenter2) + aRadius1 = arcRadius(theArc1) + aRadius2 = arcRadius(theArc2) + aRadSum = aRadius1 + aRadius2 + aRadDiff = math.fabs(aRadius1 - aRadius2) + assert(math.fabs(aDistance - aRadSum) < TOLERANCE or math.fabs(aDistance - aRadDiff) < TOLERANCE) + +def getCoincidences(theSketch): + aCoincidences = [] + for anIndex in range(0, theSketch.numberOfSubs()): + aSubFeature = theSketch.subFeature(anIndex) + if aSubFeature.getKind == "SketchConstraintCoincidence": + anEntityA = aSubFeature.refattr("ConstraintEntityA") + anEntityB = aSubFeature.refattr("ConstraintEntityB") + if not anEntityA.isObject() and not anEntityB.isObject(): + aCoincidences.append(aSubFeature) + return aCoincidences + +def connectedFeatures(theCoincidence): + anEntityA = aSubFeature.refattr("ConstraintEntityA") + anEntityB = aSubFeature.refattr("ConstraintEntityB") + return [anEntityA.attr().owner(), anEntityB.attr().owner()] + +def arcRadius(theArc): + aCenter = geomDataAPI_Point2D(theArc.attribute("ArcCenter")) + aStart = geomDataAPI_Point2D(theArc.attribute("ArcStartPoint")) + return distancePointPoint(aCenter, aStart) + +def distancePointPoint(thePoint1, thePoint2): + return math.hypot(thePoint1.x() - thePoint2.x(), thePoint1.y() - thePoint2.y()) + +def distancePointLine(thePoint, theLine): + aLineStart = geomDataAPI_Point2D(theLine.attribute("StartPoint")) + aLineEnd = geomDataAPI_Point2D(theLine.attribute("EndPoint")) + aLength = distancePointPoint(aLineStart, aLineEnd) + + aDir1x, aDir1y = aLineEnd.x() - aLineStart.x(), aLineEnd.y() - aLineStart.y() + aDir2x, aDir2y = thePoint.x() - aLineStart.x(), thePoint.y() - aLineStart.y() + aCross = aDir1x * aDir2y - aDir1y * aDir2x + return math.fabs(aCross) / aLength #========================================================================= @@ -181,51 +178,24 @@ aSession.finishOperation() #========================================================================= # Initialize sketch by three connected lines #========================================================================= -aSession.startOperation() -aFeaturesList = createSketch1(aSketchFeature) -aSession.finishOperation() -aSketchSubFeatures = [] -for aSubIndex in range(0, aSketchFeature.numberOfSubs()): - aSketchSubFeatures.append(aSketchFeature.subFeature(aSubIndex)) +createSketch1(aSketchFeature) assert (model.dof(aSketchFeature) == 8) #========================================================================= -# Global variables -#========================================================================= -FILLET_RADIUS1 = 3. -FILLET_RADIUS2 = 5. -#========================================================================= # Create the Fillet #========================================================================= aSession.startOperation() -aFillet = aSketchFeature.addFeature("SketchConstraintFillet") -aRefAttrA = aFillet.data().refattrlist("ConstraintEntityA"); -aRefAttrA.append(aEndPoint1) -aRefAttrA.append(aEndPoint2) -aRadius = aFillet.real("ConstraintValue") -aRadius.setValue(FILLET_RADIUS1) -aFillet.execute() -aResObjects = [] -for aSubIndex in range(0, aSketchFeature.numberOfSubs()): - aSubFeature = aSketchFeature.subFeature(aSubIndex) - if aSubFeature not in aSketchSubFeatures: - if aSubFeature.getKind() == "SketchLine": - aResObjects.insert(0, aSubFeature) - elif aSubFeature.getKind() == "SketchArc": - aResObjects.append(aSubFeature) +aFillet = aSketchFeature.addFeature("SketchFillet") +aFillet.refattr("fillet_point").setAttr(aEndPoint1); +aSession.finishOperation() +aSession.startOperation() +aFillet = aSketchFeature.addFeature("SketchFillet") +aFillet.refattr("fillet_point").setAttr(aEndPoint2); +aSession.finishOperation() #========================================================================= # Verify the objects of fillet are created #========================================================================= -assert(aResObjects) -checkFillet(aResObjects, FILLET_RADIUS1) -assert model.dof(aSketchFeature) == 8, "PlaneGCS limitation: if you see this message, then PlaneGCS has solved DoF for sketch with fillet correctly (expected DoF = 10, observed = {0}".format(model.dof(aSketchFeature)) -#========================================================================= -# Change Fillet radius -#========================================================================= -aRadius.setValue(FILLET_RADIUS2) -aFillet.execute() -aSession.finishOperation() -checkFillet(aResObjects, FILLET_RADIUS2) -assert model.dof(aSketchFeature) == 8, "PlaneGCS limitation: if you see this message, then PlaneGCS has solved DoF for sketch with fillet correctly (expected DoF = 10, observed = {0}".format(model.dof(aSketchFeature)) +checkSmoothness(aSketchFeature) +assert model.dof(aSketchFeature) == 14, "PlaneGCS limitation: if you see this message, then maybe PlaneGCS has solved DoF for sketch with fillet correctly (expected DoF = 10, observed = {0}".format(model.dof(aSketchFeature)) #========================================================================= # Create another sketch @@ -243,45 +213,20 @@ aSession.finishOperation() #========================================================================= # Initialize sketch by line and arc #========================================================================= -aSession.startOperation() -aFeaturesList = createSketch2(aSketchFeature) -aSession.finishOperation() -aSketchSubFeatures = [] -for aSubIndex in range(0, aSketchFeature.numberOfSubs()): - aSketchSubFeatures.append(aSketchFeature.subFeature(aSubIndex)) +createSketch2(aSketchFeature) assert (model.dof(aSketchFeature) == 7) #========================================================================= # Create the Fillet #========================================================================= aSession.startOperation() -aFillet = aSketchFeature.addFeature("SketchConstraintFillet") -aRefAttrA = aFillet.data().refattrlist("ConstraintEntityA"); -aRefAttrA.append(aStartPoint1) -aRadius = aFillet.real("ConstraintValue") -aRadius.setValue(FILLET_RADIUS1) -aFillet.execute() -aResObjects = [] -for aSubIndex in range(0, aSketchFeature.numberOfSubs()): - aSubFeature = aSketchFeature.subFeature(aSubIndex) - if aSubFeature not in aSketchSubFeatures: - if aSubFeature.getKind() == "SketchLine": - aResObjects.insert(0, aSubFeature) - elif aSubFeature.getKind() == "SketchArc": - aResObjects.append(aSubFeature) +aFillet = aSketchFeature.addFeature("SketchFillet") +aFillet.refattr("fillet_point").setAttr(aStartPoint1) +aSession.finishOperation() #========================================================================= # Verify the objects of fillet are created #========================================================================= -assert(aResObjects) -checkFillet(aResObjects, FILLET_RADIUS1) -assert model.dof(aSketchFeature) == 7, "PlaneGCS limitation: if you see this message, then PlaneGCS has solved DoF for sketch with fillet correctly (expected DoF = 8, observed = {0}".format(model.dof(aSketchFeature)) -#========================================================================= -# Change Fillet radius -#========================================================================= -aRadius.setValue(FILLET_RADIUS2) -aFillet.execute() -aSession.finishOperation() -checkFillet(aResObjects, FILLET_RADIUS2) -assert model.dof(aSketchFeature) == 11, "PlaneGCS limitation: if you see this message, then PlaneGCS has solved DoF for sketch with fillet correctly (expected DoF = 8, observed = {0}".format(model.dof(aSketchFeature)) +checkSmoothness(aSketchFeature) +assert model.dof(aSketchFeature) == 10, "PlaneGCS limitation: if you see this message, then maybe PlaneGCS has solved DoF for sketch with fillet correctly (expected DoF = 8, observed = {0}".format(model.dof(aSketchFeature)) #========================================================================= # End of test #========================================================================= diff --git a/src/SketchPlugin/plugin-Sketch.xml b/src/SketchPlugin/plugin-Sketch.xml index bf5db26b3..6ad62415b 100644 --- a/src/SketchPlugin/plugin-Sketch.xml +++ b/src/SketchPlugin/plugin-Sketch.xml @@ -119,7 +119,7 @@ - + applySolution(); if (myDOF < 0) myDOF = myEquationSystem->dofsNumber(); aStatus = STATUS_OK; - } else - aStatus = STATUS_FAILED; + } return aStatus; } diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp index 9dc93f371..3dd68b54b 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp @@ -473,10 +473,19 @@ ConstraintWrapperPtr createConstraintTangent( { GCSConstraintPtr aNewConstr; if (theType == CONSTRAINT_TANGENT_CIRCLE_LINE) { + GCSCurvePtr anEntCirc, anEntLine; + if (theEntity1->type() == ENTITY_LINE) { + anEntLine = theEntity1->entity(); + anEntCirc = theEntity2->entity(); + } else { + anEntLine = theEntity2->entity(); + anEntCirc = theEntity1->entity(); + } + std::shared_ptr aCirc = - std::dynamic_pointer_cast(theEntity1->entity()); + std::dynamic_pointer_cast(anEntCirc); std::shared_ptr aLine = - std::dynamic_pointer_cast(theEntity2->entity()); + std::dynamic_pointer_cast(anEntLine); aNewConstr = GCSConstraintPtr(new GCS::ConstraintP2LDistance(aCirc->center, *aLine, aCirc->rad)); diff --git a/src/SketchSolver/SketchSolver_ConstraintTangent.cpp b/src/SketchSolver/SketchSolver_ConstraintTangent.cpp index 1bf442634..8a61e1a99 100644 --- a/src/SketchSolver/SketchSolver_ConstraintTangent.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintTangent.cpp @@ -49,15 +49,12 @@ void SketchSolver_ConstraintTangent::getAttributes( // Check the quantity of entities of each type and their order (arcs first) int aNbLines = 0; int aNbCircles = 0; - bool isSwap = false; // whether need to swap arguments (arc goes before line) std::vector::iterator anEntIt = theAttributes.begin() + 2; for (; anEntIt != theAttributes.end(); ++anEntIt) { if ((*anEntIt)->type() == ENTITY_LINE) ++aNbLines; - else if ((*anEntIt)->type() == ENTITY_ARC || (*anEntIt)->type() == ENTITY_CIRCLE) { + else if ((*anEntIt)->type() == ENTITY_ARC || (*anEntIt)->type() == ENTITY_CIRCLE) ++aNbCircles; - isSwap = aNbLines > 0; - } } if (aNbCircles < 1) { @@ -86,12 +83,6 @@ void SketchSolver_ConstraintTangent::getAttributes( if (!hasSingleCoincidence(aFeature1, aFeature2)) myErrorMsg = SketchSolver_Error::TANGENCY_FAILED(); } - - if (isSwap) { - EntityWrapperPtr aTemp = theAttributes[2]; - theAttributes[2] = theAttributes[3]; - theAttributes[3] = aTemp; - } } void SketchSolver_ConstraintTangent::adjustConstraint() -- 2.30.2