// 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);
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);
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;
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);
+}
#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.
/// 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
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;
return false;
}
+ bool hasEdgesOrWires = false;
+ bool hasFaces = false;
+
// Collect base shapes.
ListOfShape anEdges;
for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
}
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;
}
}
}
- // 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;
# 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())
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"))
# 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())
# 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())
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"))
from salome.shaper import model
+# =============================================================================
+# Test 2. Complete contour by selecting only one edge
+# =============================================================================
+
model.begin()
partSet = model.moduleDocument()
Part_1 = model.addPart(partSet)
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())
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>
<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>
<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>
tooltip="Select faces or shells."
type_choice="faces shells"
concealment="true">
+ <validator id="BuildPlugin_ValidatorBaseForBuild" parameters="face,shell"/>
</multi_selector>
</source>