Salome HOME
Merge branch 'V9_5_BR'
authorvsr <vsr@opencascade.com>
Fri, 10 Jul 2020 16:24:56 +0000 (19:24 +0300)
committervsr <vsr@opencascade.com>
Fri, 10 Jul 2020 16:24:56 +0000 (19:24 +0300)
99 files changed:
CMakeLists.txt
doc/gui/index.rst.in
env_Salome.bat
src/ConnectorAPI/Test/__main__.py [new file with mode: 0644]
src/ConnectorPlugin/ConnectorPlugin_PublishToStudyFeature.py
src/ConnectorPlugin/ConnectorPlugin_msg_fr.ts
src/ConstructionPlugin/CMakeLists.txt
src/ConstructionPlugin/ConstructionPlugin_Plugin.cpp
src/ConstructionPlugin/ConstructionPlugin_Validators.cpp
src/ConstructionPlugin/ConstructionPlugin_Validators.h
src/ConstructionPlugin/ConstructionPlugin_msg_en.ts
src/ConstructionPlugin/ConstructionPlugin_msg_fr.ts
src/ConstructionPlugin/Test/Test19207.py [new file with mode: 0644]
src/ConstructionPlugin/Test/Test19471.py [new file with mode: 0644]
src/ConstructionPlugin/point_widget.xml
src/ExchangePlugin/Test/TestExport.py
src/FeaturesPlugin/CMakeLists.txt
src/FeaturesPlugin/FeaturesPlugin_BooleanFuse.cpp
src/FeaturesPlugin/FeaturesPlugin_Translation.cpp
src/FeaturesPlugin/Test/Test19115.py [new file with mode: 0644]
src/FeaturesPlugin/Test/Test19196.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestExtrusionCut_ThroughAll.py
src/FeaturesPlugin/Test/TestExtrusion_ByFaces19.py
src/FeaturesPlugin/doc/FeaturesPlugin.rst
src/FeaturesPlugin/doc/booleanArguments.rst [new file with mode: 0644]
src/FeaturesPlugin/doc/booleanOperations.rst [new file with mode: 0644]
src/FeaturesPlugin/doc/commonFeature.rst
src/FeaturesPlugin/doc/cutFeature.rst
src/FeaturesPlugin/doc/fuseFeature.rst
src/FeaturesPlugin/doc/intersectionFeature.rst
src/FeaturesPlugin/doc/partitionFeature.rst
src/FeaturesPlugin/doc/smashFeature.rst
src/FeaturesPlugin/doc/splitFeature.rst
src/FeaturesPlugin/doc/unionFeature.rst
src/FeaturesPlugin/plugin-Features.xml
src/FiltersPlugin/CMakeLists.txt
src/FiltersPlugin/Test/Test19190.py [new file with mode: 0644]
src/FiltersPlugin/Test/Test3241.py [new file with mode: 0644]
src/FiltersPlugin/doc/FiltersPlugin.rst
src/GeomAPI/GeomAPI_BSpline2d.cpp
src/GeomAPI/GeomAPI_Face.cpp
src/GeomAPI/GeomAPI_Shape.cpp
src/GeomAPI/GeomAPI_Vertex.cpp
src/GeomAPI/GeomAPI_Vertex.h
src/GeomAlgoAPI/GeomAlgoAPI_Boolean.cpp
src/GeomAlgoAPI/GeomAlgoAPI_Prism.cpp
src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp
src/GeomAlgoAPI/GeomAlgoAPI_SolidClassifier.cpp
src/GeomValidators/GeomValidators_ShapeType.cpp
src/InitializationPlugin/InitializationPlugin_EvalListener.cpp
src/InitializationPlugin/InitializationPlugin_EvalListener.h
src/InitializationPlugin/InitializationPlugin_Plugin.cpp
src/InitializationPlugin/InitializationPlugin_PyInterp.cpp
src/InitializationPlugin/InitializationPlugin_PyInterp.h
src/Model/Model_AttributeSelection.cpp
src/Model/Model_AttributeSelection.h
src/Model/Model_Document.cpp
src/Model/Model_Objects.cpp
src/Model/Model_ResultPart.cpp
src/Model/Model_Session.cpp
src/Model/Model_Update.cpp
src/ModelAPI/CMakeLists.txt
src/ModelAPI/ModelAPI_AttributeSelection.h
src/ModelAPI/Test/Test19217.py [new file with mode: 0644]
src/ModelAPI/Test/Test19707.py [new file with mode: 0644]
src/ModelAPI/Test/Test19726.py [new file with mode: 0644]
src/ModelGeomAlgo/ModelGeomAlgo_Shape.cpp
src/ModelHighAPI/ModelHighAPI_Interface.cpp
src/ModuleBase/ModuleBase_Tools.cpp
src/ModuleBase/ModuleBase_WidgetSelectionFilter.cpp
src/PartSet/PartSet_Module.cpp
src/PartSet/PartSet_OperationPrs.cpp
src/PartSet/PartSet_PreviewSketchPlane.cpp
src/PartSet/PartSet_SketcherMgr.cpp
src/PartSet/PartSet_Tools.cpp
src/PartSet/PartSet_WidgetSketchLabel.cpp
src/PythonAddons/doc/compoundVerticesFeature.rst
src/PythonAddons/doc/importParametersFeature.rst
src/SHAPERGUI/SHAPERGUI.cpp
src/SHAPERGUI/SHAPERGUI.h
src/SHAPERGUI/SHAPERGUI_DataModel.h
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/SketchPlugin_ConstraintAngle.cpp
src/SketchPlugin/SketchPlugin_Validators.cpp
src/SketchPlugin/SketchPlugin_msg_en.ts
src/SketchPlugin/Test/Test3240.py [new file with mode: 0644]
src/SketchPlugin/plugin-Sketch.xml
src/SketcherPrs/SketcherPrs_LengthDimension.cpp
src/SketcherPrs/SketcherPrs_LengthDimension.h
src/XGUI/XGUI_ContextMenuMgr.cpp
src/XGUI/XGUI_DataModel.cpp
src/XGUI/XGUI_Displayer.cpp
src/XGUI/XGUI_Workshop.cpp
test.compatibility/bushing.py
test.hdfs/CuveN4_Tubulures.py
test.hdfs/horseshoe.py [new file with mode: 0644]
test.models/bushing.py
test.models/plug.py
test.models/visor_support.py [new file with mode: 0644]

index ca220ba10bf238004723d9f63d4b8d4213a594cb..cfee8962aadb2053f643a048a0b13f2c11045d00 100644 (file)
@@ -26,7 +26,7 @@ IF(WIN32)
   CMAKE_POLICY(SET CMP0020 OLD) # disable automatic linking to qtmain.lib
 ENDIF(WIN32)
 
-SET (SHAPER_Version 9.4.0)
+SET (SHAPER_Version 9.5.0)
 
 SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMakeCommon" ${CMAKE_MODULE_PATH})
 
index 0f549fd301307e7f404f3aab1fbe1dce027c84b7..bfdca582e82a66fa979081d35c0a412865fca277 100644 (file)
@@ -8,9 +8,13 @@ Welcome to SHAPER documentation!
 
 .. toctree::
    :titlesonly:
-   :maxdepth: 2
+   :maxdepth: 3
 
    General/Introduction.rst
    General/Tutorial.rst
 <insert here>
+
+.. toctree::
+   :hidden:
+
    General/TUI_scripts.rst
index 83c073b3447c49110cfd279a1778daf80708b1a5..1fa82488b0b4598876337268699a7ee9b9d4d817 100644 (file)
@@ -36,7 +36,7 @@ if "%BOOST_ROOT_DIR%" == "" (
 cd /d %SALOME_ROOT_DIR%\WORK
 call set_env.bat %1
 
-if "%2" == run (
+if "%2" == "run" (
   call "%PDIR%\env_launch.bat"
 ) else (
   call "%PDIR%\env_compile.bat"
diff --git a/src/ConnectorAPI/Test/__main__.py b/src/ConnectorAPI/Test/__main__.py
new file mode 100644 (file)
index 0000000..02a1983
--- /dev/null
@@ -0,0 +1,24 @@
+# Copyright (C) 2016-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
+#
+
+# ============================================================ #
+#                                                              #
+#  Attention: Keep this file for correct execution on Windows  #
+#                                                              #
+# ============================================================ #
index 6e3629fbfb2b0c14257852073c92b8d89ff800e8..a2e401aae849520225473c1b214435a0bf1cb9bf 100644 (file)
@@ -83,9 +83,9 @@ class PublishToStudyFeature(ModelAPI.ModelAPI_Feature):
           aPartRes = ModelAPI.modelAPI_ResultPart(ModelAPI.modelAPI_Result(aPartObject))
           aPartDoc = aPartRes.partDoc()
           if aPartDoc is None and aPartObject is not None:
-            EventsAPI.Events_InfoMessage("PublishToStudy", "For publish to SHAPER-STUDY some Part is not activated", self).send()
+            EventsAPI.Events_InfoMessage("PublishToStudy", "To publish to SHAPER-STUDY, activate Parts in SHAPER", self).send()
             break
-          aPartFeatureId = aPartSet.feature(aPartRes).data().featureId()
+          aPartFeatureId = aPartSet.feature(aPartRes.original()).data().featureId()
           # Collects all features of exported results to find results of the same features and extend id.
           # Map from feature index to index of result. If index is zero (initial), no surrfix to entry is added.
           aFeaturesIndices = {}
@@ -173,25 +173,15 @@ class PublishToStudyFeature(ModelAPI.ModelAPI_Feature):
         else:
           aSelList = aRef.selectionList("group_list")
         aSelType = GeomAPI_Shape.shapeTypeByStr(aSelList.selectionType())
-        for aSelIndex in range(aSelList.size()):
-          aSelection = aSelList.value(aSelIndex)
-          if aSelection.contextObject():
-            aShape = aSelection.value()
-            if aShape:
-              allShapesList = [] # collect all sub-shapes selected in the group
-              if aShape.shapeType() == 0 or aShape.shapeType() != aSelType: # compound or whole res
-                anExplorer = GeomAPI_ShapeExplorer(aShape, aSelType)
-                while anExplorer.more():
-                  allShapesList.append(anExplorer.current())
-                  anExplorer.next()
-              else:
-                allShapesList.append(aShape)
-              # get index of each selected shape: if 0, this sub-shape is not in our result
-              for aSelected in allShapesList:
-                anId = GeomAlgoAPI.GeomAlgoAPI_CompoundBuilder.id(aResShape, aSelected)
-                if anId > 0 and not anId in aGroupHasIndex:
-                  aGroupIndices.append(anId)
-                  aGroupHasIndex[anId] = 0
+        for aGroupRes in aRef.results():
+          aShape = aGroupRes.shape()
+          anExplorer = GeomAPI_ShapeExplorer(aShape, aSelType)
+          while anExplorer.more():
+            anId = GeomAlgoAPI.GeomAlgoAPI_CompoundBuilder.id(aResShape, anExplorer.current())
+            if anId > 0 and not anId in aGroupHasIndex:
+              aGroupIndices.append(anId)
+              aGroupHasIndex[anId] = 0
+            anExplorer.next()
         if len(aGroupIndices): # create group
           aGroupFeatureId = aRef.data().featureId()
           if theFields:
@@ -234,7 +224,10 @@ class PublishToStudyFeature(ModelAPI.ModelAPI_Feature):
     def fillField(self, theField, theFeature, theEngine, theSelectionIndices):
       aTables = theFeature.tables("values")
       aValType = aTables.type() # type of the values
-      theField.SetValuesType(aValType)
+      aValTypeToSet = aValType
+      if aValType == 3: # strings do not supported by SMESH, so, make them empty boolean table
+        aValTypeToSet = 0
+      theField.SetValuesType(aValTypeToSet)
       aNumSteps = aTables.tables() # number of steps is number of tables
       aSteps = []
       for aVal in range(aNumSteps):
index 5182d51346085b8b56db0375a77910f411a874c6..f063a15b6c2673fb93ebe284de3ff81af0d4381e 100644 (file)
@@ -23,8 +23,8 @@
       <translation>Toutes les pièces de l'assemblage ne sont pas Ã  jour, rien n'est publié. Veuillez mettre la dernière fonctionnalité Ã  jour.</translation>
     </message>
     <message>
-      <source>For publish to SHAPER-STUDY some Part is not activated</source>
-      <translation>Pour la publication sur SHAPER-STUDY, une pièce n'est pas activée</translation>
+      <source>To publish to SHAPER-STUDY, activate Parts in SHAPER</source>
+      <translation>Pour publier dans SHAPER-STUDY, activez les pièces dans SHAPER</translation>
     </message>
   </context>
 </TS>
index 3f75a54afae774dd9d2c590c733f35b85f7dcfd5..11fd87eaf0a2b1ce03e9f0982a85091ed5ac7af0 100644 (file)
@@ -97,4 +97,6 @@ ADD_UNIT_TESTS(TestAxisCreation.py
                TestPlane.py
                TestPlane_ErrorMsg.py
                TestPlane_FaceValidator.py
+               Test19207.py
+               Test19471.py
 )
index 96b6aee66dc80bf4d5b37bbbcc7a2dbe4dfe96bc..69e900fdc50dbc1a1ad715ed14da817521634c8b 100644 (file)
@@ -53,6 +53,8 @@ ConstructionPlugin_Plugin::ConstructionPlugin_Plugin()
                               new ConstructionPlugin_ValidatorAxisTwoNotParallelPlanes());
   aFactory->registerValidator("ConstructionPlugin_ValidatorPointThreeNonParallelPlanes",
                               new ConstructionPlugin_ValidatorPointThreeNonParallelPlanes());
+  aFactory->registerValidator("ConstructionPlugin_ValidatorNotFeature",
+                              new ConstructionPlugin_ValidatorNotFeature());
 
   Config_PropManager::registerProp(SKETCH_TAB_NAME, "planes_size", "Size", Config_Prop::DblSpin,
                                    PLANE_SIZE, "0", "1000");
index b36b2bd513f5ea04d340915aea2599359469d172..aedbb596803dc65902321fc22ff33050c6d5e4bf 100644 (file)
@@ -470,6 +470,29 @@ bool ConstructionPlugin_ValidatorPointThreeNonParallelPlanes::isValid(
   return true;
 }
 
+//==================================================================================================
+bool ConstructionPlugin_ValidatorNotFeature::isValid(
+    const AttributePtr& theAttribute,
+    const std::list<std::string>& /*theArguments*/,
+    Events_InfoMessage& theError) const
+{
+  AttributeSelectionPtr aSelAttr =
+      std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
+  if (!aSelAttr) {
+    theError = "Wrong attribute";
+    return false;
+  }
+
+  FeaturePtr aContextFeature = aSelAttr->contextFeature();
+  if (aContextFeature) {
+    theError = "Feature should not be selected";
+    return false;
+  }
+  return true;
+}
+
+//==================================================================================================
+
 std::shared_ptr<GeomAPI_Edge> getEdge(const GeomShapePtr theShape)
 {
   GeomEdgePtr anEdge;
index c6c5be91873c3ebbc99937ee428c4c7313398403..accbf19943f42eba68cca8bad9a3419f44e6a8a0 100644 (file)
@@ -127,4 +127,19 @@ public:
                        Events_InfoMessage& theError) const;
 };
 
+/// \class ConstructionPlugin_ValidatorNotFeature
+/// \ingroup Validators
+/// \brief A validator for selection of a result but not a feature.
+class ConstructionPlugin_ValidatorNotFeature : public ModelAPI_AttributeValidator
+{
+public:
+  //! \return True if the attribute is valid.
+  //! \param[in] theAttribute the checked attribute.
+  //! \param[in] theArguments arguments of the attribute.
+  //! \param[out] theError error message.
+  virtual bool isValid(const AttributePtr& theAttribute,
+                       const std::list<std::string>& theArguments,
+                       Events_InfoMessage& theError) const;
+};
+
 #endif
\ No newline at end of file
index d81fdc7b65eaa461c2389020a6c38d3778d68162..ecb0de35dc81dba5384c511d2779133363163414 100644 (file)
       <translation>Select an edge.</translation>
     </message>
   </context>
+  <context>
+    <name>Point:edge:ConstructionPlugin_ValidatorNotFeature</name>
+    <message>
+      <source>Wrong attribute</source>
+      <translation>Wrong attribute.</translation>
+    </message>
+    <message>
+      <source>Feature should not be selected</source>
+      <translation>Feature should not be selected.</translation>
+    </message>
+  </context>
   <context>
     <name>Point:edge_for_point_projection</name>
     <message>
index e06b61c5f12b446f95e3a9dd9f360feb80e2d43c..21fa8315f62378e141438c94bcfdcb8f70c212cf 100644 (file)
       <translation>Sélectionnez l&apos;arête de référence.</translation>
     </message>
   </context>
+  <context>
+    <name>Point:edge:ConstructionPlugin_ValidatorNotFeature</name>
+    <message>
+      <source>Wrong attribute</source>
+      <translation>Attribut incorrect.</translation>
+    </message>
+    <message>
+      <source>Feature should not be selected</source>
+      <translation>La fonction ne doit pas Ãªtre sélectionnée.</translation>
+    </message>
+  </context>
   <context>
     <name>Point:edge_for_point_projection</name>
     <message>
diff --git a/src/ConstructionPlugin/Test/Test19207.py b/src/ConstructionPlugin/Test/Test19207.py
new file mode 100644 (file)
index 0000000..f4dd3c7
--- /dev/null
@@ -0,0 +1,36 @@
+# 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 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(-27.27564593372983, -98.06529667720862, 118.6032908025252, -158.4943424420008)
+SketchLine_2 = Sketch_1.addLine(48.47982068764622, 136.9061129612801, 209.0029126232743, 12.63448992263632)
+model.do()
+Filling_1 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchLine_1"), model.selection("EDGE", "Sketch_1/SketchLine_2")])
+Plane_1 = model.addPlane(Part_1_doc, model.selection("FACE", "Filling_1_1"), 10, False)
+model.end()
+
+from ModelAPI import *
+factory = ModelAPI_Session.get().validators()
+assert(factory.validate(Plane_1.feature()))
diff --git a/src/ConstructionPlugin/Test/Test19471.py b/src/ConstructionPlugin/Test/Test19471.py
new file mode 100644 (file)
index 0000000..04937e0
--- /dev/null
@@ -0,0 +1,32 @@
+# 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 salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Point_2 = model.addPoint(Part_1_doc, 5, 0, 0)
+Point_3 = model.addPoint(Part_1_doc, 20, 0, 0)
+Edge_1 = model.addEdge(Part_1_doc, model.selection("VERTEX", "Point_1"), model.selection("VERTEX", "Point_2"))
+Point_4 = model.addPoint(Part_1_doc, model.selection("EDGE", "all-in-Edge_1"), 10, False, False)
+model.end()
+
+assert(Point_4.feature().error() != "")
index 450dadd33f32adad79d5486b8294f719509deae9..1acb33893c524be2a192ec07d6c55c0a2962f295 100644 (file)
@@ -16,6 +16,7 @@
                       icon="icons/Construction/edge.png"
                       shape_types="edge">
         <validator id="GeomValidators_Finite"/>
+        <validator id="ConstructionPlugin_ValidatorNotFeature"/>
       </shape_selector>
       <radiobox id="offset_type">
         <radio id="offset_type_by_distance"
index 72e1a15e1725a1e08165cee48b6ac64c09db0e5e..511b95835f9b936dca4d17d5c55b73a6ba5fa8a2 100644 (file)
@@ -157,8 +157,15 @@ def testExportXAO(theFile, theEmptyFormat = False):
 
     # Check exported file
     aRefPath = os.path.join(os.getenv("DATA_DIR"), "Shapes", "Xao", "box2.xao")
-    import filecmp
-    assert filecmp.cmp(theFile, aRefPath)
+    # endlines may be different on different platforms, thus compare files line-by-line
+    areFilesEqual = True
+    with open(theFile, 'r') as file, open(aRefPath, 'r') as ref:
+        l1 = l2 = True
+        while l1 and l2 and areFilesEqual:
+            l1 = file.readline()
+            l2 = ref.readline()
+            areFilesEqual = l1 == l2
+    assert areFilesEqual
 
 if __name__ == '__main__':
     with TemporaryDirectory() as tmp_dir:
index fcd93d08cbbb61afc50b3856db4bb6e85cdcb281..0169cd9e3bea23cb95db9b87af56cfd3eb622f88 100644 (file)
@@ -665,6 +665,8 @@ ADD_UNIT_TESTS(TestExtrusion.py
                Test2817.py
                Test19065.py
                Test19066.py
+               Test19115.py
+               Test19196.py
                TestFillet1D_ErrorMsg.py
                TestFillet1D_Vertices_1.py
                TestFillet1D_Vertices_2.py
index 2eb87085dc165d7e1a546ac460e6ab615f3139ca..4c43be8cc7e3840ac65d03260ea4e9f15657f070 100644 (file)
@@ -113,6 +113,8 @@ void FeaturesPlugin_BooleanFuse::execute()
   // in boolean operation and will be added to result.
   bool isProcessCompsolid = !isSimpleCreation || !aFuseVersion.empty();
   ListOfShape aShapesToAdd;
+  int aNbCompsolids = 0; // number of compsolids, which subs is taken into operation
+  bool hasSeparateSolids = false; // are solids or full results exist
   for (GeomAPI_ShapeHierarchy::iterator anObjectsIt = anObjectsHierarchy.begin();
        isProcessCompsolid && anObjectsIt != anObjectsHierarchy.end();
        ++anObjectsIt) {
@@ -120,6 +122,7 @@ void FeaturesPlugin_BooleanFuse::execute()
     GeomShapePtr aParent = anObjectsHierarchy.parent(anObject, false);
 
     if (aParent && aParent->shapeType() == GeomAPI_Shape::COMPSOLID) {
+      ++aNbCompsolids;
       // mark all subs of this parent as precessed to avoid handling twice
       aParent = anObjectsHierarchy.parent(anObject);
 
@@ -127,7 +130,10 @@ void FeaturesPlugin_BooleanFuse::execute()
       anObjectsHierarchy.splitCompound(aParent, aUsed, aNotUsed);
       aShapesToAdd.insert(aShapesToAdd.end(), aNotUsed.begin(), aNotUsed.end());
     }
+    else
+      hasSeparateSolids = true;
   }
+  bool isSingleCompsolid = aNbCompsolids == 1 && !hasSeparateSolids;
 
   ListOfShape anOriginalShapes = aSolidsToFuse;
   anOriginalShapes.insert(anOriginalShapes.end(), aShapesToAdd.begin(), aShapesToAdd.end());
@@ -150,7 +156,7 @@ void FeaturesPlugin_BooleanFuse::execute()
   }
 
   // If we have compsolids then cut with not used solids all others.
-  if (!aShapesToAdd.empty()) {
+  if (!aShapesToAdd.empty() && !isSingleCompsolid) {
     aSolidsToFuse.clear();
     for (ListOfShape::iterator
          anIt = anOriginalShapes.begin(); anIt != anOriginalShapes.end(); anIt++) {
index d6554ef3ca15e99fb1001c09d2ce3dfac49f5525..37695957df3b59afc4133ca34f8c025ccc7895cd 100644 (file)
@@ -178,7 +178,9 @@ GeomTrsfPtr FeaturesPlugin_Translation::translationByTwoPoints()
   }
 
   GeomTrsfPtr aTrsf(new GeomAPI_Trsf);
-  aTrsf->setTranslation(aFirstPoint, aSecondPoint);
+  if (aFirstPoint && aSecondPoint) {
+    aTrsf->setTranslation(aFirstPoint, aSecondPoint);
+  }
   return aTrsf;
 }
 
diff --git a/src/FeaturesPlugin/Test/Test19115.py b/src/FeaturesPlugin/Test/Test19115.py
new file mode 100644 (file)
index 0000000..a93eea7
--- /dev/null
@@ -0,0 +1,87 @@
+# 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 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, "h", "1")
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 0.5, "h")
+Cylinder_2 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 0.1, "h")
+Cylinder_3 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 0.4, "h")
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/XOY"), 0.1, False)
+Partition_1_objects = [model.selection("SOLID", "Cylinder_1_1"), model.selection("SOLID", "Cylinder_2_1"), model.selection("SOLID", "Cylinder_3_1"), model.selection("FACE", "Plane_1"), model.selection("FACE", "PartSet/YOZ"), model.selection("FACE", "PartSet/XOZ")]
+Partition_1 = model.addPartition(Part_1_doc, Partition_1_objects, keepSubResults = True)
+Box_1 = model.addBox(Part_1_doc, 0.7, 0.1, 0.05)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], 0, -0.05, "0.75*h")
+Recover_1 = model.addRecover(Part_1_doc, Partition_1, [Cylinder_1.result()])
+Cut_1 = model.addCut(Part_1_doc, [model.selection("SOLID", "Translation_1_1")], [model.selection("SOLID", "Recover_1_1")], keepSubResults = True)
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Partition_1_1_14/Modified_Face&PartSet/XOZ/XOZ")])
+Recover_2 = model.addRecover(Part_1_doc, Face_1, [Partition_1.result()], True)
+Partition_2 = model.addPartition(Part_1_doc, [model.selection("COMPSOLID", "Recover_2_1"), model.selection("SOLID", "Cut_1_1")], keepSubResults = True)
+model.end()
+
+Fuse_objects = [model.selection("SOLID", "Partition_2_1_14"), model.selection("SOLID", "Partition_2_1_25"), model.selection("SOLID", "Partition_2_1_24")]
+
+
+import time
+
+tStart = time.time()
+
+model.begin()
+Union_1 = model.addUnion(Part_1_doc, Fuse_objects, keepSubResults = True)
+model.do()
+
+tUnion = time.time() - tStart
+
+model.testNbResults(Union_1, 1)
+model.testNbSubResults(Union_1, [23])
+model.testNbSubShapes(Union_1, GeomAPI_Shape.SOLID, [23])
+model.testNbSubShapes(Union_1, GeomAPI_Shape.FACE, [139])
+model.testNbSubShapes(Union_1, GeomAPI_Shape.EDGE, [550])
+model.testNbSubShapes(Union_1, GeomAPI_Shape.VERTEX, [1100])
+model.testResultsVolumes(Union_1, [0.78640233633346512398532])
+
+model.begin()
+Part_1_doc.removeFeature(Union_1.feature())
+model.end()
+
+tStart = time.time()
+
+model.begin()
+Fuse_1 = model.addFuse(Part_1_doc, Fuse_objects, keepSubResults = True)
+model.do()
+
+tFuse = time.time() - tStart
+
+model.testNbResults(Fuse_1, 1)
+model.testNbSubResults(Fuse_1, [23])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [23])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [139])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [550])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [1100])
+model.testResultsVolumes(Fuse_1, [0.78640233633346512398532])
+
+print("Elapsed time of Union: {}".format(tUnion))
+print("Elapsed time of Fuse: {}".format(tFuse))
+
+assert(tFuse <= tUnion * 1.5)
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 e19da51a6a031e6f0a7549732910b42e46208a44..54e0f6fd4c6b760179258debf9e67e193d898b44 100644 (file)
@@ -64,7 +64,7 @@ SketchCircle_3 = Sketch_3.addCircle(7, 2, 1.5)
 ExtrusionCut_3.setNestedSketch(Sketch_3)
 model.do()
 Shape = ExtrusionCut_3.results()[0].resultSubShapePair()[0].shape()
