]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Issue #3158: Fatal error when create Tangent constraint
authorazv <azv@opencascade.com>
Thu, 27 Feb 2020 13:24:46 +0000 (16:24 +0300)
committerazv <azv@opencascade.com>
Thu, 27 Feb 2020 13:25:18 +0000 (16:25 +0300)
Forbid by validators the selection of tangent entities if at least on is a B-spline curve and they have no coincident boundary point.

src/SketchPlugin/SketchPlugin_Tools.cpp
src/SketchPlugin/SketchPlugin_Validators.cpp
src/SketchPlugin/Test/TestConstraintTangentBSpline.py
src/SketchSolver/SketchSolver_ConstraintTangent.cpp

index df8e35cf60ccad6dddc455524dc1dda558dbfaac..68765a14e9620b12df1d15b5c1c00f9648d186a1 100644 (file)
@@ -120,7 +120,8 @@ std::set<FeaturePtr> findCoincidentConstraints(const FeaturePtr& theFeature)
   std::set<AttributePtr>::const_iterator aIt;
   for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
     FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aIt)->owner());
-    if (aConstrFeature && aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID())
+    if (aConstrFeature && (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
+        aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()))
       aCoincident.insert(aConstrFeature);
   }
   return aCoincident;
index 454d8c8712a1349f44b576b71ae775098ae70e37..f4d6b324cc427a9b6c506b5d4473de7f71eea169 100644 (file)
@@ -24,6 +24,7 @@
 #include "SketchPlugin_BSplinePeriodic.h"
 #include "SketchPlugin_Circle.h"
 #include "SketchPlugin_ConstraintCoincidence.h"
+#include "SketchPlugin_ConstraintCoincidenceInternal.h"
 #include "SketchPlugin_ConstraintDistance.h"
 #include "SketchPlugin_ConstraintRigid.h"
 #include "SketchPlugin_ConstraintTangent.h"
@@ -166,32 +167,81 @@ bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute
 
   bool isObject = aRefAttr->isObject();
   ObjectPtr anObject = aRefAttr->object();
