]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Issue #2386: Update features Edge, Wire, Face, Shell to be able to use sub-shapes...
authorazv <azv@opencascade.com>
Mon, 25 Dec 2017 08:54:20 +0000 (11:54 +0300)
committerazv <azv@opencascade.com>
Mon, 25 Dec 2017 08:54:20 +0000 (11:54 +0300)
src/BuildPlugin/BuildPlugin_Face.cpp
src/BuildPlugin/BuildPlugin_Face.h
src/BuildPlugin/BuildPlugin_Validators.cpp
src/BuildPlugin/Test/TestEdge.py
src/BuildPlugin/Test/TestFace.py
src/BuildPlugin/Test/TestShell.py
src/BuildPlugin/Test/TestWire.py
src/BuildPlugin/compsolid_widget.xml
src/BuildPlugin/face_widget.xml
src/BuildPlugin/shell_widget.xml
src/BuildPlugin/solid_widget.xml

index fb782101f4d6367061db8275806e8629b5531d22..391ea4bd908365dd7bfc51564660f58fe3686c1a 100644 (file)
@@ -59,6 +59,7 @@ void BuildPlugin_Face::execute()
 
   // Collect base shapes.
   ListOfShape anEdges;
+  ListOfShape anOriginalFaces;
   std::list< std::shared_ptr<GeomAPI_Dir> > aListOfNormals;
   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
     AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
@@ -67,6 +68,12 @@ void BuildPlugin_Face::execute()
     if(!aShape.get()) {
       aShape = aContext;
     }
+    // keep selected faces "as is"
+    if (aShape->shapeType() == GeomAPI_Shape::FACE) {
+      anOriginalFaces.push_back(aShape);
+      continue;
+    }
+
     for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) {
       GeomShapePtr anEdge = anExp.current();
       anEdges.push_back(anEdge);
@@ -79,39 +86,13 @@ void BuildPlugin_Face::execute()
       aListOfNormals.push_back(aSketch->norm());
   }
 
-  // Get plane.
-  std::shared_ptr<GeomAPI_Pln> aPln = GeomAlgoAPI_ShapeTools::findPlane(anEdges);
-  std::shared_ptr<GeomAPI_Dir> aNormal = aPln->direction();
-  bool isReverse = !aListOfNormals.empty();
-  std::list< std::shared_ptr<GeomAPI_Dir> >::const_iterator aNormIt = aListOfNormals.begin();
-  for (; aNormIt != aListOfNormals.end() && isReverse; ++aNormIt)
-    if ((*aNormIt)->dot(aNormal) > 1.e-7)
-      isReverse = false;
-  if (isReverse) {
-    aNormal->reverse();
-    aPln = std::shared_ptr<GeomAPI_Pln>(new GeomAPI_Pln(aPln->location(), aNormal));
-  }
-
-  // Get faces.
+  // Build faces by edges.
   ListOfShape aFaces;
-  GeomAlgoAPI_SketchBuilder::createFaces(aPln->location(), aPln->xDirection(),
-                                         aPln->direction(), anEdges, aFaces);
-
-  // Get wires from faces.
-  ListOfShape aWires;
-  for(ListOfShape::const_iterator anIt = aFaces.cbegin(); anIt != aFaces.cend(); ++anIt) {
-    aWires.push_back(GeomAlgoAPI_ShapeTools::getFaceOuterWire(*anIt));
-    //for(GeomAPI_ShapeExplorer anExp(*anIt, GeomAPI_Shape::WIRE); anExp.more(); anExp.next()) {
-    //  if(anExp.current()->orientation() == GeomAPI_Shape::REVERSED) {
-    //    continue;
-    //  }
-    //  aWires.push_back(anExp.current());
-    //}
-  }
+  if (!anEdges.empty())
+    buildFacesByEdges(anEdges, aListOfNormals, aFaces);
 
-  // Make faces with holes.
-  aFaces.clear();
-  GeomAlgoAPI_ShapeTools::makeFacesWithHoles(aPln->location(), aPln->direction(), aWires, aFaces);
+  // Add faces selected by user.
+  aFaces.insert(aFaces.end(), anOriginalFaces.begin(), anOriginalFaces.end());
 
   // Store result.
   int anIndex = 0;
@@ -136,3 +117,36 @@ void BuildPlugin_Face::execute()
 
   removeResults(anIndex);
 }