-checkMiddlePoint(Shape, 5.00008072, 5.079732577, 5.08050677)
+checkMiddlePoint(Shape, 5.00008072, 5.079732786, 5.08050663)
 
 model.end()
 
index 588e75f171b3e148a069b6328ab526bf6e57ba0f..ee57d7af9c416d4c2102f06694671f0ebf7d68ae 100644 (file)
@@ -125,7 +125,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0])
 model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [4])
 model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [16])
 model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [32])
-model.testResultsVolumes(Extrusion_1, [10769.186376787])
+model.testResultsVolumes(Extrusion_1, [5169.186376787])
 
 ParamFrom.setValue(-20)
 model.do()
@@ -135,7 +135,7 @@ model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [0])
 model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [4])
 model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [16])
 model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [32])
-model.testResultsVolumes(Extrusion_1, [5169.186376787])
+model.testResultsVolumes(Extrusion_1, [10769.186376787])
 
 model.testHaveNamingSubshapes(Extrusion_1, model, Part_1_doc)
 
index 421292b0bf65833b3227b8bab4ca254c28e3766f..fb8e2a344b707376d72df48edb52804796a2e7bf 100644 (file)
@@ -8,26 +8,22 @@ Features plug-in provides a set of common topological operations. It implements
 
 .. toctree::
    :titlesonly:
-   :maxdepth: 1
+   :maxdepth: 2
 
+   booleanOperations.rst
    angularCopyFeature.rst
    chamferFeature.rst
-   commonFeature.rst
    copyFeature.rst
-   cutFeature.rst
    defeaturingFeature.rst
    extrusionCutFeature.rst
    extrusionFeature.rst
    extrusionFuseFeature.rst
    fillet1dFeature.rst
    filletFeature.rst
-   fuseFeature.rst
    fuseFeatureFaces.rst
    importResultFeature.rst
-   intersectionFeature.rst
    linearCopyFeature.rst
    measurementFeature.rst
-   partitionFeature.rst
    pipeFeature.rst
    placementFeature.rst
    recoverFeature.rst
@@ -36,9 +32,6 @@ Features plug-in provides a set of common topological operations. It implements
    revolutionFeature.rst
    revolutionFuseFeature.rst
    rotationFeature.rst
-   smashFeature.rst
-   splitFeature.rst
    symmetryFeature.rst
    transformationFeature.rst
    translationFeature.rst
-   unionFeature.rst
diff --git a/src/FeaturesPlugin/doc/booleanArguments.rst b/src/FeaturesPlugin/doc/booleanArguments.rst
new file mode 100644 (file)
index 0000000..ad2f3c3
--- /dev/null
@@ -0,0 +1,70 @@
+.. |common.icon|    image:: images/bool_common.png
+   :height: 16px
+.. |cut.icon|    image:: images/bool_cut.png
+   :height: 16px
+.. |fuse.icon|    image:: images/bool_fuse.png
+   :height: 16px
+.. |smash.icon|    image:: images/bool_smash.png
+   :height: 16px
+.. |split.icon|    image:: images/bool_split.png
+   :height: 16px
+.. |partition.icon|    image:: images/partition_btn.png
+   :height: 16px
+.. |inter.icon|    image:: images/intersection_btn.png
+   :height: 16px
+.. |union.icon|    image:: images/union_btn.png
+   :height: 16px
+
+
+.. _bopArguments:
+
+Arguments of Boolean Operations
+===============================
+
+This section describes the shapes applicable as arguments of Boolean Operations.
+First of all, the result of Boolean Operations depends on the dimension of arguments. The following table shows the dimension and corresponding types of shapes.
+
++-----------+----------------------------+
+| Dimension | Shape types                |
++===========+============================+
+|     0     | VERTEX, COMPOUND           |
++-----------+----------------------------+
+|     1     | EDGE, WIRE, COMPOUND       |
++-----------+----------------------------+
+|     2     | FACE, SHELL, COMPOUND      |
++-----------+----------------------------+
+|     3     | SOLID, COMPSOLID, COMPOUND |
++-----------+----------------------------+
+
+*Note*: COMPOUND may consist of any shape combinations, therefore, it is present is each row.
+
+The next table aligns an operation and the dimensions of its arguments.
+Construction planes (mentioned PLANE) can be used in several operations, but not included in the table above due to their infinite nature. 
+
++-------------------------+---------------------------+-------------------------+
+|      Operation          | Dimension of objects (DO) | Dimension of tools (DT) |
++=========================+===========================+=========================+
+| |common.icon|           |            Any            |      Any (+ PLANE)      |
+| :ref:`featureCommon`    |                           |                         |
++-------------------------+---------------------------+-------------------------+
+| |cut.icon|              |            Any            |  Not less than **DO**   |
+| :ref:`featureCut`       |                           |                         |
++-------------------------+---------------------------+-------------------------+
+| |fuse.icon|             |            Any            |          Any            |
+| :ref:`featureFuse`      |                           |                         |
++-------------------------+---------------------------+-------------------------+
+| |inter.icon|            |          1 or 2           |          ---            |
+| :ref:`featureIntersect` |                           |                         |
++-------------------------+---------------------------+-------------------------+
+| |partition.icon|        |       Any (+ PLANE)       |          ---            |
+| :ref:`featurePartition` |                           |                         |
++-------------------------+---------------------------+-------------------------+
+| |smash.icon|            | 2 (planar FACE only) or 3 |    Equal to **DO**      |
+| :ref:`featureSmash`     |                           |                         |
++-------------------------+---------------------------+-------------------------+
+| |split.icon|            |            Any            |      Any (+ PLANE)      |
+| :ref:`featureSplit`     |                           |                         |
++-------------------------+---------------------------+-------------------------+
+| |union.icon|            | 3 (SOLIDs from COMPSOLID) |          ---            |
+| :ref:`featureUnion`     |                           |                         |
++-------------------------+---------------------------+-------------------------+
diff --git a/src/FeaturesPlugin/doc/booleanOperations.rst b/src/FeaturesPlugin/doc/booleanOperations.rst
new file mode 100644 (file)
index 0000000..20a2268
--- /dev/null
@@ -0,0 +1,19 @@
+
+.. _booleanOperations:
+
+Boolean Operations
+==================
+
+.. toctree::
+   :titlesonly:
+   :maxdepth: 1
+
+   commonFeature.rst
+   cutFeature.rst
+   fuseFeature.rst
+   intersectionFeature.rst
+   partitionFeature.rst
+   smashFeature.rst
+   splitFeature.rst
+   unionFeature.rst
+   booleanArguments.rst
index 5216539fe740a9d63ccdd28b5dbd70892a5af50b..a63df77cde3807f9e462a5357456a6521d85a149 100644 (file)
@@ -72,10 +72,12 @@ Advanced
 - **Objects** contains a list of objects selected in the Object Browser or in the Viewer.
   If a subshape that belongs to a compsolid/compound was selected, other shapes of this compsolid/compound will be cut from
   other objects (to avoid self-intersection) and added to the result.
-- **Tools** contains a list of objects selected in the Object Browser or in the Viewer, which will be fused with tool objects.
-  If a subshape that belongs to a compsolid/compound was selected, other shapes of this compsolid/compound  will be ignored.
+- **Tools** contains a list of objects selected in the Object Browser or in the Viewer, which will be intersected with tool objects.
+  If a subshape that belongs to a compsolid/compound was selected, other shapes of this compsolid/compound will be ignored.
 - **See preview** button shows a result of the operation.
 
+Any kind of shape is supported as an object or a tool of Common. Moreover, constructions planes can be selected as tools.
+
 **TUI Command**:
 
 .. py:function:: model.addCommon(Part_doc, objects, tools)
index 08e87586c25df7ccdc1c98f917e262069a6c4115..9ce390dbedba97e2dc95eb56f0d5f133f23368d9 100644 (file)
@@ -1,7 +1,8 @@
-.. _featureCut:
 .. |bool_cut.icon|    image:: images/bool_cut.png
    :height: 16px
 
+.. _featureCut:
+
 Cut
 ===
 
@@ -27,6 +28,8 @@ The following property panel will be opened:
   Non-selected subshapes from compsolids/compounds will be ignored.
 - **See preview** button shows a result of the operation.
 
+The minimal dimension of Tool Objects should be not less than the maximal dimension of Main Objects.
+
 **TUI Command**:
 
 .. py:function:: model.addCut(Part_doc, mainObjects, toolObjects)
index 3ff61a580c4d39d7fd537d39df89ab052f44eb70..e9fb6962038e9fab32b94eec145cfda863177b08 100644 (file)
@@ -1,6 +1,8 @@
 .. |bool_fuse.icon|    image:: images/bool_fuse.png
    :height: 16px
 
+.. _featureFuse:
+
 Fuse
 ====
 
@@ -35,8 +37,8 @@ Simple
 
    **Simple**
 
-- **Objects** - contains a list of objects selected in the Object Browser or in the Viewer, which will be fused with tool objects.
-  If a subshape that belongs to a compsolid/compound was selected, other shapes of this compsolid/compound will be ignored.
+- **Objects** - contains a list of objects selected in the Object Browser or in the Viewer, which will be fused to a single result.
+  If a subshape that belongs to a compsolid/compound was selected, other shapes of this compsolid/compound will cut the fuse shape then will be joined to the result.
 - **Remove intersection edges** -  if enabled, edges that lie on the same surface will be removed.
 - **See preview** - button shows a result of the operation.
 
index 6a3b5a67b40d615f71903761e29da278f7bba8d5..e4057a2d56d59162bb03ba492c9b4319fdbde5ce 100644 (file)
@@ -1,5 +1,7 @@
 .. |intersection_btn.icon|    image:: images/intersection_btn.png
 
+.. _featureIntersect:
+
 Intersection
 ============
 
@@ -19,6 +21,8 @@ The following property panel will be opened:
 
 **Objects** - contains a list of objects selected in the Object Browser or in the Viewer, which will be intersected.
 
+All intersected objects should be 1- or 2-dimensional (edges, faces, shells). However, it is allowed to select 3-dimensional objects, but only their shells will be taken into operation.
+
 **TUI Command**:
 
 .. py:function:: model.addIntersection(Part_doc, Objects)
index 14ee70b44e4bc4c21cc6ed318b4f8d0f7cdffb37..e549310d23a91213349f9609d1977891f1aad81c 100644 (file)
@@ -1,5 +1,7 @@
 .. |partition_btn.icon|    image:: images/partition_btn.png
 
+.. _featurePartition:
+
 Partition
 =========
 
@@ -17,7 +19,7 @@ The following property panel will be opened:
 
    **Partition operation**
 
-**Base Objects** contains a list of objects selected in the Object Browser or in the Viewer, which will be partitioned.
+**Base Objects** contains a list of objects selected in the Object Browser or in the Viewer, which will be partitioned. Constuction planes are allowed too if at least one non-construction entity is selected.
 
 **TUI Command**:
 
index 08dfc9ebeda5b1d52ccabb2813e9da92cec49f9a..2e3b45828ab3cf0674d2fce36972cb2afc3ffc1a 100644 (file)
@@ -1,6 +1,8 @@
 .. |bool_smash.icon|    image:: images/bool_smash.png
    :height: 16px
 
+.. _featureSmash:
+
 Smash
 =====
 
@@ -25,6 +27,8 @@ The following property panel will be opened:
   If a subshape that belongs to a compsolid/compound was selected, other shapes of this compsolid/compound will be ignored.
 - **See preview** button shows a result of the operation.
 
+Main objects and Tools objects should have the same dimension. There are supported 2-dimensional (face) or 3-dimensional (solid, compsolid) arguments.
+
 **TUI Command**:
 
 .. py:function:: model.addSmash(Part_doc, mainObjects, toolObjects)
index ec962928e973fbf711a10be03954b2c73553c313..61970dcd596df7e8c9e09443c7426ee6cdd67e27 100644 (file)
@@ -1,6 +1,8 @@
 .. |bool_split.icon|    image:: images/bool_split.png
    :height: 16px
 
+.. _featureSplit:
+
 Split
 =====
 
@@ -19,7 +21,7 @@ The following property panel will be opened:
    **Split operation**
 
 - **Main Objects** contains a list of objects selected in the Object Browser or in the Viewer, which will be cut and splitted by tool objects.
-- **Tool Objects** contains a list of objects selected in the Object Browser or in the Viewer, which will cut and split the main objects.
+- **Tool Objects** contains a list of objects selected in the Object Browser or in the Viewer, which will cut and split the main objects. Construction planes may be selected too.
 - **See preview** button shows a result of the operation.
 
 **TUI Command**:
index 989e9368477b16828be907694cf6a4171f46bf79..9847642861d1b33872d3dba9a5149dc500796708 100644 (file)
@@ -1,8 +1,12 @@
 .. |union_btn.icon|    image:: images/union_btn.png
 
+.. _featureUnion:
+
 Union
 =====
 
+**Caution**. This operation is obsolete. Fuse operation should be used instead.
+
 Union feature implements a Boolean operation for creation of a union of selected objects.
 
 To create a Union in the active part:
index 0a336c3981da3570c8c9751cfba679a75f9161a8..ba80beedda3367cc8fef29f58ce5dc4bcafa7734 100644 (file)
@@ -81,7 +81,7 @@
           <source path="boolean_split_widget.xml"/>
       </feature>
       <feature id="Union" title="Union" tooltip="Perform union operations with shapes"
-               icon="icons/Features/union.png" helpfile="unionFeature.html">
+               icon="icons/Features/union.png" helpfile="unionFeature.html" internal="1">
           <source path="union_widget.xml"/>
       </feature>
       <feature id="Remove_SubShapes" title="Remove Sub-Shapes" tooltip="Allows to remove sub-shapes from wires, shells, compsolids and compounds"
index bcec89ff8596a27feb4078ea33c1a290976dea7c..1c9bca5922e61a9fc274b9b8c2c653d151363ce6 100644 (file)
@@ -122,8 +122,10 @@ ADD_UNIT_TESTS(
   TestFilter_BelongsTo_Exclude.py
   TestFilter_OnPlane.py
   TestFilter_OnPlane_Exclude.py
+  TestFilter_OnPlane_Multi.py
   TestFilter_OnLine.py
   TestFilter_OnLine_Exclude.py
+  TestFilter_OnLine_Multi.py
   TestFilter_OnGeometry_Edge1.py
   TestFilter_OnGeometry_Edge2.py
   TestFilter_OnGeometry_Face1.py
@@ -140,6 +142,7 @@ ADD_UNIT_TESTS(
   TestFilter_OnPlaneSide_Plane.py
   TestFilter_OnPlaneSide_Exclude_Face.py
   TestFilter_OnPlaneSide_Exclude_Plane.py
+  TestFilter_OnPlaneSide_Multi.py
   TestFilter_OppositeToEdge.py
   TestFilter_OppositeToEdge_Exclude.py
   TestFilter_RelativeToSolid_In.py
@@ -154,6 +157,7 @@ ADD_UNIT_TESTS(
   TestFilter_RelativeToSolid_Exclude_NotOn.py
   TestFilter_RelativeToSolid_Exclude_InAndOn.py
   TestFilter_RelativeToSolid_Exclude_OutAndOn.py
+  TestFilter_RelativeToSolid_Multi.py
   TestFilter_ExternalFaces1.py
   TestFilter_ExternalFaces2.py
   TestFilter_ExternalFaces_Exclude1.py
@@ -198,13 +202,11 @@ ADD_UNIT_TESTS(
   TestFilter_TopoConnectedFaces_Prop_Exclude_Face1.py
   TestFilter_TopoConnectedFaces_Prop_Exclude_Face2.py
   TestFilter_TopoConnectedFaces_Prop_Exclude_Face3.py
+  TestFilter_TopoConnectedFaces_Multi.py
   Test2946.py
   Test2951.py
+  Test3241.py
   Test17924.py
   Test17962.py
-  TestFilter_OnLine_Multi.py
-  TestFilter_OnPlane_Multi.py
-  TestFilter_OnPlaneSide_Multi.py
-  TestFilter_RelativeToSolid_Multi.py
-  TestFilter_TopoConnectedFaces_Multi.py
+  Test19190.py
 )
diff --git a/src/FiltersPlugin/Test/Test19190.py b/src/FiltersPlugin/Test/Test19190.py
new file mode 100644 (file)
index 0000000..961708a
--- /dev/null
@@ -0,0 +1,82 @@
+# 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 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(87.62648221343873, 42.39493620569578, -76.44861660079052, 42.39493620569578)
+SketchLine_2 = Sketch_1.addLine(-76.44861660079052, 42.39493620569578, -76.44861660079052, -42.23747486149789)
+SketchLine_3 = Sketch_1.addLine(-76.44861660079052, -42.23747486149789, 87.62648221343873, -42.23747486149789)
+SketchLine_4 = Sketch_1.addLine(87.62648221343873, -42.23747486149789, 87.62648221343873, 42.39493620569578)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchLine_5 = Sketch_1.addLine(-32.93478260869566, 42.39493620569578, -17.36561264822134, -42.23747486149789)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.startPoint(), SketchLine_1.result())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_3.result())
+SketchLine_6 = Sketch_1.addLine(34.93083003952569, -42.23747486149789, 44.11264822134387, 42.39493620569579)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_6.startPoint(), SketchLine_3.result())
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_1.result())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "all-in-Sketch_1")], model.selection(), 100, 0)
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 35, 120)
+Fuse_1_objects_1 = [model.selection("SOLID", "Extrusion_1_1_1"), model.selection("SOLID", "Cylinder_1_1"), model.selection("SOLID", "Extrusion_1_1_3")]
+Fuse_1 = model.addFuse(Part_1_doc, Fuse_1_objects_1, removeEdges = True, keepSubResults = True)
+Fuse_1.result().setColor(76, 76, 153)
+Fuse_1.result().subResult(0).setColor(254, 127, 127)
+Fuse_1.result().subResult(1).setColor(153, 153, 76)
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "Fuse_1_1_2/Modified_Face&Sketch_1/SketchLine_2"), 75, True)
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "RelativeToSolid", args = [model.selection("SOLID", "Fuse_1_1_2"), "on"])])
+model.end()
+
+from GeomAPI import *
+
+model.testNbResults(Fuse_1, 1)
+model.testNbSubResults(Fuse_1, [2])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [14])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [54])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [108])
+model.testResultsVolumes(Fuse_1, [1465576.14])
+
+solid1 = Fuse_1.result().subResult(0).resultSubShapePair()[0]
+solid2 = Fuse_1.result().subResult(1).resultSubShapePair()[0]
+
+Reference = {}
+exp = GeomAPI_ShapeExplorer(solid1.shape(), GeomAPI_Shape.FACE)
+Reference[model.selection(solid1, exp.current())] = False; exp.next()
+Reference[model.selection(solid1, exp.current())] = True;  exp.next()
+while exp.more():
+    Reference[model.selection(solid1, exp.current())] = False
+    exp.next()
+exp = GeomAPI_ShapeExplorer(solid2.shape(), GeomAPI_Shape.FACE)
+while exp.more():
+    Reference[model.selection(solid1, exp.current())] = True
+    exp.next()
+
+model.checkFilter(Part_1_doc, model, Filters, Reference)
diff --git a/src/FiltersPlugin/Test/Test3241.py b/src/FiltersPlugin/Test/Test3241.py
new file mode 100644 (file)
index 0000000..ea375c2
--- /dev/null
@@ -0,0 +1,74 @@
+# 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()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 40)
+model.do()
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f"), 10, False)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Plane_1"))
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "Sketch_1/SketchCircle_1"), True)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchCircle_2 = Sketch_2.addCircle(0, 0, 50)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchCircle_2.center())
+SketchConstraintRadius_2 = Sketch_2.setRadius(SketchCircle_2.results()[1], 50)
+model.do()
+Plane_5 = model.addPlane(Part_1_doc, model.selection("FACE", "Plane_1"), 10, False)
+Sketch_3 = model.addSketch(Part_1_doc, model.selection("FACE", "Plane_2"))
+SketchProjection_3 = Sketch_3.addProjection(model.selection("VERTEX", "Sketch_1/SketchCircle_1"), True)
+SketchPoint_3 = SketchProjection_3.createdFeature()
+SketchCircle_3 = Sketch_3.addCircle(0, 0, 53)
+SketchConstraintCoincidence_3 = Sketch_3.setCoincident(SketchAPI_Point(SketchPoint_3).coordinates(), SketchCircle_3.center())
+SketchConstraintRadius_3 = Sketch_3.setRadius(SketchCircle_3.results()[1], 53)
+model.do()
+Filling_1_objects = [model.selection("EDGE", "Sketch_1/SketchCircle_1_2"), model.selection("EDGE", "Sketch_2/SketchCircle_2_2"), model.selection("EDGE", "Sketch_3/SketchCircle_3_2")]
+Filling_1 = model.addFilling(Part_1_doc, Filling_1_objects)
+Sketch_4 = model.addSketch(Part_1_doc, model.standardPlane("XOY"))
+SketchProjection_4 = Sketch_4.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_4 = SketchProjection_4.createdFeature()
+SketchProjection_5 = Sketch_4.addProjection(model.selection("EDGE", "PartSet/OX"), True)
+SketchLine_1 = SketchProjection_5.createdFeature()
+SketchMultiRotation_1 = Sketch_4.addRotation([SketchLine_1.result()], SketchAPI_Point(SketchPoint_4).coordinates(), 360, 12, True)
+[SketchLine_1, SketchLine_2, SketchLine_3, SketchLine_4, SketchLine_5, SketchLine_6, SketchLine_7, SketchLine_8, SketchLine_9, SketchLine_10, SketchLine_11, SketchLine_12] = SketchMultiRotation_1.rotated()
+model.do()
+Edge_1 = model.addEdge(Part_1_doc, [model.selection("COMPOUND", "Sketch_4")], False)
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "all-in-Edge_1")], model.selection(), model.selection("FACE", "Plane_2"), 0, model.selection(), 0)
+Split_1 = model.addSplit(Part_1_doc, [model.selection("FACE", "Filling_1_1")], [model.selection("COMPOUND", "Extrusion_1_1")], keepSubResults = True)
+FilterFace = model.filters(Part_1_doc, [model.addFilter(name = "OnGeometry", args = [model.selection("FACE", "Split_1_1_1")])])
+model.end()
+
+Reference = {}
+ResultSplit = Split_1.result().resultSubShapePair()[0]
+exp = GeomAPI_ShapeExplorer(ResultSplit.shape(), GeomAPI_Shape.FACE)
+while exp.more():
+    Reference[model.selection(ResultSplit, exp.current())] = True
+    exp.next()
+model.checkFilter(Part_1_doc, model, FilterFace, Reference)
index fd63d7a3add378e70ccbac5e0c7db6f1221ef36d..81b67a1dac2bf5debdb1c124ef9cc961daf5d8a6 100644 (file)
@@ -5,8 +5,8 @@
 
 .. _filtersPlugin:
 
-Filters Plugin
-==============
+Filters plug-in
+===============
 
 Filters plug-in provides a collection of filters used Filters property panel (for example see :ref:`groupPage` feature).
 
index 5835d9707d4a06a278429c48375e45382ab0f91f..a5bd94a16b38f853ccd561543c3acf0e5db717fe 100644 (file)
@@ -48,8 +48,15 @@ static Handle_Geom2d_BSplineCurve* newBSpline2d(
     return newBSpline2d(thePoles, theWeights, theDegree, thePeriodic);
 
   int anAuxPole = 0;
-  if (thePeriodic && thePoles.front()->distance(thePoles.back()) < Precision::Confusion())
-    anAuxPole = -1;
+  if (thePeriodic && thePoles.front()->distance(thePoles.back()) < Precision::Confusion()) {
+    // additionally check the number of poles is greater than needed for th periodic B-spline
+    int aNbPoles = 0;
+    std::list<int>::const_iterator it = theMults.begin();
+    for (++it; it != theMults.end(); ++it)
+      aNbPoles += *it;
+    if ((int)thePoles.size() > aNbPoles)
+      anAuxPole = -1;
+  }
 
   // collect arrays of poles, weights, knots and multiplicities
   TColgp_Array1OfPnt2d aPoles(1, (int)thePoles.size() + anAuxPole);
index 23f18f5dcfeb4de981bcdbd9abcd2beb377d8f4e..76f33970b3bb47c4d2753b79e755a5e8b359115e 100644 (file)
@@ -28,6 +28,8 @@
 #include "GeomAPI_Cone.h"
 #include "GeomAPI_Torus.h"
 
+#include <Bnd_Box2d.hxx>
+#include <BndLib_Add2dCurve.hxx>
 #include <BOPTools_AlgoTools.hxx>
 #include <BRep_Tool.hxx>
 #include <BRepAdaptor_Surface.hxx>
@@ -59,6 +61,9 @@
 #include <gp_Cone.hxx>
 #include <gp_Torus.hxx>
 
+static void optimalBounds(const TopoDS_Face& theFace, double& theUMin, double& theUMax,
+                                                      double& theVMin, double& theVMax);
+
 
 GeomAPI_Face::GeomAPI_Face()
   : GeomAPI_Shape()
@@ -144,6 +149,8 @@ bool GeomAPI_Face::isSameGeometry(const std::shared_ptr<GeomAPI_Shape> theShape)
 
   Handle(Geom_Surface) anOwnSurf = baseSurface(anOwnFace);
   Handle(Geom_Surface) anOtherSurf = baseSurface(anOtherFace);
+  if (anOwnSurf == anOtherSurf)
+    return true;
 
   // case of two elementary surfaces
   if (anOwnSurf->IsKind(STANDARD_TYPE(Geom_ElementarySurface)) &&
@@ -358,9 +365,8 @@ GeomPointPtr GeomAPI_Face::middlePoint() const
   if (aFace.IsNull())
     return anInnerPoint;
 
-  BRepGProp_Face aProp(aFace);
   double aUMin, aUMax, aVMin, aVMax;
-  aProp.Bounds(aUMin, aUMax, aVMin, aVMax);
+  optimalBounds(aFace, aUMin, aUMax, aVMin, aVMax);
 
   Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace);
   if (aSurf.IsNull())
@@ -370,3 +376,212 @@ GeomPointPtr GeomAPI_Face::middlePoint() const
   anInnerPoint = GeomPointPtr(new GeomAPI_Pnt(aPnt.X(), aPnt.Y(), aPnt.Z()));
   return anInnerPoint;
 }