-  if (isObject && anObject.get()) {
-    FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
+  if (!isObject || !anObject.get()) {
+    theError = "It uses an empty object";
+    return false;
+  }
 
-    AttributeRefAttrPtr aOtherAttr = anAttributeFeature->data()->refattr(aParamA);
-    ObjectPtr aOtherObject = aOtherAttr->object();
-    FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
-    if (!aOtherFea)
-      return true;
+  FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
 
-    if (aRefFea->getKind() == SketchPlugin_Line::ID() &&
-        aOtherFea->getKind() == SketchPlugin_Line::ID()) {
-      theError = "Two segments cannot be tangent";
-      return false;
-    }
-    else if (isSpline(aRefFea) && isSpline(aOtherFea)) {
-      theError = "Two B-splines cannot be tangent";
-      return false;
-    }
+  AttributeRefAttrPtr aOtherAttr = anAttributeFeature->data()->refattr(aParamA);
+  ObjectPtr aOtherObject = aOtherAttr->object();
+  FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
+  if (!aOtherFea)
     return true;
+
+  if (aRefFea->getKind() == SketchPlugin_Line::ID() &&
+      aOtherFea->getKind() == SketchPlugin_Line::ID()) {
+    theError = "Two segments cannot be tangent";
+    return false;
   }
-  else {
-    theError = "It uses an empty object";
+  else if (isSpline(aRefFea) && isSpline(aOtherFea)) {
+    theError = "Two B-splines cannot be tangent";
     return false;
   }
 
-  return true;
+  bool isValid = true;
+  bool hasSpline = isSpline(aRefFea);
+  if (!hasSpline && isSpline(aOtherFea)) {
+    hasSpline = true;
+    std::swap(aRefFea, aOtherFea);
+  }
+  if (hasSpline) {
+    auto isApplicableCoincidence = [](FeaturePtr theFeature, const std::string& theAttrName) {
+      AttributeRefAttrPtr aRefAttr = theFeature->refattr(theAttrName);
+      if (aRefAttr->isObject())
+        return false;
+      AttributePtr anAttr = aRefAttr->attr();
+      FeaturePtr anOwner = ModelAPI_Feature::feature(anAttr->owner());
+      AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
+      if (aPointAttr) {
+        return anOwner->getKind() == SketchPlugin_BSpline::ID() &&
+              (aPointAttr->id() == SketchPlugin_BSpline::START_ID() ||
+               aPointAttr->id() == SketchPlugin_BSpline::END_ID());
+      }
+
+      AttributePoint2DArrayPtr aPntArray =
+          std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(anAttr);
+      if (aPntArray) {
+        // check index of the pole
+        AttributeIntegerPtr anIndex = theAttrName == SketchPlugin_Constraint::ENTITY_A() ?
+            theFeature->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A()) :
+            theFeature->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
+        return anIndex && (anIndex->value() == 0 || anIndex->value() == aPntArray->size() - 1);
+      }
+      return false;
+    };
+
+    isValid = false;
+    AttributePoint2DArrayPtr aBSplinePoles = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+        aRefFea->attribute(SketchPlugin_BSplineBase::POLES_ID()));
+    // additional check the B-spline edge and the other edge have a coincident boundary point
+    std::set<FeaturePtr> aCoincidences = SketchPlugin_Tools::findCoincidentConstraints(aRefFea);
+    for (std::set<FeaturePtr>::iterator anIt = aCoincidences.begin();
+         anIt != aCoincidences.end() && !isValid; ++anIt) {
+      std::set<FeaturePtr> aCoinc;
+      if (isApplicableCoincidence(*anIt, SketchPlugin_Constraint::ENTITY_A()))
+        SketchPlugin_Tools::findCoincidences(*anIt, SketchPlugin_Constraint::ENTITY_B(),
+                                             aCoinc, true);
+      else if (isApplicableCoincidence(*anIt, SketchPlugin_Constraint::ENTITY_B()))
+        SketchPlugin_Tools::findCoincidences(*anIt, SketchPlugin_Constraint::ENTITY_A(),
+                                             aCoinc, true);
+
+      isValid = aCoinc.find(aOtherFea) != aCoinc.end();
+    }
+  }
+
+  return isValid;
 }
 
 bool SketchPlugin_PerpendicularAttrValidator::isValid(const AttributePtr& theAttribute,
index e3e758bb670864c0111ad496f7aeca26b831aff5..f69cd5cf8eea2db626522c6cf626a7d4cfd3eb6c 100644 (file)
@@ -118,12 +118,12 @@ class TestTangentBSpline(unittest.TestCase):
     self.myDOF += 4
     model.do()
 
-    self.mySketch.setTangent(self.mySpline.result(), aLine.result())
-    self.myNbTangency += 1
-    self.myDOF -= 1
-    model.do()
+    aTangency = self.mySketch.setTangent(self.mySpline.result(), aLine.result())
+    model.end()
 
-    self.assertTangentFeatures(aLine, self.mySpline)
+    self.assertNotEqual(aTangency.feature().error(), "")
+    model.undo()
+    model.begin()
 
   def test_circle_tangent(self):
     """ Test 2. Set tangency between B-spline and a circle
@@ -133,12 +133,12 @@ class TestTangentBSpline(unittest.TestCase):
     self.myDOF += 3
     model.do()
 
-    self.mySketch.setTangent(self.mySpline.result(), aCircle.defaultResult())
-    self.myNbTangency += 1
-    self.myDOF -= 1
-    model.do()
+    aTangency = self.mySketch.setTangent(self.mySpline.result(), aCircle.defaultResult())
+    model.end()
 
-    self.assertTangentFeatures(aCircle, self.mySpline)
+    self.assertNotEqual(aTangency.feature().error(), "")
+    model.undo()
+    model.begin()
 
   def test_arc_tangent(self):
     """ Test 3. Set tangency between B-spline and an arc
@@ -148,12 +148,12 @@ class TestTangentBSpline(unittest.TestCase):
     self.myDOF += 5
     model.do()
 
-    self.mySketch.setTangent(self.mySpline.result(), anArc.defaultResult())
-    self.myNbTangency += 1
-    self.myDOF -= 1
-    model.do()
+    aTangency = self.mySketch.setTangent(self.mySpline.result(), anArc.defaultResult())
+    model.end()
 
-    self.assertTangentFeatures(anArc, self.mySpline)
+    self.assertNotEqual(aTangency.feature().error(), "")
+    model.undo()
+    model.begin()
 
   def test_ellipse_tangent(self):
     """ Test 4. Set tangency between B-spline and an ellipse
@@ -163,12 +163,12 @@ class TestTangentBSpline(unittest.TestCase):
     self.myDOF += 5
     model.do()
 
-    self.mySketch.setTangent(self.mySpline.result(), anEllipse.defaultResult())
-    self.myNbTangency += 1
-    self.myDOF -= 1
-    model.do()
+    aTangency = self.mySketch.setTangent(self.mySpline.result(), anEllipse.defaultResult())
+    model.end()
 
-    self.assertTangentFeatures(anEllipse, self.mySpline)
+    self.assertNotEqual(aTangency.feature().error(), "")
+    model.undo()
+    model.begin()
 
   def test_elliptic_arc_tangent(self):
     """ Test 5. Set tangency between B-spline and an elliptic arc
@@ -178,12 +178,12 @@ class TestTangentBSpline(unittest.TestCase):
     self.myDOF += 7
     model.do()
 
-    self.mySketch.setTangent(self.mySpline.result(), anEllipticArc.defaultResult())
-    self.myNbTangency += 1
-    self.myDOF -= 1
-    model.do()
+    aTangency = self.mySketch.setTangent(self.mySpline.result(), anEllipticArc.defaultResult())
+    model.end()
 
-    self.assertTangentFeatures(anEllipticArc, self.mySpline)
+    self.assertNotEqual(aTangency.feature().error(), "")
+    model.undo()
+    model.begin()
 
   def test_spline_tangent(self):
     """ Test 6. Set tangency between two B-spline curves
@@ -193,13 +193,12 @@ class TestTangentBSpline(unittest.TestCase):
     self.myDOF += aSpline.poles().size() * 2
     model.do()
 
-    self.mySketch.setTangent(self.mySpline.result(), aSpline.result())
-    self.myNbTangency += 1
-    self.myDOF -= 1
-    model.do()
+    aTangency = self.mySketch.setTangent(self.mySpline.result(), aSpline.result())
+    model.end()
 
-    #self.assertTangentFeatures(aSpline, self.mySpline)
-    self.myExpectedFailure = True
+    self.assertNotEqual(aTangency.feature().error(), "")
+    model.undo()
+    model.begin()
 
 
   def test_line_tangent_coincident_by_pole(self):
@@ -215,13 +214,12 @@ class TestTangentBSpline(unittest.TestCase):
     self.myDOF -= 1
     model.do()
 
-    self.mySketch.setTangent(self.mySpline.result(), aLine.result())
-    self.myNbTangency += 1
-    self.myDOF -= 1
-    model.do()
+    aTangency = self.mySketch.setTangent(self.mySpline.result(), aLine.result())
+    model.end()
 
-    self.assertPointLineDistance(self.mySpline.startPoint(), aLine)
-    self.assertTangentFeatures(aLine, self.mySpline)
+    self.assertNotEqual(aTangency.feature().error(), "")
+    model.undo()
+    model.begin()
 
   def test_circle_tangent_coincident_by_pole(self):
     """ Test 8. Set tangency between B-spline and a circle coincident with B-spline end point
@@ -236,14 +234,12 @@ class TestTangentBSpline(unittest.TestCase):
     self.myDOF -= 1
     model.do()
 
-    self.mySketch.setTangent(self.mySpline.result(), aCircle.defaultResult())
-    self.myNbTangency += 1
-    self.myDOF -= 1
-    model.do()
+    aTangency = self.mySketch.setTangent(self.mySpline.result(), aCircle.defaultResult())
+    model.end()
 
-    self.assertTangentFeatures(aCircle, self.mySpline)
-    dist = model.distancePointPoint(self.mySpline.startPoint(), aCircle.center())
-    self.assertAlmostEqual(dist, aCircle.radius().value())
+    self.assertNotEqual(aTangency.feature().error(), "")
+    model.undo()
+    model.begin()
 
   def test_arc_tangent_coincident_by_pole(self):
     """ Test 9. Set tangency between B-spline and an arc coincident with B-spline end point
@@ -258,14 +254,12 @@ class TestTangentBSpline(unittest.TestCase):
     self.myDOF -= 1
     model.do()
 
-    self.mySketch.setTangent(self.mySpline.result(), anArc.defaultResult())
-    self.myNbTangency += 1
-    self.myDOF -= 1
-    model.do()
+    aTangency = self.mySketch.setTangent(self.mySpline.result(), anArc.defaultResult())
+    model.end()
 
-    self.assertTangentFeatures(anArc, self.mySpline)
-    dist = model.distancePointPoint(self.mySpline.endPoint(), anArc.center())
-    self.assertAlmostEqual(dist, anArc.radius().value())
+    self.assertNotEqual(aTangency.feature().error(), "")
+    model.undo()
+    model.begin()
 
   def test_ellipse_tangent_coincident_by_pole(self):
     """ Test 10. Set tangency between B-spline and an ellipse coincident with B-spline start point
@@ -280,12 +274,12 @@ class TestTangentBSpline(unittest.TestCase):
     self.myDOF -= 1
     model.do()
 
-    self.mySketch.setTangent(self.mySpline.result(), anEllipse.defaultResult())
-    self.myNbTangency += 1
-    self.myDOF -= 1
-    model.do()
+    aTangency = self.mySketch.setTangent(self.mySpline.result(), anEllipse.defaultResult())
+    model.end()
 
-    self.assertTangentLineEllipse(SketchAPI_Line(self.myControlLines[0]), anEllipse)
+    self.assertNotEqual(aTangency.feature().error(), "")
+    model.undo()
+    model.begin()
 
   def test_elliptic_arc_tangent_coincident_by_pole(self):
     """ Test 11. Set tangency between B-spline and an elliptic arc coincident with B-spline start point
@@ -300,12 +294,12 @@ class TestTangentBSpline(unittest.TestCase):
     self.myDOF -= 1
     model.do()
 
-    self.mySketch.setTangent(self.mySpline.result(), anEllipticArc.defaultResult())
-    self.myNbTangency += 1
-    self.myDOF -= 1
-    model.do()
+    aTangency = self.mySketch.setTangent(self.mySpline.result(), anEllipticArc.defaultResult())
+    model.end()
 
-    self.assertTangentLineEllipse(SketchAPI_Line(self.myControlLines[0]), anEllipticArc)
+    self.assertNotEqual(aTangency.feature().error(), "")
+    model.undo()
+    model.begin()
 
 
   def test_line_tangent_coincident_by_boundaries(self):
index f3832c24521f674cbd626acfe6815bf18710d33e..90e57e3f4d382b6cca699d765b81b7df9141cd75 100644 (file)
@@ -31,6 +31,8 @@
 #include <GeomAPI_Pnt2d.h>
 #include <GeomAPI_Ellipse2d.h>
 
+#include <GeomDataAPI_Point2DArray.h>
+
 #include <ModelAPI_AttributeInteger.h>
 
 #include <SketchPlugin_Arc.h>
@@ -423,7 +425,7 @@ std::set<AttributePtr> coincidentBoundaryPoints(FeaturePtr theFeature1, FeatureP
 {
   std::set<FeaturePtr> aCoincidences = collectCoincidences(theFeature1, theFeature2);
   // collect points only
-  std::set<AttributePtr> aCoincidentPoints;
+  std::map<FeaturePtr, std::set<AttributePtr> > aCoincidentPoints;
   std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
   for (; aCIt != aCoincidences.end(); ++ aCIt) {
     for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
@@ -435,25 +437,38 @@ std::set<AttributePtr> coincidentBoundaryPoints(FeaturePtr theFeature1, FeatureP
       FeaturePtr anOwner = ModelAPI_Feature::feature(anAttr->owner());
       if (anOwner == theFeature1 || anOwner == theFeature2) {
         if (anAttr->id() == SketchPlugin_BSplineBase::POLES_ID()) {
-          AttributeIntegerPtr anIndex = (*aCIt)->integer(i == 0 ?
-              SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A() :
-              SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
+          AttributePoint2DArrayPtr aPoles =
+              std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(anAttr);
+
+          AttributeIntegerPtr anIndex;
+          if (anOwner->getKind() == SketchPlugin_BSpline::ID()) {
+            anIndex = (*aCIt)->integer(i == 0 ?
+                SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A() :
+                SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
+          }
           if (anIndex) {
             if (anIndex->value() == 0)
               anAttr = anOwner->attribute(SketchPlugin_BSpline::START_ID());
-            else
+            else if (anIndex->value() + 1 == aPoles->size())
               anAttr = anOwner->attribute(SketchPlugin_BSpline::END_ID());
             if (anAttr)
-              aCoincidentPoints.insert(anAttr);
+              aCoincidentPoints[anOwner].insert(anAttr);
           }
         }
         else if (anAttr->id() != SketchPlugin_Arc::CENTER_ID() &&
                  anAttr->id() != SketchPlugin_Circle::CENTER_ID())
-          aCoincidentPoints.insert(anAttr);
+          aCoincidentPoints[anOwner].insert(anAttr);
       }
     }
   }
-  return aCoincidentPoints;
+
+  std::set<AttributePtr> aBoundaryPoints;
+  if (aCoincidentPoints.size() == 2) {
+    for (std::map<FeaturePtr, std::set<AttributePtr> >::iterator anIt = aCoincidentPoints.begin();
+         anIt != aCoincidentPoints.end(); ++anIt)
+      aBoundaryPoints.insert(anIt->second.begin(), anIt->second.end());
+  }
+  return aBoundaryPoints;
 }
 
 static std::set<AttributePtr> refsToFeatureAndResults(FeaturePtr theFeature)