+
+void BuildPlugin_Face::buildFacesByEdges(
+    const ListOfShape& theEdges,
+    const std::list< std::shared_ptr<GeomAPI_Dir> >& theNormals,
+    ListOfShape& theFaces) const
+{
+  // Get plane.
+  std::shared_ptr<GeomAPI_Pln> aPln = GeomAlgoAPI_ShapeTools::findPlane(theEdges);
+  std::shared_ptr<GeomAPI_Dir> aNormal = aPln->direction();
+  bool isReverse = !theNormals.empty();
+  std::list< std::shared_ptr<GeomAPI_Dir> >::const_iterator aNormIt = theNormals.begin();
+  for (; aNormIt != theNormals.end() && isReverse; ++aNormIt)
+    if ((*aNormIt)->dot(aNormal) > 1.e-7)
+      isReverse = false;
+  if (isReverse) {
+    aNormal->reverse();
+    aPln = std::shared_ptr<GeomAPI_Pln>(new GeomAPI_Pln(aPln->location(), aNormal));
+  }
+
+  // Get faces.
+  GeomAlgoAPI_SketchBuilder::createFaces(aPln->location(), aPln->xDirection(),
+                                         aPln->direction(), theEdges, theFaces);
+
+  // Get wires from faces.
+  ListOfShape aWires;
+  for(ListOfShape::const_iterator anIt = theFaces.cbegin(); anIt != theFaces.cend(); ++anIt)
+    aWires.push_back(GeomAlgoAPI_ShapeTools::getFaceOuterWire(*anIt));
+
+  // Make faces with holes.
+  theFaces.clear();
+  GeomAlgoAPI_ShapeTools::makeFacesWithHoles(aPln->location(), aPln->direction(),
+                                             aWires, theFaces);
+}
index f6c27632541bc2148c204562297a6b14887be027..633118eb7054da34dab7767efe72d3683bec9950 100644 (file)
@@ -25,6 +25,9 @@
 
 #include <ModelAPI_Feature.h>
 
+class GeomAPI_Dir;
+class GeomAPI_Shape;
+
 /// \class BuildPlugin_Face
 /// \ingroup Plugins
 /// \brief Feature for creation of face from sketch edges or existing wires.
@@ -60,6 +63,12 @@ public:
 
   /// Creates a new part document if needed.
   BUILDPLUGIN_EXPORT virtual void execute();
+
+private:
+  /// Create faces basing on the list of edges
+  void buildFacesByEdges(const std::list< std::shared_ptr<GeomAPI_Shape> >& theEdges,
+                         const std::list< std::shared_ptr<GeomAPI_Dir> >& theNormals,
+                         std::list< std::shared_ptr<GeomAPI_Shape> >& theFaces) const;
 };
 
 #endif
index e0268ef42900091d5a5a60d3fbc02b004d1ec41e..833536d400a170fd6f1d89cc6b12cab67d8e8baa 100644 (file)
@@ -112,12 +112,6 @@ bool BuildPlugin_ValidatorBaseForBuild::isValid(const AttributePtr& theAttribute
         continue;
       }
     }
-
-    if(!aShape->isEqual(aContextShape)) {
-      // Local selection on body does not allowed.
-      theError = "Selected shape is in the local selection. Only global selection is allowed.";
-      return false;
-    }
   }
 
   return true;
@@ -192,6 +186,9 @@ bool BuildPlugin_ValidatorBaseForFace::isValid(const std::shared_ptr<ModelAPI_Fe
     return false;
   }
 
+  bool hasEdgesOrWires = false;
+  bool hasFaces = false;
+
   // Collect base shapes.
   ListOfShape anEdges;
   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
@@ -204,13 +201,23 @@ bool BuildPlugin_ValidatorBaseForFace::isValid(const std::shared_ptr<ModelAPI_Fe
       }
       aShape = aSelection->context()->shape();
     }
+    if (aShape->shapeType() == GeomAPI_Shape::FACE) {
+      // skip faces exploding
+      hasFaces = true;
+      continue;
+    }
+
     for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) {
+      hasEdgesOrWires = true;
       GeomShapePtr anEdge = anExp.current();
       anEdges.push_back(anEdge);
     }
   }
 