+
+
+// ==================     Auxiliary functions     ========================
+
+void optimalBounds(const TopoDS_Face& theFace, const TopoDS_Edge& theEdge, Bnd_Box2d& theBndBox)
+{
+  Standard_Real aFirst, aLast;
+  const Handle(Geom2d_Curve) aC2D = BRep_Tool::CurveOnSurface(theEdge, theFace, aFirst, aLast);
+  if (aC2D.IsNull())
+    return;
+
+  Standard_Real aXmin = 0.0, aYmin = 0.0, aXmax = 0.0, aYmax = 0.0;
+  Standard_Real aUmin, aUmax, aVmin, aVmax;
+  Bnd_Box2d aBoxC, aBoxS;
+  BndLib_Add2dCurve::AddOptimal(aC2D, aFirst, aLast, 0., aBoxC);
+  if (aBoxC.IsVoid())
+    return;
+
+  aBoxC.Get(aXmin, aYmin, aXmax, aYmax);
+
+  TopLoc_Location aLoc;
+  Handle(Geom_Surface) aS = BRep_Tool::Surface(theFace, aLoc);
+  aS->Bounds(aUmin, aUmax, aVmin, aVmax);
+
+  if (aS->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface))
+  {
+    const Handle(Geom_RectangularTrimmedSurface) aSt =
+        Handle(Geom_RectangularTrimmedSurface)::DownCast(aS);
+    aS = aSt->BasisSurface();
+  }
+
+  //
+  if (!aS->IsUPeriodic())
+  {
+    Standard_Boolean isUPeriodic = Standard_False;
+
+    // Additional verification for U-periodicity for B-spline surfaces.
+    // 1. Verify that the surface is U-closed (if such flag is false). Verification uses 2 points.
+    // 2. Verify periodicity of surface inside UV-bounds of the edge. It uses 3 or 6 points.
+    if (aS->DynamicType() == STANDARD_TYPE(Geom_BSplineSurface) &&
+      (aXmin < aUmin || aXmax > aUmax))
+    {
+      Standard_Real aTol2 = 100 * Precision::SquareConfusion();
+      isUPeriodic = Standard_True;
+      gp_Pnt P1, P2;
+      // 1. Verify that the surface is U-closed
+      if (!aS->IsUClosed())
+      {
+        Standard_Real aVStep = aVmax - aVmin;
+        for (Standard_Real aV = aVmin; aV <= aVmax; aV += aVStep)
+        {
+          P1 = aS->Value(aUmin, aV);
+          P2 = aS->Value(aUmax, aV);
+          if (P1.SquareDistance(P2) > aTol2)
+          {
+            isUPeriodic = Standard_False;
+            break;
+          }
+        }
+      }
+      // 2. Verify periodicity of surface inside UV-bounds of the edge
+      if (isUPeriodic) // the flag still not changed
+      {
+        Standard_Real aV = (aVmin + aVmax) * 0.5;
+        Standard_Real aU[6]; // values of U lying out of surface boundaries
+        Standard_Real aUpp[6]; // corresponding U-values plus/minus period
+        Standard_Integer aNbPnt = 0;
+        if (aXmin < aUmin)
+        {
+          aU[0] = aXmin;
+          aU[1] = (aXmin + aUmin) * 0.5;
+          aU[2] = aUmin;
+          aUpp[0] = aU[0] + aUmax - aUmin;
+          aUpp[1] = aU[1] + aUmax - aUmin;
+          aUpp[2] = aU[2] + aUmax - aUmin;
+          aNbPnt += 3;
+        }
+        if (aXmax > aUmax)
+        {
+          aU[aNbPnt] = aUmax;
+          aU[aNbPnt + 1] = (aXmax + aUmax) * 0.5;
+          aU[aNbPnt + 2] = aXmax;
+          aUpp[aNbPnt] = aU[aNbPnt] - aUmax + aUmin;
+          aUpp[aNbPnt + 1] = aU[aNbPnt + 1] - aUmax + aUmin;
+          aUpp[aNbPnt + 2] = aU[aNbPnt + 2] - aUmax + aUmin;
+          aNbPnt += 3;
+        }
+        for (Standard_Integer anInd = 0; anInd < aNbPnt; anInd++)
+        {
+          P1 = aS->Value(aU[anInd], aV);
+          P2 = aS->Value(aUpp[anInd], aV);
+          if (P1.SquareDistance(P2) > aTol2)
+          {
+            isUPeriodic = Standard_False;
+            break;
+          }
+        }
+      }
+    }
+
+    if (!isUPeriodic)
+    {
+      if ((aXmin < aUmin) && (aUmin < aXmax))
+      {
+        aXmin = aUmin;
+      }
+      if ((aXmin < aUmax) && (aUmax < aXmax))
+      {
+        aXmax = aUmax;
+      }
+    }
+  }
+
+  if (!aS->IsVPeriodic())
+  {
+    Standard_Boolean isVPeriodic = Standard_False;
+
+    // Additional verification for V-periodicity for B-spline surfaces.
+    // 1. Verify that the surface is V-closed (if such flag is false). Verification uses 2 points.
+    // 2. Verify periodicity of surface inside UV-bounds of the edge. It uses 3 or 6 points.
+    if (aS->DynamicType() == STANDARD_TYPE(Geom_BSplineSurface) &&
+      (aYmin < aVmin || aYmax > aVmax))
+    {
+      Standard_Real aTol2 = 100 * Precision::SquareConfusion();
+      isVPeriodic = Standard_True;
+      gp_Pnt P1, P2;
+      // 1. Verify that the surface is V-closed
+      if (!aS->IsVClosed())
+      {
+        Standard_Real aUStep = aUmax - aUmin;
+        for (Standard_Real aU = aUmin; aU <= aUmax; aU += aUStep)
+        {
+          P1 = aS->Value(aU, aVmin);
+          P2 = aS->Value(aU, aVmax);
+          if (P1.SquareDistance(P2) > aTol2)
+          {
+            isVPeriodic = Standard_False;
+            break;
+          }
+        }
+      }
+      // 2. Verify periodicity of surface inside UV-bounds of the edge
+      if (isVPeriodic) // the flag still not changed
+      {
+        Standard_Real aU = (aUmin + aUmax) * 0.5;
+        Standard_Real aV[6]; // values of V lying out of surface boundaries
+        Standard_Real aVpp[6]; // corresponding V-values plus/minus period
+        Standard_Integer aNbPnt = 0;
+        if (aYmin < aVmin)
+        {
+          aV[0] = aYmin;
+          aV[1] = (aYmin + aVmin) * 0.5;
+          aV[2] = aVmin;
+          aVpp[0] = aV[0] + aVmax - aVmin;
+          aVpp[1] = aV[1] + aVmax - aVmin;
+          aVpp[2] = aV[2] + aVmax - aVmin;
+          aNbPnt += 3;
+        }
+        if (aYmax > aVmax)
+        {
+          aV[aNbPnt] = aVmax;
+          aV[aNbPnt + 1] = (aYmax + aVmax) * 0.5;
+          aV[aNbPnt + 2] = aYmax;
+          aVpp[aNbPnt] = aV[aNbPnt] - aVmax + aVmin;
+          aVpp[aNbPnt + 1] = aV[aNbPnt + 1] - aVmax + aVmin;
+          aVpp[aNbPnt + 2] = aV[aNbPnt + 2] - aVmax + aVmin;
+          aNbPnt += 3;
+        }
+        for (Standard_Integer anInd = 0; anInd < aNbPnt; anInd++)
+        {
+          P1 = aS->Value(aU, aV[anInd]);
+          P2 = aS->Value(aU, aVpp[anInd]);
+          if (P1.SquareDistance(P2) > aTol2)
+          {
+            isVPeriodic = Standard_False;
+            break;
+          }
+        }
+      }
+    }
+
+    if (!isVPeriodic)
+    {
+      if ((aYmin < aVmin) && (aVmin < aYmax))
+      {
+        aYmin = aVmin;
+      }
+      if ((aYmin < aVmax) && (aVmax < aYmax))
+      {
+        aYmax = aVmax;
+      }
+    }
+  }
+
+  aBoxS.Update(aXmin, aYmin, aXmax, aYmax);
+
+  theBndBox.Add(aBoxS);
+}
+
+void optimalBounds(const TopoDS_Face& theFace, double& theUMin, double& theUMax,
+                                               double& theVMin, double& theVMax)
+{
+  Bnd_Box2d aBB;
+
+  for (TopExp_Explorer anExp(theFace, TopAbs_EDGE); anExp.More(); anExp.Next())
+    optimalBounds(theFace, TopoDS::Edge(anExp.Current()), aBB);
+
+  aBB.Get(theUMin, theVMin, theUMax, theVMax);
+}
index 99d21c30741cc5a9d7e0f54221b6b3c07eca86a2..4ddbe474e83b8a396880f1cf503837213033f630 100644 (file)
@@ -46,6 +46,7 @@
 #include <Geom_Plane.hxx>
 #include <Geom_RectangularTrimmedSurface.hxx>
 #include <Geom_TrimmedCurve.hxx>
+#include <GeomLib_IsPlanarSurface.hxx>
 #include <TopExp_Explorer.hxx>
 #include <TopoDS.hxx>
 #include <TopoDS_Iterator.hxx>
@@ -287,15 +288,13 @@ bool GeomAPI_Shape::isPlanar() const
   if(aShapeType == TopAbs_VERTEX) {
     return true;
   } else if(aShapeType == TopAbs_FACE) {
-    const Handle(Geom_Surface)& aSurface = BRep_Tool::Surface(TopoDS::Face(aShape));
-    Handle(Standard_Type) aType = aSurface->DynamicType();
-
-    if(aType == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) {
+    Handle(Geom_Surface) aSurface = BRep_Tool::Surface(TopoDS::Face(aShape));
+    if(aSurface->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) {
       Handle(Geom_RectangularTrimmedSurface) aTrimSurface =
-        Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurface);
-      aType = aTrimSurface->BasisSurface()->DynamicType();
+          Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurface);
+      aSurface = aTrimSurface->BasisSurface();
     }
-    return (aType == STANDARD_TYPE(Geom_Plane)) == Standard_True;
+    return GeomLib_IsPlanarSurface(aSurface).IsPlanar();
   } else {
     BRepBuilderAPI_FindPlane aFindPlane(aShape);
     bool isFound = aFindPlane.Found() == Standard_True;
index 042b9d5c320297662fa9524d361af47b965642f7..43a43e7eb772a0cf4fef4fb13aa1a8cb9477cc98 100644 (file)
 #include <gp_Pnt.hxx>
 #include <Precision.hxx>
 
+static TopoDS_Shape* buildVertex(const gp_Pnt& thePoint)
+{
+  TopoDS_Vertex aVertex;
+  BRep_Builder aBuilder;
+  aBuilder.MakeVertex(aVertex, thePoint, Precision::Confusion());
+  return new TopoDS_Shape(aVertex);
+}
+
 GeomAPI_Vertex::GeomAPI_Vertex()
   : GeomAPI_Shape()
 {
@@ -41,12 +49,14 @@ GeomAPI_Vertex::GeomAPI_Vertex(const std::shared_ptr<GeomAPI_Shape>& theShape)
   }
 }
 
+GeomAPI_Vertex::GeomAPI_Vertex(const std::shared_ptr<GeomAPI_Pnt>& thePoint)
+{
+  setImpl(buildVertex(thePoint->impl<gp_Pnt>()));
+}
+
 GeomAPI_Vertex::GeomAPI_Vertex(double theX, double theY, double theZ)
 {
-  TopoDS_Vertex aVertex;
-  BRep_Builder aBuilder;
-  aBuilder.MakeVertex(aVertex, gp_Pnt(theX, theY, theZ), Precision::Confusion());
-  setImpl(new TopoDS_Shape(aVertex));
+  setImpl(buildVertex(gp_Pnt(theX, theY, theZ)));
 }
 
 std::shared_ptr<GeomAPI_Pnt> GeomAPI_Vertex::point()
index cded80618ff744e9a6b0aebf3b97e70f2dfdba2b..53aed1f9135ce6af2680fbc4c661662619f838ed 100644 (file)
@@ -38,6 +38,10 @@ public:
   GEOMAPI_EXPORT
   GeomAPI_Vertex(const std::shared_ptr<GeomAPI_Shape>& theShape);
 
+  /// Creation of vertex by the given point.
+  GEOMAPI_EXPORT
+  GeomAPI_Vertex(const std::shared_ptr<GeomAPI_Pnt>& thePoint);
+
    /// Creation of vertex by 3d coordinates.
   GEOMAPI_EXPORT
   GeomAPI_Vertex(double theX, double theY, double theZ);
index 120917cb3ee28f3c59833a58867d7f13aed0edd1..9af92e6f922bbd8d4e38f20b4cede60a7f48ad2b 100644 (file)
@@ -110,6 +110,10 @@ void GeomAlgoAPI_Boolean::build(const ListOfShape& theObjects,
   Standard_Boolean bRunParallel = Standard_True;
   aBuilder->SetRunParallel(bRunParallel);
 
+  // Set fuzzy value to eliminate thin results
+  static const Standard_Real aFuzzy = 1.e-5;
+  aBuilder->SetFuzzyValue(aFuzzy);
+
   // Building and getting result.
   aBuilder->Perform();
   if (aBuilder->HasErrors())
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()));
   }
index 867bb355bc962e30ca001226ccf8625f911761a9..6e1abc12816f2bc2c8903f494300f3df97801bed 100644 (file)
@@ -202,7 +202,7 @@ static void sortAreas(TopTools_ListOfShape& theAreas,
 
 void GeomAlgoAPI_SketchBuilder::build(
     const std::shared_ptr<GeomAPI_Pnt>& theOrigin,
-    const std::shared_ptr<GeomAPI_Dir>& /*theDirX*/,
+    const std::shared_ptr<GeomAPI_Dir>& theDirX,
     const std::shared_ptr<GeomAPI_Dir>& theNorm,
     const std::list<std::shared_ptr<GeomAPI_Shape> >& theEdges)
 {
@@ -213,7 +213,8 @@ void GeomAlgoAPI_SketchBuilder::build(
 
   BRep_Builder aBuilder;
   // Planar face, where the sketch was built
-  Handle(Geom_Surface) aPlane(new Geom_Plane(theOrigin->impl<gp_Pnt>(), theNorm->impl<gp_Dir>()));
+  gp_Ax3 aPlnAxes(theOrigin->impl<gp_Pnt>(), theNorm->impl<gp_Dir>(), theDirX->impl<gp_Dir>());
+  Handle(Geom_Surface) aPlane(new Geom_Plane(aPlnAxes));
   TopoDS_Face aPlnFace;
   aBuilder.MakeFace(aPlnFace, aPlane, Precision::Confusion());
 
@@ -221,8 +222,8 @@ void GeomAlgoAPI_SketchBuilder::build(
   BOPAlgo_Builder* aBB = new BOPAlgo_Builder;
   aBB->AddArgument(aPlnFace);
   // Set fuzzy value for BOP, because PlaneGCS can solve the set of constraints with
-  // the precision up to 1e-5 if the sketch contains arcs.
-  static const double THE_FUZZY_TOL = 1.e-5;
+  // the precision up to 5.e-5 if the sketch contains arcs.
+  static const double THE_FUZZY_TOL = 5.e-5;
   aBB->SetFuzzyValue(THE_FUZZY_TOL);
 
   setImpl(aBB);
index 7034eb3191ac69f1be6561c7bcbf8dbaa7536593..9e49e502d87c16ab2640528df765721658dbd82a 100644 (file)
@@ -26,6 +26,8 @@
 #include <BRep_Tool.hxx>
 #include <BRepAdaptor_Curve.hxx>
 #include <BRepAdaptor_Surface.hxx>
+#include <BRepBuilderAPI_MakeVertex.hxx>
+#include <BRepClass_FaceClassifier.hxx>
 #include <BRepClass3d_SolidClassifier.hxx>
 #include <BRepExtrema_DistShapeShape.hxx>
 #include <TopoDS.hxx>
@@ -58,7 +60,20 @@ classifyMiddlePoint(BRepClass3d_SolidClassifier& theClassifier,
                     const double theTolerance)
 {
   GeomPointPtr aMiddlePoint = theShape->middlePoint();
-  theClassifier.Perform(aMiddlePoint->impl<gp_Pnt>(), theTolerance);
+  gp_Pnt aPointOnFace = aMiddlePoint->impl<gp_Pnt>();
+  if (theShape->shapeType() == GeomAPI_Shape::FACE) {
+    // middle point may be out of face (within a hole),
+    // in this case, find the nearest point on the face
+    const TopoDS_Face& aFace = theShape->impl<TopoDS_Face>();
+    BRepClass_FaceClassifier aFaceClassifier(aFace, aPointOnFace, theTolerance);
+    if (aFaceClassifier.State() == TopAbs_OUT) {
+      BRepBuilderAPI_MakeVertex aVertex(aPointOnFace);
+      BRepExtrema_DistShapeShape aDistance(aVertex.Vertex(), aFace);
+      if (aDistance.NbSolution())
+        aPointOnFace = aDistance.PointOnShape2(1);
+    }
+  }
+  theClassifier.Perform(aPointOnFace, theTolerance);
   return stateToState(theClassifier.State());
 }
 
index 1db9dd7526f486f3d778b905a3b04044c52656e9..4b81b7eec129a702b80b7cac89d75e0cc6507b93 100644 (file)
@@ -179,6 +179,8 @@ bool GeomValidators_ShapeType::isValidAttribute(const AttributePtr& theAttribute
         }
       }
     }
+    else
+      aValid = false;
   }
   else if (anAttributeType == ModelAPI_AttributeReference::typeId()) {
     AttributeReferencePtr anAttr =
index a8265d4414505b94c12678d0c01b7a6435c81c5c..6e5e7d29c10a3589d4ba72945f7e90f75dcdca96 100644 (file)
@@ -219,3 +219,8 @@ void InitializationPlugin_EvalListener::processEvaluationEvent(
                                     aCalculatedValue[1]);
   }
 }
+
+void InitializationPlugin_EvalListener::initDataModel()
+{
+  myInterp->runString("salome_iapp.register_module_in_study(\"Shaper\")");
+}
index ca381b2e45c66e1d514b06dc201424cad6854836..5b6f3d7be7cf7a5b59378166204790a5ebcbaf69 100644 (file)
@@ -45,6 +45,9 @@ class InitializationPlugin_EvalListener : public Events_Listener
   INITIALIZATIONPLUGIN_EXPORT
     virtual void processEvent(const std::shared_ptr<Events_Message>& theMessage);
 
+  // performs the python call to initialize high level data model on internal data model creation
+  void initDataModel();
+
  protected:
   /// Evaluates theExpression and returns its value.
    double evaluate(std::shared_ptr<ModelAPI_Feature> theParameter,
index 872a603722251cc71ebd111f74cfa334fb052b45..6ddcc0af70d18a9cb32e276f7aaa7c40123174fe 100644 (file)
@@ -63,6 +63,8 @@ void InitializationPlugin_Plugin::processEvent(const std::shared_ptr<Events_Mess
     if (aDoc != ModelAPI_Session::get()->moduleDocument())
       return;
 
+    myEvalListener->initDataModel();
+
     std::list<FeaturePtr> aFeatures;
 
     // the viewer update should be blocked in order to avoid the features blinking before they are
index e64fc378841c9c4e1aa34033a005c33ca5c29320..0e07f96967e4d972b16ac40f379422cc40ea219e 100644 (file)
@@ -255,3 +255,9 @@ void InitializationPlugin_PyInterp::closeContext()
   Py_XDECREF(_local_context);
   PyInterp_Interp::closeContext();
 }
+
+bool InitializationPlugin_PyInterp::runString(std::string theString)
+{
+  PyLockWrapper lck; // Acquire GIL until the end of the method
+  return PyRun_SimpleString(theString.c_str());
+}
index 094d4fbc9771f899b39bd88f6262f384aa8a9a9b..b34a8df82ba0b213c71c2b2f81f49722eb3579ee 100644 (file)
@@ -50,6 +50,9 @@ class INITIALIZATIONPLUGIN_EXPORT InitializationPlugin_PyInterp : public PyInter
   /// Evaluates theExpression and returns its value.
   double evaluate(const std::string& theExpression, std::string& theError);
 
+  /// Runs the string command in the python interpreter. Returns true if no error is in result.
+  bool runString(std::string theString);
+
  protected:
   /// Returns error message.
   std::string errorMessage();
index 68c9c32030abd45a78567c6c4d57d908d5e05b78..27ef884adca2e21cc522a4fd07ef4f9cabf8e303 100644 (file)
@@ -1316,7 +1316,8 @@ void Model_AttributeSelection::computeValues(
 
 void Model_AttributeSelection::concealedFeature(
   const FeaturePtr theFeature, const FeaturePtr theStop, const bool theCheckCopy,
-  std::list<FeaturePtr>& theConcealers, const ResultPtr theResultOfFeature)
+  std::list<FeaturePtr>& theConcealers, const ResultPtr theResultOfFeature,
+  const bool theCheckWholeFeature)
 {
   std::set<FeaturePtr> alreadyProcessed;
   alreadyProcessed.insert(theFeature);
@@ -1332,16 +1333,21 @@ void Model_AttributeSelection::concealedFeature(
   }
   std::list<ResultPtr>::const_iterator aRootIter = aRootRes.cbegin();
   for(; aRootIter != aRootRes.cend(); aRootIter++) {
-    std::list<ResultPtr> allRes;
-    allRes.push_back(*aRootIter);
+    std::list<DataPtr> allRes;
+    allRes.push_back((*aRootIter)->data());
     ResultBodyPtr aRootBody = ModelAPI_Tools::bodyOwner(*aRootIter, true);
     if (!aRootBody.get())
       aRootBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aRootIter);
     if (aRootBody.get()) {
-      ModelAPI_Tools::allSubs(aRootBody, allRes);
-    }
-    for(std::list<ResultPtr>::iterator aRIter = allRes.begin(); aRIter != allRes.end(); aRIter++) {
-      const std::set<AttributePtr>& aRefs = (*aRIter)->data()->refsToMe();
+      std::list<ResultPtr> allSub;
+      ModelAPI_Tools::allSubs(aRootBody, allSub);
+      for(std::list<ResultPtr>::iterator anIt = allSub.begin(); anIt != allSub.end(); anIt++)
+        allRes.push_back((*anIt)->data());
+    }
+    if (theCheckWholeFeature)
+      allRes.push_back(theFeature->data());
+    for(std::list<DataPtr>::iterator aRIter = allRes.begin(); aRIter != allRes.end(); aRIter++) {
+      const std::set<AttributePtr>& aRefs = (*aRIter)->refsToMe();
       std::set<AttributePtr>::const_iterator aRef = aRefs.cbegin();
       for (; aRef != aRefs.cend(); aRef++) {
         if (!aRef->get() || !(*aRef)->owner().get())
@@ -2092,10 +2098,16 @@ ResultPtr Model_AttributeSelection::newestContext(
       }
     }
   }
-  // in case sketch line was selected for wire, but wire was concealed and not such line anymore,
-  // so, actually, the sketch element was selected (which is never concealed)
-  if (aResult != theCurrent && aResult->isConcealed())
-    aResult = theCurrent;
+  // in case sketch line was selected for wire, but wire was concealed and there is no such line
+  // anymore, so, actually, the sketch element was selected (which is never concealed)
+  if (aResult != theCurrent && theCurrent->groupName() == ModelAPI_ResultConstruction::group()) {
+    std::list<FeaturePtr> aConcealers;
+    FeaturePtr aResFeature = aDoc->feature(aResult);
+    FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
+    concealedFeature(aResFeature, aThisFeature, false, aConcealers, aResult, true);
+    if (aConcealers.size())
+      aResult = theCurrent;
+  }
   return aResult;
 }
 
index e5dc6d482c72a2a5f31ac44c38bf32f974259071..ab7f06cf4a7ab1a2e399df573c84b3a7d215421c 100644 (file)
@@ -123,7 +123,7 @@ public:
   /// Updates the arguments of selection if something was affected by creation
   /// or reorder of features upper in the history line (issue #1757)
   /// Returns theRemove true if this attribute must be removed (become deleted)
-  MODEL_EXPORT virtual void updateInHistory(bool& theRemove);
+  MODEL_EXPORT virtual void updateInHistory(bool& theRemove) override;
 
   // Implementation of the name generator method from the Selector package
   // This method returns the context name by the label of the sub-selected shape
@@ -210,7 +210,8 @@ protected:
   /// theResultOfFeature if not null defines exact referenced result of a feature
   void concealedFeature(
     const FeaturePtr theFeature, const FeaturePtr theStop, const bool theCheckCopy,
-    std::list<FeaturePtr>& theConcealers, const ResultPtr theResultOfFeature);
+    std::list<FeaturePtr>& theConcealers, const ResultPtr theResultOfFeature,
+    const bool theCheckWholeFeature = false);
 
   friend class Model_Data;
   friend class Model_AttributeSelectionList;
