Salome HOME
Issue #19196: Features in error after a change of parameter in a sketch although...
authorArtem Zhidkov <Artem.Zhidkov@opencascade.com>
Thu, 28 May 2020 08:48:48 +0000 (11:48 +0300)
committerArtem Zhidkov <Artem.Zhidkov@opencascade.com>
Thu, 28 May 2020 11:28:08 +0000 (14:28 +0300)
Stabilize the orientation of extrusion built on a wire.

src/FeaturesPlugin/CMakeLists.txt
src/FeaturesPlugin/Test/Test19196.py [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_Prism.cpp

index 5f3aa87e4303e3acbddaaaa45c8bfdeae2b07a7d..1801536207d4688af539af76427628c5eea5b48b 100644 (file)
@@ -663,4 +663,5 @@ ADD_UNIT_TESTS(TestExtrusion.py
                Test19065.py
                Test19066.py
                Test19115.py
+               Test19196.py
 )
diff --git a/src/FeaturesPlugin/Test/Test19196.py b/src/FeaturesPlugin/Test/Test19196.py
new file mode 100644 (file)
index 0000000..4dae685
--- /dev/null
@@ -0,0 +1,160 @@
+# Copyright (C) 2020  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
+#
+
+from GeomAPI import *
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+model.addParameter(Part_1_doc, "r_ext", "80")
+model.addParameter(Part_1_doc, "r_int", "60")
+model.addParameter(Part_1_doc, "r_cut", "30")
+model.addParameter(Part_1_doc, "h", "200")
+ParamSize = model.addParameter(Part_1_doc, "size", "r_int*3/4")
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), "r_int", "h")
+Cylinder_2 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), "r_ext", "h")
+Sphere_1 = model.addSphere(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), "r_ext")
+Sphere_2 = model.addSphere(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), "r_int")
+Rotation_1 = model.addRotation(Part_1_doc, [model.selection("SOLID", "Sphere_1_1")], axis = model.selection("EDGE", "PartSet/OY"), angle = 90, keepSubResults = True)
+Rotation_2 = model.addRotation(Part_1_doc, [model.selection("SOLID", "Sphere_2_1")], axis = model.selection("EDGE", "PartSet/OY"), angle = 90, keepSubResults = True)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Rotation_1_1"), model.selection("SOLID", "Rotation_2_1")], axis = model.selection("EDGE", "PartSet/OZ"), distance = "h", keepSubResults = True)
+Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Cylinder_1_1"), model.selection("SOLID", "Translation_1_2")], removeEdges = True, keepSubResults = True)
+Fuse_2 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Cylinder_2_1"), model.selection("SOLID", "Translation_1_1")], removeEdges = True, keepSubResults = True)
+Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Fuse_1_1"), model.selection("SOLID", "Fuse_2_1")], keepSubResults = True)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(0, 124.9999999998943, 0, 45.00000000000152)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_2 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_1.result())
+SketchLine_3 = Sketch_1.addLine(0, 45.00000000000152, -45, 0)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_3.startPoint())
+SketchLine_4 = Sketch_1.addLine(-45, 0, 0, -45.00000000000152)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchLine_5 = Sketch_1.addLine(0, -45.00000000000152, 44.99999999998636, 0)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_1.addLine(44.99999999998636, 0, 0, 45.00000000000152)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_6.endPoint())
+SketchLine_7 = Sketch_1.addLine(0, -45.00000000000152, 0, -124.9999999997331)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_7.startPoint())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_7.result())
+SketchLine_8 = Sketch_1.addLine(-45, 0, -125, 0)
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_8.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_8.result())
+SketchLine_9 = Sketch_1.addLine(44.99999999998636, 0, 124.9999999999994, 0)
+SketchProjection_2 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_10 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchLine_9.endPoint(), SketchLine_10.result())
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_9.startPoint())
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_10.result())
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchLine_8.startPoint(), SketchLine_10.result())
+SketchConstraintCoincidence_13 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_2.result())
+SketchConstraintParallel_1 = Sketch_1.setParallel(SketchLine_3.result(), SketchLine_5.result())
+SketchConstraintParallel_2 = Sketch_1.setParallel(SketchLine_4.result(), SketchLine_6.result())
+SketchConstraintPerpendicular_1 = Sketch_1.setPerpendicular(SketchLine_3.result(), SketchLine_4.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_8.result(), "r_ext")
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchLine_8.startPoint(), SketchLine_7.result(), "size", True)
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_8.result(), SketchLine_1.result())
+SketchConstraintEqual_2 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_9.result())
+SketchConstraintEqual_3 = Sketch_1.setEqual(SketchLine_7.result(), SketchLine_9.result())
+model.do()
+Wire_1_objects = [model.selection("EDGE", "Sketch_1/SketchLine_8"), model.selection("EDGE", "Sketch_1/SketchLine_4"), model.selection("EDGE", "Sketch_1/SketchLine_7"), model.selection("EDGE", "Sketch_1/SketchLine_5"), model.selection("EDGE", "Sketch_1/SketchLine_9"), model.selection("EDGE", "Sketch_1/SketchLine_6"), model.selection("EDGE", "Sketch_1/SketchLine_3"), model.selection("EDGE", "Sketch_1/SketchLine_1")]
+Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False)
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("WIRE", "Wire_1_1")], model.selection(), "h", 0)
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/XOY"), "h", False)
+Split_1 = model.addSplit(Part_1_doc, [model.selection("COMPSOLID", "Partition_1_1")], [model.selection("FACE", "Plane_1"), model.selection("SHELL", "Extrusion_1_1")], keepSubResults = True)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Split_1_1_7/Modified_Face&Plane_1/Plane_1&new_weak_name_3"))
+SketchProjection_3 = Sketch_2.addProjection(model.selection("EDGE", "Extrusion_1_1/To_Edge_2"), True)
+SketchLine_11 = SketchProjection_3.createdFeature()
+SketchProjection_4 = Sketch_2.addProjection(model.selection("EDGE", "Extrusion_1_1/To_Edge_5"), True)
+SketchLine_12 = SketchProjection_4.createdFeature()
+SketchProjection_5 = Sketch_2.addProjection(model.selection("EDGE", "Extrusion_1_1/To_Edge_6"), True)
+SketchLine_13 = SketchProjection_5.createdFeature()
+SketchProjection_6 = Sketch_2.addProjection(model.selection("EDGE", "Extrusion_1_1/To_Edge_3"), True)
+SketchLine_14 = SketchProjection_6.createdFeature()
+model.do()
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "Sketch_2")], model.selection(), "r_cut/sqrt(2)", 0)
+Sketch_3 = model.addSketch(Part_1_doc, model.defaultPlane("YOZ"))
+SketchProjection_7 = Sketch_3.addProjection(model.selection("EDGE", "Split_1_1_3/Modified_Edge&Extrusion_1_1/To_Edge_4"), True)
+SketchLine_15 = SketchProjection_7.createdFeature()
+SketchProjection_8 = Sketch_3.addProjection(model.selection("EDGE", "Split_1_1_9/Modified_Edge&Extrusion_1_1/To_Edge_4"), True)
+SketchLine_16 = SketchProjection_8.createdFeature()
+SketchProjection_9 = Sketch_3.addProjection(model.selection("EDGE", "[Extrusion_2_1/Generated_Face&Sketch_2/SketchProjection_3][Extrusion_2_1/Generated_Face&Sketch_2/SketchProjection_4]"), True)
+SketchLine_17 = SketchProjection_9.createdFeature()
+SketchLine_18 = Sketch_3.addLine(-45.00000000000152, 221.2132034355964, -99.71358592313776, 275.9267893638306)
+SketchLine_19 = Sketch_3.addLine(-99.71358592313776, 275.9267893638306, -80, 200)
+SketchConstraintCoincidence_14 = Sketch_3.setCoincident(SketchLine_18.endPoint(), SketchLine_19.startPoint())
+SketchConstraintCoincidence_15 = Sketch_3.setCoincident(SketchAPI_Line(SketchLine_16).endPoint(), SketchLine_19.endPoint())
+SketchConstraintCoincidence_16 = Sketch_3.setCoincident(SketchLine_18.startPoint(), SketchAPI_Line(SketchLine_17).endPoint())
+SketchConstraintAngle_1 = Sketch_3.setAngle(SketchLine_18.result(), SketchLine_16.result(), 45, type = "")
+model.do()
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_3/Face-SketchProjection_9f-SketchLine_18f-SketchLine_19f-SketchProjection_8r-SketchProjection_7r")])
+AngularCopy_1 = model.addMultiRotation(Part_1_doc, [model.selection("FACE", "Face_1_1")], model.selection("EDGE", "PartSet/OZ"), 4, keepSubResults = True)
+Plane_5 = model.addPlane(Part_1_doc, model.selection("VERTEX", "AngularCopy_1_1_1/MV:Rotated&Sketch_3/SketchLine_19_StartVertex&Sketch_3/SketchLine_18_EndVertex"), model.selection("VERTEX", "AngularCopy_1_1_4/MV:Rotated&Sketch_3/SketchLine_19_StartVertex&Sketch_3/SketchLine_18_EndVertex"), model.selection("VERTEX", "AngularCopy_1_1_4/MV:Rotated&Sketch_3/SketchLine_18_StartVertex&Sketch_3/SketchProjection_9_EndVertex"))
+Sketch_4 = model.addSketch(Part_1_doc, model.selection("FACE", "Plane_2"))
+SketchLine_20 = Sketch_4.addLine(-71.93873905691365, 265.6178566586798, -194.0624420262377, 195.1097038792864)
+SketchProjection_10 = Sketch_4.addProjection(model.selection("VERTEX", "Sketch_3/SketchLine_18_EndVertex"), False)
+SketchPoint_1 = SketchProjection_10.createdFeature()
+SketchConstraintCoincidence_17 = Sketch_4.setCoincident(SketchLine_20.startPoint(), SketchPoint_1.result())
+SketchProjection_11 = Sketch_4.addProjection(model.selection("VERTEX", "AngularCopy_1_1_4/MV:Rotated&Sketch_3/SketchLine_19_StartVertex&Sketch_3/SketchLine_18_EndVertex"), False)
+SketchPoint_2 = SketchProjection_11.createdFeature()
+SketchConstraintCoincidence_18 = Sketch_4.setCoincident(SketchLine_20.endPoint(), SketchPoint_2.result())
+SketchProjection_12 = Sketch_4.addProjection(model.selection("EDGE", "Sketch_3/SketchLine_18"), True)
+SketchLine_21 = SketchProjection_12.createdFeature()
+SketchProjection_13 = Sketch_4.addProjection(model.selection("EDGE", "[Extrusion_2_1/Generated_Face&Sketch_2/SketchProjection_3][Extrusion_2_1/To_Face]"), True)
+SketchLine_22 = SketchProjection_13.createdFeature()
+SketchProjection_14 = Sketch_4.addProjection(model.selection("EDGE", "AngularCopy_1_1_4/ME:Rotated&Sketch_3/SketchLine_18"), True)
+SketchLine_23 = SketchProjection_14.createdFeature()
+model.do()
+Face_2 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_4/Face-SketchLine_20r-SketchProjection_14r-SketchProjection_13f-SketchProjection_12f")])
+AngularCopy_2 = model.addMultiRotation(Part_1_doc, [model.selection("FACE", "Face_2_1")], model.selection("EDGE", "PartSet/OZ"), 4, keepSubResults = True)
+Split_2_objects_2 = [model.selection("SOLID", "Extrusion_2_1"), model.selection("COMPOUND", "AngularCopy_1_1"), model.selection("COMPOUND", "AngularCopy_2_1")]
+Split_2 = model.addSplit(Part_1_doc, [model.selection("COMPSOLID", "Split_1_1")], Split_2_objects_2, keepSubResults = True)
+Group_1_objects = [model.selection("FACE", "Split_2_1_7/Modified_Face&Cylinder_1_1/Face_1"), model.selection("FACE", "Split_2_1_8/Modified_Face&Cylinder_1_1/Face_1"), model.selection("FACE", "Split_2_1_9/Modified_Face&Cylinder_1_1/Face_1"), model.selection("FACE", "Split_2_1_10/Modified_Face&Cylinder_1_1/Face_1")]
+Group_1 = model.addGroup(Part_1_doc, "Faces", Group_1_objects)
+Group_1.setName("shared_face_cyl")
+Group_1.result().setName("shared_face_cyl")
+model.end()
+
+model.testNbResults(Split_2, 1)
+model.testNbSubResults(Split_2, [20])
+model.testNbSubShapes(Split_2, GeomAPI_Shape.SOLID, [20])
+model.testNbSubShapes(Split_2, GeomAPI_Shape.FACE, [120])
+model.testNbSubShapes(Split_2, GeomAPI_Shape.EDGE, [492])
+model.testNbSubShapes(Split_2, GeomAPI_Shape.VERTEX, [984])
+model.testResultsVolumes(Split_2, [5093568.888962713])
+
+model.begin()
+ParamSize.expression().setValue("r_int/2")
+model.end()
+
+model.testNbResults(Split_2, 1)
+model.testNbSubResults(Split_2, [20])
+model.testNbSubShapes(Split_2, GeomAPI_Shape.SOLID, [20])
+model.testNbSubShapes(Split_2, GeomAPI_Shape.FACE, [120])
+model.testNbSubShapes(Split_2, GeomAPI_Shape.EDGE, [492])
+model.testNbSubShapes(Split_2, GeomAPI_Shape.VERTEX, [984])
+model.testResultsVolumes(Split_2, [5093568.888962713])
+
+assert(model.checkPythonDump())
index c21e0326bb4765e4c06e0160cedd2c0655f2ea18..50b2ef2b16cc004b3d1c5d3b197f87962958cd21 100644 (file)
@@ -102,6 +102,32 @@ static GeomShapePtr toShape(const TopoDS_Shape& theShape)
   return aShape;
 }
 
