Salome HOME
Update test cases according to new Fillet API.
authorazv <azv@opencascade.com>
Fri, 10 Mar 2017 14:28:40 +0000 (17:28 +0300)
committerazv <azv@opencascade.com>
Mon, 13 Mar 2017 12:28:20 +0000 (15:28 +0300)
Fix several problems with fillet and tangent constraint

12 files changed:
src/PythonAPI/Test/TestSketcherSetFillet.py
src/PythonAPI/examples/Platine.py
src/SketchAPI/SketchAPI_Sketch.cpp
src/SketchAPI/SketchAPI_Sketch.h
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/SketchPlugin_Fillet.cpp
src/SketchPlugin/SketchPlugin_Fillet.h
src/SketchPlugin/Test/TestFillet.py
src/SketchPlugin/plugin-Sketch.xml
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp
src/SketchSolver/SketchSolver_ConstraintTangent.cpp

index f7e8260f0add2a7b030c47b60f816bb53107ef7d..f121be4db8b00e56d0861ae4e4b0d5cbb439189a 100644 (file)
@@ -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
index c2b01fa0c205e8b9f4f47cbf97154cb930db99eb..bd40881fcbdd4e8e5cfea41eab08eedb2c534201 100644 (file)
@@ -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()  #!!!
 
index e9953784c604f6c6b0cbb0cad5fd0555e90fb9c5..ec05c13773bd2b13a26eee659cda9bd2dd9a18a3 100644 (file)
@@ -31,6 +31,7 @@
 //--------------------------------------------------------------------------------------
 #include <ModelAPI_CompositeFeature.h>
 #include <ModelAPI_ResultConstruction.h>
+#include <ModelHighAPI_Double.h>
 #include <ModelHighAPI_Dumper.h>
 #include <ModelHighAPI_RefAttr.h>
 #include <ModelHighAPI_Selection.h>