index 5a9c7b4c454f92e438817408840e306e2a9c7fa5..6893930feef6bfad68286a496580eba73aae3c27 100644 (file)
@@ -1150,6 +1150,8 @@ FeaturePtr Model_Document::addFeature(std::string theID, const bool theMakeCurre
 {
   std::shared_ptr<Model_Session> aSession =
     std::dynamic_pointer_cast<Model_Session>(ModelAPI_Session::get());
+  if (!aSession->hasModuleDocument() || !myObjs)
+    return FeaturePtr(); // this may be on close of the document
   FeaturePtr aFeature = aSession->createFeature(theID, this);
   if (!aFeature)
     return aFeature;
index 69955315d99dfaa6886197997d7697067b2064a0..ce23976c3b7feae52fde59411bc1d9e5a8c4e5d8 100644 (file)
@@ -2028,6 +2028,8 @@ FeaturePtr Model_Objects::lastFeature()
 
 bool Model_Objects::isLater(FeaturePtr theLater, FeaturePtr theCurrent) const
 {
+  if (theLater->getKind() == "InternalSelectionInPartFeature")
+    return true;
   std::shared_ptr<Model_Data> aLaterD = std::static_pointer_cast<Model_Data>(theLater->data());
   std::shared_ptr<Model_Data> aCurrentD = std::static_pointer_cast<Model_Data>(theCurrent->data());
   if (aLaterD.get() && aLaterD->isValid() && aCurrentD.get() && aCurrentD->isValid()) {
index 044893237ec599e8bef4d356bc5b6b0f19da9d8c..3c52f0986756e0152b4e7d4a6f0cc0802bb0d4f6 100644 (file)
@@ -327,7 +327,11 @@ bool Model_ResultPart::updateInPart(const int theIndex)
     AttributeSelectionListPtr aSelAttr = aDoc->selectionInPartFeature();
     AttributeSelectionPtr aThisAttr = aSelAttr->value(theIndex - 1);
     if (aThisAttr.get()) {
-      return aThisAttr->update();
+      if (aThisAttr->update()) {
+        bool aRemove = false;
+        aThisAttr->updateInHistory(aRemove);
+        return true; // it was updated
+      }
     }
   }
   return false; // something is wrong
index de686eebce3042c127d3d637b6c0ea52371abc1c..01d35426856e2e5f9c58f95dd05a5f1924f9d5bc 100644 (file)
@@ -73,6 +73,7 @@ void Model_Session::closeAll()
 {
   Model_Application::getApplication()->deleteAllDocuments();
   static const Events_ID aDocChangeEvent = Events_Loop::eventByName(EVENT_DOCUMENT_CHANGED);
+  myCurrentDoc = NULL;
   static std::shared_ptr<Events_Message> aMsg(new Events_Message(aDocChangeEvent));
   Events_Loop::loop()->send(aMsg);
   Events_Loop::loop()->flush(aDocChangeEvent);
@@ -251,6 +252,12 @@ std::shared_ptr<ModelAPI_Document> Model_Session::moduleDocument()
     anApp->createDocument(0); // 0 is a root ID
     // creation of the root document is always outside of the transaction, so, avoid checking it
     setCheckTransactions(true);
+    if (!myCurrentDoc || !Model_Application::getApplication()->hasDocument(myCurrentDoc->id())) {
+      myCurrentDoc = moduleDocument();
+      static std::shared_ptr<Events_Message> aMsg(
+        new Events_Message(Events_Loop::eventByName(EVENT_DOCUMENT_CHANGED)));
+      Events_Loop::loop()->send(aMsg);
+    }
   }
   return anApp->rootDocument();
 }
@@ -268,8 +275,9 @@ bool Model_Session::hasModuleDocument()
 
 std::shared_ptr<ModelAPI_Document> Model_Session::activeDocument()
 {
-  if (!myCurrentDoc || !Model_Application::getApplication()->hasDocument(myCurrentDoc->id()))
-    myCurrentDoc = moduleDocument();
+  if (!myCurrentDoc || !Model_Application::getApplication()->hasDocument(myCurrentDoc->id())) {
+    return moduleDocument();
+  }
   return myCurrentDoc;
 }
 
index 659b7ca9a2764290a121241f5f7ea5da83cba458..a2bcdfacbcbb937ed1e2792b68c20157071532f5 100644 (file)
@@ -21,7 +21,6 @@
 #include <Model_Document.h>
 #include <Model_Data.h>
 #include <Model_Objects.h>
-#include <Model_AttributeSelection.h>
 #include <ModelAPI_Feature.h>
 #include <ModelAPI_Data.h>
 #include <ModelAPI_Document.h>
@@ -308,6 +307,10 @@ void Model_Update::processEvent(const std::shared_ptr<Events_Message>& theMessag
           aFeatures.push_back(*anObjIter);
         } else {
           aResults.push_back(*anObjIter);
+          ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(*anObjIter);
+          if (aPart.get() && aPart->data().get() && aPart->data()->isValid()) {
+            aPart->shape(); // to update the shape on creation of the result
+          }
         }
       }
     }
@@ -904,6 +907,13 @@ void Model_Update::updateArguments(FeaturePtr theFeature) {
       bool isObligatory = aFactory->isCase(theFeature, theFeature->data()->id(aSel));
       if (isObligatory)
         aState = ModelAPI_StateInvalidArgument;
+    } else if (theFeature->getKind() == "Sketch" && aSel->id() == "External" &&
+               aSel->isInitialized()) {
+      // #19703 : if sketch plane was selected, but after context disappears, it must become invalid
+      aSel->update();
+      if (aSel->isInvalid()) {
+          aState = ModelAPI_StateInvalidArgument;
+      }
     }
   }
   // update the selection list attributes if any