+static void changeOrientationIfNeeded(const TopoDS_Shape& theShape, gp_Vec& theNormal)
+{
+  TopExp_Explorer anExp(theShape, TopAbs_VERTEX);
+  gp_Pnt aPnt0 = BRep_Tool::Pnt(TopoDS::Vertex(anExp.Current()));
+  gp_Dir aDir01;
+  for (anExp.Next(); anExp.More(); anExp.Next()) {
+    gp_Pnt aPnt1 = BRep_Tool::Pnt(TopoDS::Vertex(anExp.Current()));
+    if (aPnt1.SquareDistance(aPnt0) > Precision::SquareConfusion()) {
+      aDir01 = gp_Dir(gp_Vec(aPnt0, aPnt1));
+      break;
+    }
+  }
+  gp_Vec aNormal;
+  for (; anExp.More(); anExp.Next()) {
+    gp_Pnt aPnt2 = BRep_Tool::Pnt(TopoDS::Vertex(anExp.Current()));
+    if (aPnt2.SquareDistance(aPnt0) > Precision::SquareConfusion()) {
+      aNormal = gp_Vec(aDir01) ^ gp_Vec(aPnt0, aPnt2);
+      if (aNormal.SquareMagnitude() > Precision::SquareConfusion())
+        break;
+    }
+  }
+  if (anExp.More() && aNormal.XYZ().Dot(theNormal.XYZ()) < -Precision::Confusion()) {
+    // directions differ, reverse the normal
+    theNormal.Reverse();
+  }
+}
 
 //==================================================================================================
 GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr theBaseShape,
