Salome HOME
Set the orientation of the Distance constraint
authorazv <azv@opencascade.com>
Thu, 29 Jun 2017 12:48:00 +0000 (15:48 +0300)
committerazv <azv@opencascade.com>
Thu, 29 Jun 2017 12:48:30 +0000 (15:48 +0300)
19 files changed:
src/ModelHighAPI/ModelHighAPI.i
src/PythonAPI/model/sketcher/tools.py
src/SketchAPI/SketchAPI_Constraint.cpp
src/SketchAPI/SketchAPI_Sketch.cpp
src/SketchAPI/SketchAPI_Sketch.h
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/SketchPlugin_ConstraintDistance.cpp
src/SketchPlugin/SketchPlugin_ConstraintDistance.h
src/SketchPlugin/Test/TestDistanceSignedVsUnsigned01.py [new file with mode: 0644]
src/SketchPlugin/Test/TestDistanceSignedVsUnsigned02.py [new file with mode: 0644]
src/SketchPlugin/Test/TestDistanceSignedVsUnsigned03.py [new file with mode: 0644]
src/SketchPlugin/Test/TestDistanceSignedVsUnsigned04.py [new file with mode: 0644]
src/SketchPlugin/Test/TestDistanceSignedVsUnsigned05.py [new file with mode: 0644]
src/SketchPlugin/Test/TestSignedDistancePointLine.py [new file with mode: 0644]
src/SketchPlugin/Test/TestSignedDistancePointPoint.py [new file with mode: 0644]
src/SketchPlugin/plugin-Sketch.xml
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp
src/SketchSolver/SketchSolver_ConstraintDistance.cpp
src/SketchSolver/SketchSolver_ConstraintDistance.h

index 5b09cc980fab7b581f1dc1a2198e3b87829d075f..7010d848143a09e50c63e061a6426e09b2fa5984 100644 (file)
   std::shared_ptr<ModelAPI_Attribute> * temp_attribute;
   std::shared_ptr<ModelAPI_Object> * temp_object;
   std::shared_ptr<ModelHighAPI_Interface> * temp_interface;
