From 8715e3164ba7b59be1f4409e83c1a1e6b00faba4 Mon Sep 17 00:00:00 2001 From: azv Date: Mon, 25 Dec 2017 11:54:20 +0300 Subject: [PATCH] Issue #2386: Update features Edge, Wire, Face, Shell to be able to use sub-shapes of already existent results --- src/BuildPlugin/BuildPlugin_Face.cpp | 76 +++++++++++++--------- src/BuildPlugin/BuildPlugin_Face.h | 9 +++ src/BuildPlugin/BuildPlugin_Validators.cpp | 49 ++++++++------ src/BuildPlugin/Test/TestEdge.py | 36 ++++++++++ src/BuildPlugin/Test/TestFace.py | 58 +++++++++++++++++ src/BuildPlugin/Test/TestShell.py | 25 +++++++ src/BuildPlugin/Test/TestWire.py | 38 +++++++++++ src/BuildPlugin/compsolid_widget.xml | 1 + src/BuildPlugin/face_widget.xml | 4 +- src/BuildPlugin/shell_widget.xml | 4 +- src/BuildPlugin/solid_widget.xml | 1 + 11 files changed, 246 insertions(+), 55 deletions(-) diff --git a/src/BuildPlugin/BuildPlugin_Face.cpp b/src/BuildPlugin/BuildPlugin_Face.cpp index fb782101f..391ea4bd9 100644 --- a/src/BuildPlugin/BuildPlugin_Face.cpp +++ b/src/BuildPlugin/BuildPlugin_Face.cpp @@ -59,6 +59,7 @@ void BuildPlugin_Face::execute() // Collect base shapes. ListOfShape anEdges; + ListOfShape anOriginalFaces; std::list< std::shared_ptr > 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 aPln = GeomAlgoAPI_ShapeTools::findPlane(anEdges); - std::shared_ptr aNormal = aPln->direction(); - bool isReverse = !aListOfNormals.empty(); - std::list< std::shared_ptr >::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(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 >& theNormals, + ListOfShape& theFaces) const +{ + // Get plane. + std::shared_ptr aPln = GeomAlgoAPI_ShapeTools::findPlane(theEdges); + std::shared_ptr aNormal = aPln->direction(); + bool isReverse = !theNormals.empty(); + std::list< std::shared_ptr >::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(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); +} diff --git a/src/BuildPlugin/BuildPlugin_Face.h b/src/BuildPlugin/BuildPlugin_Face.h index f6c276325..633118eb7 100644 --- a/src/BuildPlugin/BuildPlugin_Face.h +++ b/src/BuildPlugin/BuildPlugin_Face.h @@ -25,6 +25,9 @@ #include +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 >& theEdges, + const std::list< std::shared_ptr >& theNormals, + std::list< std::shared_ptr >& theFaces) const; }; #endif diff --git a/src/BuildPlugin/BuildPlugin_Validators.cpp b/src/BuildPlugin/BuildPlugin_Validators.cpp index e0268ef42..833536d40 100644 --- a/src/BuildPlugin/BuildPlugin_Validators.cpp +++ b/src/BuildPlugin/BuildPlugin_Validators.cpp @@ -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_ptrsize(); ++anIndex) { @@ -204,13 +201,23 @@ bool BuildPlugin_ValidatorBaseForFace::isValid(const std::shared_ptrcontext()->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 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 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; diff --git a/src/BuildPlugin/Test/TestEdge.py b/src/BuildPlugin/Test/TestEdge.py index 98f6b478b..c64cae8e0 100644 --- a/src/BuildPlugin/Test/TestEdge.py +++ b/src/BuildPlugin/Test/TestEdge.py @@ -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()) diff --git a/src/BuildPlugin/Test/TestFace.py b/src/BuildPlugin/Test/TestFace.py index f48681703..a88618c8f 100644 --- a/src/BuildPlugin/Test/TestFace.py +++ b/src/BuildPlugin/Test/TestFace.py @@ -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()) diff --git a/src/BuildPlugin/Test/TestShell.py b/src/BuildPlugin/Test/TestShell.py index 52d37b68b..4b371b972 100644 --- a/src/BuildPlugin/Test/TestShell.py +++ b/src/BuildPlugin/Test/TestShell.py @@ -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()) diff --git a/src/BuildPlugin/Test/TestWire.py b/src/BuildPlugin/Test/TestWire.py index 46d5de5e9..351a29017 100644 --- a/src/BuildPlugin/Test/TestWire.py +++ b/src/BuildPlugin/Test/TestWire.py @@ -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()) diff --git a/src/BuildPlugin/compsolid_widget.xml b/src/BuildPlugin/compsolid_widget.xml index 61f18f7aa..ab3626ab9 100644 --- a/src/BuildPlugin/compsolid_widget.xml +++ b/src/BuildPlugin/compsolid_widget.xml @@ -25,5 +25,6 @@ email : webmaster.salome@opencascade.com + diff --git a/src/BuildPlugin/face_widget.xml b/src/BuildPlugin/face_widget.xml index a472e1f3d..38bce7384 100644 --- a/src/BuildPlugin/face_widget.xml +++ b/src/BuildPlugin/face_widget.xml @@ -23,9 +23,9 @@ email : webmaster.salome@opencascade.com - + diff --git a/src/BuildPlugin/shell_widget.xml b/src/BuildPlugin/shell_widget.xml index d454678c6..f5ad26107 100644 --- a/src/BuildPlugin/shell_widget.xml +++ b/src/BuildPlugin/shell_widget.xml @@ -23,8 +23,8 @@ email : webmaster.salome@opencascade.com - + diff --git a/src/BuildPlugin/solid_widget.xml b/src/BuildPlugin/solid_widget.xml index 9f2b49cd8..f45b981d7 100644 --- a/src/BuildPlugin/solid_widget.xml +++ b/src/BuildPlugin/solid_widget.xml @@ -25,5 +25,6 @@ email : webmaster.salome@opencascade.com + -- 2.39.2