@@ -603,17 +604,33 @@ std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setEqual(
 }
 
 std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setFillet(
-    const std::list<ModelHighAPI_RefAttr> & thePoints,
-    const ModelHighAPI_Double & theRadius)
+    const ModelHighAPI_RefAttr & thePoint)
 {
   std::shared_ptr<ModelAPI_Feature> 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<ModelHighAPI_Interface> 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<ModelHighAPI_Interface> SketchAPI_Sketch::setFixed(
     const ModelHighAPI_RefAttr & theObject)
 {
index 216474474f66f55ecfd08bad78eec15f59446068..792a8ee79845a6281488d53c9dc04a9c9e92d15c 100644 (file)
@@ -318,7 +318,12 @@ public:
   /// Set fillet
   SKETCHAPI_EXPORT
   std::shared_ptr<ModelHighAPI_Interface> setFillet(
-      const std::list<ModelHighAPI_RefAttr> & thePoints,
+      const ModelHighAPI_RefAttr & thePoint);
+
+  /// Set fillet with additional radius constraint
+  SKETCHAPI_EXPORT
+  std::shared_ptr<ModelHighAPI_Interface> setFilletWithRadius(
+      const ModelHighAPI_RefAttr & thePoint,
       const ModelHighAPI_Double & theRadius);
 
   /// Set fixed
index 46448c8a4500937853998f277ef50af98bc84a18..f1d18eea26308c4020760f498dd73fee53b5b171 100644 (file)
@@ -139,6 +139,7 @@ ADD_UNIT_TESTS(TestSketchPointLine.py
                TestConstraintMiddlePoint.py
                TestMultiRotation.py
                TestMultiTranslation.py
+               TestFillet.py
                TestRectangle.py
                TestProjection.py
                TestSplit.py
index 9a163403fdd93b9249d2deae0ae5839fddb2cce4..f56b27d73e8c0a7a6a79dd9a8e94196b55f0c603 100644 (file)
@@ -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<GeomDataAPI_Point2D> aFilletPoint2D =
-    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointRefAttr->attr());
-  if (!aFilletPoint2D.get()) {
+  if (!calculateFilletParameters())
     return AISObjectPtr();
-  }
 
-  // Obtain constraint coincidence for the fillet point.
-  FeaturePtr aConstraintCoincidence;
-  const std::set<AttributePtr>& aRefsList = aFilletPoint2D->owner()->data()->refsToMe();
-  for(std::set<AttributePtr>::const_iterator anIt = aRefsList.cbegin();
-      anIt != aRefsList.cend();
-      ++anIt) {
-    std::shared_ptr<ModelAPI_Attribute> anAttr = (*anIt);
-    FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
-    if(aFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
-      AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-        aFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
-      AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
-        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<GeomAPI_Pnt> aCenterPnt(aSketch->to3D(myCenterXY->x(), myCenterXY->y()));
+  std::shared_ptr<GeomAPI_Pnt> aTangentPnt1(aSketch->to3D(myTangentXY1->x(),
+                                                          myTangentXY1->y()));
+  std::shared_ptr<GeomAPI_Pnt> aTangentPnt2(aSketch->to3D(myTangentXY2->x(),
+                                                          myTangentXY2->y()));
+  std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+    aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
+  std::shared_ptr<GeomAPI_Shape> 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<FeaturePtr> 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<GeomDataAPI_Point2D> aFilletPoint2D =
+    std::dynamic_pointer_cast<GeomDataAPI_Point2D>(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<FeaturePtr>::iterator aLinesIt = anEdgeFeatures.begin();
-  anEdgeFeature1 = *aLinesIt++;
-  anEdgeFeature2 = *aLinesIt;
-
   // Getting points located at 1/3 of edge length from fillet point.
   std::shared_ptr<GeomAPI_Pnt2d> aFilletPnt2d = aFilletPoint2D->pnt();
   std::shared_ptr<GeomAPI_Pnt2d> 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<GeomAPI_Pnt2d> 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<GeomDataAPI_Point2D>(
@@ -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<GeomAPI_Pnt> aCenterPnt(aSketch->to3D(myCenterXY->x(), myCenterXY->y()));
-  std::shared_ptr<GeomAPI_Pnt> aTangentPnt1(aSketch->to3D(myTangentXY1->x(),
-                                                          myTangentXY1->y()));
-  std::shared_ptr<GeomAPI_Pnt> aTangentPnt2(aSketch->to3D(myTangentXY2->x(),
-                                                          myTangentXY2->y()));
-  std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
-    aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
-  std::shared_ptr<GeomAPI_Shape> 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<GeomDataAPI_Point2D> theFilletPoint)
+{
+  // Obtain constraint coincidence for the fillet point.
+  FeaturePtr aConstraintCoincidence;
+  const std::set<AttributePtr>& aRefsList = theFilletPoint->owner()->data()->refsToMe();
+  for(std::set<AttributePtr>::const_iterator anIt = aRefsList.cbegin();
+      anIt != aRefsList.cend();
+      ++anIt) {
+    std::shared_ptr<ModelAPI_Attribute> anAttr = (*anIt);
+    FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(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<FeaturePtr> anEdgeFeatures = getCoincides(aConstraintCoincidence);
+  std::set<FeaturePtr>::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   =================
index b25e0257d0f1a2d05021032350c4e72d4cf86385..49388f26a5aad2382cf7ec1ac1ae015b428027f7 100644 (file)
@@ -12,6 +12,7 @@
 #include "SketchPlugin_SketchEntity.h"
 
 #include <GeomAPI_IPresentable.h>
+#include <GeomDataAPI_Point2D.h>
 
 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<GeomDataAPI_Point2D> theFilletPoint);
+
 private:
     FeaturePtr myBaseFeatures[2];
     std::string myFeatAttributes[4]; // attributes of features
index 79a82b7b69ae943aa56fb7184978a66a770bc2ee..fd5ce78bf0d2485d463b3b7a899125b1c1c9b99e 100644 (file)
@@ -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
 #=========================================================================
index bf5db26b3dca4746f3c114b2525d585db8e89195..6ad62415b897a30cf1b1d2af268fa4d07ecb28c9 100644 (file)
         <boolvalue id="Auxiliary" label="Auxiliary" default="false" tooltip="Construction element" obligatory="0"/>
       </feature>
 
-      <!--  SketchConstraintFillet  -->
+      <!--  SketchFillet  -->
       <feature id="SketchFillet"
                title="Fillet"
                tooltip="Create constraint defining fillet between two objects"
index 5b34fd59a0f5abcd3b2b0baf3e97d3e661bf4d15..e9be8a299f31ccd34f080f5eb6185b7489d27f8e 100644 (file)
@@ -101,13 +101,14 @@ PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Solver::solve()
   }
 
   SolveStatus aStatus;
-  if (aResult == GCS::Success) {
+  if (aResult == GCS::Failed)
+    aStatus = STATUS_FAILED;
+  else {
     myEquationSystem->applySolution();
     if (myDOF < 0)
       myDOF = myEquationSystem->dofsNumber();
     aStatus = STATUS_OK;
-  } else
-    aStatus = STATUS_FAILED;
+  }
 
   return aStatus;
 }
index 9dc93f371b9b82b4fe475e763b1eb9261f618c74..3dd68b54b56d78de73ca62459bdaf9c3c1d56703 100644 (file)
@@ -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<GCS::Circle> aCirc =
-      std::dynamic_pointer_cast<GCS::Circle>(theEntity1->entity());
+      std::dynamic_pointer_cast<GCS::Circle>(anEntCirc);
     std::shared_ptr<GCS::Line> aLine =
-      std::dynamic_pointer_cast<GCS::Line>(theEntity2->entity());
+      std::dynamic_pointer_cast<GCS::Line>(anEntLine);
 
     aNewConstr =
       GCSConstraintPtr(new GCS::ConstraintP2LDistance(aCirc->center, *aLine, aCirc->rad));
index 1bf442634e914bc9286a85af8290a96adf060f4b..8a61e1a993834fb60894db047030f289565d6b44 100644 (file)
@@ -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<EntityWrapperPtr>::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()