-  if(anEdges.empty()) {
+  if (hasFaces && hasEdgesOrWires) {
+    theError = "Faces and edges/wires should be selected together.";
+    return false;
+  } else if (hasEdgesOrWires && anEdges.empty()) {
     theError = "Objects are not selected.";
     return false;
   }
@@ -235,20 +242,22 @@ bool BuildPlugin_ValidatorBaseForFace::isValid(const std::shared_ptr<ModelAPI_Fe
     }
   }
 
-  // Check that they are planar.
-  std::shared_ptr<GeomAPI_Pln> aPln = GeomAlgoAPI_ShapeTools::findPlane(anEdges);
-  if(!aPln.get()) {
-    theError = "Selected object(s) should belong to only one plane.";
-    return false;
-  }
+  if (!anEdges.empty()) {
+    // Check that they are planar.
+    std::shared_ptr<GeomAPI_Pln> aPln = GeomAlgoAPI_ShapeTools::findPlane(anEdges);
+    if(!aPln.get()) {
+      theError = "Selected object(s) should belong to only one plane.";
+      return false;
+    }
 
-  // Check that selected objects have closed contours.
-  ListOfShape aFaces;
-  GeomAlgoAPI_SketchBuilder::createFaces(aPln->location(), aPln->xDirection(),
-                                         aPln->direction(), anEdges, aFaces);
-  if(aFaces.empty()) {
-    theError = "Selected objects do not generate closed contour.";
-    return false;
+    // Check that selected objects have closed contours.
+    ListOfShape aFaces;
+    GeomAlgoAPI_SketchBuilder::createFaces(aPln->location(), aPln->xDirection(),
+                                           aPln->direction(), anEdges, aFaces);
+    if(aFaces.empty()) {
+      theError = "Selected objects do not generate closed contour.";
+      return false;
+    }
   }
 
   return true;
index 98f6b478ba8027ba8458d6b51106384be60fb4f1..c64cae8e0fd86c69e61589cdf106b0c1af1ae39d 100644 (file)
@@ -75,5 +75,41 @@ aSession.finishOperation()
 # Test results
 assert (len(anEdgeFeature.results()) == aNumOfLines)
 
+# Test edge building on edge of another result
+aSession.startOperation()
+aBox = aPart.addFeature("Box")
+aBox.string("CreationMethod").setValue("BoxByDimensions")
+aBox.real("dx").setValue(50)
+aBox.real("dy").setValue(50)
+aBox.real("dz").setValue(50)
+aSession.finishOperation()
+aBoxResult = aBox.firstResult()
+aBoxShape = aBoxResult.shape()
+
+# Create edges
+aSession.startOperation()
+anEdgeFeature2 = aPart.addFeature("Edge")
+aBaseObjectsList = anEdgeFeature2.selectionList("base_objects")
+aShapeExplorer = GeomAPI_ShapeExplorer(aBoxShape, GeomAPI_Shape.EDGE)
+aShapes = []
+while aShapeExplorer.more():
+    # keep unique shapes only
+    aCurrent = aShapeExplorer.current()
+    isNewShape = True
+    for s in aShapes:
+        if s.isSame(aCurrent):
+            isNewShape = False
+            break
+    if isNewShape:
+        aShapes.append(aCurrent)
+    aShapeExplorer.next()
+
+for s in aShapes:
+    aBaseObjectsList.append(aBoxResult, s)
+aSession.finishOperation()
+
+# Test results
+assert (len(anEdgeFeature2.results()) == 12)
+
 from salome.shaper import model
 assert(model.checkPythonDump())
index f486817034c1faaa7a08296a66b08884a528eb4c..a88618c8f22e06a4a8ae1a7952741094be2c58e3 100644 (file)
@@ -35,6 +35,10 @@ aSession.finishOperation()
 aPartResult = modelAPI_ResultPart(aPartFeature.firstResult())
 aPart = aPartResult.partDoc()
 
+# =============================================================================
+# Test 1. Create face from edges of sketch
+# =============================================================================
+
 # Create a sketch
 aSession.startOperation()
 aSketchFeature = featureToCompositeFeature(aPart.addFeature("Sketch"))
@@ -83,5 +87,59 @@ aSession.finishOperation()
 # Test results
 assert (len(aFaceFeature.results()) > 0)
 
+# =============================================================================
+# Test 2. Create face from edges of solid
+# =============================================================================
+
+# Cylinder
+aSession.startOperation()
+aCylinder = aPart.addFeature("Cylinder")
+aCylinder.string("CreationMethod").setValue("Cylinder")
+aCylinder.selection("base_point").selectSubShape("VERTEX", "PartSet/Origin")
+aCylinder.selection("axis").selectSubShape("EDGE", "PartSet/OZ")
+aCylinder.real("radius").setValue(5)
+aCylinder.real("height").setValue(10)
+aSession.finishOperation()
+aCylinderResult = aCylinder.firstResult()
+aCylinderShape = aCylinderResult.shape()
+
+# Create face
+aSession.startOperation()
+aFaceFeature2 = aPart.addFeature("Face")
+aBaseObjectsList = aFaceFeature2.selectionList("base_objects")
+aBaseObjectsList.append("Cylinder_1_1/Face_1&Cylinder_1_1/Face_2", "EDGE")
+aSession.finishOperation()
+assert (len(aFaceFeature2.results()) > 0)
+
+# =============================================================================
+# Test 3. Create face from face of solid
+# =============================================================================
+
+aSession.startOperation()
+aFaceFeature3 = aPart.addFeature("Face")
+aBaseObjectsList = aFaceFeature3.selectionList("base_objects")
+aBaseObjectsList.append("Cylinder_1_1/Face_1", "FACE")
+aSession.finishOperation()
+assert (len(aFaceFeature3.results()) > 0)
+
+# =============================================================================
+# Test 4. Verify error is reported if selection of face feature is mixed (edges and face)
+# =============================================================================
+
+aSession.startOperation()
+aFaceFeature4 = aPart.addFeature("Face")
+aBaseObjectsList = aFaceFeature4.selectionList("base_objects")
+aShapeExplorer = GeomAPI_ShapeExplorer(aSketchShape, GeomAPI_Shape.EDGE)
+while aShapeExplorer.more():
+    aBaseObjectsList.append(aSketchResult, aShapeExplorer.current())
+    aShapeExplorer.next()
+aBaseObjectsList.append("Cylinder_1_1/Face_3", "FACE")
+aSession.finishOperation()
+assert (len(aFaceFeature4.results()) == 0)
+# remove failed feature
+aSession.startOperation()
+aPart.removeFeature(aFaceFeature4)
+aSession.finishOperation()
+
 from salome.shaper import model
 assert(model.checkPythonDump())
index 52d37b68bf223b1ea087d7a6a964b77e2841ccad..4b371b9728cd60f77a7f6694e2e483c682db0538 100644 (file)
@@ -98,5 +98,30 @@ aSession.finishOperation()
 # Test results
 assert (len(aShellFeature.results()) > 0)
 
+# Test shell building on set of faces from another result
+
+# Cylinder
+aSession.startOperation()
+aCylinder = aPart.addFeature("Cylinder")
+aCylinder.string("CreationMethod").setValue("Cylinder")
+aCylinder.selection("base_point").selectSubShape("VERTEX", "PartSet/Origin")
+aCylinder.selection("axis").selectSubShape("EDGE", "PartSet/OZ")
+aCylinder.real("radius").setValue(25)
+aCylinder.real("height").setValue(50)
+aSession.finishOperation()
+aCylinderResult = aCylinder.firstResult()
+aCylinderShape = aCylinderResult.shape()
+
+# Create shell
+aSession.startOperation()
+aShellFeature2 = aPart.addFeature("Shell")
+aBaseObjectsList = aShellFeature2.selectionList("base_objects")
+aBaseObjectsList.append("Cylinder_1_1/Face_1", "FACE")
+aBaseObjectsList.append("Cylinder_1_1/Face_3", "FACE")
+aSession.finishOperation()
+
+# Test results
+assert (len(aShellFeature2.results()) > 0)
+
 from salome.shaper import model
 assert(model.checkPythonDump())
index 46d5de5e914b94677abcbe5808178d0b9395f338..351a29017c2d4edc72362fd9819b06a34b7adc6c 100644 (file)
@@ -35,6 +35,10 @@ aSession.finishOperation()
 aPartResult = modelAPI_ResultPart(aPartFeature.firstResult())
 aPart = aPartResult.partDoc()
 
+# =============================================================================
+# Test 1. Create wire from edges of sketch
+# =============================================================================
+
 # Create a sketch
 aSession.startOperation()
 aSketchFeature = featureToCompositeFeature(aPart.addFeature("Sketch"))
@@ -85,6 +89,10 @@ assert (len(aWireFeature.results()) > 0)
 
 from salome.shaper import model
 
+# =============================================================================
+# Test 2. Complete contour by selecting only one edge
+# =============================================================================
+
 model.begin()
 partSet = model.moduleDocument()
 Part_1 = model.addPart(partSet)
@@ -107,4 +115,34 @@ Wire_1 = model.addWire(Part_1_doc, [model.selection("EDGE", "Sketch_1/Edge-Sketc
 Wire_1.addContour()
 model.end()
 
+# =============================================================================
+# Test 3. Create wire from edges of solid
+# =============================================================================
+
+# Box
+aSession.startOperation()
+aBox = aPart.addFeature("Box")
+aBox.string("CreationMethod").setValue("BoxByDimensions")
+aBox.real("dx").setValue(20)
+aBox.real("dy").setValue(20)
+aBox.real("dz").setValue(20)
+aSession.finishOperation()
+aBoxResult = aBox.firstResult()
+aBoxShape = aBoxResult.shape()
+
+# Wire
+aSession.startOperation()
+aWireFeature2 = aPart.addFeature("Wire")
+aBaseObjectsList = aWireFeature2.selectionList("base_objects")
+aBaseObjectsList.append("Box_1_1/Front&Box_1_1/Bottom", "EDGE")
+aBaseObjectsList.append("Box_1_1/Front&Box_1_1/Right", "EDGE")
+aBaseObjectsList.append("Box_1_1/Right&Box_1_1/Top", "EDGE")
+aBaseObjectsList.append("Box_1_1/Back&Box_1_1/Top", "EDGE")
+aBaseObjectsList.append("Box_1_1/Back&Box_1_1/Left", "EDGE")
+aBaseObjectsList.append("Box_1_1/Left&Box_1_1/Bottom", "EDGE")
+aSession.finishOperation()
+
+# Test results
+assert (len(aWireFeature2.results()) == 1)
+
 assert(model.checkPythonDump())
index 61f18f7aaaa3944587637275957bcf5affb8bbff..ab3626ab9e8910e15603ce1de7876808a0024bf5 100644 (file)
@@ -25,5 +25,6 @@ email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com
                   tooltip="Select solids or compsolids."
                   type_choice="faces shells solids compsolids"
                   concealment="true">
+    <validator id="BuildPlugin_ValidatorBaseForBuild" parameters="face,shell,solid,compsolid"/>
   </multi_selector>
 </source>
index a472e1f3dc5093bc030884c1e9a424f6838887be..38bce738472b8dcb2fbea87b872afaa8a44468dc 100644 (file)
@@ -23,9 +23,9 @@ email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com
   <multi_selector id="base_objects"
                   label="Segments and wires:"
                   tooltip="Select edges on sketch, edges or wires objects."
-                  type_choice="edges wires"
+                  type_choice="edges wires faces"
                   concealment="true">
-    <validator id="BuildPlugin_ValidatorBaseForBuild" parameters="edge,wire"/>
+    <validator id="BuildPlugin_ValidatorBaseForBuild" parameters="edge,wire,face"/>
   </multi_selector>
   <validator id="BuildPlugin_ValidatorBaseForFace" parameters="base_objects"/>
 </source>
index d454678c6d68e77d116addcde33912ddc6ae031d..f5ad261073a40766de1b55d6f83899bd28b590a3 100644 (file)
@@ -23,8 +23,8 @@ email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com
   <multi_selector id="base_objects"
                   label="Faces and shells:"
                   tooltip="Select faces or shells objects."
-                  type_choice="objects"
+                  type_choice="faces shells"
                   concealment="true">
-    <validator id="GeomValidators_ShapeType" parameters="face,shell"/>
+    <validator id="BuildPlugin_ValidatorBaseForBuild" parameters="face,shell"/>
   </multi_selector>
 </source>
index 9f2b49cd80464e739e139f07f1039137bac0cecd..f45b981d709f4f8e627c7a5818141e7c1e11f93c 100644 (file)
@@ -25,5 +25,6 @@ email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com
                   tooltip="Select faces or shells."
                   type_choice="faces shells"
                   concealment="true">
+    <validator id="BuildPlugin_ValidatorBaseForBuild" parameters="face,shell"/>
   </multi_selector>
 </source>