From: dbv Date: Fri, 22 Apr 2016 11:07:14 +0000 (+0300) Subject: Issue #1369: Added "Create Face" feature. X-Git-Tag: V_2.3.0~134 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=37bd12bd6f4626fc2bfa7764c8f4927dc5b01b9c;p=modules%2Fshaper.git Issue #1369: Added "Create Face" feature. --- diff --git a/src/BuildPlugin/BuildPlugin_Face.cpp b/src/BuildPlugin/BuildPlugin_Face.cpp new file mode 100644 index 000000000..36ef2b3e8 --- /dev/null +++ b/src/BuildPlugin/BuildPlugin_Face.cpp @@ -0,0 +1,108 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: BuildPlugin_Face.cpp +// Created: 14 April 2016 +// Author: Dmitry Bobylev + +#include "BuildPlugin_Face.h" + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +//================================================================================================= +BuildPlugin_Face::BuildPlugin_Face() +{ +} + +//================================================================================================= +void BuildPlugin_Face::initAttributes() +{ + data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId()); +} + +//================================================================================================= +void BuildPlugin_Face::execute() +{ + // Get base objects list. + AttributeSelectionListPtr aSelectionList = selectionList(BASE_OBJECTS_ID()); + if(!aSelectionList.get()) { + setError("Error: Could not get selection list."); + return; + } + if(aSelectionList->size() == 0) { + setError("Error: Empty selection list."); + return; + } + + // Collect base shapes. + ListOfShape anEdges; + for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) { + AttributeSelectionPtr aSelection = aSelectionList->value(anIndex); + GeomShapePtr aShape = aSelection->value(); + if(!aShape.get()) { + aShape = aSelection->context()->shape(); + } + for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) { + GeomShapePtr anEdge = anExp.current(); + anEdges.push_back(anEdge); + } + } + + // Get plane. + std::shared_ptr aPln = GeomAlgoAPI_ShapeTools::findPlane(anEdges); + + // Get faces. + 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) { + for(GeomAPI_ShapeExplorer anExp(*anIt, GeomAPI_Shape::WIRE); anExp.more(); anExp.next()) { + aWires.push_back(anExp.current()); + } + } + + // Make faces with holes. + aFaces.clear(); + GeomAlgoAPI_ShapeTools::makeFacesWithHoles(aPln->location(), aPln->direction(), aWires, aFaces); + + // Store result. + int anIndex = 0; + for(ListOfShape::const_iterator anIt = aFaces.cbegin(); anIt != aFaces.cend(); ++anIt) { + ResultBodyPtr aResultBody = document()->createBody(data(), anIndex); + GeomShapePtr aShape = *anIt; + aResultBody->store(aShape); + + for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) { + GeomShapePtr anEdgeInResult = anExp.current(); + for(ListOfShape::const_iterator anIt = anEdges.cbegin(); anIt != anEdges.cend(); ++anIt) { + std::shared_ptr anEdgeInList(new GeomAPI_Edge(*anIt)); + if(anEdgeInList->isEqual(anEdgeInResult)) { + aResultBody->modified(anEdgeInList, anEdgeInResult, "Edge"); + break; + } + } + } + + setResult(aResultBody, anIndex); + ++anIndex; + } + + removeResults(anIndex); +} diff --git a/src/BuildPlugin/BuildPlugin_Face.h b/src/BuildPlugin/BuildPlugin_Face.h new file mode 100644 index 000000000..fafd51dca --- /dev/null +++ b/src/BuildPlugin/BuildPlugin_Face.h @@ -0,0 +1,51 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: BuildPlugin_Face.h +// Created: 14 April 2016 +// Author: Dmitry Bobylev + +#ifndef BuildPlugin_Face_H_ +#define BuildPlugin_Face_H_ + +#include "BuildPlugin.h" + +#include + +/// \class BuildPlugin_Face +/// \ingroup Plugins +/// \brief Feature for creation of face from sketch edges or existing wires. +class BuildPlugin_Face: public ModelAPI_Feature +{ +public: + /// Use plugin manager for features creation + BuildPlugin_Face(); + + /// Feature kind. + inline static const std::string& ID() + { + static const std::string MY_ID("Face"); + return MY_ID; + } + + /// Attribute name of base objects. + inline static const std::string& BASE_OBJECTS_ID() + { + static const std::string MY_BASE_OBJECTS_ID("base_objects"); + return MY_BASE_OBJECTS_ID; + } + + /// \return the kind of a feature. + BUILDPLUGIN_EXPORT virtual const std::string& getKind() + { + static std::string MY_KIND = BuildPlugin_Face::ID(); + return MY_KIND; + } + + /// Request for initialization of data model of the feature: adding all attributes. + BUILDPLUGIN_EXPORT virtual void initAttributes(); + + /// Creates a new part document if needed. + BUILDPLUGIN_EXPORT virtual void execute(); +}; + +#endif diff --git a/src/BuildPlugin/BuildPlugin_Plugin.cpp b/src/BuildPlugin/BuildPlugin_Plugin.cpp index f26c60ace..f11e4ba6e 100644 --- a/src/BuildPlugin/BuildPlugin_Plugin.cpp +++ b/src/BuildPlugin/BuildPlugin_Plugin.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include // the only created instance of this plugin @@ -27,6 +28,8 @@ BuildPlugin_Plugin::BuildPlugin_Plugin() new BuildPlugin_ValidatorBaseForBuild()); aFactory->registerValidator("BuildPlugin_ValidatorBaseForWire", new BuildPlugin_ValidatorBaseForWire()); + aFactory->registerValidator("BuildPlugin_ValidatorBaseForFace", + new BuildPlugin_ValidatorBaseForFace()); // Register this plugin. ModelAPI_Session::get()->registerPlugin(this); @@ -41,6 +44,8 @@ FeaturePtr BuildPlugin_Plugin::createFeature(std::string theFeatureID) return FeaturePtr(new BuildPlugin_Edge()); } else if(theFeatureID == BuildPlugin_Wire::ID()) { return FeaturePtr(new BuildPlugin_Wire()); + } else if(theFeatureID == BuildPlugin_Face::ID()) { + return FeaturePtr(new BuildPlugin_Face()); } // Feature of such kind is not found. diff --git a/src/BuildPlugin/BuildPlugin_Validators.cpp b/src/BuildPlugin/BuildPlugin_Validators.cpp index 7204aebce..5097fea40 100644 --- a/src/BuildPlugin/BuildPlugin_Validators.cpp +++ b/src/BuildPlugin/BuildPlugin_Validators.cpp @@ -10,8 +10,13 @@ #include #include +#include +#include #include +#include +#include +#include #include #include @@ -100,23 +105,17 @@ bool BuildPlugin_ValidatorBaseForWire::isValid(const std::shared_ptrattribute(theArguments.front()); - - // Check base objects list. - BuildPlugin_ValidatorBaseForBuild aValidatorBaseForBuild; - std::list anArguments; - anArguments.push_back("edge"); - anArguments.push_back("wire"); - if(!aValidatorBaseForBuild.isValid(anAttribute, anArguments, theError)) { + AttributeSelectionListPtr aSelectionList = theFeature->selectionList(theArguments.front()); + if(!aSelectionList.get()) { + theError = "Empty attribute \"" + theArguments.front() + "\"."; return false; } + // Collect base shapes. - AttributeSelectionListPtr aSelectionList = - std::dynamic_pointer_cast(anAttribute); ListOfShape aListOfShapes; for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) { AttributeSelectionPtr aSelection = aSelectionList->value(anIndex); @@ -138,40 +137,80 @@ bool BuildPlugin_ValidatorBaseForWire::isValid(const std::shared_ptr& theFeature, const std::list& theArguments, std::string& theError) const { - // Get base objects list. - BuildPlugin_ValidatorBaseForBuild aValidatorBaseForBuild; - std::list anArguments; - anArguments.push_back("edge"); - anArguments.push_back("wire"); - if(!aValidatorBaseForBuild.isValid(theAttribute, anArguments, theError)) { + // Get attribute. + if(theArguments.size() != 1) { + Events_Error::send("Error: BuildPlugin_ValidatorBaseForFace should be used only with 1 parameter (ID of base objects list)."); + return false; + } + AttributeSelectionListPtr aSelectionList = theFeature->selectionList(theArguments.front()); + if(!aSelectionList.get()) { + theError = "Empty attribute \"" + theArguments.front() + "\"."; return false; } // Collect base shapes. - AttributeSelectionListPtr aSelectionList = - std::dynamic_pointer_cast(theAttribute); - ListOfShape aListOfShapes; + ListOfShape anEdges; for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) { AttributeSelectionPtr aSelection = aSelectionList->value(anIndex); GeomShapePtr aShape = aSelection->value(); if(!aShape.get()) { aShape = aSelection->context()->shape(); } - aListOfShapes.push_back(aShape); + for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) { + GeomShapePtr anEdge = anExp.current(); + anEdges.push_back(anEdge); + } + } + + // Check that edges does not have intersections. + if(anEdges.size() > 1) { + GeomAlgoAPI_PaveFiller aPaveFiller(anEdges, false); + if(!aPaveFiller.isDone()) { + theError = "Error while checking if edges intersects."; + return false; + } + GeomShapePtr aSectedEdges = aPaveFiller.shape(); + + int anEdgesNum = 0; + for(GeomAPI_ShapeExplorer anExp(aSectedEdges, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) { + anEdgesNum++; + } + if(anEdgesNum != anEdges.size()) { + theError = "Selected objects have intersections."; + return false; + } } // Check that they are planar. - GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aListOfShapes); + std::shared_ptr aPln = GeomAlgoAPI_ShapeTools::findPlane(anEdges); + if(!aPln.get()) { + theError = "Selected objects are not planar."; + return false; + } - return aCompound->isPlanar(); + // 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 does not have closed contours."; + return false; + } + + return true; +} + +//================================================================================================= +bool BuildPlugin_ValidatorBaseForFace::isNotObligatory(std::string theFeature, std::string theAttribute) +{ + return false; } diff --git a/src/BuildPlugin/BuildPlugin_Validators.h b/src/BuildPlugin/BuildPlugin_Validators.h index 8792c42ce..1f2091efe 100644 --- a/src/BuildPlugin/BuildPlugin_Validators.h +++ b/src/BuildPlugin/BuildPlugin_Validators.h @@ -48,17 +48,20 @@ public: /// \class BuildPlugin_ValidatorBaseForFace /// \ingroup Validators /// \brief A validator for selection base shapes for face. Allows to select sketch edges, edges and -/// wires objects that lie in the same plane. -class BuildPlugin_ValidatorBaseForFace: public ModelAPI_AttributeValidator +/// wires objects that lie in the same plane and don't have intersections. +class BuildPlugin_ValidatorBaseForFace: public ModelAPI_FeatureValidator { public: - //! Returns true if attribute is ok. - //! \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& theArguments, - std::string& theError) const; + //! Returns true if attributes is ok. + //! \param theFeature the checked feature. + //! \param theArguments arguments of the feature. + //! \param theError error message. + virtual bool isValid(const std::shared_ptr& theFeature, + const std::list& theArguments, + std::string& theError) const; + + /// \return true if the attribute in feature is not obligatory for the feature execution + virtual bool isNotObligatory(std::string theFeature, std::string theAttribute); }; #endif diff --git a/src/BuildPlugin/BuildPlugin_Wire.cpp b/src/BuildPlugin/BuildPlugin_Wire.cpp index 5a69e9f49..99d6bd74e 100644 --- a/src/BuildPlugin/BuildPlugin_Wire.cpp +++ b/src/BuildPlugin/BuildPlugin_Wire.cpp @@ -67,7 +67,7 @@ void BuildPlugin_Wire::execute() // Create wire. GeomShapePtr aWire = GeomAlgoAPI_WireBuilder::wire(aListOfShapes); if(!aWire.get()) { - setError("Error: Result wire empty. Probably it has disconnected edges or non-manifold."); + setError("Error: Result wire is empty. Probably it has disconnected edges or non-manifold."); return; } diff --git a/src/BuildPlugin/CMakeLists.txt b/src/BuildPlugin/CMakeLists.txt index 3c159e8d6..a2ada0459 100644 --- a/src/BuildPlugin/CMakeLists.txt +++ b/src/BuildPlugin/CMakeLists.txt @@ -17,6 +17,7 @@ SET(PROJECT_HEADERS BuildPlugin_Vertex.h BuildPlugin_Edge.h BuildPlugin_Wire.h + BuildPlugin_Face.h BuildPlugin_Validators.h ) @@ -25,6 +26,7 @@ SET(PROJECT_SOURCES BuildPlugin_Vertex.cpp BuildPlugin_Edge.cpp BuildPlugin_Wire.cpp + BuildPlugin_Face.cpp BuildPlugin_Validators.cpp ) @@ -33,6 +35,7 @@ SET(XML_RESOURCES vertex_widget.xml edge_widget.xml wire_widget.xml + face_widget.xml ) SET(PROJECT_LIBRARIES diff --git a/src/BuildPlugin/face_widget.xml b/src/BuildPlugin/face_widget.xml new file mode 100644 index 000000000..8a05c4adf --- /dev/null +++ b/src/BuildPlugin/face_widget.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/src/BuildPlugin/icons/feature_face.png b/src/BuildPlugin/icons/feature_face.png new file mode 100644 index 000000000..6abc697c0 Binary files /dev/null and b/src/BuildPlugin/icons/feature_face.png differ diff --git a/src/BuildPlugin/plugin-Build.xml b/src/BuildPlugin/plugin-Build.xml index 0c2161f68..cfa04ecf0 100644 --- a/src/BuildPlugin/plugin-Build.xml +++ b/src/BuildPlugin/plugin-Build.xml @@ -12,6 +12,9 @@ + + + diff --git a/src/GeomAPI/GeomAPI_Pln.cpp b/src/GeomAPI/GeomAPI_Pln.cpp index 347e994f4..8dcce0a70 100644 --- a/src/GeomAPI/GeomAPI_Pln.cpp +++ b/src/GeomAPI/GeomAPI_Pln.cpp @@ -43,6 +43,12 @@ std::shared_ptr GeomAPI_Pln::direction() const return std::shared_ptr(new GeomAPI_Dir(aDir.X(), aDir.Y(), aDir.Z())); } +std::shared_ptr GeomAPI_Pln::xDirection() const +{ + const gp_Dir& aDir = impl().XAxis().Direction(); + return std::shared_ptr(new GeomAPI_Dir(aDir.X(), aDir.Y(), aDir.Z())); +} + void GeomAPI_Pln::coefficients(double& theA, double& theB, double& theC, double& theD) { impl().Coefficients(theA, theB, theC, theD); diff --git a/src/GeomAPI/GeomAPI_Pln.h b/src/GeomAPI/GeomAPI_Pln.h index 3c319b789..5c173838d 100644 --- a/src/GeomAPI/GeomAPI_Pln.h +++ b/src/GeomAPI/GeomAPI_Pln.h @@ -44,6 +44,10 @@ class GeomAPI_Pln : public GeomAPI_Interface GEOMAPI_EXPORT std::shared_ptr direction() const; + /// Returns a plane x direction + GEOMAPI_EXPORT + std::shared_ptr xDirection() const; + /// Returns the plane coefficients (Ax+By+Cz+D=0) GEOMAPI_EXPORT void coefficients(double& theA, double& theB, double& theC, double& theD); diff --git a/src/GeomAPI/GeomAPI_Shape.cpp b/src/GeomAPI/GeomAPI_Shape.cpp index 279e3738a..cba5be5ce 100644 --- a/src/GeomAPI/GeomAPI_Shape.cpp +++ b/src/GeomAPI/GeomAPI_Shape.cpp @@ -11,8 +11,16 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include #include #include +#include #include #include #include @@ -95,19 +103,28 @@ bool GeomAPI_Shape::isCompSolid() const bool GeomAPI_Shape::isPlanar() const { - const TopoDS_Shape& aShape = const_cast(this)->impl(); + TopoDS_Shape aShape = impl(); if(aShape.IsNull()) { return false; } TopAbs_ShapeEnum aShapeType = aShape.ShapeType(); + if(aShapeType == TopAbs_COMPOUND) { + TopoDS_Iterator anIt(aShape); + int aShNum = 0; + for(; anIt.More(); anIt.Next()) { + ++aShNum; + } + if(aShNum == 1) { + anIt.Initialize(aShape); + aShape = anIt.Value(); + } + } + aShapeType = aShape.ShapeType(); if(aShapeType == TopAbs_VERTEX) { return true; - } else if(aShapeType == TopAbs_EDGE || aShapeType == TopAbs_WIRE || aShapeType == TopAbs_SHELL) { - BRepBuilderAPI_FindPlane aFindPlane(aShape); - return aFindPlane.Found() == Standard_True; } else if(aShapeType == TopAbs_FACE) { const Handle(Geom_Surface)& aSurface = BRep_Tool::Surface(TopoDS::Face(aShape)); Handle(Standard_Type) aType = aSurface->DynamicType(); @@ -118,8 +135,33 @@ bool GeomAPI_Shape::isPlanar() const } return (aType == STANDARD_TYPE(Geom_Plane)) == Standard_True; } else { - return false; + BRepBuilderAPI_FindPlane aFindPlane(aShape); + bool isFound = aFindPlane.Found() == Standard_True; + + if(!isFound && aShapeType == TopAbs_EDGE) { + Standard_Real aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(TopoDS::Edge(aShape), aFirst, aLast); + Handle(Standard_Type) aType = aCurve->DynamicType(); + + if(aType == STANDARD_TYPE(Geom_TrimmedCurve)) { + Handle(Geom_TrimmedCurve) aTrimCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve); + aType = aTrimCurve->BasisCurve()->DynamicType(); + } + + if(aType == STANDARD_TYPE(Geom_Line) + || aType == STANDARD_TYPE(Geom_Conic) + || aType == STANDARD_TYPE(Geom_Circle) + || aType == STANDARD_TYPE(Geom_Ellipse) + || aType == STANDARD_TYPE(Geom_Hyperbola) + || aType == STANDARD_TYPE(Geom_Parabola)) { + isFound = true; + } + } + + return isFound; } + + return false; } GeomAPI_Shape::ShapeType GeomAPI_Shape::shapeType() const diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp index 2a5fd2083..47d05e566 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -17,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -38,10 +40,6 @@ #include #include - -void mapWireFaces(const TopoDS_Shape& theShape, - BOPCol_IndexedDataMapOfShapeListOfShape& theMapWireFaces); - //================================================================================================= double GeomAlgoAPI_ShapeTools::volume(const std::shared_ptr theShape) { @@ -372,3 +370,31 @@ void GeomAlgoAPI_ShapeTools::makeFacesWithHoles(const std::shared_ptr GeomAlgoAPI_ShapeTools::findPlane(const ListOfShape& theShapes) +{ + TopoDS_Compound aCompound; + BRep_Builder aBuilder; + aBuilder.MakeCompound(aCompound); + + for(ListOfShape::const_iterator anIt = theShapes.cbegin(); anIt != theShapes.cend(); ++anIt) { + aBuilder.Add(aCompound, (*anIt)->impl()); + } + BRepBuilderAPI_FindPlane aFindPlane(aCompound); + + if(aFindPlane.Found() != Standard_True) { + return std::shared_ptr(); + } + + Handle(Geom_Plane) aPlane = aFindPlane.Plane(); + gp_Pnt aLoc = aPlane->Location(); + gp_Dir aDir = aPlane->Axis().Direction(); + + std::shared_ptr aGeomPnt(new GeomAPI_Pnt(aLoc.X(), aLoc.Y(), aLoc.Z())); + std::shared_ptr aGeomDir(new GeomAPI_Dir(aDir.X(), aDir.Y(), aDir.Z())); + + std::shared_ptr aPln(new GeomAPI_Pln(aGeomPnt, aGeomDir)); + + return aPln; +} diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h index 6136d6c10..07d6704ab 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h @@ -14,6 +14,7 @@ class GeomAPI_Dir; class GeomAPI_PlanarEdges; +class GeomAPI_Pln; class GeomAPI_Pnt; /// \class GeomAlgoAPI_ShapeTools @@ -65,13 +66,18 @@ public: std::shared_ptr& theV1, std::shared_ptr& theV2); - /// \Creates faces with holes from wires. + /// \brief Creates faces with holes from wires. /// \param[in] theWires base wires. /// \param[out] theFaces resulting faces. static void makeFacesWithHoles(const std::shared_ptr theOrigin, const std::shared_ptr theDirection, const ListOfShape& theWires, ListOfShape& theFaces); + + /// \brief Return a plane for list of shapes if they are all planar. + /// \param[in] theShapes shapes to find plane. + /// \return plane where all shapes lie or empty ptr if they not planar. + static std::shared_ptr findPlane(const ListOfShape& theShapes); }; #endif