Implement checking degenerated geometry after resolving a set of sketch constraints.
aDistCE = tools.distancePointPoint(aCenterPnt, aEndPnt)
assert math.fabs(aDistCS - aDistCE) < TOLERANCE, "Wrong arc: center-start distance {}, center-end distance {}".format(aDistCS, aDistCE)
assert math.fabs(aRadius.value() - aDistCS) < TOLERANCE, "Wrong arc: radius is {}, expected {}".format(aRadius.value(), aDistCS)
+
+
+def checkSketch(theSketch, theDOF = -1):
+ """ Tests the sketch is valid and DoF is equal to the given
+ """
+ assert(theSketch.feature().error() == ""), "Sketch failed: {}".format(theSketch.feature().error())
+ assert(theSketch.solverError().value() == ""), "Sketch solver failed: {}".format(theSketch.solverError().value())
+ if theDOF != -1:
+ aDOF = sketcher.tools.dof(theSketch)
+ assert(aDOF == theDOF), "Sketch DoF {} is wrong. Expected {}".format(aDOF, theDOF)
+
+
+def checkSketchErrorDegenerated(theSketch):
+ """ Verify the sketch reports error about degenerated geometry
+ """
+ errorValue = theSketch.solverError().value()
+ assert(errorValue != "")
+ assert(errorValue.find("degenerated") >= 0)
theModel.testNbSubShapes(theFeature, GeomAPI_Shape.EDGE, NbEdge)
theModel.testNbSubShapes(theFeature, GeomAPI_Shape.VERTEX, NbVertex)
-def checkSketch(theSketch, theDOF = -1):
- """ Tests the sketch is valid and DoF is equal to the given
- """
- assert(theSketch.feature().error() == ""), "Sketch failed: {}".format(theSketch.feature().error())
- assert(theSketch.solverError().value() == ""), "Sketch solver failed: {}".format(theSketch.solverError().value())
- if theDOF != -1:
- aDOF = sketcher.tools.dof(theSketch)
- assert(aDOF == theDOF), "Sketch DoF {} is wrong. Expected {}".format(aDOF, theDOF)
-
def checkGroup(theGroup, theShapeType):
""" Check that all selected shapes in group have correct shape type and unique name
"""
Test2034_2.py
Test2034_3.py
Test2134.py
+ TestDegeneratedGeometry.py
+ Test2119.py
+ Test2224.py
+ Test2427.py
)
if(${SKETCHER_CHANGE_RADIUS_WHEN_MOVE})
--- /dev/null
+## Copyright (C) 2018-20xx 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>
+##
+
+"""
+ Test2119.py
+ Test case for issue #2119 "Sketch lost when creating a tangent constraint"
+"""
+
+from salome.shaper import model
+
+from ModelAPI import *
+from SketchAPI import *
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+model.addParameter(Part_1_doc, "a", "63")
+model.addParameter(Part_1_doc, "b", "50")
+model.addParameter(Part_1_doc, "c", "100")
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOZ"))
+SketchLine_1 = Sketch_1.addLine(-45, 0, 0, 0)
+SketchLine_2 = Sketch_1.addLine(0, 0, 23.33965093306752, 8.494938217797719)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(33.83092017818969, 6.16907982180411, 40, 0)
+SketchLine_4 = Sketch_1.addLine(40, 0, 55, 0)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchLine_5 = Sketch_1.addLine(55, 0, 55, 48)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_1.addLine(55, 48, 15, 48)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchLine_7 = Sketch_1.addLine(15, 48, 15, 63)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchLine_8 = Sketch_1.addLine(15, 63, -15, 63)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_7.endPoint(), SketchLine_8.startPoint())
+SketchLine_9 = Sketch_1.addLine(-15, 63, -15, 35)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_8.endPoint(), SketchLine_9.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_6.result())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_8.result())
+SketchConstraintCollinear_1 = Sketch_1.setCollinear(SketchLine_1.result(), SketchLine_4.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_9.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_7.result())
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchLine_3.endPoint(), SketchLine_4.endPoint(), 15, False)
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchLine_3.endPoint(), SketchLine_1.endPoint(), 40, False)
+SketchConstraintDistance_3 = Sketch_1.setDistance(SketchLine_1.startPoint(), SketchLine_4.endPoint(), "c", False)
+SketchConstraintDistance_4 = Sketch_1.setDistance(SketchLine_8.startPoint(), SketchLine_6.result(), 15, False)
+SketchConstraintDistance_5 = Sketch_1.setDistance(SketchLine_8.startPoint(), SketchLine_5.result(), 40, False)
+SketchLine_10 = Sketch_1.addLine(-45, 5, -45, 0)
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_10.endPoint())
+SketchConstraintVertical_4 = Sketch_1.setVertical(SketchLine_10.result())
+SketchConstraintDistance_6 = Sketch_1.setDistance(SketchLine_9.startPoint(), SketchLine_1.result(), "a", False)
+SketchArc_1 = Sketch_1.addArc(-45, 35, -45, 5, -15, 35, False)
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchArc_1.center(), SketchLine_10.result())
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchArc_1.startPoint(), SketchLine_10.startPoint())
+SketchConstraintAngle_1 = Sketch_1.setAngle(SketchLine_3.result(), SketchLine_1.result(), 45)
+SketchConstraintAngle_2 = Sketch_1.setAngleBackward(SketchLine_2.result(), SketchLine_4.result(), 20)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_9.endPoint())
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchArc_1.results()[1], SketchLine_9.result())
+SketchConstraintDistance_7 = Sketch_1.setDistance(SketchArc_1.center(), SketchLine_1.result(), 35, False)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchArc_1.results()[1], 30)
+SketchArc_2 = Sketch_1.addArc(26.75985236632421, -0.9019879900613652, 33.83092017818969, 6.16907982180411, 23.33965093306752, 8.494938217797719, False)
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchArc_2.startPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_13 = Sketch_1.setCoincident(SketchArc_2.endPoint(), SketchLine_2.endPoint())
+SketchConstraintTangent_2 = Sketch_1.setTangent(SketchArc_2.results()[1], SketchLine_2.result())
+SketchConstraintTangent_3 = Sketch_1.setTangent(SketchArc_2.results()[1], SketchLine_3.result())
+SketchConstraintRadius_2 = Sketch_1.setRadius(SketchArc_2.results()[1], 10)
+SketchPoint_1 = Sketch_1.addPoint(model.selection("VERTEX", "PartSet/Origin"))
+SketchConstraintCoincidence_14 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchPoint_1.coordinates())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1f-SketchLine_2f-SketchLine_3f-SketchLine_4f-SketchLine_5f-SketchLine_6f-SketchLine_7f-SketchLine_8f-SketchLine_9f-SketchLine_10f-SketchArc_1_2r-SketchArc_2_2r")], model.selection(), "b/2", "b/2")
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face_1"))
+SketchProjection_1 = Sketch_2.addProjection(model.selection("VERTEX", "Extrusion_1_1/Generated_Face_3&Extrusion_1_1/Generated_Face_2&Extrusion_1_1/To_Face_1"), False)
+SketchPoint_2 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_2.addCircle(-15, 35, 25)
+SketchConstraintCoincidence_15 = Sketch_2.setCoincident(SketchCircle_1.center(), SketchPoint_2.result())
+SketchConstraintRadius_3 = Sketch_2.setRadius(SketchCircle_1.results()[1], "50/2")
+model.do()
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [model.selection("WIRE", "Sketch_2/Wire-SketchCircle_1_2f")], model.selection(), 0, 13, [model.selection("SOLID", "Extrusion_1_1")])
+Sketch_3 = model.addSketch(Part_1_doc, model.selection("FACE", "ExtrusionCut_1_1/Modfied_4"))
+SketchProjection_2 = Sketch_3.addProjection(model.selection("VERTEX", "ExtrusionCut_1_1/Modfied_2&ExtrusionCut_1_1/Modfied_3&ExtrusionCut_1_1/Modfied_4"), False)
+SketchPoint_3 = SketchProjection_2.createdFeature()
+SketchProjection_3 = Sketch_3.addProjection(model.selection("EDGE", "ExtrusionCut_1_1/Modfied_3&ExtrusionCut_1_1/Modfied_4"), False)
+SketchLine_11 = SketchProjection_3.createdFeature()
+SketchArc_3 = Sketch_3.addArc(-15, 35, -15, 46.0103340429751, -17.02045759563166, 24.17663606626138, True)
+SketchConstraintCoincidence_16 = Sketch_3.setCoincident(SketchPoint_3.result(), SketchArc_3.center())
+SketchConstraintCoincidence_17 = Sketch_3.setCoincident(SketchLine_11.result(), SketchArc_3.startPoint())
+SketchProjection_4 = Sketch_3.addProjection(model.selection("EDGE", "ExtrusionCut_1_1/Modfied_2&ExtrusionCut_1_1/Modfied_4"), False)
+SketchArc_4 = SketchProjection_4.createdFeature()
+SketchConstraintCoincidence_18 = Sketch_3.setCoincident(SketchArc_3.endPoint(), SketchArc_4.results()[1])
+SketchLine_12 = Sketch_3.addLine(-15, 46.0103340429751, -15, 35)
+SketchConstraintCoincidence_19 = Sketch_3.setCoincident(SketchArc_3.startPoint(), SketchLine_12.startPoint())
+SketchArc_5 = Sketch_3.addArc(-24.92022800465918, 31.2515971841183, -15, 35, -17.02045759563166, 24.17663606626138, True)
+SketchConstraintCoincidence_20 = Sketch_3.setCoincident(SketchAPI_Point(SketchPoint_3).coordinates(), SketchArc_5.startPoint())
+SketchConstraintCoincidence_21 = Sketch_3.setCoincident(SketchArc_3.endPoint(), SketchArc_5.endPoint())
+model.do()
+model.end()
+
+
+# case 1: undo the error
+model.begin()
+aTangent = Sketch_3.setTangent(SketchArc_5.results()[1], SketchArc_4.results()[1])
+model.do()
+model.end()
+model.checkSketchErrorDegenerated(Sketch_3)
+model.undo()
+model.checkSketch(Sketch_3)
+
+# case 2: remove degeneracy-producting constraint
+model.begin()
+aTangent = Sketch_3.setTangent(SketchArc_5.results()[1], SketchArc_4.results()[1])
+model.do()
+model.checkSketchErrorDegenerated(Sketch_3)
+Part_1_doc.removeFeature(aTangent.feature())
+model.do()
+model.end()
+model.checkSketch(Sketch_3)
+
+# case 3: remove degenerated edge
+model.begin()
+aTangent = Sketch_3.setTangent(SketchArc_5.results()[1], SketchArc_4.results()[1])
+model.do()
+model.checkSketchErrorDegenerated(Sketch_3)
+ModelAPI.removeFeaturesAndReferences(FeatureSet([SketchArc_5.feature()]))
+model.do()
+model.end()
+model.checkSketch(Sketch_3)
+
+assert(model.checkPythonDump())
--- /dev/null
+## Copyright (C) 2018-20xx 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>
+##
+
+"""
+ Test2224.py
+ Test case for issue #2224 "tangent arc problem when end point is on edge that is tangent to arc"
+"""
+
+from salome.shaper import model
+
+from ModelAPI import *
+from SketchAPI import *
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(8.985073018276022, 21.83713948745567, 31.50462311471469, 21.83713948745567)
+SketchArc_1 = Sketch_1.addArc(31.50462311471469, -6.977379981512561, 31.50462311471469, 21.83713948745567, 25.29690414212808, 21.16050830785517, True)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchArc_1.startPoint())
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchLine_1.result(), SketchArc_1.results()[1])
+model.do()
+model.end()
+
+
+# case 1: undo the error
+model.begin()
+aCoincidence = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_1.result())
+model.do()
+model.end()
+model.checkSketchErrorDegenerated(Sketch_1)
+model.undo()
+model.checkSketch(Sketch_1)
+
+# case 2: remove degeneracy-producting constraint
+model.begin()
+aCoincidence = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_1.result())
+model.do()
+model.checkSketchErrorDegenerated(Sketch_1)
+Part_1_doc.removeFeature(aCoincidence.feature())
+model.do()
+model.end()
+model.checkSketch(Sketch_1)
+
+# case 3: remove degenerated edge
+model.begin()
+aCoincidence = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_1.result())
+model.do()
+model.checkSketchErrorDegenerated(Sketch_1)
+ModelAPI.removeFeaturesAndReferences(FeatureSet([SketchArc_1.feature()]))
+model.do()
+model.end()
+model.checkSketch(Sketch_1)
--- /dev/null
+## Copyright (C) 2018-20xx 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>
+##
+
+"""
+ Test2427.py
+ Test case for issue #2427 "error in sketch solver"
+"""
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(0, 0, 9.085455512028094, 9.085455512028094)
+SketchLine_1.setAuxiliary(True)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_2 = SketchProjection_1.createdFeature()
+SketchConstraintAngle_1 = Sketch_1.setAngle(SketchLine_2.result(), SketchLine_1.result(), 45)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchAPI_Line(SketchLine_2).startPoint())
+SketchArc_1 = Sketch_1.addArc(0, 0, 3.427521359192312, 2.062061427864143, 2.06206142786378, 3.427521359191917, True)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchArc_1.center())
+SketchLine_3 = Sketch_1.addLine(6, 7.365459931328136, 6, 12)
+SketchLine_4 = Sketch_1.addLine(6, 12, -6, 12)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchLine_5 = Sketch_1.addLine(-6, 12, -6, 7.365459931328136)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchArc_1.results()[1], 4)
+SketchLine_6 = Sketch_1.addLine(-5.8309518948453, -7.5, -11, -7.5)
+SketchLine_7 = Sketch_1.addLine(-11, -7.5, -11, -10)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_7.startPoint())
+SketchLine_8 = Sketch_1.addLine(-11, -10, 11, -10)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_7.endPoint(), SketchLine_8.startPoint())
+SketchLine_9 = Sketch_1.addLine(11, -10, 11, -7.5)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_8.endPoint(), SketchLine_9.startPoint())
+SketchLine_10 = Sketch_1.addLine(11, -7.5, 5.830951894845301, -7.5)
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchLine_10.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_6.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_10.result())
+SketchConstraintHorizontal_3 = Sketch_1.setHorizontal(SketchLine_8.result())
+SketchConstraintHorizontal_4 = Sketch_1.setHorizontal(SketchLine_4.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_7.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_9.result())
+SketchConstraintVertical_3 = Sketch_1.setVertical(SketchLine_3.result())
+SketchConstraintVertical_4 = Sketch_1.setVertical(SketchLine_5.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_8.result(), 22)
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_4.result(), 12)
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchLine_4.result(), SketchLine_7.endPoint(), 22, True)
+SketchConstraintLength_3 = Sketch_1.setLength(SketchLine_7.result(), 2.5)
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchLine_8.endPoint(), SketchLine_2.result(), 10, True)
+SketchPoint_1 = Sketch_1.addPoint(0, -10)
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchPoint_1.coordinates(), SketchLine_8.result())
+SketchConstraintMiddle_1 = Sketch_1.setMiddlePoint(SketchLine_8.result(), SketchPoint_1.coordinates())
+SketchProjection_2 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_11 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_11.result(), SketchPoint_1.coordinates())
+SketchLine_12 = Sketch_1.addLine(2.06206142786378, 3.427521359191917, 6, 7.365459931328136)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchLine_12.startPoint())
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_12.endPoint(), SketchLine_3.startPoint())
+SketchConstraintParallel_1 = Sketch_1.setParallel(SketchLine_12.result(), SketchLine_1.result())
+SketchLine_13 = Sketch_1.addLine(3.427521359192312, 2.062061427864143, 8.000256151511394, 5.123075395720331)
+SketchConstraintCoincidence_13 = Sketch_1.setCoincident(SketchArc_1.startPoint(), SketchLine_13.startPoint())
+SketchArc_2 = Sketch_1.addArc(0, 0, 8.000256151511394, 5.123075395720331, 5.830951894845301, -7.5, True)
+SketchConstraintCoincidence_14 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchArc_2.center())
+SketchConstraintCoincidence_15 = Sketch_1.setCoincident(SketchArc_2.startPoint(), SketchLine_13.endPoint())
+SketchConstraintCoincidence_16 = Sketch_1.setCoincident(SketchLine_10.endPoint(), SketchArc_2.endPoint())
+SketchConstraintRadius_2 = Sketch_1.setRadius(SketchArc_2.results()[1], 9.5)
+SketchLine_14 = Sketch_1.addLine(3.427521359192312, 2.062061427864143, 2.06206142786378, 3.427521359191917)
+SketchLine_14.setAuxiliary(True)
+SketchConstraintCoincidence_17 = Sketch_1.setCoincident(SketchArc_1.startPoint(), SketchLine_14.startPoint())
+SketchConstraintCoincidence_18 = Sketch_1.setCoincident(SketchLine_14.endPoint(), SketchArc_1.endPoint())
+SketchPoint_2 = Sketch_1.addPoint(2.744791393527834, 2.744791393527835)
+SketchConstraintCoincidence_19 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_14.result())
+SketchConstraintMiddle_2 = Sketch_1.setMiddlePoint(SketchLine_14.result(), SketchPoint_2.coordinates())
+SketchConstraintCoincidence_20 = Sketch_1.setCoincident(SketchLine_14.result(), SketchPoint_2.coordinates())
+SketchConstraintCoincidence_21 = Sketch_1.setCoincident(SketchPoint_2.coordinates(), SketchLine_1.result())
+SketchArc_3 = Sketch_1.addArc(0, 0, -6, 7.365459931328136, -5.8309518948453, -7.5, False)
+SketchConstraintCoincidence_22 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchArc_3.startPoint())
+SketchConstraintCoincidence_23 = Sketch_1.setCoincident(SketchLine_6.startPoint(), SketchArc_3.endPoint())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchArc_2.results()[1], SketchArc_3.results()[1])
+SketchPoint_3 = Sketch_1.addPoint(0, 12)
+SketchConstraintMiddle_3 = Sketch_1.setMiddlePoint(SketchLine_4.result(), SketchPoint_3.coordinates())
+SketchConstraintCoincidence_24 = Sketch_1.setCoincident(SketchPoint_3.coordinates(), SketchLine_11.result())
+SketchConstraintEqual_2 = Sketch_1.setEqual(SketchLine_7.result(), SketchLine_9.result())
+SketchConstraintEqual_3 = Sketch_1.setEqual(SketchLine_6.result(), SketchLine_10.result())
+SketchConstraintEqual_4 = Sketch_1.setEqual(SketchLine_3.result(), SketchLine_5.result())
+SketchConstraintDistance_3 = Sketch_1.setDistance(SketchLine_13.endPoint(), SketchLine_12.result(), 3, True)
+SketchConstraintCoincidence_25 = Sketch_1.setCoincident(SketchArc_3.center(), SketchLine_1.result())
+model.do()
+model.end()
+
+
+# Test 1. Add constraint to make auxiliary line degenerated, then undo
+model.begin()
+aParallel = Sketch_1.setParallel(SketchLine_1.result(), SketchLine_13.result())
+model.do()
+model.end()
+model.checkSketchErrorDegenerated(Sketch_1)
+model.undo()
+model.checkSketch(Sketch_1)
+
+# Test 2. Add constraint to make auxiliary line degenerated, then remove such constraint
+model.begin()
+aParallel = Sketch_1.setParallel(SketchLine_1.result(), SketchLine_13.result())
+model.do()
+model.checkSketchErrorDegenerated(Sketch_1)
+Part_1_doc.removeFeature(aParallel.feature())
+model.do()
+model.end()
+model.checkSketch(Sketch_1)
+
+assert(model.checkPythonDump())
--- /dev/null
+## Copyright (C) 2018-20xx 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 *
+from ModelAPI import *
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+#######################################
+# Test 1. Make a circle degenerated
+#######################################
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(25, 20, 25)
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchLine_1.result(), SketchCircle_1.results()[1])
+model.do()
+model.end()
+
+# case 1: undo the error
+model.begin()
+aCoincidence = Sketch_1.setCoincident(SketchAPI_Line(SketchLine_1).startPoint(), SketchCircle_1.center())
+model.do()
+model.end()
+model.checkSketchErrorDegenerated(Sketch_1)
+model.undo()
+model.checkSketch(Sketch_1)
+
+# case 2: remove degeneracy-producting constraint
+model.begin()
+aCoincidence = Sketch_1.setCoincident(SketchAPI_Line(SketchLine_1).startPoint(), SketchCircle_1.center())
+model.do()
+model.checkSketchErrorDegenerated(Sketch_1)
+Part_1_doc.removeFeature(aCoincidence.feature())
+model.do()
+model.end()
+model.checkSketch(Sketch_1)
+
+# case 3: remove degenerated edge
+model.begin()
+aCoincidence = Sketch_1.setCoincident(SketchAPI_Line(SketchLine_1).startPoint(), SketchCircle_1.center())
+model.do()
+model.checkSketchErrorDegenerated(Sketch_1)
+ModelAPI.removeFeaturesAndReferences(FeatureSet([SketchCircle_1.feature()]))
+model.do()
+model.end()
+model.checkSketch(Sketch_1)
+
+
+#######################################
+# Test 2. Make a line degenerated
+#######################################
+model.begin()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_2 = Sketch_2.addLine(15, 15, 40, 40)
+SketchProjection_2 = Sketch_2.addProjection(model.selection("EDGE", "PartSet/OX"), True)
+SketchLine_3 = SketchProjection_2.createdFeature()
+SketchProjection_3 = Sketch_2.addProjection(model.selection("EDGE", "PartSet/OY"), True)
+SketchLine_4 = SketchProjection_3.createdFeature()
+model.do()
+model.end()
+
+# case 1: undo the error
+model.begin()
+aParallel1 = Sketch_2.setParallel(SketchLine_2.result(), SketchLine_3.result())
+aParallel2 = Sketch_2.setParallel(SketchLine_2.result(), SketchLine_4.result())
+model.do()
+model.end()
+model.checkSketchErrorDegenerated(Sketch_2)
+model.undo()
+model.do()
+model.checkSketch(Sketch_2)
+
+# case 2: remove degeneracy-producting constraint
+model.begin()
+aParallel1 = Sketch_2.setParallel(SketchLine_2.result(), SketchLine_3.result())
+aParallel2 = Sketch_2.setParallel(SketchLine_2.result(), SketchLine_4.result())
+model.do()
+model.checkSketchErrorDegenerated(Sketch_2)
+Part_1_doc.removeFeature(aParallel1.feature())
+Part_1_doc.removeFeature(aParallel2.feature())
+model.do()
+model.end()
+model.checkSketch(Sketch_2)
+
+# case 3: remove degenerated edge
+model.begin()
+aParallel1 = Sketch_2.setParallel(SketchLine_2.result(), SketchLine_3.result())
+aParallel2 = Sketch_2.setParallel(SketchLine_2.result(), SketchLine_4.result())
+model.do()
+model.checkSketchErrorDegenerated(Sketch_2)
+ModelAPI.removeFeaturesAndReferences(FeatureSet([SketchLine_2.feature()]))
+model.do()
+model.end()
+model.checkSketch(Sketch_2)
+
+
+#######################################
+# Test 3. Make an arc degenerated
+#######################################
+model.begin()
+Sketch_3 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchArc_1 = Sketch_3.addArc(-23.95261096318143, -9.48105223640866, -4.386575834490306, -17.91131183048461, -20.45766592507274, 11.53523589116715, False)
+model.do()
+model.end()
+
+# case 1: undo the error
+model.begin()
+aCoincidence = Sketch_3.setCoincident(SketchArc_1.startPoint(), SketchArc_1.endPoint())
+model.do()
+model.end()
+model.checkSketchErrorDegenerated(Sketch_3)
+model.undo()
+model.do()
+model.checkSketch(Sketch_3)
+
+# case 2: remove degeneracy-producting constraint
+model.begin()
+aCoincidence = Sketch_3.setCoincident(SketchArc_1.startPoint(), SketchArc_1.endPoint())
+model.do()
+model.checkSketchErrorDegenerated(Sketch_3)
+Part_1_doc.removeFeature(aCoincidence.feature())
+model.do()
+model.end()
+model.checkSketch(Sketch_3)
+
+# case 3: remove degenerated edge
+model.begin()
+aCoincidence = Sketch_3.setCoincident(SketchArc_1.startPoint(), SketchArc_1.endPoint())
+model.do()
+model.checkSketchErrorDegenerated(Sketch_3)
+ModelAPI.removeFeaturesAndReferences(FeatureSet([SketchArc_1.feature()]))
+model.do()
+model.end()
+assert(Sketch_3.solverError().value() == "")
//
#include <PlaneGCSSolver_EdgeWrapper.h>
+#include <cmath>
PlaneGCSSolver_EdgeWrapper::PlaneGCSSolver_EdgeWrapper(const GCSCurvePtr theEntity)
: myEntity(theEntity)
}
}
}
+
+static double squareDistance(const GCS::Point& theP1, const GCS::Point& theP2)
+{
+ double dx = *theP1.x - *theP2.x;
+ double dy = *theP1.y - *theP2.y;
+ return dx*dx + dy*dy;
+}
+
+bool PlaneGCSSolver_EdgeWrapper::isDegenerated() const
+{
+ static const double aSqTol = tolerance * 1e-2;
+ static const double aMaxRadius = 1e8;
+ if (myType == ENTITY_LINE) {
+ std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(myEntity);
+ return squareDistance(aLine->p1, aLine->p2) < aSqTol;
+ }
+ else if (myType == ENTITY_CIRCLE) {
+ std::shared_ptr<GCS::Circle> aCircle = std::dynamic_pointer_cast<GCS::Circle>(myEntity);
+ return *aCircle->rad < tolerance || *aCircle->rad > aMaxRadius;
+ }
+ else if (myType == ENTITY_ARC) {
+ static const double anAngleTol = 1.e-5;
+ std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(myEntity);
+ double anAngleDiff = fabs(*anArc->startAngle - *anArc->endAngle);
+ double aSqRadius = squareDistance(anArc->center, anArc->start);
+ return aSqRadius < aSqTol || aSqRadius > aMaxRadius * aMaxRadius || // <- arc radius
+ anAngleDiff < anAngleTol || fabs(anAngleDiff - 2*PI) < anAngleTol; // <- arc angle
+ }
+ return false;
+}
virtual SketchSolver_EntityType type() const
{ return myType; }
+ bool isDegenerated() const;
+
private:
SketchSolver_EntityType myType;
GCSCurvePtr myEntity;
STATUS_OK,
STATUS_INCONSISTENT,
STATUS_EMPTYSET,
+ STATUS_DEGENERATED,
STATUS_FAILED, // set if no one other status is applicable
STATUS_UNKNOWN // set for newly created groups
};
for (; aFIt != anUpdatedFeatures.end(); ++aFIt)
notify(*aFIt);
}
+
+PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Storage::checkDegeneratedGeometry() const
+{
+ std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
+ for (; aFIt != myFeatureMap.end(); ++aFIt) {
+ EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aFIt->second);
+ if (anEdge && anEdge->isDegenerated())
+ return PlaneGCSSolver_Solver::STATUS_DEGENERATED;
+ }
+ return PlaneGCSSolver_Solver::STATUS_OK;
+}
/// \return \c true if the constraint and all its parameters are removed successfully
virtual bool removeConstraint(ConstraintPtr theConstraint);
+ /// \brief Verify, the sketch contains degenerated geometry
+ /// after resolving the set of constraints
+ /// \return STATUS_OK if the geometry is valid, STATUS_DEGENERATED otherwise.
+ virtual PlaneGCSSolver_Solver::SolveStatus checkDegeneratedGeometry() const;
+
/// \brief Update SketchPlugin features after resolving constraints
virtual void refresh() const;
static const std::string MY_ERROR_VALUE("Unsupported type of constraint");
return MY_ERROR_VALUE;
}
+ /// Sketch contains degenerated geometry
+ inline static const std::string& DEGENERATED_GEOMETRY()
+ {
+ static const std::string MY_ERROR_VALUE(
+ "The set of constraints lead to degenerated geometry. "
+ "To fix this, you can either undo your operation or "
+ "remove a constraint or the degenerated geometry.");
+ return MY_ERROR_VALUE;
+ }
};
#endif
removeTemporaryConstraints();
aResult = mySketchSolver->solve();
}
+ // check degenerated geometry after constraints resolving
+ if (aResult == PlaneGCSSolver_Solver::STATUS_OK)
+ aResult = myStorage->checkDegeneratedGeometry();
} catch (...) {
getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())
->setValue(SketchSolver_Error::SOLVESPACE_CRASH());
mySketchSolver->undo();
if (!myConstraints.empty()) {
// the error message should be changed before sending the message
- getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())
- ->setValue(SketchSolver_Error::CONSTRAINTS());
+ const std::string& aErrorMsg = aResult == PlaneGCSSolver_Solver::STATUS_DEGENERATED ?
+ SketchSolver_Error::DEGENERATED_GEOMETRY() :
+ SketchSolver_Error::CONSTRAINTS();
+ getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(aErrorMsg);
if (myPrevResult != aResult ||
myPrevResult == PlaneGCSSolver_Solver::STATUS_UNKNOWN ||
myPrevResult == PlaneGCSSolver_Solver::STATUS_FAILED) {
}
}
- } else if (isGroupEmpty && isWorkplaneValid())
+ }
+ else if (isGroupEmpty && isWorkplaneValid()) {
+ // clear error related to previously degenerated entities
+ if (myPrevResult == PlaneGCSSolver_Solver::STATUS_DEGENERATED) {
+ getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue("");
+ myPrevResult = PlaneGCSSolver_Solver::STATUS_OK;
+ // the error message should be changed before sending the message
+ myConflictingConstraints.clear();
+ sendMessage(EVENT_SOLVER_REPAIRED, myConflictingConstraints);
+ }
+
computeDoF();
+ }
removeTemporaryConstraints();
myStorage->setNeedToResolve(false);
return aResolved;
/// \brief Return list of conflicting constraints
std::set<ObjectPtr> getConflictingConstraints(SolverPtr theSolver) const;
+ /// \brief Verify, the sketch contains degenerated geometry
+ /// after resolving the set of constraints
+ /// \return STATUS_OK if the geometry is valid, STATUS_DEGENERATED otherwise.
+ virtual PlaneGCSSolver_Solver::SolveStatus checkDegeneratedGeometry() const = 0;
+
/// \brief Update SketchPlugin features after resolving constraints
virtual void refresh() const = 0;
<source>Caution: SolveSpace crash! Constraints are wrong</source>
<translation>Caution: SolveSpace crash! Constraints are wrong</translation>
</message>
+ <message>
+ <source>The set of constraints lead to degenerated geometry. To fix this, you can either undo your operation or remove a constraint or the degenerated geometry.</source>
+ <translation>The set of constraints lead to degenerated geometry. To fix this, you can either undo your operation or remove a constraint or the degenerated geometry.</translation>
+ </message>
</context>
</TS>