@@ -147,6 +173,7 @@ GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr theBaseShape,
   BRepBuilderAPI_FindPlane aFindPlane(aBaseShape);
   if(aFindPlane.Found() == Standard_True)
   {
+    bool checkOrientation = false;
     Handle(Geom_Plane) aPlane;
     if(aBaseShape.ShapeType() == TopAbs_FACE || aBaseShape.ShapeType() == TopAbs_SHELL) {
       TopExp_Explorer anExp(aBaseShape, TopAbs_FACE);
@@ -163,9 +190,17 @@ GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr theBaseShape,
       aPlane = Handle(Geom_Plane)::DownCast(aSurface);
     } else {
       aPlane = aFindPlane.Plane();
+      checkOrientation = true;
     }
     gp_Pnt aLoc = aPlane->Axis().Location();
     aBaseVec = aPlane->Axis().Direction();
+
+    if (checkOrientation) {
+      // to stabilize the result of algorithm, if base shape is a wire, compare the orientation
+      // of calculated plane with the normal vector got iterating on vertices
+      changeOrientationIfNeeded(aBaseShape, aBaseVec);
+    }
+
     aBaseLoc.reset(new GeomAPI_Pnt(aLoc.X(), aLoc.Y(), aLoc.Z()));
     aBaseDir.reset(new GeomAPI_Dir(aBaseVec.X(), aBaseVec.Y(), aBaseVec.Z()));
   }