@@ -1076,8 +1086,8 @@ void Model_Update::updateSelection(const std::set<std::shared_ptr<ModelAPI_Objec
       (*anObj)->data()->attributes(ModelAPI_AttributeSelection::typeId());
     std::list<AttributePtr>::iterator aRefsIter = aRefs.begin();
     for (; aRefsIter != aRefs.end(); aRefsIter++) {
-      std::shared_ptr<Model_AttributeSelection> aSel =
-        std::dynamic_pointer_cast<Model_AttributeSelection>(*aRefsIter);
+      AttributeSelectionPtr aSel =
+        std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(*aRefsIter);
       bool aRemove = false;
       aSel->updateInHistory(aRemove);
     }
@@ -1088,12 +1098,12 @@ void Model_Update::updateSelection(const std::set<std::shared_ptr<ModelAPI_Objec
       std::shared_ptr<ModelAPI_AttributeSelectionList> aSel =
         std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(*aRefsIter);
       for(int a = aSel->size() - 1; a >= 0; a--) {
-        std::shared_ptr<Model_AttributeSelection> aSelAttr =
-          std::dynamic_pointer_cast<Model_AttributeSelection>(aSel->value(a));
+        AttributeSelectionPtr aSelAttr =
+          std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(aSel->value(a));
         if (aSelAttr.get()) {
-          bool theRemove = false;
-          aSelAttr->updateInHistory(theRemove);
-          if (theRemove) {
+          bool aRemove = false;
+          aSelAttr->updateInHistory(aRemove);
+          if (aRemove) {
             aRemoveSet.insert(a);
           }
         }
index 19ad06cf76a5828234644186d2b0542c9777bb2b..4ac152b264143322b9cf9f707f0700be516254f7 100644 (file)
@@ -259,4 +259,7 @@ ADD_UNIT_TESTS(TestConstants.py
                Test19019_2.py
                Test19031.py
                Test19058.py
+               Test19217.py
+               Test19707.py
+               Test19726.py
 )
index aba0818d9ff7c4e627cb8a7b25f4cfa9b13b541d..fa5b5605319026dc5d26e6918e58a3191f6545ff 100644 (file)
@@ -123,6 +123,11 @@ class ModelAPI_AttributeSelection : public ModelAPI_Attribute
   /// Makes the current local selection becomes all sub-shapes with same base geometry.
   MODELAPI_EXPORT virtual void combineGeometrical() = 0;
 
+  /// Updates the arguments of selection if something was affected by creation
+  /// or reorder of features upper in the history line.
+  /// Returns theRemove true if this attribute must be removed (become deleted)
+  MODELAPI_EXPORT virtual void updateInHistory(bool& theRemove) = 0;
+
  protected:
   /// Objects are created for features automatically
   MODELAPI_EXPORT ModelAPI_AttributeSelection();
diff --git a/src/ModelAPI/Test/Test19217.py b/src/ModelAPI/Test/Test19217.py
new file mode 100644 (file)
index 0000000..b85b013
--- /dev/null
@@ -0,0 +1,42 @@
+# Copyright (C) 2014-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
+#
+
+# Test if the Model_AttributeSelection::newestContext method work in case
+# the initial shell is concealed by multi-rotation (all-feature selection)
+# and the same sketch is used by a next shell.
+
+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("XOZ"))
+SketchCircle_1 = Sketch_1.addCircle(47.53111880904039, 63.23707920074999, 11.27757708463696)
+model.do()
+Shell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2r")])
+AngularCopy_1 = model.addMultiRotation(Part_1_doc, [model.selection("COMPOUND", "all-in-Shell_1")], model.selection("EDGE", "PartSet/OZ"), 3, keepSubResults = True)
+Shell_2 = model.addShell(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2r")])
+model.end()
+
+from ModelAPI import *
+aFactory = ModelAPI_Session.get().validators()
+assert(aFactory.validate(Shell_2.feature()))
+
+assert(model.checkPythonDump())
\ No newline at end of file
diff --git a/src/ModelAPI/Test/Test19707.py b/src/ModelAPI/Test/Test19707.py
new file mode 100644 (file)
index 0000000..1c3b3a5
--- /dev/null
@@ -0,0 +1,62 @@
+# Copyright (C) 2014-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 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(-59.0465954847056, -128.5053642637967, 53.14364970069066, -170.5009266857805)
+SketchLine_2 = Sketch_1.addLine(53.14364970069066, -170.5009266857805, 137.6705343466976, -112.5874503884433)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(137.6705343466976, -112.5874503884433, 64.87485797099055, -26.90480166687218)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchLine_4 = Sketch_1.addLine(64.87485797099055, -26.90480166687218, 3.969957323886124, -72.35673939469255)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchLine_5 = Sketch_1.addLine(3.969957323886124, -72.35673939469255, -79.2369959888606, -34.8592213882167)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_1.addLine(-79.2369959888606, -34.8592213882167, -59.0465954847056, -128.5053642637967)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_6.endPoint())
+SketchLine_7 = Sketch_1.addLine(53.14364970069066, -170.5009266857805, 3.969957323886124, -72.35673939469255)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_7.endPoint())
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchLine_7.startPoint(), SketchLine_1.endPoint())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "Sketch_1")], model.selection(), 10, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1_2/Generated_Face&Sketch_1/SketchLine_3"))
+SketchCircle_1 = Sketch_2.addCircle(110.5461396183937, -4.403937604408839, 25.15832463432426)
+model.do()
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchCircle_1_2r")], model.selection(), 10, 0)
+model.end()
+
+from ModelAPI import *
+aFactory = ModelAPI_Session.get().validators()
+assert(aFactory.validate(Sketch_2.feature()))
+assert(aFactory.validate(Extrusion_2.feature()))
+
+# update the first extrusion to make the second bas plane selection invalid
+model.begin()
+Extrusion_1.setBase([model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_7f-SketchLine_5f-SketchLine_6f")])
+model.end()
+
+# check that the second sketch and extrusion become invalid
+assert(len(Sketch_2.results()) == 0)
+assert(len(Extrusion_2.results()) == 0)
diff --git a/src/ModelAPI/Test/Test19726.py b/src/ModelAPI/Test/Test19726.py
new file mode 100644 (file)
index 0000000..f6e82b2
--- /dev/null
@@ -0,0 +1,49 @@
+# Copyright (C) 2014-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 salome.shaper import model
+from ModelAPI 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("XOZ"))
+SketchCircle_1 = Sketch_1.addCircle(18.39021699364881, 11.50401662688171, 4.123179523509023)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2r")], model.selection(), 10, 0)
+model.do()
+Translation_1 = model.addTranslation(partSet, [model.selection("COMPOUND", "Part_1/")], axis = model.selection("EDGE", "Part_1/([Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/From_Face])([Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face])"), distance = 20, keepSubResults = True)
+aName1 = Translation_1.axisObject().namingName()
+model.end()
+
+# update the extrusion in the part, so, outside the part selection must be moved in history
+model.begin()
+Rotation_1 = model.addRotation(Part_1_doc, [model.selection("SOLID", "Extrusion_1_1")], axis = model.selection("EDGE", "PartSet/OY"), angle = 45)
+model.do()
+aSession = ModelAPI_Session.get()
+aSession.setActiveDocument(partSet)
+model.end()
+
+# check that name was changed to the rotation
+aName2 = Translation_1.axisObject().namingName()
+assert(aName1 != aName2)
+assert(len(aName2) > 7)
+
+assert(model.checkPythonDump())
index 5de56ada29a79404a712b5617dc513664c684b73..b92bf677bd3b6a590c1ae8564098be036e91186c 100644 (file)
@@ -33,6 +33,8 @@
 #include <GeomAPI_PlanarEdges.h>
 #include <GeomAPI_Pnt.h>
 
+#include <GeomAlgoAPI_ShapeTools.h>
+
 
 #ifdef WIN32
 #pragma warning(disable : 4996) // for sprintf
@@ -78,7 +80,25 @@ namespace ModelGeomAlgo_Shape
     for (std::list<GeomShapePtr>::const_iterator aSubIt = aSubs.begin();
          aSubIt != aSubs.end(); ++aSubIt) {
       GeomPointPtr aMiddlePoint = (*aSubIt)->middlePoint();
-      if (aMiddlePoint && aMiddlePoint->distance(thePoint) < theTolerance)
+      if (!aMiddlePoint)
+        continue;
+
+      double aDistance = aMiddlePoint->distance(thePoint);
+      bool isFound = aDistance < theTolerance;
+      // issue #19019: special workaround for faces, because if the face contains B-spline contour,
+      // the middle point is calculated with respect to its poles, but not a curve itself.
+      // Thus is some operations (like BOP) the curve may have different number of poles
+      // from time to time, as a result, the face parametric boundaries are floating
+      // as well as the middle point.
+      // The workaround is to find a distance from the picking point to the face, if the distance
+      // between the picking point and the middle point on the face is small to some extend.
+      static const double THE_THRESHOLD = 100.;
+      if (!isFound && aDistance < THE_THRESHOLD * theTolerance && (*aSubIt)->isFace()) {
+        GeomVertexPtr aVertex(new GeomAPI_Vertex(thePoint));
+        aDistance = GeomAlgoAPI_ShapeTools::minimalDistance(aVertex, *aSubIt);
+        isFound = aDistance < theTolerance;
+      }
+      if (isFound)
         aFoundSubs.push_back(*aSubIt);
     }
     return aFoundSubs;
index 9555b977de91c5d76eb4e9aed10f57db0b7c75c5..cec0fb1cec3a359bc2d59d28c5199dda95875d49 100644 (file)
@@ -88,8 +88,11 @@ void ModelHighAPI_Interface::execute(bool isForce)
 
 void ModelHighAPI_Interface::setName(const std::string& theName)
 {
-  if (feature().get())
+  if (feature().get() && feature()->data()->isValid())
     feature()->data()->setName(theName);
+  else {
+    std::cout<<"Error: set name "<<theName.c_str()<<" for an invalid feature"<<std::endl;
+  }
 }
 
 std::string ModelHighAPI_Interface::name() const
index a3697ee37f0c09d7f889585b732882b2b708af8e..e190a8fab4ae9181e82fdb7583690ec2ad086b27 100644 (file)
@@ -1208,7 +1208,7 @@ FeaturePtr createParameter(const QString& theText)
   SessionPtr aMgr = ModelAPI_Session::get();
   std::shared_ptr<ModelAPI_Document> aDoc = aMgr->activeDocument();
 
-  aParameter = aDoc->addFeature("Parameter");
+  aParameter = aDoc->addFeature("Parameter", false);
   if (aParameter.get()) {
     AttributeStringPtr aNameAttr = aParameter->string("variable");
     aNameAttr->setValue(aParamName.toStdString());
index 9b09b72057e4957b663cdad891314dc9aa697119..33bb8470ccb51068b65d67db615dfe4c2bcb2303 100644 (file)
@@ -520,33 +520,40 @@ void ModuleBase_WidgetSelectionFilter::updatePreview(const TopoDS_Shape& theShap
 
 void ModuleBase_WidgetSelectionFilter::onShowOnly(bool theShow)
 {
-  if (myPreview.IsNull())
-    return;
   Handle(AIS_InteractiveContext) aCtx = myWorkshop->viewer()->AISContext();
-
   if (theShow) {
     AIS_ListOfInteractive aList;
     aCtx->DisplayedObjects(AIS_KOI_Shape, -1, aList);
-    aList.Remove(myPreview);
+    if (!myPreview.IsNull())
+      aList.Remove(myPreview);
     if (aList.Size() > 0)
       myListIO = aList;
   }
   AIS_ListOfInteractive::const_iterator aIt;
   Handle(AIS_Shape) aShapeIO;
+  bool isModified = false;
   for (aIt = myListIO.cbegin(); aIt != myListIO.cend(); aIt++) {
     aShapeIO = Handle(AIS_Shape)::DownCast(*aIt);
     if (!aShapeIO.IsNull()) {
-      if (theShow)
-        aCtx->Erase(aShapeIO, false);
+      if (theShow) {
+        if (aCtx->IsDisplayed(aShapeIO)) {
+          aCtx->Erase(aShapeIO, false);
+          isModified = true;
+        }
+      }
       else {
-        aCtx->Display(aShapeIO, false);
-        std::shared_ptr<GeomAPI_AISObject> anAISObj = AISObjectPtr(new GeomAPI_AISObject());
-        anAISObj->setImpl(new Handle(AIS_InteractiveObject)(aShapeIO));
-        myWorkshop->applyCurrentSelectionModes(anAISObj);
+        if (!aCtx->IsDisplayed(aShapeIO)) {
+          aCtx->Display(aShapeIO, false);
+          std::shared_ptr<GeomAPI_AISObject> anAISObj = AISObjectPtr(new GeomAPI_AISObject());
+          anAISObj->setImpl(new Handle(AIS_InteractiveObject)(aShapeIO));
+          myWorkshop->applyCurrentSelectionModes(anAISObj);
+          isModified = true;
+        }
       }
     }
   }
-  myWorkshop->viewer()->update();
+  if (isModified)
+    myWorkshop->viewer()->update();
 }
 
 void ModuleBase_WidgetSelectionFilter::updateSelectBtn()
@@ -559,11 +566,16 @@ void ModuleBase_WidgetSelectionFilter::updateNumberSelected()
 {
   int aNb = myValues.size();
   myNbLbl->setText(QString::number(aNb));
-  if (aNb == 0)
+  if (aNb == 0) {
     myFeature->setError(translate("Selection is empty").toStdString(), false, false);
+    myShowBtn->setChecked(false);
+    onShowOnly(false);
+    myShowBtn->setEnabled(false);
+  }
   else {
     myFeature->setError("", false, false);
     myFeature->data()->execState(ModelAPI_StateDone);
+    myShowBtn->setEnabled(true);
   }
 }
 
index 1be514700ac7cc10af53f3a77fffa625cc78f1eb..446b253b31c064f3380bb860c37458d7bbafe409 100644 (file)
@@ -347,15 +347,7 @@ void PartSet_Module::operationCommitted(ModuleBase_Operation* theOperation)
 
   /// Restart sketcher operations automatically
   if (!mySketchReentrantMgr->operationCommitted(theOperation)) {
-
-    ModuleBase_OperationFeature* aFOperation =
-      dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
-    if (aFOperation && !aFOperation->isEditOperation()) {
-      // the selection is cleared after commit the create operation
-      // in order to do not use the same selected objects in the restarted operation
-      // for common behaviour, the selection is cleared even if the operation is not restarted
-      getWorkshop()->selector()->clearSelection();
-    }
+    getWorkshop()->selector()->clearSelection();
   }
 }
 
@@ -367,6 +359,8 @@ void PartSet_Module::operationAborted(ModuleBase_Operation* theOperation)
   /// deactivate of overconstraint listener should be performed after Sketch abort (#2176)
   if (PartSet_SketcherMgr::isSketchOperation(theOperation))
     overconstraintListener()->setActive(false);
+
+  getWorkshop()->selector()->clearSelection();
 }
 
 //******************************************************
@@ -1543,6 +1537,9 @@ if (aObjIndex.isValid()) { \
 void PartSet_Module::processEvent(const std::shared_ptr<Events_Message>& theMessage)
 {
   if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_DOCUMENT_CHANGED)) {
+    SessionPtr aMgr = ModelAPI_Session::get();
+    if (!aMgr->hasModuleDocument()) // if document is closed, do not call the document creation
+      return;
     // Do not change activation of parts if an operation active
     static QStringList aAllowActivationList;
     if (aAllowActivationList.isEmpty())
@@ -1554,32 +1551,34 @@ void PartSet_Module::processEvent(const std::shared_ptr<Events_Message>& theMess
       (!aAllowActivationList.contains(myWorkshop->currentOperation()->id())))
       return;
     XGUI_Workshop* aWorkshop = getWorkshop();
-    XGUI_DataTree* aTreeView = aWorkshop->objectBrowser()->treeView();
-    QLabel* aLabel = aWorkshop->objectBrowser()->activeDocLabel();
-    QPalette aPalet = aLabel->palette();
+    bool needUpdate = false;
+    XGUI_DataTree* aTreeView;
+    if (aWorkshop->objectBrowser()) {
+      aTreeView = aWorkshop->objectBrowser()->treeView();
+      QLabel* aLabel = aWorkshop->objectBrowser()->activeDocLabel();
+      QPalette aPalet = aLabel->palette();
 
-    SessionPtr aMgr = ModelAPI_Session::get();
-    DocumentPtr aActiveDoc = aMgr->activeDocument();
+      DocumentPtr aActiveDoc = aMgr->activeDocument();
 
-    // Clear active part index if there is no Part documents
-    // It could be not null if document was closed and opened a new
-    // without closeDocument call
-    if (aMgr->allOpenedDocuments().size() <= 1)
-      myActivePartIndex = QModelIndex();
+      // Clear active part index if there is no Part documents
+      // It could be not null if document was closed and opened a new
+      // without closeDocument call
+      if (aMgr->allOpenedDocuments().size() <= 1)
+        myActivePartIndex = QModelIndex();
 
-    XGUI_DataModel* aDataModel = aWorkshop->objectBrowser()->dataModel();
-    QModelIndex aOldActive = myActivePartIndex;
-    myActivePartIndex = aDataModel->documentRootIndex(aActiveDoc, 0);
-    bool needUpdate = false;
-    if (myActivePartIndex.isValid()) {
-      needUpdate = aTreeView->isExpanded(myActivePartIndex);
-      if (!needUpdate)
-        aTreeView->setExpanded(myActivePartIndex, true);
-    }
-    if ((aOldActive != myActivePartIndex) && (aOldActive.isValid()))
-      aTreeView->setExpanded(aOldActive, false);
+      XGUI_DataModel* aDataModel = aWorkshop->objectBrowser()->dataModel();
+      QModelIndex aOldActive = myActivePartIndex;
+      myActivePartIndex = aDataModel->documentRootIndex(aActiveDoc, 0);
+      if (myActivePartIndex.isValid()) {
+        needUpdate = aTreeView->isExpanded(myActivePartIndex);
+        if (!needUpdate)
+          aTreeView->setExpanded(myActivePartIndex, true);
+      }
+      if ((aOldActive != myActivePartIndex) && (aOldActive.isValid()))
+        aTreeView->setExpanded(aOldActive, false);
 
-    aLabel->setPalette(aPalet);
+      aLabel->setPalette(aPalet);
+    }
     aWorkshop->updateCommandStatus();
 
     // Update displayed objects in order to update active color
index 78b6430bc14753c2036bc2df5f1ae96b099b47b2..cd6b78cbd559d6651e70bef7ae44ae41e6a0b570 100644 (file)
@@ -135,7 +135,8 @@ void PartSet_OperationPrs::Compute(
     // change deviation coefficient to provide more precise circle
     // as there is no result, the shape is processed to correct deviation. To be unified
     ModuleBase_Tools::setDefaultDeviationCoefficient(aShape, aDrawer);
-    ModuleBase_Tools::setDefaultDeviationCoefficient(aShape, DynamicHilightAttributes());
+    //This presentation is not used for selection, so it don't need highlighting
+    //ModuleBase_Tools::setDefaultDeviationCoefficient(aShape, DynamicHilightAttributes());
 
     if (myUseAISWidth) {
       Handle(AIS_InteractiveObject) anIO = anIter.Value();
@@ -364,8 +365,10 @@ void PartSet_OperationPrs::getResultShapes(const FeaturePtr& theFeature,
                                        aRLast = aResults.end();
   for (; aRIt != aRLast; aRIt++) {
     ResultPtr aResult = *aRIt;
-    GeomShapePtr aGeomShape = aResult->shape();
-    appendShapeIfVisible(theWorkshop, aResult, aGeomShape, theObjectShapes);
+    if (!aResult->isDisabled()) {
+      GeomShapePtr aGeomShape = aResult->shape();
+      appendShapeIfVisible(theWorkshop, aResult, aGeomShape, theObjectShapes);
+    }
   }
 }
 
index 9d7164d220743bce65e683115f516780fb608316..83529e23891f309d9eab8290d9d5932e6a84470b 100644 (file)
@@ -104,6 +104,21 @@ void PartSet_PreviewSketchPlane::createSketchPlane(const CompositeFeaturePtr& th
     myShape = GeomAlgoAPI_FaceBuilder::squareFace(
       myViewCentralPoint.get() ? myViewCentralPoint : anOrigin->pnt(), aNormal->dir(), aFaceSize);
   }
+  else if (myIsUseSizeOfView && (mySizeOfView > 0)) {
+    std::shared_ptr<GeomAPI_Face> aFace(new GeomAPI_Face(myShape));
+    std::shared_ptr<GeomAPI_Pln> aPlane = aFace->getPlane();
+    if (aPlane.get()) {
+      double anA, aB, aC, aD;
+      aPlane->coefficients(anA, aB, aC, aD);
+      std::shared_ptr<GeomAPI_Dir> aNormDir(new GeomAPI_Dir(anA, aB, aC));
+      std::shared_ptr<GeomAPI_XYZ> aCoords = aNormDir->xyz();
+      std::shared_ptr<GeomAPI_XYZ> aZero(new GeomAPI_XYZ(0, 0, 0));
+      aCoords = aCoords->multiplied(-aD * aCoords->distance(aZero));
+      std::shared_ptr<GeomAPI_Pnt> anOrigPnt(new GeomAPI_Pnt(aCoords));
+      myShape = GeomAlgoAPI_FaceBuilder::squareFace(
+        myViewCentralPoint.get() ? myViewCentralPoint : anOrigPnt, aNormDir, mySizeOfView);
+    }
+  }
   myPlane = createPreviewPlane();
 
   aDisp->displayAIS(myPlane, false/*load object in selection*/, 1/*shaded*/, false);
index b52154da9ceb5dd2b88e414a797af7528f638b7f..689c034b591fbe42854076736793db0ae6291a38 100644 (file)
@@ -468,19 +468,6 @@ void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseE
       }
       myPreviousDrawModeEnabled = aViewer->enableDrawMode(false);
       launchEditing();
-      if (aFeature.get() != NULL) {
-        std::shared_ptr<SketchPlugin_Feature> aSPFeature =
-                  std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
-        if (aSPFeature.get() &&
-          (aSPFeature->getKind() == SketchPlugin_ConstraintRadius::ID() ||
-           aSPFeature->getKind() == SketchPlugin_ConstraintAngle::ID())) {
-          DataPtr aData = aSPFeature->data();
-          AttributePtr aAttr = aData->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT());
-          std::shared_ptr<GeomDataAPI_Point2D> aFPAttr =
-            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aAttr);
-          aFPAttr->setValue(myCurrentPoint.myCurX, myCurrentPoint.myCurY);
-        }
-      }
     } else if (isSketchOpe && isEditing) {
       // If selected another object commit current result
       bool aPrevLaunchingState = myIsEditLaunching;
@@ -2286,17 +2273,18 @@ std::vector<int> PartSet_SketcherMgr::colorOfObject(const ObjectPtr& theObject,
   if (aOCListener->isConflictingObject(theObject)) {
     return Config_PropManager::color("Visualization", "sketch_overconstraint_color");
   }
-  if (aOCListener->isFullyConstrained()) {
-    return Config_PropManager::color("Visualization", "sketch_fully_constrained_color");
-  }
   if (isDistanceKind(aKind)) {
     return Config_PropManager::color("Visualization", "sketch_dimension_color");
   }
+  if (isExternal(theFeature))
+    return Config_PropManager::color("Visualization", "sketch_external_color");
+
+  if (aOCListener->isFullyConstrained()) {
+    return Config_PropManager::color("Visualization", "sketch_fully_constrained_color");
+  }
   if (aKind == SketchPlugin_ConstraintCoincidence::ID())
     return std::vector<int>(3, 0);
 
-  if (isExternal(theFeature))
-    return Config_PropManager::color("Visualization", "sketch_external_color");
   if (isConstruction)
     return Config_PropManager::color("Visualization", "sketch_auxiliary_color");
 
index fc615f4d1e00a6b55014ab567973208d652ac182..169ea993dd0f519ebb6e2172b9cb0134765eccc1 100644 (file)
@@ -384,10 +384,13 @@ ResultPtr PartSet_Tools::createFixedObjectByExternal(
   anIntoResult->setValue(SKETCH_PROJECTION_INCLUDE_INTO_RESULT);
   aProjectionFeature->execute();
 
+  ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators();
+  bool isValid = aValidators->validate(aProjectionFeature);
+
   // if projection feature has not been created, exit
   AttributeRefAttrPtr aRefAttr = aProjectionFeature->data()->refattr(
     SketchPlugin_Projection::PROJECTED_FEATURE_ID());
-  if (!aRefAttr || !aRefAttr->isInitialized())
+  if (!isValid || !aRefAttr || !aRefAttr->isInitialized())
   {
     // remove external feature if the attribute is not filled
     std::set<FeaturePtr> aFeatures;
index 7f79a51eb2434d5feaa68a403968be18886d8151..83b82a90449fa7f1fb4736a659c6da9da1511ede 100644 (file)
@@ -39,7 +39,6 @@
 #include <ModelAPI_Tools.h>
 #include <ModelAPI_AttributeString.h>
 #include <ModelAPI_Events.h>
-#include <ModelAPI_ResultConstruction.h>
 
 #include <ModuleBase_Operation.h>
 #include <ModuleBase_ViewerPrs.h>
@@ -352,21 +351,22 @@ void PartSet_WidgetSketchLabel::updateByPlaneSelected(const ModuleBase_ViewerPrs
   // 1. hide main planes if they have been displayed and display sketch preview plane
   myPreviewPlanes->erasePreviewPlanes(myWorkshop);
 
+  QString aSizeOfViewStr = mySizeOfView->text();
+  bool isSetSizeOfView = false;
+  double aSizeOfView = 0;
+  if (!aSizeOfViewStr.isEmpty()) {
+    aSizeOfView = aSizeOfViewStr.toDouble(&isSetSizeOfView);
+    if (isSetSizeOfView && aSizeOfView <= 0) {
+      isSetSizeOfView = false;
+    }
+  }
   PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
   if (aModule) {
     CompositeFeaturePtr aSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
-    bool isSetSizeOfView = false;
-    double aSizeOfView = 0;
-    QString aSizeOfViewStr = mySizeOfView->text();
-    if (!aSizeOfViewStr.isEmpty()) {
-      aSizeOfView = aSizeOfViewStr.toDouble(&isSetSizeOfView);
-      if (isSetSizeOfView && aSizeOfView <= 0) {
-        isSetSizeOfView = false;
-      }
-    }
     aModule->sketchMgr()->previewSketchPlane()->setSizeOfView(aSizeOfView, isSetSizeOfView);
-    if (myViewVisible->isChecked())
-      aModule->sketchMgr()->previewSketchPlane()->createSketchPlane(aSketch, myWorkshop);
+    // Call of createSketchPlane is managed by events Loop
+    //if (myViewVisible->isChecked())
+    //  aModule->sketchMgr()->previewSketchPlane()->createSketchPlane(aSketch, myWorkshop);
   }
   // 2. if the planes were displayed, change the view projection
 
@@ -380,18 +380,13 @@ void PartSet_WidgetSketchLabel::updateByPlaneSelected(const ModuleBase_ViewerPrs
   if (aRotate) {
     myWorkshop->viewer()->setViewProjection(aXYZ.X(), aXYZ.Y(), aXYZ.Z(), aTwist);
   }
-  QString aSizeOfViewStr = mySizeOfView->text();
-  if (!aSizeOfViewStr.isEmpty()) {
-    bool isOk;
-    double aSizeOfView = aSizeOfViewStr.toDouble(&isOk);
-    if (isOk && aSizeOfView > 0) {
-      Handle(V3d_View) aView3d = myWorkshop->viewer()->activeView();
-      if (!aView3d.IsNull()) {
-        Bnd_Box aBndBox;
-        double aHalfSize = aSizeOfView/2.0;
-        aBndBox.Update(-aHalfSize, -aHalfSize, -aHalfSize, aHalfSize, aHalfSize, aHalfSize);
-        aView3d->FitAll(aBndBox, 0.01, false);
-      }
+  if (isSetSizeOfView && aSizeOfView > 0) {
+    Handle(V3d_View) aView3d = myWorkshop->viewer()->activeView();
+    if (!aView3d.IsNull()) {
+      Bnd_Box aBndBox;
+      double aHalfSize = aSizeOfView/2.0;
+      aBndBox.Update(-aHalfSize, -aHalfSize, -aHalfSize, aHalfSize, aHalfSize, aHalfSize);
+      aView3d->FitAll(aBndBox, 0.01, false);
     }
   }
   if (myOpenTransaction) {
@@ -512,61 +507,48 @@ bool PartSet_WidgetSketchLabel::fillSketchPlaneBySelection(const ModuleBase_View
 {
   bool isOwnerSet = false;
 
-  GeomShapePtr aShape = thePrs->shape();
+  const GeomShapePtr& aShape = thePrs->shape();
   std::shared_ptr<GeomAPI_Dir> aDir;
 
-  if (!aShape.get() || aShape->isNull()) {
-    if (thePrs->object() && (feature() != thePrs->object())) {
-      if (thePrs->object()->groupName() == ModelAPI_ResultConstruction::group()) {
-        ResultConstructionPtr aConstruction =
-          std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(thePrs->object());
-        if (aConstruction.get())
-          aShape = aConstruction->shape();
-      }
-    }
-  }
-
   if (aShape.get() && !aShape->isNull()) {
     const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
     aDir = setSketchPlane(aTDShape);
     isOwnerSet = aDir.get();
   }
   if (thePrs->object() && (feature() != thePrs->object())) {
-    if (thePrs->object()->groupName() != ModelAPI_ResultConstruction::group()) {
-      FeaturePtr aFeature = ModelAPI_Feature::feature(thePrs->object());
-      DataPtr aData = feature()->data();
-      AttributeSelectionPtr aSelAttr =
-        std::dynamic_pointer_cast<ModelAPI_AttributeSelection>
-        (aData->attribute(SketchPlugin_SketchEntity::EXTERNAL_ID()));
-      if (aSelAttr.get()) {
-        ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(thePrs->object());
-        if (aRes.get()) {
-          GeomShapePtr aShapePtr;
-          if (!aShape.get() || aShape->isNull()) {  // selection happens in the OCC viewer
-            aShapePtr = ModelAPI_Tools::shape(aRes);
-          }
-          else { // selection happens in OB browser
-            aShapePtr = aShape;
-          }
-          if (aShapePtr.get() && aShapePtr->isFace()) {
-            const TopoDS_Shape& aTDShape = aShapePtr->impl<TopoDS_Shape>();
-            setSketchPlane(aTDShape);
-            aSelAttr->setValue(aRes, aShapePtr);
-            isOwnerSet = true;
-          }
+    FeaturePtr aFeature = ModelAPI_Feature::feature(thePrs->object());
+    DataPtr aData = feature()->data();
+    AttributeSelectionPtr aSelAttr =
+      std::dynamic_pointer_cast<ModelAPI_AttributeSelection>
+      (aData->attribute(SketchPlugin_SketchEntity::EXTERNAL_ID()));
+    if (aSelAttr.get()) {
+      ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(thePrs->object());
+      if (aRes.get()) {
+        GeomShapePtr aShapePtr;
+        if (!aShape.get() || aShape->isNull()) {  // selection happens in the OCC viewer
+          aShapePtr = ModelAPI_Tools::shape(aRes);
         }
-        else {
-          aSelAttr->setValue(aFeature, GeomShapePtr());
-          GeomShapePtr aSelShape = aSelAttr->value();
-          if (!aSelShape.get() && aSelAttr->contextFeature().get() &&
-            aSelAttr->contextFeature()->firstResult().get()) {
-            aSelShape = aSelAttr->contextFeature()->firstResult()->shape();
-          }
-          if (aSelShape.get() && aSelShape->isPlanar()) {
-            const TopoDS_Shape& aTDShape = aSelShape->impl<TopoDS_Shape>();
-            setSketchPlane(aTDShape);
-            isOwnerSet = true;
-          }
+        else { // selection happens in OB browser
+          aShapePtr = aShape;
+        }
+        if (aShapePtr.get() && aShapePtr->isFace()) {
+          const TopoDS_Shape& aTDShape = aShapePtr->impl<TopoDS_Shape>();
+          setSketchPlane(aTDShape);
+          aSelAttr->setValue(aRes, aShapePtr);
+          isOwnerSet = true;
+        }
+      }
+      else {
+        aSelAttr->setValue(aFeature, GeomShapePtr());
+        GeomShapePtr aSelShape = aSelAttr->value();
+        if (!aSelShape.get() && aSelAttr->contextFeature().get() &&
+          aSelAttr->contextFeature()->firstResult().get()) {
+          aSelShape = aSelAttr->contextFeature()->firstResult()->shape();
+        }
+        if (aSelShape.get() && aSelShape->isPlanar()) {
+          const TopoDS_Shape& aTDShape = aSelShape->impl<TopoDS_Shape>();
+          setSketchPlane(aTDShape);
+          isOwnerSet = true;
         }
       }
     }
index 707c07773529de44c4c5b1fe081e0c9941ba00ce..54168cc60e3893c0f49c7c1f0943cb2d05d78d3e 100644 (file)
@@ -1,7 +1,7 @@
 .. _create_compound_Vertices:
 .. |compoundVertices.icon|    image:: images/compound.png
 
-compound Vertices
+Compound Vertices
 =================
 
 Compound Vertices is a feature and can be edited after execution.
index 7a97e263221433af1c7866202741cbd42c7d373e..89443ed3231d4460d55092f17fcd99cdb54528a5 100644 (file)
@@ -1,7 +1,7 @@
 .. _create_import_Parameters:
 .. |importParameters.icon|    image:: images/importParameters.png
 
-import Parameters
+Import Parameters
 =================
 
 Import Parameters is a macro-feature and can not be edited after execution.
index efdddb88e124d6bd2f8003829b06c16361a34a9a..956e97bbe56acc5408c7f170a2f1465ee1329e3f 100644 (file)
@@ -74,6 +74,8 @@
 #include <QMenu>
 #include <QToolBar>
 
+#include <ModelAPI_Session.h>
+
 #if OCC_VERSION_HEX < 0x070400
   #define SALOME_PATCH_FOR_CTRL_WHEEL
 #endif
@@ -205,6 +207,13 @@ void SHAPERGUI::initialize(CAM_Application* theApp)
 #endif
     createMenu(aId, aEditMenu);
 
+  if (!myInspectionPanel) {
+    myInspectionPanel = myWorkshop->inspectionPanel();
+    connect(myInspectionPanel->toggleViewAction(), SIGNAL(toggled(bool)),
+      this, SLOT(onWhatIs(bool)));
+  }
+  hideInternalWindows();
+
   // Initialize viewer proxy if OCC viewer is already exist
   ViewManagerList aOCCViewManagers;
   application()->viewManagers(OCCViewer_Viewer::Type(), aOCCViewManagers);
@@ -224,6 +233,8 @@ void SHAPERGUI::initialize(CAM_Application* theApp)
       }
     }
   }
+  SHAPERGUI_DataModel* aDataModel = dynamic_cast<SHAPERGUI_DataModel*>(dataModel());
+  aDataModel->initRootObject();
 }
 
 //******************************************************
@@ -265,12 +276,17 @@ void SHAPERGUI::viewManagers(QStringList& theList) const
 //******************************************************
 bool SHAPERGUI::activateModule(SUIT_Study* theStudy)
 {
-  bool isDone = LightApp_Module::activateModule(theStudy);
-  loadToolbarsConfig();
+  ModelAPI_Session::get()->moduleDocument(); // initialize a root document if not done yet
 
+  // this must be done in the initialization and in activation (on the second activation
+  // initialization in not called, so SComponent must be added anyway
   SHAPERGUI_DataModel* aDataModel = dynamic_cast<SHAPERGUI_DataModel*>(dataModel());
   aDataModel->initRootObject();
 
+
+  bool isDone = LightApp_Module::activateModule(theStudy);
+  loadToolbarsConfig();
+
   if (isDone) {
     setMenuShown(true);
     setToolShown(true);
@@ -284,11 +300,6 @@ bool SHAPERGUI::activateModule(SUIT_Study* theStudy)
       aObjDoc->toggleViewAction()->setVisible(true);
     }
 
-    if (!myInspectionPanel) {
-      myInspectionPanel = myWorkshop->inspectionPanel();
-      connect(myInspectionPanel->toggleViewAction(), SIGNAL(toggled(bool)),
-              this, SLOT(onWhatIs(bool)));
-    }
     myInspectionPanel->toggleViewAction()->setVisible(true);
 
     myWorkshop->facesPanel()->toggleViewAction()->setVisible(true);
@@ -387,16 +398,12 @@ bool SHAPERGUI::activateModule(SUIT_Study* theStudy)
 }
 
 //******************************************************
-bool SHAPERGUI::deactivateModule(SUIT_Study* theStudy)
+void SHAPERGUI::hideInternalWindows()
 {
-  saveToolbarsConfig();
-
   myProxyViewer->activateViewer(false);
   setMenuShown(false);
   setToolShown(false);
 
-  myWorkshop->deactivateModule();
-
   QObject* aObj = myWorkshop->objectBrowser()->parent();
   QDockWidget* aObjDoc = dynamic_cast<QDockWidget*>(aObj);
   if (aObjDoc) {
@@ -405,17 +412,30 @@ bool SHAPERGUI::deactivateModule(SUIT_Study* theStudy)
     aObjDoc->toggleViewAction()->setVisible(false);
   }
 
-  myIsInspectionVisible = myInspectionPanel->isVisible();
   myInspectionPanel->hide();
   myInspectionPanel->toggleViewAction()->setVisible(false);
 
-  myIsFacesPanelVisible = myWorkshop->facesPanel()->isVisible();
   myWorkshop->facesPanel()->hide();
   myWorkshop->facesPanel()->toggleViewAction()->setVisible(false);
 
   myWorkshop->propertyPanel()->hide();
   myWorkshop->propertyPanel()->toggleViewAction()->setVisible(false);
 
+  myWorkshop->hidePanel(myWorkshop->facesPanel());
+}
+
+
+//******************************************************
+bool SHAPERGUI::deactivateModule(SUIT_Study* theStudy)
+{
+  saveToolbarsConfig();
+  myWorkshop->deactivateModule();
+
+  myIsInspectionVisible = myInspectionPanel->isVisible();
+  myIsFacesPanelVisible = myWorkshop->facesPanel()->isVisible();
+  hideInternalWindows();
+
+
   // the active operation should be stopped for the next activation.
   // There should not be active operation and visualized preview.
   // Abort operation should be performed before the selection's remove
@@ -447,7 +467,6 @@ bool SHAPERGUI::deactivateModule(SUIT_Study* theStudy)
     mySelector = 0;
   }
 
-  myWorkshop->hidePanel(myWorkshop->facesPanel());
   //myWorkshop->contextMenuMgr()->disconnectViewer();
 
   SUIT_ResourceMgr* aResMgr = application()->resourceMgr();
@@ -1226,6 +1245,6 @@ void SHAPERGUI::resetToolbars()
 
 void SHAPERGUI::publishToStudy()
 {
-  if (isActiveModule())
+  if (isActiveModule() && ModelAPI_Session::get()->hasModuleDocument())
     myWorkshop->module()->launchOperation("PublishToStudy", false);
 }
index ee3d34a8a9ecd3d4e562fb807732ccc99ff9a40d..864cc4c9010580332924bf88c39233b8faabd867 100644 (file)
@@ -241,6 +241,9 @@ private slots:
   void saveToolbarsConfig();
   void loadToolbarsConfig();
 
+
+  void hideInternalWindows();
+
   /// List of registered nested actions
   QStringList myNestedActionsList;
 
index 8c206de6b99150fd818d59dc9ed3b408c3ef67ed..3c062fb5ddbdfa1c4921fcf8d2e8d113e792352b 100644 (file)
@@ -70,7 +70,7 @@ class SHAPERGUI_EXPORT SHAPERGUI_DataModel : public LightApp_DataModel
   /// Creates a module root object if it has not been created yet
   /// and append it to the active study. It is necessary for correct persistent
   /// of the model.
-  void initRootObject();
+  virtual void initRootObject() override;
 
   /// Update data object
   /// \param theObj an data object
index 8093a9062b653f925c4b17ef085e77204eb787e9..13e6ae0fad1acd1c2360da5daa56a72808f1fa84 100644 (file)
@@ -228,6 +228,7 @@ ADD_UNIT_TESTS(
   Test3132.py
   Test3154.py
   Test3170.py
+  Test3240.py
   Test19089.py
   Test19101.py
   TestArcBehavior.py
index 7e38b253e7f2836f51aa6b62c30985e9e995c68f..d8b7d5bca4475f1faa4f5262f92c0273fd3e46b0 100644 (file)
 #include <cmath>
 #include <regex>
 #include <sstream>
+#include <vector>
 
 const double tolerance = 1.e-7;
 #define PI 3.1415926535897932
 
+// To support old types of GCC (less than 4.9), check the regular expressions are working
+#if (__cplusplus >= 201103L || _MSVC_LANG >= 201103L)  && \
+    (__cplusplus >= 201402L || !defined(__GLIBCXX__)   || \
+        (defined(_GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMIT) || \
+         defined(_GLIBCXX_REGEX_STATE_LIMIT)           || \
+         (defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE > 4)))
+#define HAVE_WORKING_REGEX 1
+#else
+#define HAVE_WORKING_REGEX 0
+#endif
+
+
 /// \brief Calculate intersection point of two lines
 static std::shared_ptr<GeomAPI_Pnt2d> intersect(FeaturePtr theLine1, FeaturePtr theLine2);
 
@@ -308,6 +321,46 @@ double SketchPlugin_ConstraintAngle::getAngleForType(double theAngle,
   return anAngle;
 }
 
+#if !HAVE_WORKING_REGEX
+static bool parseString(const std::string& theString, std::ostringstream* theResult)
+{
+  // skip leading spaces
+  size_t aLength = theString.size();
+  size_t aPos = theString.find_first_not_of(' ');
+  if (aPos == std::string::npos)
+    return false;
+  // first should be a value
+  if (theString[aPos] == '-' || theString[aPos] == '+')
+    theResult[1] << theString[aPos++];
+  while (aPos < aLength && theString[aPos] >= '0' && theString[aPos] <= '9')
+    theResult[1] << theString[aPos++];
+  if (theString[aPos] != ' ') {
+    if (theString[aPos] != '.')
+      return false;
+    theResult[1] << theString[aPos++];
+    while (aPos < aLength && theString[aPos] >= '0' && theString[aPos] <= '9')
+      theResult[1] << theString[aPos++];
+  }
+
+  // next, find the sign
+  aPos = theString.find_first_not_of(' ', aPos);
+  if (aPos == std::string::npos)
+    return false;
+  if (theString[aPos] == '-' || theString[aPos] == '+')
+    theResult[2] << theString[aPos++];
+
+  // a variable should be at the end
+  aPos = theString.find_first_not_of(' ', aPos);
+  if (aPos == std::string::npos)
+    return false;
+  if (theString[aPos] != '(' || theString.back() != ')')
+    return false;
+  theResult[3] << theString.substr(aPos + 1, aLength - aPos - 2);
+
+  return true;
+}
+#endif
+
 // Convert angle value or a text expression from one angle type to another
 static void convertAngle(AttributeDoublePtr theAngle,
                          const int thePrevType, const int theNewType)
@@ -324,15 +377,23 @@ static void convertAngle(AttributeDoublePtr theAngle,
     else {
       // process the parametric value
       std::string anAngleText = theAngle->text();
+#if HAVE_WORKING_REGEX
       std::regex anAngleRegex("\\s*([-+]?[0-9]*\\.?[0-9]*)\\s*([-+])\\s*\\((.*)\\)$",
                               std::regex_constants::ECMAScript);
+#endif
 
       double anAnglePrefix = 0.0;
       static const char aSignPrefix[2] = { '-', '+' };
       int aSignInd = 1;
 
+#if HAVE_WORKING_REGEX
       std::smatch aResult;
       if (std::regex_search(anAngleText, aResult, anAngleRegex)) {
+#else
+      // workaround to support old versions of GCC (less than 4.9)
+      std::ostringstream aResult[4];
+      if (parseString(anAngleText, aResult)) {
+#endif
         anAnglePrefix = std::atof(aResult[1].str().c_str());
         aSignInd = aResult[2].str()[0] == aSignPrefix[0] ? 0 : 1;
         anAngleText = aResult[3].str();
index 14920c109ad5b1d9dd76c73d0ff88e9ff1cb869a..e226f229e8a22af9f84b98dc27a5c414fa6adf7f 100644 (file)
@@ -65,6 +65,7 @@
 #include <GeomAlgoAPI_EdgeBuilder.h>
 #include <GeomAlgoAPI_ShapeTools.h>
 
+#include <GeomAPI_BSpline.h>
 #include <GeomAPI_Circ.h>
 #include <GeomAPI_Dir2d.h>
 #include <GeomAPI_Ellipse.h>
@@ -242,7 +243,13 @@ bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute
         SketchPlugin_Tools::findCoincidences(*anIt, SketchPlugin_Constraint::ENTITY_A(),
                                              aCoinc, true);
 
-      isValid = aCoinc.find(aOtherFea) != aCoinc.end();
+      std::set<FeaturePtr>::iterator aFoundCoinc = aCoinc.find(aOtherFea);
+      if (aFoundCoinc != aCoinc.end()) {
+        // do not take into account internal constraints
+        AttributeReferencePtr aParent =
+            (*aFoundCoinc)->reference(SketchPlugin_SketchEntity::PARENT_ID());
+        isValid = !aParent || !aParent->isInitialized() || aParent->value() != aRefFea;
+      }
     }
   }
 
@@ -1264,6 +1271,31 @@ bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute,
       theError.arg(anEdge->isClosed() ? "Error: Ellipse is orthogonal to the sketch plane."
                                       : "Error: Elliptic Arc is orthogonal to the sketch plane.");
   }
+  else if (anEdge->isBSpline()) {
+    // check B-spline is periodic and planar
+    std::shared_ptr<GeomAPI_Curve> aCurve(new GeomAPI_Curve(anEdge));
+    std::shared_ptr<GeomAPI_BSpline> aBSpline(new GeomAPI_BSpline(aCurve));
+    if (aBSpline->isPeriodic()) {
+      GeomPlanePtr aBSplinePlane = GeomAlgoAPI_ShapeTools::findPlane(ListOfShape(1, anEdge));
+      if (aBSplinePlane) {
+        std::shared_ptr<GeomAPI_Dir> aBSplineNormal = aBSplinePlane->direction();
+        double aDot = fabs(aNormal->dot(aBSplineNormal));
+        aValid = fabs(aDot - 1.0) <= tolerance * tolerance;
+        if (!aValid) {
+          // B-spline's plane is orthogonal to the sketch plane,
+          // thus, need to check whether B-spline is planar.
+          std::list<GeomPointPtr> aPoles = aBSpline->poles();
+          for (std::list<GeomPointPtr>::iterator it = aPoles.begin();
+            it != aPoles.end() && !aValid; ++it) {
+            if (aBSplinePlane->distance(*it) > tolerance)
+              aValid = true; // non-planar B-spline curve
+          }
+          if (!aValid)
+            theError = "Error: Periodic B-spline is orthogonal to the sketch plane.";
+        }
+      }
+    }
+  }
 
   return aValid;
 }
@@ -1803,8 +1835,20 @@ bool SketchPlugin_ReplicationReferenceValidator::isValid(
   if (!aCopyAttr || !aCopyAttr->value())
     return true; // feature is not a copy, thus valid
 
-  // check the copy feature is already referred by the "Multi" feature
   FeaturePtr aMultiFeature = ModelAPI_Feature::feature(theAttribute->owner());
+  // Collect original entities
+  std::set<FeaturePtr> anOriginalFeatures;
+  if (theArguments.size() > 1) {
+    AttributeRefListPtr anOrigList = aMultiFeature->reflist(theArguments.back());
+    for (int i = 0; i < anOrigList->size(); ++i)
+    {
+      FeaturePtr aFeature = ModelAPI_Feature::feature(anOrigList->object(i));
+      if (aFeature == anAttrOwnerFeature)
+        return true;
+    }
+  }
+
+  // check the copy feature is already referred by the "Multi" feature
   AttributeRefListPtr aRefList = aMultiFeature->reflist(theArguments.front());
   for (int i = 0; i < aRefList->size(); ++i)
   {
index 6ee4690a42735494f26d4f1e23b3ce8aef97c03e..f88fab7538aa76ece5295f3b289dbcd076e97813 100644 (file)
       <source>Error: Elliptic Arc is orthogonal to the sketch plane.</source>
       <translation>Error: Elliptic Arc is orthogonal to the sketch plane.</translation>
     </message>
+    <message>
+      <source>Error: Periodic B-spline is orthogonal to the sketch plane.</source>
+      <translation>Error: Periodic B-spline is orthogonal to the sketch plane.</translation>
+    </message>
     <message>
       <source>Error: Selected object is not supported for projection.</source>
       <translation>Error: Selected object is not supported for projection.</translation>
diff --git a/src/SketchPlugin/Test/Test3240.py b/src/SketchPlugin/Test/Test3240.py
new file mode 100644 (file)
index 0000000..c6b0a29
--- /dev/null
@@ -0,0 +1,46 @@
+# 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
+
+ORIGIN = GeomAPI_Pnt(0, 0, 0)
+NB_COPIES = 8
+TOLERANCE = 1.e-7
+
+model.begin()
+partSet = model.moduleDocument()
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "OX"), True)
+SketchLine_1 = SketchProjection_1.createdFeature()
+SketchMultiRotation_1 = Sketch_1.addRotation([SketchLine_1.result()], SketchAPI_Line(SketchLine_1).startPoint(), 360, NB_COPIES, True)
+[SketchLine_1, SketchLine_2, SketchLine_3, SketchLine_4, SketchLine_5, SketchLine_6, SketchLine_7, SketchLine_8] = SketchMultiRotation_1.rotated()
+model.do()
+model.end()
+
+model.testNbResults(Sketch_1, 1)
+model.testNbSubShapes(Sketch_1, GeomAPI_Shape.EDGE, [NB_COPIES])
+model.testNbSubShapes(Sketch_1, GeomAPI_Shape.VERTEX, [2 * NB_COPIES])
+
+midPnt = Sketch_1.defaultResult().shape().middlePoint()
+assert(midPnt.distance(ORIGIN) < TOLERANCE)
+
+assert(model.checkPythonDump())
index f5f6f3f314eb1cbb8690f78d8161f01fbac81ee1..824e6281b2c9b60f4145dc74efe6a0fd50fbb68b 100644 (file)
         <sketch_shape_selector id="ConstraintEntityA"
             label="Mirror line" tooltip="Select mirror line" shape_types="edge">
           <validator id="GeomValidators_ShapeType" parameters="line"/>
-          <validator id="SketchPlugin_ReplicationReference" parameters="ConstraintEntityC"/>
+          <validator id="SketchPlugin_ReplicationReference" parameters="ConstraintEntityC,ConstraintEntityB"/>
         </sketch_shape_selector>
         <sketch_multi_selector id="ConstraintMirrorList"
             label="Segments"
                     shape_types="vertex">
                 <validator id="PartSet_DifferentObjects"/>
                 <validator id="GeomValidators_ShapeType" parameters="vertex"/>
-                <validator id="SketchPlugin_ReplicationReference" parameters="ConstraintEntityB"/>
+                <validator id="SketchPlugin_ReplicationReference" parameters="ConstraintEntityB,ConstraintEntityA"/>
               </sketch_shape_selector>
               <sketch_shape_selector
                     id="MultiTranslationEndPoint"
                     shape_types="vertex">
                 <validator id="PartSet_DifferentObjects"/>
                 <validator id="GeomValidators_ShapeType" parameters="vertex"/>
-                <validator id="SketchPlugin_ReplicationReference" parameters="ConstraintEntityB"/>
+                <validator id="SketchPlugin_ReplicationReference" parameters="ConstraintEntityB,ConstraintEntityA"/>
               </sketch_shape_selector>
             </groupbox>
           </box>
                     shape_types="vertex">
                 <validator id="PartSet_DifferentObjects"/>
                 <validator id="GeomValidators_ShapeType" parameters="vertex"/>
-                <validator id="SketchPlugin_ReplicationReference" parameters="ConstraintEntityB"/>
+                <validator id="SketchPlugin_ReplicationReference" parameters="ConstraintEntityB,ConstraintEntityA"/>
               </sketch_shape_selector>
               <sketch_shape_selector
                     id="MultiTranslationEndPoint"
                     shape_types="vertex">
                 <validator id="PartSet_DifferentObjects"/>
                 <validator id="GeomValidators_ShapeType" parameters="vertex"/>
-                <validator id="SketchPlugin_ReplicationReference" parameters="ConstraintEntityB"/>
+                <validator id="SketchPlugin_ReplicationReference" parameters="ConstraintEntityB,ConstraintEntityA"/>
               </sketch_shape_selector>
             </groupbox>
           </box>
               tooltip="Center of rotation"
               shape_types="vertex">
           <validator id="GeomValidators_ShapeType" parameters="vertex"/>
-          <validator id="SketchPlugin_ReplicationReference" parameters="ConstraintEntityB"/>
+          <validator id="SketchPlugin_ReplicationReference" parameters="ConstraintEntityB,ConstraintEntityA"/>
         </sketch_shape_selector>
         <toolbox id="AngleType">
           <box id="FullAngle" title="Full angle" icon="icons/Sketch/angle_up_full_32x32.png">
index 1ac0cf756283787c7b23bdf528f577ae9519b095..b2cabccc3af7a23f293ae7b5443d47dec5bbf619 100644 (file)
@@ -133,21 +133,21 @@ SketcherPrs_LengthDimension::~SketcherPrs_LengthDimension()
 bool SketcherPrs_LengthDimension::IsReadyToDisplay(ModelAPI_Feature* theConstraint,
                                          const std::shared_ptr<GeomAPI_Ax3>& thePlane)
 {
-  gp_Pnt aPnt1, aPnt2;
+  gp_Pnt2d aPnt1, aPnt2;
   return readyToDisplay(theConstraint, thePlane, aPnt1, aPnt2);
 }
 
 static bool isEqualPoints(ModelAPI_Feature* theConstraint,
-                          const gp_Pnt& thePoint1,
-                          const gp_Pnt& thePoint2)
+  const gp_Pnt2d& theP1, const gp_Pnt2d& theP2)
 {
   bool isEqual = false;
   if (theConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID())
-    isEqual = Abs(thePoint1.X() - thePoint2.X()) < Precision::Confusion();
+    isEqual = Abs(theP1.X() - theP2.X()) < Precision::Confusion();
   else if (theConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID())
-    isEqual = Abs(thePoint1.Y() - thePoint2.Y()) < Precision::Confusion();
-  else
-    isEqual = thePoint1.SquareDistance(thePoint2) < Precision::SquareConfusion();
+    isEqual = Abs(theP1.Y() - theP2.Y()) < Precision::Confusion();
+  else {
+    isEqual = theP1.SquareDistance(theP2) < Precision::SquareConfusion();
+  }
   return isEqual;
 }
 
@@ -158,10 +158,10 @@ void SketcherPrs_LengthDimension::Compute(
 {
   if (!plane().get())
     return;
-  gp_Pnt aPnt1, aPnt2;
-  bool aReadyToDisplay = readyToDisplay(myConstraint, plane(), aPnt1, aPnt2);
+  gp_Pnt2d aP1, aP2;
+  bool aReadyToDisplay = readyToDisplay(myConstraint, plane(), aP1, aP2);
   if (aReadyToDisplay) {
-    if (isEqualPoints(myConstraint, aPnt1, aPnt2)) {
+    if (isEqualPoints(myConstraint, aP1, aP2)) {
       // adjust points to draw the dimension presentation
       std::shared_ptr<GeomDataAPI_Dir> aDirAttr = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
           myConstraint->attribute(SketchPlugin_ConstraintDistance::DIRECTION_ID()));
@@ -176,15 +176,14 @@ void SketcherPrs_LengthDimension::Compute(
         y = 1.0;
       else
         x = 1.0;
-      GeomPointPtr aCoord = plane()->to3D(x, y);
 
-      gp_XYZ aDir(aCoord->x(), aCoord->y(), aCoord->z());
-      aPnt1.ChangeCoord().Add(aDir * (-Precision::Confusion()));
-      aPnt2.ChangeCoord().Add(aDir * Precision::Confusion());
+      gp_XY aDir(x, y);
+      aP1.ChangeCoord().Add(aDir * (-Precision::Confusion()));
+      aP2.ChangeCoord().Add(aDir * Precision::Confusion());
     }
 
-    myFirstPoint = aPnt1;
-    mySecondPoint = aPnt2;
+    myFirstPoint = plane()->to3D(aP1.X(), aP1.Y())->impl<gp_Pnt>();
+    mySecondPoint = plane()->to3D(aP2.X(), aP2.Y())->impl<gp_Pnt>();
 
     myDistance = SketcherPrs_Tools::getFlyoutDistance(myConstraint);
     myPlane = gp_Pln(plane()->impl<gp_Ax3>());
@@ -238,7 +237,7 @@ void SketcherPrs_LengthDimension::Compute(
 
 bool SketcherPrs_LengthDimension::readyToDisplay(ModelAPI_Feature* theConstraint,
                                                  const std::shared_ptr<GeomAPI_Ax3>& thePlane,
-                                                 gp_Pnt& thePnt1, gp_Pnt& thePnt2)
+                                                 gp_Pnt2d& thePnt1, gp_Pnt2d& thePnt2)
 {
   if (!thePlane)
     return false;
@@ -264,8 +263,8 @@ bool SketcherPrs_LengthDimension::readyToDisplay(ModelAPI_Feature* theConstraint
     std::shared_ptr<GeomDataAPI_Point2D> aEndPoint =
       std::dynamic_pointer_cast<GeomDataAPI_Point2D>
       (aLineData->attribute(SketchPlugin_Line::END_ID()));
-    thePnt1 = thePlane->to3D(aStartPoint->x(), aStartPoint->y())->impl<gp_Pnt>();
-    thePnt2 = thePlane->to3D(aEndPoint->x(), aEndPoint->y())->impl<gp_Pnt>();
+    thePnt1 = gp_Pnt2d(aStartPoint->x(), aStartPoint->y());
+    thePnt2 = gp_Pnt2d(aEndPoint->x(), aEndPoint->y());
     return true;
 
   } else if (theConstraint->getKind() == SketchPlugin_ConstraintDistance::ID() ||
@@ -303,20 +302,9 @@ bool SketcherPrs_LengthDimension::readyToDisplay(ModelAPI_Feature* theConstraint
     if (!aPnt_A || !aPnt_B) // Objects not found
       return false;
 
-    /*if (theConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID()) {
-      if (fabs(aPnt_A->x() - aPnt_B->x()) < Precision::Confusion())
-        return false;
-    }
-    else if (theConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID()) {
-      if (fabs(aPnt_A->y() - aPnt_B->y()) < Precision::Confusion())
-        return false;
-    }*/
-
     // Get points from these object
-    std::shared_ptr<GeomAPI_Pnt> aPoint1 = thePlane->to3D(aPnt_A->x(), aPnt_A->y());
-    std::shared_ptr<GeomAPI_Pnt> aPoint2 = thePlane->to3D(aPnt_B->x(), aPnt_B->y());
-    thePnt1 = aPoint1->impl<gp_Pnt>();
-    thePnt2 = aPoint2->impl<gp_Pnt>();
+    thePnt1 = gp_Pnt2d(aPnt_A->x(), aPnt_A->y());
+    thePnt2 = gp_Pnt2d(aPnt_B->x(), aPnt_B->y());
     return true;
   }
   return false;
index 620d616883b0d9973ff7a2a551d6f43db5b05a39..ff2d26beaa130f3728f516cfc201aecd7efb4df6 100644 (file)
@@ -81,7 +81,7 @@ protected:
 private:
   static bool readyToDisplay(ModelAPI_Feature* theConstraint,
                              const std::shared_ptr<GeomAPI_Ax3>& thePlane,
-                             gp_Pnt& thePnt1, gp_Pnt& thePnt2);
+                             gp_Pnt2d& thePnt1, gp_Pnt2d& thePnt2);
 
   /// Set the direction for horizontal/vertical constraint
   void setDirection(ModelAPI_Feature* theConstraint,
index 787ddc25c70697907825def41408cc2542c0296e..d5b9bf15a782ee514f2f9a709c650e6fd01d5e3b 100644 (file)
@@ -538,9 +538,7 @@ void XGUI_ContextMenuMgr::updateViewerMenu()
         canBeShaded = aDisplayer->canBeShaded(aObject);
       }
       if (aShape.get()) {
-        if (aShape->isPlanar()) {
-          hasPlanar = true;
-        }
+        hasPlanar = (aShape->isFace() && aShape->isPlanar());
       }
     }
     if (isVisible) {
index e3a1fb6329fa7cfba576d745e4f3be364f562103..5b15106a862a75750621e20f2f9ee48795a77a06 100644 (file)
@@ -201,10 +201,12 @@ void XGUI_DataModel::processEvent(const std::shared_ptr<Events_Message>& theMess
     }
   }
   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_DOCUMENT_CHANGED)) {
-    DocumentPtr aDoc = ModelAPI_Session::get()->activeDocument();
-    ModuleBase_ITreeNode* aRoot = myRoot->findRoot(aDoc);
-    if (aRoot) {
-      updateSubTree(aRoot);
+    if (ModelAPI_Session::get()->hasModuleDocument()) {
+      DocumentPtr aDoc = ModelAPI_Session::get()->activeDocument();
+      ModuleBase_ITreeNode* aRoot = myRoot->findRoot(aDoc);
+      if (aRoot) {
+        updateSubTree(aRoot);
+      }
     }
   }
   else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY)) {
index e9d1f320d96d171a4960a69f44e6d7c99441d151..096749adb72ec4a89e3729695329a17e895a349e 100644 (file)
@@ -1115,6 +1115,14 @@ void XGUI_Displayer::AddOrRemoveSelectedShapes(Handle(AIS_InteractiveContext) th
     Handle(StdSelect_BRepOwner) BROwnr = Handle(StdSelect_BRepOwner)::DownCast(anOwner);
     if (!BROwnr.IsNull() && BROwnr->HasShape()) {
       const TopoDS_Shape& aShape = BROwnr->Shape();
+
+      Handle(ModuleBase_ResultPrs) aResPrs =
+          Handle(ModuleBase_ResultPrs)::DownCast(BROwnr->Selectable());
+      TopoDS_Shape aRealShape;
+      if (!aResPrs.IsNull()) {
+        aRealShape = aResPrs->originalShape();
+      }
+
       if (aShape.IsNull())
         continue;
 
@@ -1131,7 +1139,15 @@ void XGUI_Displayer::AddOrRemoveSelectedShapes(Handle(AIS_InteractiveContext) th
           // isSame should be used here as it does not check orientation of shapes
           // despite on isEqual of shapes or IsBound for shape in QMap. Orientation is
           // different for Edges shapes in model shape and owner even if this is the same shape
-        if (ModuleBase_Tools::isSameShape(aParameterShape, aShape)) {
+        bool isSame = ModuleBase_Tools::isSameShape(aParameterShape, aShape);
+        if (!isSame) {
+          // In case of using HideFaces panel we can have instead of an original shape
+          // a compaund of faces which represent original shape with hidden faces.
+          // So, we have to compare the parameter with original shape
+          if (!aRealShape.IsNull())
+            isSame = ModuleBase_Tools::isSameShape(aParameterShape, aRealShape);
+        }
+        if (isSame) {
           Handle(AIS_InteractiveObject) anOwnerPresentation =
             Handle(AIS_InteractiveObject)::DownCast(anOwner->Selectable());
           NCollection_Map<Handle(AIS_InteractiveObject)> aPresentations =
index 3a15e274e42ea7b2d49b1c41ecf2b49a676b315e..19d750c8614fcc0fe78560323a0fc0d37829e4d9 100644 (file)
@@ -1954,7 +1954,7 @@ void XGUI_Workshop::deleteObjects()
     ResultConstructionPtr aConstr = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aObj);
     FeaturePtr aFeature = ModelAPI_Feature::feature(aObj);
     if (aFeature) {
-      notDelete = (!aFeature->isInHistory()) && aConstr->isInfinite();
+      notDelete = (!aFeature->isInHistory()) && (aConstr && aConstr->isInfinite());
       if (notDelete) {
         anObjects.removeAll(aObj);
         aIt--;
@@ -2785,7 +2785,7 @@ void XGUI_Workshop::setNormalView(bool toInvert)
   GeomShapePtr aPlanarFace;
   foreach(ModuleBase_ViewerPrsPtr aPrs, aPrsList) {
     GeomShapePtr aShape = aPrs->shape();
-    if (aShape.get() && aShape->isPlanar()) {
+    if (aShape.get() && aShape->isFace() && aShape->isPlanar()) {
       aPlanarFace = aShape;
       break;
     }
index 77ffaf2057b888e9208c80e8bc261850d0c5373c..ac2fb483471d40136c810c90e91b9bae34a14d3b 100644 (file)
@@ -588,7 +588,7 @@ ExtrusionCut_2 = model.addExtrusionCut(Part_1_doc, [model.selection("FACE", "Ske
 # Test reexecution after parameter change
 Parameter_H.setValue(14)
 model.do()
-model.testResultsVolumes(ExtrusionCut_2, [10205.255531030932615976780653000])
+model.testResultsVolumes(ExtrusionCut_2, [10205.25717])
 Parameter_H.setValue(12)
 model.end()
 
index 96851297ed27286e4a9317b78cfcb96d55811cdf..14407a32e9d597ed7b891c58848157dd0e31b4ef 100644 (file)
@@ -21,8 +21,8 @@ if __name__ == "__main__":
   aPartFeature = locals()["Part_1"]
   model.testNbResults(aPartFeature, 1)
   model.testNbSubResults(aPartFeature, [0])
-  model.testNbSubShapes(aPartFeature, GeomAPI_Shape.SOLID, [552])
-  model.testNbSubShapes(aPartFeature, GeomAPI_Shape.FACE, [4086])
-  model.testNbSubShapes(aPartFeature, GeomAPI_Shape.EDGE, [17086])
-  model.testNbSubShapes(aPartFeature, GeomAPI_Shape.VERTEX, [34172])
-  model.testResultsVolumes(aPartFeature, [55.645173358299])
+  model.testNbSubShapes(aPartFeature, GeomAPI_Shape.SOLID, [553])
+  model.testNbSubShapes(aPartFeature, GeomAPI_Shape.FACE, [4089])
+  model.testNbSubShapes(aPartFeature, GeomAPI_Shape.EDGE, [17094])
+  model.testNbSubShapes(aPartFeature, GeomAPI_Shape.VERTEX, [34188])
+  model.testResultsVolumes(aPartFeature, [55.64517345856])
diff --git a/test.hdfs/horseshoe.py b/test.hdfs/horseshoe.py
new file mode 100644 (file)
index 0000000..346c376
--- /dev/null
@@ -0,0 +1,109 @@
+# 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
+#
+
+if __name__ == "__main__":
+  Part_1 = locals()["Part_1"]
+  model.testNbResults(Part_1, 1)
+  model.testNbSubResults(Part_1, [0])
+  model.testNbSubShapes(Part_1, GeomAPI_Shape.SOLID, [1])
+  model.testNbSubShapes(Part_1, GeomAPI_Shape.FACE, [20])
+  model.testNbSubShapes(Part_1, GeomAPI_Shape.EDGE, [104])
+  model.testNbSubShapes(Part_1, GeomAPI_Shape.VERTEX, [208])
+  model.testResultsVolumes(Part_1, [937708.6935593])
+
+  Part_2 = locals()["Part_2"]
+  model.testNbResults(Part_2, 1)
+  model.testNbSubResults(Part_2, [0])
+  model.testNbSubShapes(Part_2, GeomAPI_Shape.SOLID, [1])
+  model.testNbSubShapes(Part_2, GeomAPI_Shape.FACE, [12])
+  model.testNbSubShapes(Part_2, GeomAPI_Shape.EDGE, [60])
+  model.testNbSubShapes(Part_2, GeomAPI_Shape.VERTEX, [120])
+  model.testResultsVolumes(Part_2, [256665.8235477])
+
+  Part_3 = locals()["Part_3"]
+  model.testNbResults(Part_3, 1)
+  model.testNbSubResults(Part_3, [0])
+  model.testNbSubShapes(Part_3, GeomAPI_Shape.SOLID, [1])
+  model.testNbSubShapes(Part_3, GeomAPI_Shape.FACE, [12])
+  model.testNbSubShapes(Part_3, GeomAPI_Shape.EDGE, [60])
+  model.testNbSubShapes(Part_3, GeomAPI_Shape.VERTEX, [120])
+  model.testResultsVolumes(Part_3, [2719045.0529109])
+
+  Part_4 = locals()["Part_4"]
+  model.testNbResults(Part_4, 1)
+  model.testNbSubResults(Part_4, [0])
+  model.testNbSubShapes(Part_4, GeomAPI_Shape.SOLID, [1])
+  model.testNbSubShapes(Part_4, GeomAPI_Shape.FACE, [6])
+  model.testNbSubShapes(Part_4, GeomAPI_Shape.EDGE, [24])
+  model.testNbSubShapes(Part_4, GeomAPI_Shape.VERTEX, [48])
+  model.testResultsVolumes(Part_4, [534313.7153742])
+
+  Part_5 = locals()["Part_5"]
+  model.testNbResults(Part_5, 1)
+  model.testNbSubResults(Part_5, [0])
+  model.testNbSubShapes(Part_5, GeomAPI_Shape.SOLID, [1])
+  model.testNbSubShapes(Part_5, GeomAPI_Shape.FACE, [19])
+  model.testNbSubShapes(Part_5, GeomAPI_Shape.EDGE, [96])
+  model.testNbSubShapes(Part_5, GeomAPI_Shape.VERTEX, [192])
+  model.testResultsVolumes(Part_5, [1111187.2858512])
+
+  Part_6 = locals()["Part_6"]
+  model.testNbResults(Part_6, 1)
+  model.testNbSubResults(Part_6, [0])
+  model.testNbSubShapes(Part_6, GeomAPI_Shape.SOLID, [1])
+  model.testNbSubShapes(Part_6, GeomAPI_Shape.FACE, [12])
+  model.testNbSubShapes(Part_6, GeomAPI_Shape.EDGE, [60])
+  model.testNbSubShapes(Part_6, GeomAPI_Shape.VERTEX, [120])
+  model.testResultsVolumes(Part_6, [124567.8141964])
+
+  Part_7 = locals()["Part_7"]
+  model.testNbResults(Part_7, 1)
+  model.testNbSubResults(Part_7, [0])
+  model.testNbSubShapes(Part_7, GeomAPI_Shape.SOLID, [1])
+  model.testNbSubShapes(Part_7, GeomAPI_Shape.FACE, [12])
+  model.testNbSubShapes(Part_7, GeomAPI_Shape.EDGE, [60])
+  model.testNbSubShapes(Part_7, GeomAPI_Shape.VERTEX, [120])
+  model.testResultsVolumes(Part_7, [3106355.9518294])
+
+  Part_8 = locals()["Part_8"]
+  model.testNbResults(Part_8, 1)
+  model.testNbSubResults(Part_8, [0])
+  model.testNbSubShapes(Part_8, GeomAPI_Shape.SOLID, [1])
+  model.testNbSubShapes(Part_8, GeomAPI_Shape.FACE, [6])
+  model.testNbSubShapes(Part_8, GeomAPI_Shape.EDGE, [24])
+  model.testNbSubShapes(Part_8, GeomAPI_Shape.VERTEX, [48])
+  model.testResultsVolumes(Part_8, [570471.5090269])
+
+  Part_9 = locals()["Part_9"]
+  model.testNbResults(Part_9, 1)
+  model.testNbSubResults(Part_9, [0])
+  model.testNbSubShapes(Part_9, GeomAPI_Shape.SOLID, [1])
+  model.testNbSubShapes(Part_9, GeomAPI_Shape.FACE, [7])
+  model.testNbSubShapes(Part_9, GeomAPI_Shape.EDGE, [30])
+  model.testNbSubShapes(Part_9, GeomAPI_Shape.VERTEX, [60])
+  model.testResultsVolumes(Part_9, [1688917.3777022])
+
+  Part_10 = locals()["Part_10"]
+  model.testNbResults(Part_10, 1)
+  model.testNbSubResults(Part_10, [0])
+  model.testNbSubShapes(Part_10, GeomAPI_Shape.SOLID, [1])
+  model.testNbSubShapes(Part_10, GeomAPI_Shape.FACE, [10])
+  model.testNbSubShapes(Part_10, GeomAPI_Shape.EDGE, [48])
+  model.testNbSubShapes(Part_10, GeomAPI_Shape.VERTEX, [96])
+  model.testResultsVolumes(Part_10, [6604147.6151849])
index 98ea6ff8934678c145a2e05b76295b1adc9a2393..57f7624057a6707546ce8e663bf22446b7d4d461 100644 (file)
@@ -588,7 +588,7 @@ ExtrusionCut_2 = model.addExtrusionCut(Part_1_doc, [model.selection("FACE", "Ske
 # Test reexecution after parameter change
 Parameter_H.setValue(14)
 model.do()
-model.testResultsVolumes(ExtrusionCut_2, [10205.255531030932615976780653000])
+model.testResultsVolumes(ExtrusionCut_2, [10205.25717])
 Parameter_H.setValue(12)
 model.end()
 
@@ -598,8 +598,8 @@ model.testNbResults(ExtrusionCut_2, 1)
 model.testNbSubResults(ExtrusionCut_2, [0])
 model.testNbSubShapes(ExtrusionCut_2, GeomAPI_Shape.SOLID, [1])
 model.testNbSubShapes(ExtrusionCut_2, GeomAPI_Shape.FACE, [551])
-model.testNbSubShapes(ExtrusionCut_2, GeomAPI_Shape.EDGE, [3473])
-model.testNbSubShapes(ExtrusionCut_2, GeomAPI_Shape.VERTEX, [6946])
-model.testResultsVolumes(ExtrusionCut_2, [10362.335163710422420990653336048])
+model.testNbSubShapes(ExtrusionCut_2, GeomAPI_Shape.EDGE, [3481])
+model.testNbSubShapes(ExtrusionCut_2, GeomAPI_Shape.VERTEX, [6962])
+model.testResultsVolumes(ExtrusionCut_2, [10362.3368])
 
 assert(model.checkPythonDump())
index 89264f19a91f4b02ac690035cc146360547f875e..648e9564009a6cfc7eca808a6879ff69c2a3ae8a 100644 (file)
@@ -300,7 +300,7 @@ SketchConstraintCoincidence_43 = Sketch_3.setCoincident(SketchLine_41.endPoint()
 SketchConstraintCoincidence_44 = Sketch_3.setCoincident(SketchLine_42.endPoint(), SketchLine_37.startPoint())
 SketchProjection_5 = Sketch_3.addProjection(model.selection("EDGE", "PartSet/OX"), False)
 SketchLine_43 = SketchProjection_5.createdFeature()
-SketchProjection_6 = Sketch_3.addProjection(model.selection("EDGE", "([Revolution_1_1/Generated_Face&Sketch_1/SketchLine_34][Revolution_1_1/Generated_Face&Sketch_1/SketchLine_33])([Revolution_1_1/Generated_Face&Sketch_1/SketchLine_33][Fillet_2_1/MF:Fillet&Sketch_1/SketchLine_32])_Fillet_2_1"), False)
+SketchProjection_6 = Sketch_3.addProjection(model.selection("EDGE", "([Revolution_1_1/Generated_Face&Sketch_1/SketchLine_34][Revolution_1_1/Generated_Face&Sketch_1/SketchLine_33])([Revolution_1_1/Generated_Face&Sketch_1/SketchLine_33][Fillet_2_1/MF:Fillet&Sketch_1/SketchLine_32])_Fillet_5_1"), False)
 SketchLine_44 = SketchProjection_6.createdFeature()
 SketchProjection_9 = Sketch_3.addProjection(model.selection("EDGE", "Sketch_1/SketchLine_32"), False)
 SketchLine_47 = SketchProjection_9.createdFeature()
diff --git a/test.models/visor_support.py b/test.models/visor_support.py
new file mode 100644 (file)
index 0000000..e35d0ef
--- /dev/null
@@ -0,0 +1,568 @@
+# 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, "size_x", "150")
+ParamSize = model.addParameter(Part_1_doc, "size_y", "180")
+model.addParameter(Part_1_doc, "size_z", "5")
+model.addParameter(Part_1_doc, "chamfer", "0.8")
+model.addParameter(Part_1_doc, "thickness", "4")
+
+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()
+SketchArc_1 = Sketch_1.addArc(0, -145, 0, 30, 50, 22.70509831248424, True)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.result(), SketchArc_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchArc_1.center(), SketchLine_1.result())
+SketchConstraintDistance_1 = Sketch_1.setDistance(SketchArc_1.center(), SketchAPI_Line(SketchLine_1).startPoint(), "size_y-35", True)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchArc_1.results()[1], "size_y-5")
+SketchArc_2 = Sketch_1.addArc(47.42857142857143, 14.08026468498505, 50, 22.70509831248424, 56.4024789026646, 13.39544014803082, True)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchArc_1.endPoint(), SketchArc_2.startPoint())
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchArc_1.results()[1], SketchArc_2.results()[1])
+SketchConstraintRadius_2 = Sketch_1.setRadius(SketchArc_2.results()[1], 9)
+SketchArc_3 = Sketch_1.addArc(66.37348720721259, 12.63452399585945, 56.4024789026646, 13.39544014803082, 65.54400934016748, 2.668985050670266, False)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchArc_2.endPoint(), SketchArc_3.startPoint())
+SketchConstraintTangent_2 = Sketch_1.setTangent(SketchArc_2.results()[1], SketchArc_3.results()[1])
+SketchConstraintRadius_3 = Sketch_1.setRadius(SketchArc_3.results()[1], 10)
+SketchArc_4 = Sketch_1.addArc(64.79747925982687, -6.3, 65.54400934016748, 2.668985050670266, 73.72335126899428, -5.147260273972602, True)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchArc_3.endPoint(), SketchArc_4.startPoint())
+SketchConstraintTangent_3 = Sketch_1.setTangent(SketchArc_3.results()[1], SketchArc_4.results()[1])
+SketchConstraintRadius_4 = Sketch_1.setRadius(SketchArc_4.results()[1], 9)
+SketchArc_5 = Sketch_1.addArc(-80, -25, 73.72335126899428, -5.147260273972602, 28.47740289468357, -135.7142857142857, True)
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchArc_4.endPoint(), SketchArc_5.startPoint())
+SketchConstraintTangent_4 = Sketch_1.setTangent(SketchArc_4.results()[1], SketchArc_5.results()[1])
+SketchConstraintRadius_5 = Sketch_1.setRadius(SketchArc_5.results()[1], "size_x+5")
+SketchArc_6 = Sketch_1.addArc(32.67652816802617, -140, 28.47740289468357, -135.7142857142857, 36.96224245374191, -135.8008747266572, False)
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchArc_5.endPoint(), SketchArc_6.startPoint())
+SketchConstraintTangent_5 = Sketch_1.setTangent(SketchArc_5.results()[1], SketchArc_6.results()[1])
+SketchConstraintRadius_6 = Sketch_1.setRadius(SketchArc_6.results()[1], 6)
+SketchArc_7 = Sketch_1.addArc(38.39081388227633, -134.4011663021575, 36.96224245374191, -135.8008747266572, 39.81938531083141, -133.0014578776889, True)
+SketchConstraintCoincidence_8 = Sketch_1.setCoincident(SketchArc_6.endPoint(), SketchArc_7.startPoint())
+SketchConstraintTangent_6 = Sketch_1.setTangent(SketchArc_6.results()[1], SketchArc_7.results()[1])
+SketchConstraintRadius_7 = Sketch_1.setRadius(SketchArc_7.results()[1], "thickness/2")
+SketchArc_8 = Sketch_1.addArc(32.67652816802617, -140, 39.81938531083141, -133.0014578776889, 25.67798604578851, -132.8571428571429, True)
+SketchConstraintCoincidence_9 = Sketch_1.setCoincident(SketchArc_7.endPoint(), SketchArc_8.startPoint())
+SketchConstraintTangent_7 = Sketch_1.setTangent(SketchArc_7.results()[1], SketchArc_8.results()[1])
+SketchConstraintCoincidence_10 = Sketch_1.setCoincident(SketchArc_8.center(), SketchArc_6.center())
+SketchArc_9 = Sketch_1.addArc(-80, -25, 25.67798604578851, -132.8571428571429, 69.75629704269767, -5.659589041095889, False)
+SketchConstraintCoincidence_11 = Sketch_1.setCoincident(SketchArc_8.endPoint(), SketchArc_9.startPoint())
+SketchConstraintTangent_8 = Sketch_1.setTangent(SketchArc_8.results()[1], SketchArc_9.results()[1])
+SketchConstraintCoincidence_12 = Sketch_1.setCoincident(SketchArc_9.center(), SketchArc_5.center())
+SketchArc_10 = Sketch_1.addArc(64.79747925982687, -6.3, 69.75629704269767, -5.659589041095889, 65.21221819334943, -1.317230527405396, False)
+SketchConstraintCoincidence_13 = Sketch_1.setCoincident(SketchArc_9.endPoint(), SketchArc_10.startPoint())
+SketchConstraintTangent_9 = Sketch_1.setTangent(SketchArc_9.results()[1], SketchArc_10.results()[1])
+SketchConstraintCoincidence_14 = Sketch_1.setCoincident(SketchArc_4.center(), SketchArc_10.center())
+SketchArc_11 = Sketch_1.addArc(66.37348720721259, 12.63452399585945, 65.21221819334943, -1.317230527405396, 52.41407558084543, 13.69980660889937, True)
+SketchConstraintCoincidence_15 = Sketch_1.setCoincident(SketchArc_10.endPoint(), SketchArc_11.startPoint())
+SketchConstraintTangent_10 = Sketch_1.setTangent(SketchArc_10.results()[1], SketchArc_11.results()[1])
+SketchConstraintCoincidence_16 = Sketch_1.setCoincident(SketchArc_11.center(), SketchArc_3.center())
+SketchArc_12 = Sketch_1.addArc(47.42857142857143, 14.08026468498505, 52.41407558084543, 13.69980660889937, 52.31556879671711, 15.13726833859206, False)
+SketchConstraintCoincidence_17 = Sketch_1.setCoincident(SketchArc_11.endPoint(), SketchArc_12.startPoint())
+SketchConstraintTangent_11 = Sketch_1.setTangent(SketchArc_11.results()[1], SketchArc_12.results()[1])
+SketchConstraintCoincidence_18 = Sketch_1.setCoincident(SketchArc_12.center(), SketchArc_2.center())
+SketchArc_13 = Sketch_1.addArc(51.92460900726545, 15.0527080463035, 52.31556879671711, 15.13726833859206, 51.52598744945789, 15.0858871609853, False)
+SketchConstraintCoincidence_19 = Sketch_1.setCoincident(SketchArc_12.endPoint(), SketchArc_13.startPoint())
+SketchConstraintTangent_12 = Sketch_1.setTangent(SketchArc_12.results()[1], SketchArc_13.results()[1])
+SketchConstraintRadius_8 = Sketch_1.setRadius(SketchArc_13.results()[1], 0.4)
+SketchLine_2 = Sketch_1.addLine(51.52598744945789, 15.0858871609853, 50.80630122186367, 6.439410365943716)
+SketchConstraintCoincidence_20 = Sketch_1.setCoincident(SketchArc_13.endPoint(), SketchLine_2.startPoint())
+SketchConstraintTangent_13 = Sketch_1.setTangent(SketchLine_2.result(), SketchArc_13.results()[1])
+SketchArc_14 = Sketch_1.addArc(47.81663953830692, 6.68825372605725, 50.80630122186367, 6.439410365943716, 47.56779617819338, 3.698592042500495, True)
+SketchConstraintCoincidence_21 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchArc_14.startPoint())
+SketchConstraintTangent_14 = Sketch_1.setTangent(SketchLine_2.result(), SketchArc_14.results()[1])
+SketchConstraintRadius_9 = Sketch_1.setRadius(SketchArc_14.results()[1], 3)
+SketchArc_15 = Sketch_1.addArc(47.73369175160241, 5.691699831538332, 47.56779617819338, 3.698592042500495, 46.66684983267853, 4, True)
+SketchConstraintCoincidence_22 = Sketch_1.setCoincident(SketchArc_14.endPoint(), SketchArc_15.startPoint())
+SketchConstraintTangent_15 = Sketch_1.setTangent(SketchArc_14.results()[1], SketchArc_15.results()[1])
+SketchConstraintRadius_10 = Sketch_1.setRadius(SketchArc_15.results()[1], 2)
+SketchArc_16 = Sketch_1.addArc(0, -70, 46.66684983267853, 4, 0, 17.48596957973185, False)
+SketchConstraintCoincidence_23 = Sketch_1.setCoincident(SketchArc_15.endPoint(), SketchArc_16.startPoint())
+SketchConstraintTangent_16 = Sketch_1.setTangent(SketchArc_15.results()[1], SketchArc_16.results()[1])
+SketchConstraintCoincidence_24 = Sketch_1.setCoincident(SketchArc_16.endPoint(), SketchLine_1.result())
+SketchConstraintCoincidence_25 = Sketch_1.setCoincident(SketchArc_16.center(), SketchLine_1.result())
+SketchConstraintDistance_2 = Sketch_1.setDistance(SketchArc_16.center(), SketchAPI_Line(SketchLine_1).startPoint(), "size_y/2-20", True)
+SketchLine_3 = Sketch_1.addLine(64.79747925982687, -6.3, 66.37348720721259, 12.63452399585945)
+SketchLine_3.setAuxiliary(True)
+SketchConstraintCoincidence_26 = Sketch_1.setCoincident(SketchArc_4.center(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_27 = Sketch_1.setCoincident(SketchArc_3.center(), SketchLine_3.endPoint())
+SketchLine_4 = Sketch_1.addLine(47.73369175160241, 5.691699831538332, 47.81663953830692, 6.68825372605725)
+SketchLine_4.setAuxiliary(True)
+SketchConstraintCoincidence_28 = Sketch_1.setCoincident(SketchArc_15.center(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_29 = Sketch_1.setCoincident(SketchArc_14.center(), SketchLine_4.endPoint())
+SketchConstraintParallel_1 = Sketch_1.setParallel(SketchLine_2.result(), SketchLine_3.result())
+SketchConstraintParallel_2 = Sketch_1.setParallel(SketchLine_2.result(), SketchLine_4.result())
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchArc_5.center(), SketchAPI_Line(SketchLine_1).startPoint(), "size_x/2+5")
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchArc_5.center(), SketchAPI_Line(SketchLine_1).startPoint(), 25)
+SketchConstraintDistance_3 = Sketch_1.setDistance(SketchArc_11.endPoint(), SketchLine_2.result(), 1, True)
+SketchConstraintDistanceVertical_2 = Sketch_1.setVerticalDistance(SketchArc_8.center(), SketchAPI_Line(SketchLine_1).startPoint(), "size_y-40")
+SketchConstraintDistance_4 = Sketch_1.setDistance(SketchArc_1.endPoint(), SketchLine_1.result(), 50, True)
+SketchLine_5 = Sketch_1.addLine(28.47740289468357, -135.7142857142857, 32.67652816802617, -140)
+SketchLine_5.setAuxiliary(True)
+SketchConstraintCoincidence_30 = Sketch_1.setCoincident(SketchArc_5.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_31 = Sketch_1.setCoincident(SketchArc_6.center(), SketchLine_5.endPoint())
+SketchLine_6 = Sketch_1.addLine(32.67652816802617, -140, 36.96224245374191, -135.8008747266572)
+SketchLine_6.setAuxiliary(True)
+SketchConstraintCoincidence_32 = Sketch_1.setCoincident(SketchArc_6.center(), SketchLine_6.startPoint())
+SketchConstraintCoincidence_33 = Sketch_1.setCoincident(SketchArc_6.endPoint(), SketchLine_6.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_1.setPerpendicular(SketchLine_5.result(), SketchLine_6.result())
+SketchConstraintDistanceVertical_3 = Sketch_1.setVerticalDistance(SketchAPI_Line(SketchLine_1).startPoint(), SketchArc_16.startPoint(), 4)
+SketchConstraintDistanceVertical_4 = Sketch_1.setVerticalDistance(SketchArc_4.center(), SketchAPI_Line(SketchLine_1).startPoint(), 6.3)
+SketchConstraintMirror_1_objects = [SketchArc_1.results()[1], SketchArc_2.results()[1], SketchArc_3.results()[1], SketchArc_4.results()[1], SketchArc_5.results()[1], SketchArc_6.results()[1], SketchArc_7.results()[1], SketchArc_8.results()[1], SketchArc_9.results()[1], SketchArc_10.results()[1], SketchArc_11.results()[1], SketchArc_12.results()[1], SketchArc_13.results()[1], SketchLine_2.result(), SketchArc_14.results()[1], SketchArc_15.results()[1], SketchArc_16.results()[1]]
+SketchConstraintMirror_1 = Sketch_1.addMirror(SketchLine_1.result(), SketchConstraintMirror_1_objects)
+[SketchArc_17, SketchArc_18, SketchArc_19, SketchArc_20, SketchArc_21, SketchArc_22, SketchArc_23, SketchArc_24, SketchArc_25, SketchArc_26, SketchArc_27, SketchArc_28, SketchArc_29, SketchLine_7, SketchArc_30, SketchArc_31, SketchArc_32] = SketchConstraintMirror_1.mirrored()
+SketchLine_8 = Sketch_1.addLine(0, -145, 31.89121696112821, 27.06960882369163)
+SketchLine_8.setName("SketchLine_43")
+SketchLine_8.result().setName("SketchLine_43")
+SketchLine_8.setAuxiliary(True)
+SketchConstraintCoincidence_34 = Sketch_1.setCoincident(SketchArc_1.center(), SketchLine_8.startPoint())
+SketchConstraintCoincidence_35 = Sketch_1.setCoincident(SketchLine_8.endPoint(), SketchArc_1.results()[1])
+SketchConstraintAngle_1 = Sketch_1.setAngle(SketchLine_8.result(), SketchLine_1.result(), 10.5, type = "Direct")
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "Sketch_1")], model.selection(), "size_z", 0)
+
+model.testNbResults(Extrusion_1, 1)
+model.testNbSubResults(Extrusion_1, [0])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.FACE, [36])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.EDGE, [204])
+model.testNbSubShapes(Extrusion_1, GeomAPI_Shape.VERTEX, [408])
+model.testResultsVolumes(Extrusion_1, [16403.0029])
+
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_2 = Sketch_2.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_9 = SketchProjection_2.createdFeature()
+SketchLine_9.setName("SketchLine_8")
+SketchLine_9.result().setName("SketchLine_8")
+SketchArc_33 = Sketch_2.addArc(0, -145, 0, 26, 48.1858267258401, 19.0704912613701, True)
+SketchConstraintCoincidence_36 = Sketch_2.setCoincident(SketchLine_9.result(), SketchArc_33.startPoint())
+SketchProjection_3 = Sketch_2.addProjection(model.selection("VERTEX", "Sketch_1/SketchArc_1_2__cc"), False)
+SketchPoint_1 = SketchProjection_3.createdFeature()
+SketchConstraintCoincidence_37 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_1).coordinates(), SketchArc_33.center())
+SketchProjection_4 = Sketch_2.addProjection(model.selection("VERTEX", "Sketch_1/SketchArc_17_2_StartVertex"), False)
+SketchPoint_2 = SketchProjection_4.createdFeature()
+SketchConstraintDistance_5 = Sketch_2.setDistance(SketchArc_33.startPoint(), SketchAPI_Point(SketchPoint_2).coordinates(), 4, True)
+SketchLine_10 = Sketch_2.addLine(48.1858267258401, 19.0704912613701, 49.7056919497355, 16.28668032699112)
+SketchLine_10.setName("SketchLine_9")
+SketchLine_10.result().setName("SketchLine_9")
+SketchConstraintCoincidence_38 = Sketch_2.setCoincident(SketchArc_33.endPoint(), SketchLine_10.startPoint())
+SketchArc_34 = Sketch_2.addArc(48.03804881864168, 15.3762044144511, 49.7056919497355, 16.28668032699112, 49.93150121822762, 15.21860361971252, True)
+SketchConstraintCoincidence_39 = Sketch_2.setCoincident(SketchLine_10.endPoint(), SketchArc_34.startPoint())
+SketchConstraintTangent_17 = Sketch_2.setTangent(SketchLine_10.result(), SketchArc_34.results()[1])
+SketchLine_11 = Sketch_2.addLine(49.93150121822762, 15.21860361971252, 49.21181499063341, 6.57212682467093)
+SketchLine_11.setName("SketchLine_10")
+SketchLine_11.result().setName("SketchLine_10")
+SketchConstraintCoincidence_40 = Sketch_2.setCoincident(SketchArc_34.endPoint(), SketchLine_11.startPoint())
+SketchConstraintTangent_18 = Sketch_2.setTangent(SketchLine_11.result(), SketchArc_34.results()[1])
+SketchProjection_5 = Sketch_2.addProjection(model.selection("EDGE", "Sketch_1/SketchLine_2"), False)
+SketchLine_12 = SketchProjection_5.createdFeature()
+SketchLine_12.setName("SketchLine_11")
+SketchLine_12.result().setName("SketchLine_11")
+SketchConstraintParallel_3 = Sketch_2.setParallel(SketchLine_12.result(), SketchLine_11.result())
+SketchConstraintDistance_6 = Sketch_2.setDistance(SketchLine_11.startPoint(), SketchLine_12.result(), 1.6, True)
+SketchArc_35 = Sketch_2.addArc(47.81663953830692, 6.68825372605725, 49.21181499063341, 6.57212682467093, 47.07590600961045, 5.500266419952984, True)
+SketchConstraintCoincidence_41 = Sketch_2.setCoincident(SketchLine_11.endPoint(), SketchArc_35.startPoint())
+SketchConstraintTangent_19 = Sketch_2.setTangent(SketchLine_11.result(), SketchArc_35.results()[1])
+SketchProjection_6 = Sketch_2.addProjection(model.selection("VERTEX", "Sketch_1/SketchArc_14_2__cc"), False)
+SketchPoint_3 = SketchProjection_6.createdFeature()
+SketchConstraintCoincidence_42 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_3).coordinates(), SketchArc_35.center())
+SketchArc_36 = Sketch_2.addArc(0, -70, 47.07590600961045, 5.500266419952984, 0, 18.97432863534041, False)
+SketchConstraintCoincidence_43 = Sketch_2.setCoincident(SketchArc_35.endPoint(), SketchArc_36.startPoint())
+SketchConstraintTangent_20 = Sketch_2.setTangent(SketchArc_35.results()[1], SketchArc_36.results()[1])
+SketchConstraintCoincidence_44 = Sketch_2.setCoincident(SketchArc_36.endPoint(), SketchLine_9.result())
+SketchProjection_7 = Sketch_2.addProjection(model.selection("VERTEX", "Sketch_1/SketchArc_32_2__cc"), False)
+SketchPoint_4 = SketchProjection_7.createdFeature()
+SketchConstraintCoincidence_45 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_4).coordinates(), SketchArc_36.center())
+SketchLine_13 = Sketch_2.addLine(51.52598744945789, 15.0858871609853, 49.93150121822762, 15.21860361971252)
+SketchLine_13.setName("SketchLine_12")
+SketchLine_13.result().setName("SketchLine_12")
+SketchLine_13.setAuxiliary(True)
+SketchConstraintCoincidence_46 = Sketch_2.setCoincident(SketchAPI_Line(SketchLine_12).startPoint(), SketchLine_13.startPoint())
+SketchConstraintCoincidence_47 = Sketch_2.setCoincident(SketchArc_34.endPoint(), SketchLine_13.endPoint())
+SketchConstraintPerpendicular_2 = Sketch_2.setPerpendicular(SketchLine_11.result(), SketchLine_13.result())
+SketchLine_14 = Sketch_2.addLine(0, 33.22217618290702, 48.1858267258401, 19.0704912613701)
+SketchLine_14.setName("SketchLine_13")
+SketchLine_14.result().setName("SketchLine_13")
+SketchLine_14.setAuxiliary(True)
+SketchConstraintCoincidence_48 = Sketch_2.setCoincident(SketchLine_14.startPoint(), SketchLine_9.result())
+SketchConstraintCoincidence_49 = Sketch_2.setCoincident(SketchArc_33.endPoint(), SketchLine_14.endPoint())
+SketchConstraintTangent_21 = Sketch_2.setTangent(SketchArc_33.results()[1], SketchLine_14.result())
+SketchConstraintAngle_2 = Sketch_2.setAngle(SketchLine_14.result(), SketchLine_10.result(), 135, type = "Direct")
+SketchConstraintRadius_11 = Sketch_2.setRadius(SketchArc_34.results()[1], 1.9)
+SketchConstraintMirror_2_objects = [SketchArc_33.results()[1], SketchLine_10.result(), SketchArc_34.results()[1], SketchLine_11.result(), SketchArc_35.results()[1], SketchArc_36.results()[1]]
+SketchConstraintMirror_2 = Sketch_2.addMirror(SketchLine_9.result(), SketchConstraintMirror_2_objects)
+[SketchArc_37, SketchLine_15, SketchArc_38, SketchLine_16, SketchArc_39, SketchArc_40] = SketchConstraintMirror_2.mirrored()
+SketchLine_16.setName("SketchLine_15")
+SketchLine_16.result().setName("SketchLine_15")
+SketchLine_15.setName("SketchLine_14")
+SketchLine_15.result().setName("SketchLine_14")
+model.do()
+ExtrusionCut_1 = model.addExtrusionCut(Part_1_doc, [model.selection("COMPOUND", "Sketch_2")], model.selection(), model.selection("FACE", "Extrusion_1_1/To_Face"), 0, model.selection("FACE", "Extrusion_1_1/To_Face"), 4.4, [model.selection("SOLID", "Extrusion_1_1")])
+
+model.testNbResults(ExtrusionCut_1, 1)
+model.testNbSubResults(ExtrusionCut_1, [0])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.FACE, [49])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.EDGE, [276])
+model.testNbSubShapes(ExtrusionCut_1, GeomAPI_Shape.VERTEX, [552])
+model.testResultsVolumes(ExtrusionCut_1, [12313.7939])
+
+Chamfer_1 = model.addChamfer(Part_1_doc, [model.selection("FACE", "Extrusion_1_1/From_Face")], True, "chamfer", "chamfer", keepSubResults = True)
+
+model.testNbResults(Chamfer_1, 1)
+model.testNbSubResults(Chamfer_1, [0])
+model.testNbSubShapes(Chamfer_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Chamfer_1, GeomAPI_Shape.FACE, [83])
+model.testNbSubShapes(Chamfer_1, GeomAPI_Shape.EDGE, [412])
+model.testNbSubShapes(Chamfer_1, GeomAPI_Shape.VERTEX, [824])
+model.testResultsVolumes(Chamfer_1, [11962.2801])
+
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/XOY"), "chamfer", True)
+Sketch_3 = model.addSketch(Part_1_doc, model.selection("FACE", "Plane_1"))
+SketchProjection_8 = Sketch_3.addProjection(model.selection("EDGE", "Sketch_1/SketchArc_12_2"), False)
+SketchArc_41 = SketchProjection_8.createdFeature()
+SketchArc_42 = Sketch_3.addArc(47.42857142857143, 14.08026468498505, 53.87940795452356, 15.47550950774626, 42.38734178332437, 18.34007731747046, False)
+SketchConstraintCoincidence_50 = Sketch_3.setCoincident(SketchAPI_Arc(SketchArc_41).center(), SketchArc_42.center())
+SketchConstraintCoincidence_50.setName("SketchConstraintCoincidence_48")
+SketchLine_17 = Sketch_3.addLine(47.42857142857143, 14.08026468498505, 52.31556879671699, 15.13726833859203)
+SketchLine_17.setName("SketchLine_16")
+SketchLine_17.result().setName("SketchLine_16")
+SketchLine_17.setAuxiliary(True)
+SketchConstraintCoincidence_51 = Sketch_3.setCoincident(SketchAPI_Arc(SketchArc_41).center(), SketchLine_17.startPoint())
+SketchConstraintCoincidence_52 = Sketch_3.setCoincident(SketchAPI_Arc(SketchArc_41).endPoint(), SketchLine_17.endPoint())
+SketchConstraintCoincidence_53 = Sketch_3.setCoincident(SketchArc_42.startPoint(), SketchLine_17.result())
+SketchConstraintDistance_7 = Sketch_3.setDistance(SketchLine_17.endPoint(), SketchArc_42.startPoint(), "2*chamfer", True)
+SketchProjection_9 = Sketch_3.addProjection(model.selection("EDGE", "Sketch_2/SketchArc_34_2"), False)
+SketchArc_43 = SketchProjection_9.createdFeature()
+SketchArc_44 = Sketch_3.addArc(45.66073233717504, 15.57407945314024, 49.93150121822762, 15.21860361971246, 42.38734178332437, 18.34007731747046, False)
+SketchProjection_10 = Sketch_3.addProjection(model.selection("EDGE", "Sketch_2/SketchLine_12"), False)
+SketchLine_18 = SketchProjection_10.createdFeature()
+SketchLine_18.setName("SketchLine_17")
+SketchLine_18.result().setName("SketchLine_17")
+SketchConstraintCoincidence_54 = Sketch_3.setCoincident(SketchArc_44.startPoint(), SketchLine_18.result())
+SketchConstraintDistance_8 = Sketch_3.setDistance(SketchArc_44.startPoint(), SketchAPI_Line(SketchLine_18).startPoint(), "2*chamfer", True)
+SketchLine_19 = Sketch_3.addLine(47.42857142857143, 14.08026468498505, 42.38734178332437, 18.34007731747046)
+SketchLine_19.setName("SketchLine_18")
+SketchLine_19.result().setName("SketchLine_18")
+SketchLine_19.setAuxiliary(True)
+SketchConstraintCoincidence_55 = Sketch_3.setCoincident(SketchAPI_Arc(SketchArc_41).center(), SketchLine_19.startPoint())
+SketchConstraintCoincidence_56 = Sketch_3.setCoincident(SketchArc_42.endPoint(), SketchLine_19.endPoint())
+SketchConstraintPerpendicular_3 = Sketch_3.setPerpendicular(SketchArc_44.results()[1], SketchLine_18.result())
+SketchConstraintCoincidence_57 = Sketch_3.setCoincident(SketchArc_44.endPoint(), SketchLine_19.endPoint())
+SketchLine_20 = Sketch_3.addLine(49.93150121822762, 15.21860361971252, 53.87940795452356, 15.47550950774626)
+SketchLine_20.setName("SketchLine_22")
+SketchLine_20.result().setName("SketchLine_22")
+SketchConstraintCoincidence_58 = Sketch_3.setCoincident(SketchAPI_Arc(SketchArc_43).startPoint(), SketchLine_20.startPoint())
+SketchConstraintCoincidence_59 = Sketch_3.setCoincident(SketchArc_42.startPoint(), SketchLine_20.endPoint())
+SketchConstraintCoincidence_60 = Sketch_3.setCoincident(SketchArc_44.center(), SketchLine_19.result())
+model.do()
+
+Plane_5 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/XOY"), "2*chamfer", False)
+Sketch_4 = model.addSketch(Part_1_doc, model.selection("FACE", "Plane_2"))
+SketchProjection_11 = Sketch_4.addProjection(model.selection("EDGE", "Sketch_3/SketchArc_42_2"), False)
+SketchArc_45 = SketchProjection_11.createdFeature()
+SketchArc_46 = Sketch_4.addArc(47.42857142857143, 14.08026468498505, 51.5336492178137, 14.96814775401492, 44.22051619977783, 16.79105454202122, False)
+SketchConstraintCoincidence_61 = Sketch_4.setCoincident(SketchAPI_Arc(SketchArc_45).center(), SketchArc_46.center())
+SketchProjection_12 = Sketch_4.addProjection(model.selection("EDGE", "Sketch_3/SketchLine_16"), False)
+SketchLine_21 = SketchProjection_12.createdFeature()
+SketchLine_21.setName("SketchLine_19")
+SketchLine_21.result().setName("SketchLine_19")
+SketchProjection_13 = Sketch_4.addProjection(model.selection("EDGE", "Sketch_3/SketchLine_18"), False)
+SketchLine_22 = SketchProjection_13.createdFeature()
+SketchLine_22.setName("SketchLine_20")
+SketchLine_22.result().setName("SketchLine_20")
+SketchConstraintCoincidence_62 = Sketch_4.setCoincident(SketchArc_46.startPoint(), SketchLine_21.result())
+SketchConstraintCoincidence_63 = Sketch_4.setCoincident(SketchArc_46.endPoint(), SketchLine_22.result())
+SketchConstraintDistance_9 = Sketch_4.setDistance(SketchArc_46.startPoint(), SketchAPI_Arc(SketchArc_45).startPoint(), "3*chamfer", True)
+SketchProjection_14 = Sketch_4.addProjection(model.selection("EDGE", "Sketch_3/SketchArc_44_2"), False)
+SketchArc_47 = SketchProjection_14.createdFeature()
+SketchArc_48 = Sketch_4.addArc(45.66073233717504, 15.57407945314024, 52.32323056507302, 15.01952893162158, 40.55416736687089, 19.8891000929197, False)
+SketchConstraintCoincidence_64 = Sketch_4.setCoincident(SketchAPI_Arc(SketchArc_47).center(), SketchArc_48.center())
+SketchLine_23 = Sketch_4.addLine(45.66073233717504, 15.57407945314024, 49.93150121822762, 15.21860361971246)
+SketchLine_23.setName("SketchLine_21")
+SketchLine_23.result().setName("SketchLine_21")
+SketchLine_23.setAuxiliary(True)
+SketchConstraintCoincidence_65 = Sketch_4.setCoincident(SketchAPI_Arc(SketchArc_47).center(), SketchLine_23.startPoint())
+SketchConstraintCoincidence_66 = Sketch_4.setCoincident(SketchAPI_Arc(SketchArc_47).startPoint(), SketchLine_23.endPoint())
+SketchConstraintCoincidence_67 = Sketch_4.setCoincident(SketchArc_48.startPoint(), SketchLine_23.result())
+SketchConstraintCoincidence_68 = Sketch_4.setCoincident(SketchArc_48.endPoint(), SketchLine_22.result())
+SketchConstraintDistance_10 = Sketch_4.setDistance(SketchLine_23.endPoint(), SketchArc_48.startPoint(), "3*chamfer", True)
+model.do()
+
+Filling_1 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Sketch_3/SketchArc_42_2"), model.selection("EDGE", "Sketch_4/SketchArc_46_2")])
+Filling_2 = model.addFilling(Part_1_doc, [model.selection("EDGE", "Sketch_3/SketchArc_44_2"), model.selection("EDGE", "Sketch_4/SketchArc_48_2")])
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_3/Face-SketchArc_42_2f-SketchArc_44_2r-SketchLine_22f")])
+
+Plane_6 = model.addPlane(Part_1_doc, model.selection("EDGE", "Sketch_3/SketchLine_22"), model.selection("VERTEX", "[Filling_2_1/Edge_0_1]e[Filling_2_1/Edge_0_4]e"), False)
+Sketch_5 = model.addSketch(Part_1_doc, model.selection("FACE", "Plane_3"))
+SketchProjection_15 = Sketch_5.addProjection(model.selection("EDGE", "Sketch_3/SketchLine_22"), True)
+SketchLine_24 = SketchProjection_15.createdFeature()
+SketchLine_24.setName("SketchLine_23")
+SketchLine_24.result().setName("SketchLine_23")
+SketchProjection_16 = Sketch_5.addProjection(model.selection("EDGE", "Filling_1_1/Edge_0_1"), False)
+SketchBSpline_1 = SketchProjection_16.createdFeature()
+SketchProjection_17 = Sketch_5.addProjection(model.selection("EDGE", "Filling_2_1/Edge_0_1"), False)
+SketchBSpline_2 = SketchProjection_17.createdFeature()
+SketchLine_25 = Sketch_5.addLine(54.7440877920758, -3.054064947639794, 52.78524259618538, -1.013740096412265)
+SketchLine_25.setName("SketchLine_24")
+SketchLine_25.result().setName("SketchLine_24")
+SketchConstraintCoincidence_69 = Sketch_5.setCoincident(SketchAPI_Line(SketchLine_24).endPoint(), SketchLine_25.startPoint())
+SketchLine_26 = Sketch_5.addLine(52.78524259618538, -1.013740096412265, 50.78800926284204, -3.016502941130004)
+SketchLine_26.setName("SketchLine_25")
+SketchLine_26.result().setName("SketchLine_25")
+SketchConstraintCoincidence_70 = Sketch_5.setCoincident(SketchLine_25.endPoint(), SketchLine_26.startPoint())
+SketchConstraintCoincidence_71 = Sketch_5.setCoincident(SketchAPI_Line(SketchLine_24).startPoint(), SketchLine_26.endPoint())
+SketchConstraintCoincidence_72 = Sketch_5.setCoincident(SketchLine_26.startPoint(), SketchBSpline_1.result())
+SketchConstraintCoincidence_73 = Sketch_5.setCoincident(SketchLine_26.startPoint(), SketchBSpline_2.result())
+model.do()
+Face_2 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_5/Face-SketchProjection_15r-SketchLine_24f-SketchLine_25f")])
+
+Solid_1_objects = [model.selection("FACE", "Filling_1_1"), model.selection("FACE", "Filling_2_1"), model.selection("FACE", "Face_1_1"), model.selection("FACE", "Face_2_1")]
+Solid_1 = model.addSolid(Part_1_doc, Solid_1_objects)
+
+model.testNbResults(Solid_1, 1)
+model.testNbSubResults(Solid_1, [0])
+model.testNbSubShapes(Solid_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Solid_1, GeomAPI_Shape.FACE, [4])
+model.testNbSubShapes(Solid_1, GeomAPI_Shape.EDGE, [12])
+model.testNbSubShapes(Solid_1, GeomAPI_Shape.VERTEX, [24])
+model.testResultsVolumes(Solid_1, [13.6834876])
+
+Fillet_1 = model.addFillet(Part_1_doc, [model.selection("EDGE", "[Solid_1_1/Modified_Face&Filling_1_1/Filling_1_1][Solid_1_1/Modified_Face&Filling_2_1/Filling_2_1]")], 0.4, keepSubResults = True)
+
+model.testNbResults(Fillet_1, 1)
+model.testNbSubResults(Fillet_1, [0])
+model.testNbSubShapes(Fillet_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Fillet_1, GeomAPI_Shape.FACE, [5])
+model.testNbSubShapes(Fillet_1, GeomAPI_Shape.EDGE, [18])
+model.testNbSubShapes(Fillet_1, GeomAPI_Shape.VERTEX, [36])
+model.testResultsVolumes(Fillet_1, [13.34526088678])
+
+Symmetry_1 = model.addSymmetry(Part_1_doc, [model.selection("SOLID", "Fillet_1_1")], model.selection("FACE", "PartSet/YOZ"), keepOriginal = True, keepSubResults = True)
+Cut_1 = model.addCut(Part_1_doc, [model.selection("SOLID", "Chamfer_1_1")], [model.selection("COMPOUND", "Symmetry_1_1")], keepSubResults = True)
+
+model.testNbResults(Cut_1, 1)
+model.testNbSubResults(Cut_1, [0])
+model.testNbSubShapes(Cut_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Cut_1, GeomAPI_Shape.FACE, [87])
+model.testNbSubShapes(Cut_1, GeomAPI_Shape.EDGE, [436])
+model.testNbSubShapes(Cut_1, GeomAPI_Shape.VERTEX, [872])
+model.testResultsVolumes(Cut_1, [11957.973])
+
+Sketch_6 = model.addSketch(Part_1_doc, model.standardPlane("YOZ"))
+SketchLine_27 = Sketch_6.addLine(-32, 0, -29, 0)
+SketchLine_27.setName("SketchLine_26")
+SketchLine_27.result().setName("SketchLine_26")
+SketchLine_28 = Sketch_6.addLine(-29, 0, -28, 1)
+SketchLine_28.setName("SketchLine_27")
+SketchLine_28.result().setName("SketchLine_27")
+SketchConstraintCoincidence_74 = Sketch_6.setCoincident(SketchLine_27.endPoint(), SketchLine_28.startPoint())
+SketchLine_29 = Sketch_6.addLine(-28, 1, -28, 4)
+SketchLine_29.setName("SketchLine_28")
+SketchLine_29.result().setName("SketchLine_28")
+SketchConstraintCoincidence_75 = Sketch_6.setCoincident(SketchLine_28.endPoint(), SketchLine_29.startPoint())
+SketchConstraintVertical_1 = Sketch_6.setVertical(SketchLine_29.result())
+SketchLine_30 = Sketch_6.addLine(-28, 4, -29, 5)
+SketchLine_30.setName("SketchLine_29")
+SketchLine_30.result().setName("SketchLine_29")
+SketchConstraintCoincidence_76 = Sketch_6.setCoincident(SketchLine_29.endPoint(), SketchLine_30.startPoint())
+SketchLine_31 = Sketch_6.addLine(-29, 5, -32, 5)
+SketchLine_31.setName("SketchLine_30")
+SketchLine_31.result().setName("SketchLine_30")
+SketchConstraintCoincidence_77 = Sketch_6.setCoincident(SketchLine_30.endPoint(), SketchLine_31.startPoint())
+SketchConstraintHorizontal_1 = Sketch_6.setHorizontal(SketchLine_31.result())
+SketchLine_32 = Sketch_6.addLine(-32, 5, -33, 4)
+SketchLine_32.setName("SketchLine_31")
+SketchLine_32.result().setName("SketchLine_31")
+SketchConstraintCoincidence_78 = Sketch_6.setCoincident(SketchLine_31.endPoint(), SketchLine_32.startPoint())
+SketchLine_33 = Sketch_6.addLine(-33, 4, -33, 1)
+SketchLine_33.setName("SketchLine_32")
+SketchLine_33.result().setName("SketchLine_32")
+SketchConstraintCoincidence_79 = Sketch_6.setCoincident(SketchLine_32.endPoint(), SketchLine_33.startPoint())
+SketchConstraintVertical_2 = Sketch_6.setVertical(SketchLine_33.result())
+SketchLine_34 = Sketch_6.addLine(-33, 1, -32, 0)
+SketchLine_34.setName("SketchLine_33")
+SketchLine_34.result().setName("SketchLine_33")
+SketchConstraintCoincidence_80 = Sketch_6.setCoincident(SketchLine_33.endPoint(), SketchLine_34.startPoint())
+SketchConstraintCoincidence_81 = Sketch_6.setCoincident(SketchLine_27.startPoint(), SketchLine_34.endPoint())
+SketchProjection_18 = Sketch_6.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_35 = SketchProjection_18.createdFeature()
+SketchLine_35.setName("SketchLine_34")
+SketchLine_35.result().setName("SketchLine_34")
+SketchConstraintCollinear_1 = Sketch_6.setCollinear(SketchLine_35.result(), SketchLine_27.result())
+SketchConstraintLength_1 = Sketch_6.setLength(SketchLine_27.result(), "size_z-2")
+SketchConstraintEqual_1 = Sketch_6.setEqual(SketchLine_27.result(), SketchLine_29.result())
+SketchConstraintEqual_2 = Sketch_6.setEqual(SketchLine_29.result(), SketchLine_31.result())
+SketchConstraintEqual_3 = Sketch_6.setEqual(SketchLine_31.result(), SketchLine_33.result())
+SketchConstraintEqual_4 = Sketch_6.setEqual(SketchLine_28.result(), SketchLine_30.result())
+SketchConstraintEqual_5 = Sketch_6.setEqual(SketchLine_30.result(), SketchLine_32.result())
+SketchConstraintEqual_6 = Sketch_6.setEqual(SketchLine_32.result(), SketchLine_34.result())
+SketchConstraintDistanceHorizontal_2 = Sketch_6.setHorizontalDistance(SketchLine_27.endPoint(), SketchLine_28.endPoint(), 1)
+SketchConstraintDistanceHorizontal_3 = Sketch_6.setHorizontalDistance(SketchLine_31.startPoint(), SketchLine_29.endPoint(), 1)
+SketchConstraintDistanceVertical_5 = Sketch_6.setVerticalDistance(SketchLine_27.endPoint(), SketchLine_28.endPoint(), 1)
+SketchConstraintDistance_11 = Sketch_6.setDistance(SketchAPI_Line(SketchLine_35).startPoint(), SketchLine_29.result(), 28, True)
+model.do()
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "Sketch_6")], model.selection(), 79, -76.5)
+
+Sketch_7 = model.addSketch(Part_1_doc, model.selection("FACE", "Sketch_6/Face-SketchLine_26r-SketchLine_27f-SketchLine_28f-SketchLine_29f-SketchLine_30f-SketchLine_31f-SketchLine_32f-SketchLine_33f"))
+SketchProjection_19 = Sketch_7.addProjection(model.selection("EDGE", "Sketch_6/SketchLine_27"), True)
+SketchLine_36 = SketchProjection_19.createdFeature()
+SketchLine_36.setName("SketchLine_35")
+SketchLine_36.result().setName("SketchLine_35")
+SketchProjection_20 = Sketch_7.addProjection(model.selection("EDGE", "Sketch_6/SketchLine_28"), True)
+SketchLine_37 = SketchProjection_20.createdFeature()
+SketchLine_37.setName("SketchLine_36")
+SketchLine_37.result().setName("SketchLine_36")
+SketchProjection_21 = Sketch_7.addProjection(model.selection("EDGE", "Sketch_6/SketchLine_29"), True)
+SketchLine_38 = SketchProjection_21.createdFeature()
+SketchLine_38.setName("SketchLine_37")
+SketchLine_38.result().setName("SketchLine_37")
+SketchLine_39 = Sketch_7.addLine(-29, 5, -31, 5)
+SketchLine_39.setName("SketchLine_38")
+SketchLine_39.result().setName("SketchLine_38")
+SketchConstraintCoincidence_82 = Sketch_7.setCoincident(SketchAPI_Line(SketchLine_38).endPoint(), SketchLine_39.startPoint())
+SketchLine_40 = Sketch_7.addLine(-31, 5, -32, 4)
+SketchLine_40.setName("SketchLine_39")
+SketchLine_40.result().setName("SketchLine_39")
+SketchConstraintCoincidence_83 = Sketch_7.setCoincident(SketchLine_39.endPoint(), SketchLine_40.startPoint())
+SketchLine_41 = Sketch_7.addLine(-32, 4, -32, 1)
+SketchLine_41.setName("SketchLine_40")
+SketchLine_41.result().setName("SketchLine_40")
+SketchConstraintCoincidence_84 = Sketch_7.setCoincident(SketchLine_40.endPoint(), SketchLine_41.startPoint())
+SketchConstraintVertical_3 = Sketch_7.setVertical(SketchLine_41.result())
+SketchLine_42 = Sketch_7.addLine(-32, 1, -31, 0)
+SketchLine_42.setName("SketchLine_41")
+SketchLine_42.result().setName("SketchLine_41")
+SketchConstraintCoincidence_85 = Sketch_7.setCoincident(SketchLine_41.endPoint(), SketchLine_42.startPoint())
+SketchLine_43 = Sketch_7.addLine(-31, 0, -29, 0)
+SketchLine_43.setName("SketchLine_42")
+SketchLine_43.result().setName("SketchLine_42")
+SketchConstraintCoincidence_86 = Sketch_7.setCoincident(SketchLine_42.endPoint(), SketchLine_43.startPoint())
+SketchConstraintCoincidence_87 = Sketch_7.setCoincident(SketchAPI_Line(SketchLine_36).startPoint(), SketchLine_43.endPoint())
+SketchConstraintHorizontal_2 = Sketch_7.setHorizontal(SketchLine_43.result())
+SketchConstraintHorizontal_3 = Sketch_7.setHorizontal(SketchLine_39.result())
+SketchConstraintEqual_7 = Sketch_7.setEqual(SketchLine_40.result(), SketchLine_42.result())
+SketchConstraintEqual_8 = Sketch_7.setEqual(SketchLine_42.result(), SketchLine_36.result())
+SketchConstraintEqual_9 = Sketch_7.setEqual(SketchLine_37.result(), SketchLine_41.result())
+SketchConstraintEqual_10 = Sketch_7.setEqual(SketchLine_39.result(), SketchLine_43.result())
+SketchConstraintLength_2 = Sketch_7.setLength(SketchLine_39.result(), 2)
+model.do()
+ExtrusionFuse_1 = model.addExtrusionFuse(Part_1_doc, [model.selection("COMPOUND", "Sketch_7")], model.selection(), model.selection("FACE", "Extrusion_2_1/From_Face"), 0, model.selection("FACE", "Extrusion_2_1/From_Face"), "1.6+2*chamfer", [model.selection("SOLID", "Extrusion_2_1")])
+
+model.testNbResults(ExtrusionFuse_1, 1)
+model.testNbSubResults(ExtrusionFuse_1, [0])
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.FACE, [19])
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.EDGE, [90])
+model.testNbSubShapes(ExtrusionFuse_1, GeomAPI_Shape.VERTEX, [180])
+model.testResultsVolumes(ExtrusionFuse_1, [115.1])
+
+Plane_7 = model.addPlane(Part_1_doc, model.selection("EDGE", "Sketch_1/SketchLine_43"), model.selection("VERTEX", "Sketch_1/SketchArc_1"), True)
+Sketch_8 = model.addSketch(Part_1_doc, model.selection("FACE", "Plane_4"))
+SketchLine_44 = Sketch_8.addLine(30.42415119636338, 0, 27.42415119636338, 0)
+SketchConstraintHorizontal_4 = Sketch_8.setHorizontal(SketchLine_44.result())
+SketchLine_45 = Sketch_8.addLine(27.42415119636338, 0, 26.42415119636338, -1)
+SketchConstraintCoincidence_88 = Sketch_8.setCoincident(SketchLine_44.endPoint(), SketchLine_45.startPoint())
+SketchLine_46 = Sketch_8.addLine(26.42415119636338, -1, 26.42415119636338, -4)
+SketchConstraintCoincidence_89 = Sketch_8.setCoincident(SketchLine_45.endPoint(), SketchLine_46.startPoint())
+SketchConstraintVertical_4 = Sketch_8.setVertical(SketchLine_46.result())
+SketchLine_47 = Sketch_8.addLine(26.42415119636338, -4, 27.42415119636338, -5)
+SketchConstraintCoincidence_90 = Sketch_8.setCoincident(SketchLine_46.endPoint(), SketchLine_47.startPoint())
+SketchLine_48 = Sketch_8.addLine(27.42415119636338, -5, 30.42415119636338, -5)
+SketchConstraintCoincidence_91 = Sketch_8.setCoincident(SketchLine_47.endPoint(), SketchLine_48.startPoint())
+SketchConstraintHorizontal_5 = Sketch_8.setHorizontal(SketchLine_48.result())
+SketchLine_49 = Sketch_8.addLine(30.42415119636338, -5, 31.4241511964612, -4)
+SketchConstraintCoincidence_92 = Sketch_8.setCoincident(SketchLine_48.endPoint(), SketchLine_49.startPoint())
+SketchLine_50 = Sketch_8.addLine(31.4241511964612, -4, 31.4241511964612, -1)
+SketchConstraintCoincidence_93 = Sketch_8.setCoincident(SketchLine_49.endPoint(), SketchLine_50.startPoint())
+SketchConstraintVertical_5 = Sketch_8.setVertical(SketchLine_50.result())
+SketchLine_51 = Sketch_8.addLine(31.4241511964612, -1, 30.42415119636338, 0)
+SketchConstraintCoincidence_94 = Sketch_8.setCoincident(SketchLine_50.endPoint(), SketchLine_51.startPoint())
+SketchConstraintCoincidence_95 = Sketch_8.setCoincident(SketchLine_44.startPoint(), SketchLine_51.endPoint())
+SketchProjection_22 = Sketch_8.addProjection(model.selection("VERTEX", "Sketch_1/SketchArc_1"), False)
+SketchPoint_5 = SketchProjection_22.createdFeature()
+SketchConstraintLength_3 = Sketch_8.setLength(SketchLine_44.result(), "size_z-2")
+SketchConstraintEqual_11 = Sketch_8.setEqual(SketchLine_44.result(), SketchLine_46.result())
+SketchConstraintEqual_12 = Sketch_8.setEqual(SketchLine_46.result(), SketchLine_48.result())
+SketchConstraintEqual_13 = Sketch_8.setEqual(SketchLine_48.result(), SketchLine_50.result())
+SketchConstraintEqual_14 = Sketch_8.setEqual(SketchLine_45.result(), SketchLine_47.result())
+SketchConstraintEqual_15 = Sketch_8.setEqual(SketchLine_47.result(), SketchLine_49.result())
+SketchConstraintEqual_16 = Sketch_8.setEqual(SketchLine_49.result(), SketchLine_51.result())
+SketchConstraintDistanceHorizontal_4 = Sketch_8.setHorizontalDistance(SketchLine_45.startPoint(), SketchLine_45.endPoint(), 1)
+SketchConstraintDistanceHorizontal_5 = Sketch_8.setHorizontalDistance(SketchLine_47.endPoint(), SketchLine_46.endPoint(), 1)
+SketchConstraintDistanceVertical_6 = Sketch_8.setVerticalDistance(SketchLine_44.endPoint(), SketchLine_46.startPoint(), 1)
+SketchConstraintCoincidence_96 = Sketch_8.setCoincident(SketchAPI_Point(SketchPoint_5).coordinates(), SketchLine_44.result())
+SketchConstraintCoincidence_97 = Sketch_8.setCoincident(SketchAPI_Point(SketchPoint_5).coordinates(), SketchLine_46.result())
+model.do()
+Extrusion_3 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_8/Face-SketchLine_44r-SketchLine_45f-SketchLine_46f-SketchLine_47f-SketchLine_48f-SketchLine_49f-SketchLine_50f-SketchLine_51f")], model.selection(), "size_y-5+3.8", "-size_y+5+2*chamfer")
+
+model.testNbResults(Extrusion_3, 1)
+model.testNbSubResults(Extrusion_3, [0])
+model.testNbSubShapes(Extrusion_3, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Extrusion_3, GeomAPI_Shape.FACE, [10])
+model.testNbSubShapes(Extrusion_3, GeomAPI_Shape.EDGE, [48])
+model.testNbSubShapes(Extrusion_3, GeomAPI_Shape.VERTEX, [96])
+model.testResultsVolumes(Extrusion_3, [124.2])
+
+Symmetry_2 = model.addSymmetry(Part_1_doc, [model.selection("SOLID", "ExtrusionFuse_1_1"), model.selection("SOLID", "Extrusion_3_1")], model.selection("FACE", "PartSet/YOZ"), keepOriginal = True, keepSubResults = True)
+Fuse_1_objects_1 = [model.selection("SOLID", "Cut_1_1"), model.selection("COMPOUND", "Symmetry_2_1"), model.selection("COMPOUND", "Symmetry_2_2")]
+Fuse_1 = model.addFuse(Part_1_doc, Fuse_1_objects_1, removeEdges = True, keepSubResults = True)
+Fuse_1.result().setName("Visor")
+
+model.testNbResults(Fuse_1, 1)
+model.testNbSubResults(Fuse_1, [0])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [125])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [668])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [1336])
+model.testResultsVolumes(Fuse_1, [12309.7614])
+
+model.testHaveNamingSubshapes(Fuse_1, model, Part_1_doc)
+
+model.end()
+
+model.begin()
+ParamSize.setValue(160)
+model.end()
+
+model.testNbResults(Fuse_1, 1)
+model.testNbSubResults(Fuse_1, [0])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [125])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [668])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [1336])
+model.testResultsVolumes(Fuse_1, [10224.4774])
+
+model.undo()
+
+model.testNbResults(Fuse_1, 1)
+model.testNbSubResults(Fuse_1, [0])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [125])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [668])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [1336])
+model.testResultsVolumes(Fuse_1, [12309.7614])