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;
}
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)
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):
"""
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;
}
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,
/// 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);
TestMoveCircle.py
TestMoveArc.py
TestMovementComplex.py
+ TestDistanceSignedVsUnsigned01.py
+ TestDistanceSignedVsUnsigned02.py
+ TestDistanceSignedVsUnsigned03.py
+ TestDistanceSignedVsUnsigned04.py
+ TestDistanceSignedVsUnsigned05.py
+ TestSignedDistancePointPoint.py
+ TestSignedDistancePointLine.py
)
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,
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();
--- /dev/null
+## 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()
--- /dev/null
+## 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()
--- /dev/null
+## 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()
--- /dev/null
+## 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()
--- /dev/null
+## 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()
--- /dev/null
+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()
--- /dev/null
+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()
<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>
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)
#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>
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()
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);
+}
/// Constructor based on SketchPlugin constraint
SketchSolver_ConstraintDistance(ConstraintPtr theConstraint) :
SketchSolver_Constraint(theConstraint),
- myIsNegative(false)
+ myIsSigned(false),
+ mySignValue(0.0)
{}
/// \brief Update constraint
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