+  ModelHighAPI_Selection* temp_selection;
   int newmem = 0;
   if ((SWIG_ConvertPtrAndOwn($input, (void **)&temp_attribute, $descriptor(std::shared_ptr<ModelAPI_Attribute> *), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
     if (temp_attribute) {
     } else {
       $1 = 0;
     }
+  } else if ((SWIG_ConvertPtrAndOwn($input, (void **)&temp_selection, $descriptor(ModelHighAPI_Selection*), SWIG_POINTER_EXCEPTION, &newmem)) == 0) {
+    if (temp_selection) {
+      $1 = 1;
+    } else {
+      $1 = 0;
+    }
   } else {
     $1 = 0;
   }
index e93fec49cda0fe4247cce01accb5155b426f2e16..f3dcdb37a819049f03f325aa1c3e9e48d3783369 100644 (file)
@@ -75,7 +75,7 @@ def distancePointPoint(thePoint1, thePoint2):
     aPnt2 = toList(thePoint2)
     return math.hypot(aPnt1[0] - aPnt2[0], aPnt1[1] - aPnt2[1])
 
-def distancePointLine(thePoint, theLine):
+def signedDistancePointLine(thePoint, theLine):
     aPoint = toList(thePoint)
     aLine = toSketchFeature(theLine)
 
@@ -84,7 +84,10 @@ def distancePointLine(thePoint, theLine):
     aLineDir = aLineEnd.decreased(aLineStart)
     aLineLen = aLineEnd.distance(aLineStart)
     aCross = (aPoint[0] - aLineStart.x()) * aLineDir.y() - (aPoint[1] - aLineStart.y()) * aLineDir.x()
-    return math.fabs(aCross / aLineLen)
+    return aCross / aLineLen
+
+def distancePointLine(thePoint, theLine):
+    return math.fabs(signedDistancePointLine(thePoint, theLine))
 
 def lastSubFeature(theSketch, theKind):
     """
index d655ff2af0ca8c2a4837ebf5595d5d935521981f..c5a75fef3a135a6dacc4f8feaee90d7a74007f61 100644 (file)
@@ -192,5 +192,10 @@ void SketchAPI_Constraint::dump(ModelHighAPI_Dumper& theDumper) const
   if (aValueAttr && aValueAttr->isInitialized())
     theDumper << ", " << aValueAttr;
 
+  if (aBase->getKind() == SketchPlugin_ConstraintDistance::ID()) {
+    AttributeBooleanPtr isSigned = aBase->boolean(SketchPlugin_ConstraintDistance::SIGNED());
+    theDumper << ", " << isSigned->value();
+  }
+
   theDumper << ")" << std::endl;
 }
index daefc491e84a85f9fb5d2aa2e4e0fe60553aa750..b207823768c79c5295fb0764603af98862beb291 100644 (file)
@@ -627,17 +627,35 @@ std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setCollinear(
 std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setDistance(
     const ModelHighAPI_RefAttr & thePoint,
     const ModelHighAPI_RefAttr & thePointOrLine,
-    const ModelHighAPI_Double & theValue)
+    const ModelHighAPI_Double & theValue,
+    bool isSigned)
 {
   std::shared_ptr<ModelAPI_Feature> aFeature =
       compositeFeature()->addFeature(SketchPlugin_ConstraintDistance::ID());
   fillAttribute(thePoint, aFeature->refattr(SketchPlugin_Constraint::ENTITY_A()));
   fillAttribute(thePointOrLine, aFeature->refattr(SketchPlugin_Constraint::ENTITY_B()));
   fillAttribute(theValue, aFeature->real(SketchPlugin_Constraint::VALUE()));
+  fillAttribute(isSigned, aFeature->boolean(SketchPlugin_ConstraintDistance::SIGNED()));
   aFeature->execute();
   return InterfacePtr(new ModelHighAPI_Interface(aFeature));
 }
 
+std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setSignedDistance(
+    const ModelHighAPI_RefAttr & thePoint,
+    const ModelHighAPI_RefAttr & thePointOrLine,
+    const ModelHighAPI_Double & theValue)
+{
+  return setDistance(thePoint, thePointOrLine, theValue, true);
+}
+
+std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setUnsignedDistance(
+    const ModelHighAPI_RefAttr & thePoint,
+    const ModelHighAPI_RefAttr & thePointOrLine,
+    const ModelHighAPI_Double & theValue)
+{
+  return setDistance(thePoint, thePointOrLine, theValue, false);
+}
+
 std::shared_ptr<ModelHighAPI_Interface> SketchAPI_Sketch::setHorizontalDistance(
     const ModelHighAPI_RefAttr & thePoint1,
     const ModelHighAPI_RefAttr & thePoint2,
index f178514441a2c97ea09592e7098bd7b0d329c067..107ec5b85becf5b53df162043c7beab256467c4b 100644 (file)
@@ -329,6 +329,21 @@ public:
   /// Set distance
   SKETCHAPI_EXPORT
   std::shared_ptr<ModelHighAPI_Interface> setDistance(
+      const ModelHighAPI_RefAttr & thePoint,
+      const ModelHighAPI_RefAttr & thePointOrLine,
+      const ModelHighAPI_Double & theValue,
+      bool isSigned = false);
+
+  /// Set signed distance
+  SKETCHAPI_EXPORT
+  std::shared_ptr<ModelHighAPI_Interface> setSignedDistance(
+      const ModelHighAPI_RefAttr & thePoint,
+      const ModelHighAPI_RefAttr & thePointOrLine,
+      const ModelHighAPI_Double & theValue);
+
+  /// Set unsigned distance
+  SKETCHAPI_EXPORT
+  std::shared_ptr<ModelHighAPI_Interface> setUnsignedDistance(
       const ModelHighAPI_RefAttr & thePoint,
       const ModelHighAPI_RefAttr & thePointOrLine,
       const ModelHighAPI_Double & theValue);
index bacf4249a679c2940aae88099ebad870875e9464..152367cb51d095cd1aab11c945150389ac036e39 100644 (file)
@@ -216,4 +216,11 @@ ADD_UNIT_TESTS(TestSketchPointLine.py
                TestMoveCircle.py
                TestMoveArc.py
                TestMovementComplex.py
+               TestDistanceSignedVsUnsigned01.py
+               TestDistanceSignedVsUnsigned02.py
+               TestDistanceSignedVsUnsigned03.py
+               TestDistanceSignedVsUnsigned04.py
+               TestDistanceSignedVsUnsigned05.py
+               TestSignedDistancePointPoint.py
+               TestSignedDistancePointLine.py
 )
index f4a02ca4102db7db10e294f8ec4b8e4089fc8500..b541a3bc143b70953db80beb0c61ca3acbbe600d 100644 (file)
@@ -54,6 +54,7 @@ void SketchPlugin_ConstraintDistance::initAttributes()
   data()->addAttribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT(), GeomDataAPI_Point2D::typeId());
   data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
   data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
+  data()->addAttribute(SIGNED(), ModelAPI_AttributeBoolean::typeId());
 }
 
 void SketchPlugin_ConstraintDistance::colorConfigInfo(std::string& theSection, std::string& theName,
index c2dc3ee409e95ec77131d4488abee32c29f2cdb4..3c433e974366a39bc5452dd979dc1d74b881b260 100644 (file)
@@ -58,6 +58,13 @@ class SketchPlugin_ConstraintDistance : public SketchPlugin_ConstraintBase
     return MY_KIND;
   }
 
+  /// \brief Shows whether the point-line distance should keep its sign
+  inline static const std::string& SIGNED()
+  {
+    static const std::string MY_SIGNED("SignedDistance");
+    return MY_SIGNED;
+  }
+
   /// \brief Creates a new part document if needed
   SKETCHPLUGIN_EXPORT virtual void execute();
 
diff --git a/src/SketchPlugin/Test/TestDistanceSignedVsUnsigned01.py b/src/SketchPlugin/Test/TestDistanceSignedVsUnsigned01.py
new file mode 100644 (file)
index 0000000..6ab1c23
--- /dev/null
@@ -0,0 +1,66 @@
+## Copyright (C) 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<mailto:webmaster.salome@opencascade.com>
+##
+
+from salome.shaper import model
+from SketchAPI import *
+import math
+
+TOLERANCE = 1.e-5
+
+model.begin()
+partSet = model.moduleDocument()
+widthParam = model.addParameter(partSet, "w", "200")
+distParam = model.addParameter(partSet, "d", "30")
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+Rectangle_1 = Sketch_1.addRectangle(0, 0, 200, 100)
+[Line_1, Line_2, Line_3, Line_4] = Rectangle_1.lines()
+Origin = Sketch_1.addPoint(model.selection("VERTEX", "Origin"))
+Sketch_1.setCoincident(SketchAPI_Line(Line_1).endPoint(), Origin.result())
+Sketch_1.setLength(SketchAPI_Line(Line_1).result(), "w")
+Point_1 = Sketch_1.addPoint(230, 40)
+Sketch_1.setSignedDistance(Point_1.result(), SketchAPI_Line(Line_4).result(), "d")
+Point_2 = Sketch_1.addPoint(230, 80)
+Sketch_1.setUnsignedDistance(Point_2.result(), SketchAPI_Line(Line_4).result(), "d")
+model.do()
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+line = model.toSketchFeature(Line_4)
+signedDist1 = model.signedDistancePointLine(Point_1, line)
+signedDist2 = model.signedDistancePointLine(Point_2, line)
+
+# change rectangle width and check distances
+widthParam.setValue(2000)
+model.do()
+curDist = model.signedDistancePointLine(Point_1, line)
+assert(math.fabs(signedDist1 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist1, curDist)
+curDist = model.signedDistancePointLine(Point_2, line)
+assert(math.fabs(math.fabs(signedDist2) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist2, -curDist)
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+# revert rectangle width and check distances again
+widthParam.setValue(200)
+model.do()
+curDist = model.signedDistancePointLine(Point_1, line)
+assert(math.fabs(signedDist1 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist1, curDist)
+curDist = model.signedDistancePointLine(Point_2, line)
+assert(math.fabs(math.fabs(signedDist2) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist2, -curDist)
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+model.end()
diff --git a/src/SketchPlugin/Test/TestDistanceSignedVsUnsigned02.py b/src/SketchPlugin/Test/TestDistanceSignedVsUnsigned02.py
new file mode 100644 (file)
index 0000000..f518caa
--- /dev/null
@@ -0,0 +1,68 @@
+## Copyright (C) 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<mailto:webmaster.salome@opencascade.com>
+##
+
+from salome.shaper import model
+from SketchAPI import *
+import math
+
+TOLERANCE = 1.e-5
+
+model.begin()
+partSet = model.moduleDocument()
+widthParam = model.addParameter(partSet, "w", "200")
+distParam = model.addParameter(partSet, "d", "30")
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+Rectangle_1 = Sketch_1.addRectangle(0, 0, 200, 100)
+[Line_1, Line_2, Line_3, Line_4] = Rectangle_1.lines()
+Point_1 = Sketch_1.addPoint(model.selection("VERTEX", "Origin"))
+Sketch_1.setCoincident(SketchAPI_Line(Line_1).endPoint(), Point_1.result())
+Sketch_1.setLength(SketchAPI_Line(Line_1).result(), "w")
+Circle_1 = Sketch_1.addCircle(230, 40, 20)
+Sketch_1.setSignedDistance(Circle_1.center(), SketchAPI_Line(Line_4).result(), "d")
+Circle_2 = Sketch_1.addCircle(230, 80, 20)
+Sketch_1.setUnsignedDistance(Circle_2.center(), SketchAPI_Line(Line_4).result(), "d")
+model.do()
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+center1 = Circle_1.center()
+center2 = Circle_2.center()
+line = model.toSketchFeature(Line_4)
+signedDist1 = model.signedDistancePointLine(center1, line)
+signedDist2 = model.signedDistancePointLine(center2, line)
+
+# change rectangle width and check distances
+widthParam.setValue(2000)
+model.do()
+curDist = model.signedDistancePointLine(center1, line)
+assert(math.fabs(signedDist1 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist1, curDist)
+curDist = model.signedDistancePointLine(center2, line)
+assert(math.fabs(math.fabs(signedDist2) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist2, -curDist)
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+# revert rectangle width and check distances again
+widthParam.setValue(200)
+model.do()
+curDist = model.signedDistancePointLine(center1, line)
+assert(math.fabs(signedDist1 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist1, curDist)
+curDist = model.signedDistancePointLine(center2, line)
+assert(math.fabs(math.fabs(signedDist2) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist2, -curDist)
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+model.end()
diff --git a/src/SketchPlugin/Test/TestDistanceSignedVsUnsigned03.py b/src/SketchPlugin/Test/TestDistanceSignedVsUnsigned03.py
new file mode 100644 (file)
index 0000000..f059900
--- /dev/null
@@ -0,0 +1,67 @@
+## Copyright (C) 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<mailto:webmaster.salome@opencascade.com>
+##
+
+from salome.shaper import model
+from SketchAPI import *
+import math
+
+TOLERANCE = 1.e-5
+
+model.begin()
+partSet = model.moduleDocument()
+widthParam = model.addParameter(partSet, "w", "200")
+distParam = model.addParameter(partSet, "d", "30")
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+Rectangle_1 = Sketch_1.addRectangle(0, 0, 200, 100)
+[Line_1, Line_2, Line_3, Line_4] = Rectangle_1.lines()
+Point_1 = Sketch_1.addPoint(model.selection("VERTEX", "Origin"))
+Sketch_1.setCoincident(SketchAPI_Line(Line_1).endPoint(), Point_1.result())
+Sketch_1.setLength(SketchAPI_Line(Line_1).result(), "w")
+Line_5 = Sketch_1.addLine(230, 40, 230, 80)
+Sketch_1.setSignedDistance(Line_5.startPoint(), SketchAPI_Line(Line_4).result(), "d")
+Sketch_1.setUnsignedDistance(Line_5.endPoint(), SketchAPI_Line(Line_4).result(), "d")
+model.do()
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+start = Line_5.startPoint()
+end = Line_5.endPoint()
+line = model.toSketchFeature(Line_4)
+signedDist1 = model.signedDistancePointLine(start, line)
+signedDist2 = model.signedDistancePointLine(end, line)
+
+# change rectangle width and check distances
+widthParam.setValue(2000)
+model.do()
+curDist = model.signedDistancePointLine(start, line)
+assert(math.fabs(signedDist1 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist1, curDist)
+curDist = model.signedDistancePointLine(end, line)
+assert(math.fabs(math.fabs(signedDist2) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist2, -curDist)
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+# revert rectangle width and check distances again
+widthParam.setValue(200)
+model.do()
+curDist = model.signedDistancePointLine(start, line)
+assert(math.fabs(signedDist1 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist1, curDist)
+curDist = model.signedDistancePointLine(end, line)
+assert(math.fabs(math.fabs(signedDist2) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist2, -curDist)
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+model.end()
diff --git a/src/SketchPlugin/Test/TestDistanceSignedVsUnsigned04.py b/src/SketchPlugin/Test/TestDistanceSignedVsUnsigned04.py
new file mode 100644 (file)
index 0000000..e26fd42
--- /dev/null
@@ -0,0 +1,69 @@
+## Copyright (C) 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<mailto:webmaster.salome@opencascade.com>
+##
+
+from salome.shaper import model
+from SketchAPI import *
+import math
+
+TOLERANCE = 1.e-5
+
+model.begin()
+partSet = model.moduleDocument()
+widthParam = model.addParameter(partSet, "w", "200")
+distParam = model.addParameter(partSet, "d", "30")
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+Rectangle_1 = Sketch_1.addRectangle(0, 0, 200, 100)
+[Line_1, Line_2, Line_3, Line_4] = Rectangle_1.lines()
+Point_1 = Sketch_1.addPoint(model.selection("VERTEX", "Origin"))
+Sketch_1.setCoincident(SketchAPI_Line(Line_1).endPoint(), Point_1.result())
+Sketch_1.setLength(SketchAPI_Line(Line_1).result(), "w")
+Arc_1 = Sketch_1.addArc(250, 60, 230, 40, 230, 80, False)
+Sketch_1.setSignedDistance(Arc_1.startPoint(), SketchAPI_Line(Line_4).result(), "d")
+Sketch_1.setUnsignedDistance(Arc_1.endPoint(), SketchAPI_Line(Line_4).result(), "d")
+model.do()
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+start = Arc_1.startPoint()
+end = Arc_1.endPoint()
+line = model.toSketchFeature(Line_4)
+signedDist1 = model.signedDistancePointLine(start, line)
+signedDist2 = model.signedDistancePointLine(end, line)
+
+# change rectangle width and check distances
+widthParam.setValue(1000)
+model.do()
+curDist = model.signedDistancePointLine(start, line)
+assert(math.fabs(signedDist1 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist1, curDist)
+curDist = model.signedDistancePointLine(end, line)
+assert(math.fabs(math.fabs(signedDist2) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist2, -curDist)
+model.assertArcValidity(Arc_1)
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+# revert rectangle width and check distances again
+widthParam.setValue(200)
+model.do()
+curDist = model.signedDistancePointLine(start, line)
+assert(math.fabs(signedDist1 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist1, curDist)
+curDist = model.signedDistancePointLine(end, line)
+assert(math.fabs(math.fabs(signedDist2) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist2, -curDist)
+model.assertArcValidity(Arc_1)
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+model.end()
diff --git a/src/SketchPlugin/Test/TestDistanceSignedVsUnsigned05.py b/src/SketchPlugin/Test/TestDistanceSignedVsUnsigned05.py
new file mode 100644 (file)
index 0000000..3d476c3
--- /dev/null
@@ -0,0 +1,80 @@
+## Copyright (C) 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<mailto:webmaster.salome@opencascade.com>
+##
+
+from salome.shaper import model
+from SketchAPI import *
+import math
+
+TOLERANCE = 1.e-5
+
+model.begin()
+partSet = model.moduleDocument()
+widthParam = model.addParameter(partSet, "w", "200")
+distParam = model.addParameter(partSet, "d", "30")
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+Rectangle_1 = Sketch_1.addRectangle(0, 0, 200, 100)
+[Line_1, Line_2, Line_3, Line_4] = Rectangle_1.lines()
+Origin = Sketch_1.addPoint(model.selection("VERTEX", "Origin"))
+Sketch_1.setCoincident(SketchAPI_Line(Line_1).endPoint(), Origin.result())
+Sketch_1.setLength(SketchAPI_Line(Line_1).result(), "w")
+Point_1 = Sketch_1.addPoint(230, 40)
+Sketch_1.setSignedDistance(Point_1.result(), SketchAPI_Line(Line_4).result(), "d")
+Point_2 = Sketch_1.addPoint(230, 80)
+Sketch_1.setUnsignedDistance(Point_2.result(), SketchAPI_Line(Line_4).result(), "d")
+Line_5 = Sketch_1.addLine(260, 0, 260, 100)
+Sketch_1.setSignedDistance(Point_1.result(), Line_5.result(), "d")
+Sketch_1.setUnsignedDistance(Point_2.result(), Line_5.result(), "d")
+model.do()
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+line4 = model.toSketchFeature(Line_4)
+line5 = model.toSketchFeature(Line_5)
+signedDist14 = model.signedDistancePointLine(Point_1, line4)
+signedDist15 = model.signedDistancePointLine(Point_1, line5)
+signedDist24 = model.signedDistancePointLine(Point_2, line4)
+signedDist25 = model.signedDistancePointLine(Point_2, line5)
+
+# change rectangle width and check distances
+widthParam.setValue(2000)
+model.do()
+curDist = model.signedDistancePointLine(Point_1, line4)
+assert(math.fabs(signedDist14 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist14, curDist)
+curDist = model.signedDistancePointLine(Point_2, line4)
+assert(math.fabs(math.fabs(signedDist24) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist24, -curDist)
+curDist = model.signedDistancePointLine(Point_1, line5)
+assert(math.fabs(signedDist15 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist15, curDist)
+curDist = model.signedDistancePointLine(Point_2, line5)
+assert(math.fabs(math.fabs(signedDist25) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist25, -curDist)
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+# revert rectangle width and check distances again
+widthParam.setValue(200)
+model.do()
+curDist = model.signedDistancePointLine(Point_1, line4)
+assert(math.fabs(signedDist14 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist14, curDist)
+curDist = model.signedDistancePointLine(Point_2, line4)
+assert(math.fabs(math.fabs(signedDist24) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist24, -curDist)
+curDist = model.signedDistancePointLine(Point_1, line5)
+assert(math.fabs(signedDist15 - curDist) < TOLERANCE), "Expected {}, actual {}".format(signedDist15, curDist)
+curDist = model.signedDistancePointLine(Point_2, line5)
+assert(math.fabs(math.fabs(signedDist25) - math.fabs(curDist)) < TOLERANCE), "Expected {}, actual {}".format(signedDist25, -curDist)
+assert Sketch_1.solverError().value() == "", "FAILED: Sketch should NOT report over-constrained situation"
+
+model.end()
diff --git a/src/SketchPlugin/Test/TestSignedDistancePointLine.py b/src/SketchPlugin/Test/TestSignedDistancePointLine.py
new file mode 100644 (file)
index 0000000..5339a7a
--- /dev/null
@@ -0,0 +1,129 @@
+from salome.shaper import model
+import math
+
+TOLERANCE = 1.e-5
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+model.addParameter(Part_1_doc, "clearance", "210")
+model.addParameter(Part_1_doc, "wheel_R", "203")
+model.addParameter(Part_1_doc, "arc_R", "wheel_R+70")
+model.addParameter(Part_1_doc, "hood_height", "290")
+HeightParam = model.addParameter(Part_1_doc, "height", "900")
+LengthParam = model.addParameter(Part_1_doc, "length", "1460")
+PosParam = model.addParameter(Part_1_doc, "position", "71.99905090248758")
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-281.378739745974, 78.99909999999998, -98.87873974597397, 78.99909999999998)
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchArc_1 = Sketch_1.addArc(174.031501908677, 71.9991, -98.87873974597397, 78.99909999999998, 446.941743563328, 78.9991, True)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchArc_1.startPoint())
+SketchArc_2 = Sketch_1.addArc(-554.288981400625, 71.9991, -281.378739745974, 78.99909999999998, -827.1992230552759, 78.9991, False)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchArc_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchArc_2.endPoint(), SketchLine_1.result())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_1.result())
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchArc_2.center(), SketchLine_1.result(), "clearance-wheel_R", True)
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchArc_1.center(), SketchLine_1.result(), "clearance-wheel_R", True)
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchArc_2.results()[1], SketchArc_1.results()[1])
+SketchCircle_1 = Sketch_1.addCircle(-554.288981400625, 71.9991, 203)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchArc_2.center(), SketchCircle_1.center())
+SketchCircle_2 = Sketch_1.addCircle(174.031501908677, 71.9991, 203)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchArc_1.center(), SketchCircle_2.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], "wheel_R")
+SketchConstraintEqual_2 = Sketch_1.setEqual(SketchCircle_1.results()[1], SketchCircle_2.results()[1])
+SketchLine_2 = Sketch_1.addLine(-827.1992230552759, 78.9991, -960.4001854579536, 78.9991)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchArc_2.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(-960.4001854579536, 78.9991, -960.4001854579536, 368.9991)
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchLine_4 = Sketch_1.addLine(-891.6236641114499, 437.7756213465037, -540.5628729569305, 437.7756213465037)
+SketchLine_5 = Sketch_1.addLine(-540.5628729569305, 437.7756213465037, -349.330908394406, 768.9991)
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_1.addLine(-349.330908394406, 768.9991, 308.3678499795216, 768.9991)
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchLine_7 = Sketch_1.addLine(308.3678499795216, 768.9991, 499.5998145420464, 437.7756213465038)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchLine_8 = Sketch_1.addLine(499.5998145420464, 437.7756213465038, 499.5998145420464, 78.9991)
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_7.endPoint(), SketchLine_8.startPoint())
+SketchLine_9 = Sketch_1.addLine(499.5998145420464, 78.9991, 446.941743563328, 78.9991)
+SketchConstraintCoincidence_13 = Sketch_1.setCoincident(SketchLine_8.endPoint(), SketchLine_9.startPoint())
+SketchConstraintCoincidence_14 = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_9.endPoint())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_2.result())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_4.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_6.result())
+SketchConstraintHorizontal_5 = Sketch_1.setHorizontal(SketchLine_9.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_8.result())
+SketchArc_3 = Sketch_1.addArc(-891.6236641114499, 368.9991, -891.6236641114499, 437.7756213465037, -960.4001854579536, 368.9991, False)
+SketchConstraintCoincidence_15 = Sketch_1.setCoincident(SketchArc_3.startPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_16 = Sketch_1.setCoincident(SketchArc_3.endPoint(), SketchLine_3.endPoint())
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchArc_3.results()[1], SketchLine_3.result())
+SketchConstraintTangent_2 = Sketch_1.setTangent(SketchArc_3.results()[1], SketchLine_4.result())
+SketchConstraintAngle_1 = Sketch_1.setAngle(SketchLine_5.result(), SketchLine_4.result(), 120.0000000000006)
+SketchConstraintCoincidence_17 = Sketch_1.setCoincident(SketchLine_8.startPoint(), SketchLine_4.result())
+SketchConstraintAngle_2 = Sketch_1.setAngleBackward(SketchLine_7.result(), SketchLine_6.result(), 120.0000000000006)
+SketchConstraintDistance_3 = Sketch_1.setDistance(SketchArc_2.center(), SketchLine_2.startPoint(), "arc_R", True)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_2.endPoint(), SketchLine_5.endPoint(), "height-clearance")
+SketchConstraintDistance_4 = Sketch_1.setDistance(SketchLine_2.endPoint(), SketchLine_9.startPoint(), "length", True)
+SketchConstraintDistance_5 = Sketch_1.setDistance(SketchLine_3.endPoint(), SketchLine_2.result(), "hood_height", True)
+SketchLine_10 = Sketch_1.addLine(model.selection("EDGE", "PartSet/OX"))
+SketchConstraintDistance_6 = Sketch_1.setDistance(SketchCircle_2.center(), SketchLine_10.result(), "position", True)
+SketchPoint_1 = Sketch_1.addPoint(-910.4001854579535, 347.7756213465037)
+SketchPoint_2 = Sketch_1.addPoint(-910.9041532173604, 297.7781612460398)
+SketchConstraintDistance_7 = Sketch_1.setDistance(SketchPoint_1.coordinates(), SketchLine_3.result(), 50, True)
+SketchConstraintDistance_8 = Sketch_1.setDistance(SketchPoint_1.coordinates(), SketchLine_4.result(), 90, True)
+SketchConstraintDistance_9 = Sketch_1.setDistance(SketchPoint_2.coordinates(), SketchPoint_1.coordinates(), 50, True)
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), "length/8")
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1f-SketchArc_1_2r-SketchArc_2_2r-SketchLine_2r-SketchLine_3r-SketchLine_4r-SketchLine_5r-SketchLine_6r-SketchLine_7r-SketchLine_8r-SketchLine_9r-SketchArc_3_2f")], model.selection(), 500, 0)
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f"), model.selection("FACE", "Sketch_1/Face-SketchCircle_2_2f")], model.selection(), 500, -400)
+Extrusion_3 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f"), model.selection("FACE", "Sketch_1/Face-SketchCircle_2_2f")], model.selection(), 100, 0)
+model.do()
+
+# Verify point-line signed distance
+dist1 = model.signedDistancePointLine(SketchArc_1.center(), SketchLine_1)
+dist2 = model.signedDistancePointLine(SketchArc_2.center(), SketchLine_1)
+dist3 = model.signedDistancePointLine(SketchLine_3.endPoint(), SketchLine_2)
+dist4 = model.signedDistancePointLine(SketchPoint_1, SketchLine_3)
+dist5 = model.signedDistancePointLine(SketchPoint_1, SketchLine_4)
+
+PosParam.setValue(300)
+model.do()
+curDist1 = model.signedDistancePointLine(SketchArc_1.center(), SketchLine_1)
+curDist2 = model.signedDistancePointLine(SketchArc_2.center(), SketchLine_1)
+curDist3 = model.signedDistancePointLine(SketchLine_3.endPoint(), SketchLine_2)
+curDist4 = model.signedDistancePointLine(SketchPoint_1, SketchLine_3)
+curDist5 = model.signedDistancePointLine(SketchPoint_1, SketchLine_4)
+assert(math.fabs(dist1 - curDist1) < TOLERANCE), "Expected {}, actual {}".format(dist1, curDist1)
+assert(math.fabs(dist2 - curDist2) < TOLERANCE), "Expected {}, actual {}".format(dist2, curDist2)
+assert(math.fabs(dist3 - curDist3) < TOLERANCE), "Expected {}, actual {}".format(dist3, curDist3)
+assert(math.fabs(dist4 - curDist4) < TOLERANCE), "Expected {}, actual {}".format(dist4, curDist4)
+assert(math.fabs(dist5 - curDist5) < TOLERANCE), "Expected {}, actual {}".format(dist5, curDist5)
+
+LengthParam.setValue(2000)
+model.do()
+curDist1 = model.signedDistancePointLine(SketchArc_1.center(), SketchLine_1)
+curDist2 = model.signedDistancePointLine(SketchArc_2.center(), SketchLine_1)
+curDist3 = model.signedDistancePointLine(SketchLine_3.endPoint(), SketchLine_2)
+curDist4 = model.signedDistancePointLine(SketchPoint_1, SketchLine_3)
+curDist5 = model.signedDistancePointLine(SketchPoint_1, SketchLine_4)
+assert(math.fabs(dist1 - curDist1) < TOLERANCE), "Expected {}, actual {}".format(dist1, curDist1)
+assert(math.fabs(dist2 - curDist2) < TOLERANCE), "Expected {}, actual {}".format(dist2, curDist2)
+assert(math.fabs(dist3 - curDist3) < TOLERANCE), "Expected {}, actual {}".format(dist3, curDist3)
+assert(math.fabs(dist4 - curDist4) < TOLERANCE), "Expected {}, actual {}".format(dist4, curDist4)
+assert(math.fabs(dist5 - curDist5) < TOLERANCE), "Expected {}, actual {}".format(dist5, curDist5)
+
+HeightParam.setValue(1200)
+model.do()
+curDist1 = model.signedDistancePointLine(SketchArc_1.center(), SketchLine_1)
+curDist2 = model.signedDistancePointLine(SketchArc_2.center(), SketchLine_1)
+curDist3 = model.signedDistancePointLine(SketchLine_3.endPoint(), SketchLine_2)
+curDist4 = model.signedDistancePointLine(SketchPoint_1, SketchLine_3)
+curDist5 = model.signedDistancePointLine(SketchPoint_1, SketchLine_4)
+assert(math.fabs(dist1 - curDist1) < TOLERANCE), "Expected {}, actual {}".format(dist1, curDist1)
+assert(math.fabs(dist2 - curDist2) < TOLERANCE), "Expected {}, actual {}".format(dist2, curDist2)
+assert(math.fabs(dist3 - curDist3) < TOLERANCE), "Expected {}, actual {}".format(dist3, curDist3)
+assert(math.fabs(dist4 - curDist4) < TOLERANCE), "Expected {}, actual {}".format(dist4, curDist4)
+assert(math.fabs(dist5 - curDist5) < TOLERANCE), "Expected {}, actual {}".format(dist5, curDist5)
+
+model.end()
diff --git a/src/SketchPlugin/Test/TestSignedDistancePointPoint.py b/src/SketchPlugin/Test/TestSignedDistancePointPoint.py
new file mode 100644 (file)
index 0000000..d2bca85
--- /dev/null
@@ -0,0 +1,108 @@
+from salome.shaper import model
+import math
+
+TOLERANCE = 1.e-5
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+model.addParameter(Part_1_doc, "clearance", "210")
+model.addParameter(Part_1_doc, "wheel_R", "203")
+model.addParameter(Part_1_doc, "arc_R", "wheel_R+70")
+model.addParameter(Part_1_doc, "hood_height", "290")
+HeightParam = model.addParameter(Part_1_doc, "height", "900")
+LengthParam = model.addParameter(Part_1_doc, "length", "1460")
+PosParam = model.addParameter(Part_1_doc, "position", "71.99905090248758")
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-281.378739745974, 78.99909999999998, -98.87873974597397, 78.99909999999998)
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchArc_1 = Sketch_1.addArc(174.031501908677, 71.9991, -98.87873974597397, 78.99909999999998, 446.941743563328, 78.9991, True)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchArc_1.startPoint())
+SketchArc_2 = Sketch_1.addArc(-554.288981400625, 71.9991, -281.378739745974, 78.99909999999998, -827.1992230552759, 78.9991, False)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchArc_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchArc_2.endPoint(), SketchLine_1.result())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_1.result())
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchArc_2.center(), SketchLine_1.result(), "clearance-wheel_R", True)
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchArc_1.center(), SketchLine_1.result(), "clearance-wheel_R", True)
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchArc_2.results()[1], SketchArc_1.results()[1])
+SketchCircle_1 = Sketch_1.addCircle(-554.288981400625, 71.9991, 203)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchArc_2.center(), SketchCircle_1.center())
+SketchCircle_2 = Sketch_1.addCircle(174.031501908677, 71.9991, 203)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchArc_1.center(), SketchCircle_2.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], "wheel_R")
+SketchConstraintEqual_2 = Sketch_1.setEqual(SketchCircle_1.results()[1], SketchCircle_2.results()[1])
+SketchLine_2 = Sketch_1.addLine(-827.1992230552759, 78.9991, -960.4001854579536, 78.9991)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchArc_2.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(-960.4001854579536, 78.9991, -960.4001854579536, 368.9991)
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchLine_4 = Sketch_1.addLine(-891.6236641114499, 437.7756213465037, -540.5628729569305, 437.7756213465037)
+SketchLine_5 = Sketch_1.addLine(-540.5628729569305, 437.7756213465037, -349.330908394406, 768.9991)
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_1.addLine(-349.330908394406, 768.9991, 308.3678499795216, 768.9991)
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchLine_7 = Sketch_1.addLine(308.3678499795216, 768.9991, 499.5998145420464, 437.7756213465038)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchLine_8 = Sketch_1.addLine(499.5998145420464, 437.7756213465038, 499.5998145420464, 78.9991)
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_7.endPoint(), SketchLine_8.startPoint())
+SketchLine_9 = Sketch_1.addLine(499.5998145420464, 78.9991, 446.941743563328, 78.9991)
+SketchConstraintCoincidence_13 = Sketch_1.setCoincident(SketchLine_8.endPoint(), SketchLine_9.startPoint())
+SketchConstraintCoincidence_14 = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_9.endPoint())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_2.result())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_4.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_6.result())
+SketchConstraintHorizontal_5 = Sketch_1.setHorizontal(SketchLine_9.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_8.result())
+SketchArc_3 = Sketch_1.addArc(-891.6236641114499, 368.9991, -891.6236641114499, 437.7756213465037, -960.4001854579536, 368.9991, False)
+SketchConstraintCoincidence_15 = Sketch_1.setCoincident(SketchArc_3.startPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_16 = Sketch_1.setCoincident(SketchArc_3.endPoint(), SketchLine_3.endPoint())
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchArc_3.results()[1], SketchLine_3.result())
+SketchConstraintTangent_2 = Sketch_1.setTangent(SketchArc_3.results()[1], SketchLine_4.result())
+SketchConstraintAngle_1 = Sketch_1.setAngle(SketchLine_5.result(), SketchLine_4.result(), 120.0000000000006)
+SketchConstraintCoincidence_17 = Sketch_1.setCoincident(SketchLine_8.startPoint(), SketchLine_4.result())
+SketchConstraintAngle_2 = Sketch_1.setAngleBackward(SketchLine_7.result(), SketchLine_6.result(), 120.0000000000006)
+SketchConstraintDistance_3 = Sketch_1.setDistance(SketchArc_2.center(), SketchLine_2.startPoint(), "arc_R", True)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_2.endPoint(), SketchLine_5.endPoint(), "height-clearance")
+SketchConstraintDistance_4 = Sketch_1.setDistance(SketchLine_2.endPoint(), SketchLine_9.startPoint(), "length", True)
+SketchConstraintDistance_5 = Sketch_1.setDistance(SketchLine_3.endPoint(), SketchLine_2.result(), "hood_height", True)
+SketchLine_10 = Sketch_1.addLine(model.selection("EDGE", "PartSet/OX"))
+SketchConstraintDistance_6 = Sketch_1.setDistance(SketchCircle_2.center(), SketchLine_10.result(), "position", True)
+SketchPoint_1 = Sketch_1.addPoint(-910.4001854579535, 347.7756213465037)
+SketchPoint_2 = Sketch_1.addPoint(-910.9041532173604, 297.7781612460398)
+SketchConstraintDistance_7 = Sketch_1.setDistance(SketchPoint_1.coordinates(), SketchLine_3.result(), 50, True)
+SketchConstraintDistance_8 = Sketch_1.setDistance(SketchPoint_1.coordinates(), SketchLine_4.result(), 90, True)
+SketchConstraintDistance_9 = Sketch_1.setDistance(SketchPoint_2.coordinates(), SketchPoint_1.coordinates(), 50, True)
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), "length/8")
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1f-SketchArc_1_2r-SketchArc_2_2r-SketchLine_2r-SketchLine_3r-SketchLine_4r-SketchLine_5r-SketchLine_6r-SketchLine_7r-SketchLine_8r-SketchLine_9r-SketchArc_3_2f")], model.selection(), 500, 0)
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f"), model.selection("FACE", "Sketch_1/Face-SketchCircle_2_2f")], model.selection(), 500, -400)
+Extrusion_3 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f"), model.selection("FACE", "Sketch_1/Face-SketchCircle_2_2f")], model.selection(), 100, 0)
+model.do()
+
+# Verify point-point distance
+dist1 = model.distancePointPoint(SketchArc_2.center(), SketchLine_2.startPoint())
+dist2 = model.distancePointPoint(SketchPoint_1, SketchPoint_2)
+
+PosParam.setValue(300)
+model.do()
+curDist1 = model.distancePointPoint(SketchArc_2.center(), SketchLine_2.startPoint())
+curDist2 = model.distancePointPoint(SketchPoint_1, SketchPoint_2)
+assert(math.fabs(dist1 - curDist1) < TOLERANCE), "Expected {}, actual {}".format(dist1, curDist1)
+assert(math.fabs(dist2 - curDist2) < TOLERANCE), "Expected {}, actual {}".format(dist2, curDist2)
+
+LengthParam.setValue(2000)
+model.do()
+curDist1 = model.distancePointPoint(SketchArc_2.center(), SketchLine_2.startPoint())
+curDist2 = model.distancePointPoint(SketchPoint_1, SketchPoint_2)
+assert(math.fabs(dist1 - curDist1) < TOLERANCE), "Expected {}, actual {}".format(dist1, curDist1)
+assert(math.fabs(dist2 - curDist2) < TOLERANCE), "Expected {}, actual {}".format(dist2, curDist2)
+
+HeightParam.setValue(1200)
+model.do()
+curDist1 = model.distancePointPoint(SketchArc_2.center(), SketchLine_2.startPoint())
+curDist2 = model.distancePointPoint(SketchPoint_1, SketchPoint_2)
+assert(math.fabs(dist1 - curDist1) < TOLERANCE), "Expected {}, actual {}".format(dist1, curDist1)
+assert(math.fabs(dist2 - curDist2) < TOLERANCE), "Expected {}, actual {}".format(dist2, curDist2)
+
+model.end()
index b6c74bff67806359fc7bfdcc74a36c4eb29c5af6..2adc38330e6afc056beda05662187e12095ec39c 100644 (file)
@@ -653,6 +653,7 @@ email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com
           <validator id="GeomValidators_Positive"/>
         </doublevalue_editor>
 
+        <boolvalue id="SignedDistance" label="Keep orientation" default="true" tooltip="Keep distance orientation" obligatory="0"/>
         <validator id="PartSet_DistanceSelection"/>
       </feature>
 
index 9c4cad57d2a7488cc3fba558c3f5ab04b63cbd6a..75919af5f55a50f941f15f9e7d1ad41bf7253261 100644 (file)
@@ -152,6 +152,30 @@ PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Solver::solve()
   collectConflicting();
   if (!myConflictingIDs.empty())
     aResult = GCS::Failed;
+  else if (aResult == GCS::Failed) {
+    // DogLeg solver failed without conflicting constraints, try to use Levenberg-Marquardt solver
+    // if there are point-line distance constraints
+    ConstraintMap::iterator aCIt = myConstraints.begin();
+    for (; aCIt != myConstraints.end(); ++aCIt) {
+      if (aCIt->second.size() <= 1)
+        continue;
+      std::set<GCSConstraintPtr>::const_iterator anIt = aCIt->second.begin();
+      for (; anIt != aCIt->second.end(); ++anIt)
+        if ((*anIt)->getTypeId() == GCS::P2LDistance)
+          break;
+      if (anIt != aCIt->second.end())
+        break;
+    }
+
+    if (aCIt != myConstraints.end()) {
+      aResult = (GCS::SolveStatus)myEquationSystem->solve(
+          myParameters, true, GCS::LevenbergMarquardt);
+      myConfCollected = false;
+      collectConflicting();
+      if (!myConflictingIDs.empty())
+        aResult = GCS::Failed;
+    }
+  }
 
   SolveStatus aStatus;
   if (aResult == GCS::Failed)
index 901053c6d7a90d70d09cefaad4169ce0efea0f39..4aa15648da14c82c36c8e290a0d591224c0b5f60 100644 (file)
 #include <SketchSolver_Error.h>
 #include <SketchSolver_Manager.h>
 
+#include <PlaneGCSSolver_EdgeWrapper.h>
+#include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_Storage.h>
+#include <PlaneGCSSolver_Tools.h>
+
 #include <SketchPlugin_ConstraintDistanceHorizontal.h>
 #include <SketchPlugin_ConstraintDistanceVertical.h>
 
@@ -60,53 +65,18 @@ void SketchSolver_ConstraintDistance::getAttributes(
 
 void SketchSolver_ConstraintDistance::adjustConstraint()
 {
-  ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint);
+  if (getType() == CONSTRAINT_PT_LINE_DISTANCE) {
+    bool isSigned = myBaseConstraint->boolean(SketchPlugin_ConstraintDistance::SIGNED())->value();
+    if (myIsSigned == isSigned)
+      return; // distance type is not changed => nothing to adjust
 
-  // Adjust point-point distance if the points are equal
-  if (getType() == CONSTRAINT_PT_PT_DISTANCE) {
-////    AttributePtr aPt1 = myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A());
-////    AttributePtr aPt2 = myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B());
-////
-////    BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
-////    std::shared_ptr<GeomAPI_Pnt2d> aPoint1 = aBuilder->point(myStorage->entity(aPt1));
-////    EntityWrapperPtr anEntity2 = myStorage->entity(aPt2);
-////    std::shared_ptr<GeomAPI_Pnt2d> aPoint2 = aBuilder->point(anEntity2);
-////
-////////    if (aPoint1->distance(aPoint2) < tolerance) {
-////////      // Change X coordinate of second point to eliminate coincidence
-////////      ParameterWrapperPtr aX = aSubs.back()->parameters().front();
-////////      aX->setValue(aX->value() + 1.0);
-////////      myStorage->update(aX);
-////////    }
-    return;
-  }
-
-  // Adjust point-line distance
-  if (fabs(myPrevValue) == fabs(aConstraint->value())) {
-    // sign of distance is not changed
-////    aConstraint->setValue(myPrevValue);
-////    myStorage->addConstraint(myBaseConstraint, aConstraint);
-    return;
+    // Adjust point-line distance by setting/removing additional constraints
+    if (isSigned)
+      addConstraintsToKeepSign();
+    else
+      removeConstraintsKeepingSign();
+    myIsSigned = isSigned;
   }
-
-////  // Adjust the sign of constraint value
-////  BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
-////
-////  std::shared_ptr<GeomAPI_Lin2d> aLine;
-////  std::shared_ptr<GeomAPI_Pnt2d> aPoint;
-////  for (int i = 0; i < 2; ++i) {
-////    AttributePtr anAttr = myBaseConstraint->attribute(SketchPlugin_Constraint::ATTRIBUTE(i));
-////    EntityWrapperPtr anEntity = myStorage->entity(anAttr);
-////    if (anEntity->type() == ENTITY_POINT)
-////      aPoint = aBuilder->point(anEntity);
-////    else if (anEntity->type() == ENTITY_LINE)
-////      aLine = aBuilder->line(anEntity);
-////  }
-////
-////  std::shared_ptr<GeomAPI_XY> aLineVec = aLine->direction()->xy();
-////  std::shared_ptr<GeomAPI_XY> aPtLineVec = aPoint->xy()->decreased(aLine->location()->xy());
-////  if (aLineVec->cross(aPtLineVec) * aConstraint->value() < 0.0)
-////    aConstraint->setValue(aConstraint->value() * (-1.0));
 }
 
 void SketchSolver_ConstraintDistance::update()
@@ -116,3 +86,80 @@ void SketchSolver_ConstraintDistance::update()
 
   SketchSolver_Constraint::update();
 }
+
+void SketchSolver_ConstraintDistance::addConstraintsToKeepSign()
+{
+  std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
+      std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
+
+  ConstraintWrapperPtr aConstraint = aStorage->constraint(myBaseConstraint);
+  std::list<GCSConstraintPtr> aGCSConstraints = aConstraint->constraints();
+
+  // calculate projection of the point on the line and find a sign of a distance
+  EntityWrapperPtr aDistPoint, aDistLine;
+  for (int i = 0; i < 2; ++i) {
+    AttributePtr anAttr = myBaseConstraint->attribute(SketchPlugin_Constraint::ATTRIBUTE(i));
+    EntityWrapperPtr anEntity = myStorage->entity(anAttr);
+    if (anEntity->type() == ENTITY_POINT)
+      aDistPoint = anEntity;
+    else if (anEntity->type() == ENTITY_LINE)
+      aDistLine = anEntity;
+  }
+  std::shared_ptr<GeomAPI_Lin2d> aLine = PlaneGCSSolver_Tools::line(aDistLine);
+  std::shared_ptr<GeomAPI_Pnt2d> aPoint = PlaneGCSSolver_Tools::point(aDistPoint);
+
+  std::shared_ptr<GeomAPI_XY> aLineVec = aLine->direction()->xy();
+  std::shared_ptr<GeomAPI_XY> aPtLineVec = aPoint->xy()->decreased(aLine->location()->xy());
+  if (aLineVec->cross(aPtLineVec) >= 0.)
+    mySignValue = PI/2.0;
+  else
+    mySignValue = - PI/2.0;
+  double aDot = aPtLineVec->dot(aLineVec);
+  std::shared_ptr<GeomAPI_XY> aProjectedPnt =
+      aLine->location()->xy()->added(aLineVec->multiplied(aDot));
+
+  // create auxiliary point on the line and set auxiliary constraints
+  myOddPoint = GCSPointPtr(new GCS::Point);
+  myOddPoint->x = aStorage->createParameter();
+  myOddPoint->y = aStorage->createParameter();
+  *(myOddPoint->x) = aProjectedPnt->x();
+  *(myOddPoint->y) = aProjectedPnt->y();
+
+  PointWrapperPtr aPointWr = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(aDistPoint);
+  EdgeWrapperPtr anEdgeWr = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aDistLine);
+  std::shared_ptr<GCS::Line> aGCSLine = std::dynamic_pointer_cast<GCS::Line>(anEdgeWr->entity());
+  // point-on-line
+  GCSConstraintPtr aNewConstraint(new GCS::ConstraintPointOnLine(*myOddPoint, *aGCSLine));
+  aGCSConstraints.push_back(aNewConstraint);
+  // angle which keep orientation
+  aNewConstraint = GCSConstraintPtr(new GCS::ConstraintL2LAngle(
+      aGCSLine->p1, aGCSLine->p2, *myOddPoint, *(aPointWr->point()), &mySignValue));
+  aGCSConstraints.push_back(aNewConstraint);
+
+  aConstraint->setConstraints(aGCSConstraints);
+
+  aStorage->removeConstraint(myBaseConstraint);
+  aStorage->addConstraint(myBaseConstraint, aConstraint);
+}
+
+void SketchSolver_ConstraintDistance::removeConstraintsKeepingSign()
+{
+  std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
+      std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
+
+  ConstraintWrapperPtr aConstraint = aStorage->constraint(myBaseConstraint);
+  std::list<GCSConstraintPtr> aGCSConstraints = aConstraint->constraints();
+
+  aStorage->removeConstraint(myBaseConstraint);
+
+  // remove parameters related to auxiliary point
+  GCS::SET_pD aParams;
+  aParams.insert(myOddPoint->x);
+  aParams.insert(myOddPoint->y);
+  aStorage->removeParameters(aParams);
+
+  aGCSConstraints.pop_back();
+  aGCSConstraints.pop_back();
+  aConstraint->setConstraints(aGCSConstraints);
+  aStorage->addConstraint(myBaseConstraint, aConstraint);
+}
index ec7cbd3b6cd3a8db2c75e22c87ed02d856b8388e..b11ab1ea317c36e45156392a3de5870847ea3b3b 100644 (file)
@@ -33,7 +33,8 @@ public:
   /// Constructor based on SketchPlugin constraint
   SketchSolver_ConstraintDistance(ConstraintPtr theConstraint) :
       SketchSolver_Constraint(theConstraint),
-      myIsNegative(false)
+      myIsSigned(false),
+      mySignValue(0.0)
   {}
 
   /// \brief Update constraint
@@ -51,10 +52,14 @@ protected:
   virtual void adjustConstraint();
 
 private:
-  double myPrevValue; ///< previous value of distance (for correct calculation of a distance sign)
+  void addConstraintsToKeepSign();
+  void removeConstraintsKeepingSign();
 
-  /// \c true, if the point if placed rightside of line direction (SLVS_C_PT_LINE_DISTANCE only)
-  bool myIsNegative;
+private:
+  double myPrevValue; ///< previous value of distance (for correct calculation of a distance sign)
+  bool   myIsSigned;  ///< true if the sign of point-line distance should be kept everytime
+  GCSPointPtr myOddPoint; ///< auxiliary point to keep sign of distance
+  double mySignValue;
 };
 
 #endif