From: lucasjerome Date: Wed, 27 Jan 2021 18:38:10 +0000 (+0100) Subject: Lot3 : Added LOFT Feature implementation X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=refs%2Fheads%2Fnrn%2FLot3%2FFeature_LOFT;p=modules%2Fshaper.git Lot3 : Added LOFT Feature implementation --- diff --git a/src/FeaturesAPI/CMakeLists.txt b/src/FeaturesAPI/CMakeLists.txt index 6cd9ba368..822ad6cd9 100644 --- a/src/FeaturesAPI/CMakeLists.txt +++ b/src/FeaturesAPI/CMakeLists.txt @@ -37,6 +37,7 @@ SET(PROJECT_HEADERS FeaturesAPI_MultiTranslation.h FeaturesAPI_Partition.h FeaturesAPI_Pipe.h + FeaturesAPI_Loft.h FeaturesAPI_Placement.h FeaturesAPI_Recover.h FeaturesAPI_RemoveResults.h @@ -74,6 +75,7 @@ SET(PROJECT_SOURCES FeaturesAPI_MultiTranslation.cpp FeaturesAPI_Partition.cpp FeaturesAPI_Pipe.cpp + FeaturesAPI_Loft.cpp FeaturesAPI_Placement.cpp FeaturesAPI_Recover.cpp FeaturesAPI_RemoveResults.cpp diff --git a/src/FeaturesAPI/FeaturesAPI.i b/src/FeaturesAPI/FeaturesAPI.i index d9fa7c0b5..9c05372b5 100644 --- a/src/FeaturesAPI/FeaturesAPI.i +++ b/src/FeaturesAPI/FeaturesAPI.i @@ -76,6 +76,7 @@ %shared_ptr(FeaturesAPI_MultiTranslation) %shared_ptr(FeaturesAPI_Partition) %shared_ptr(FeaturesAPI_Pipe) +%shared_ptr(FeaturesAPI_Loft) %shared_ptr(FeaturesAPI_Placement) %shared_ptr(FeaturesAPI_Recover) %shared_ptr(FeaturesAPI_RemoveSubShapes) @@ -218,6 +219,7 @@ %include "FeaturesAPI_MultiTranslation.h" %include "FeaturesAPI_Partition.h" %include "FeaturesAPI_Pipe.h" +%include "FeaturesAPI_Loft.h" %include "FeaturesAPI_Placement.h" %include "FeaturesAPI_Recover.h" %include "FeaturesAPI_RemoveSubShapes.h" diff --git a/src/FeaturesAPI/FeaturesAPI_Loft.cpp b/src/FeaturesAPI/FeaturesAPI_Loft.cpp new file mode 100644 index 000000000..ad21aa52d --- /dev/null +++ b/src/FeaturesAPI/FeaturesAPI_Loft.cpp @@ -0,0 +1,77 @@ +// Copyright (C) 2014-2022 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 +// + +#include "FeaturesAPI_Loft.h" + +#include +#include + +//================================================================================================== +FeaturesAPI_Loft::FeaturesAPI_Loft(const std::shared_ptr& theFeature) +: ModelHighAPI_Interface(theFeature) +{ + initialize(); +} + +//================================================================================================== +FeaturesAPI_Loft::FeaturesAPI_Loft(const std::shared_ptr& theFeature, + const ModelHighAPI_Selection& theFirstObject, + const ModelHighAPI_Selection& theSecondObject) +: ModelHighAPI_Interface(theFeature) +{ + if(initialize()) { + fillAttribute(theFirstObject, myfisrstObject); + fillAttribute(theSecondObject, mysecondObject); + execute(); + } +} + +//================================================================================================== +FeaturesAPI_Loft::~FeaturesAPI_Loft() +{ + +} + +//================================================================================================== +void FeaturesAPI_Loft::dump(ModelHighAPI_Dumper& theDumper) const +{ + FeaturePtr aBase = feature(); + const std::string& aDocName = theDumper.name(aBase->document()); + + AttributeSelectionPtr anAttrFirstObject = + aBase->selection(FeaturesPlugin_Loft::FIRST_OBJECT_ID()); + AttributeSelectionPtr anAttrSecondObject = + aBase->selection(FeaturesPlugin_Loft::SECOND_OBJECT_ID()); + + theDumper << aBase << " = model.addLoft(" << aDocName << ", " + << anAttrFirstObject << ", " << anAttrSecondObject; + + theDumper << ")" << std::endl; +} + +//================================================================================================== +LoftPtr addLoft(const std::shared_ptr& thePart, + const ModelHighAPI_Selection& theFirstObject, + const ModelHighAPI_Selection& theSecondObject) +{ + std::shared_ptr aFeature = thePart->addFeature(FeaturesAPI_Loft::ID()); + + return LoftPtr(new FeaturesAPI_Loft(aFeature, theFirstObject, theSecondObject)); +} + diff --git a/src/FeaturesAPI/FeaturesAPI_Loft.h b/src/FeaturesAPI/FeaturesAPI_Loft.h new file mode 100644 index 000000000..aabe0dc41 --- /dev/null +++ b/src/FeaturesAPI/FeaturesAPI_Loft.h @@ -0,0 +1,74 @@ +// Copyright (C) 2014-2022 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 +// + +#ifndef FeaturesAPI_Loft_H_ +#define FeaturesAPI_Loft_H_ + +#include "FeaturesAPI.h" + +#include + +#include +#include + +class ModelHighAPI_Dumper; +class ModelHighAPI_Selection; + +/// \class FeaturesAPI_Loft +/// \ingroup CPPHighAPI +/// \brief Interface for Loft feature. +class FeaturesAPI_Loft: public ModelHighAPI_Interface +{ +public: + /// Constructor without values. + FEATURESAPI_EXPORT + explicit FeaturesAPI_Loft(const std::shared_ptr& theFeature); + + /// Constructor with values. + FEATURESAPI_EXPORT + explicit FeaturesAPI_Loft(const std::shared_ptr& theFeature, + const ModelHighAPI_Selection& theFirstObject, + const ModelHighAPI_Selection& theSecondObject); + + /// Destructor. + FEATURESAPI_EXPORT + virtual ~FeaturesAPI_Loft(); + + INTERFACE_2(FeaturesPlugin_Loft::ID(), + fisrstObject, FeaturesPlugin_Loft::FIRST_OBJECT_ID(), + ModelAPI_AttributeSelection, /** First object */, + secondObject, FeaturesPlugin_Loft::SECOND_OBJECT_ID(), + ModelAPI_AttributeSelection, /** second objexct */) + + /// Dump wrapped feature + FEATURESAPI_EXPORT + virtual void dump(ModelHighAPI_Dumper& theDumper) const; +}; + +/// Pointer on Loft object. +typedef std::shared_ptr LoftPtr; + +/// \ingroup CPPHighAPI +/// \brief Create Loft feature. +FEATURESAPI_EXPORT +LoftPtr addLoft(const std::shared_ptr& thePart, + const ModelHighAPI_Selection& theFirstObject, + const ModelHighAPI_Selection& theSecondObject); + +#endif // FeaturesAPI_Loft_H_ diff --git a/src/FeaturesAPI/FeaturesAPI_swig.h b/src/FeaturesAPI/FeaturesAPI_swig.h index ede8f2c11..3a99ed93b 100644 --- a/src/FeaturesAPI/FeaturesAPI_swig.h +++ b/src/FeaturesAPI/FeaturesAPI_swig.h @@ -40,6 +40,7 @@ #include "FeaturesAPI_MultiTranslation.h" #include "FeaturesAPI_Partition.h" #include "FeaturesAPI_Pipe.h" + #include "FeaturesAPI_Loft.h" #include "FeaturesAPI_Placement.h" #include "FeaturesAPI_Recover.h" #include "FeaturesAPI_RemoveSubShapes.h" diff --git a/src/FeaturesPlugin/CMakeLists.txt b/src/FeaturesPlugin/CMakeLists.txt index e3f25e81d..dffda7322 100644 --- a/src/FeaturesPlugin/CMakeLists.txt +++ b/src/FeaturesPlugin/CMakeLists.txt @@ -39,6 +39,7 @@ SET(PROJECT_HEADERS FeaturesPlugin_Intersection.h FeaturesPlugin_Partition.h FeaturesPlugin_Pipe.h + FeaturesPlugin_Loft.h FeaturesPlugin_Placement.h FeaturesPlugin_CompositeBoolean.h FeaturesPlugin_CompositeSketch.h @@ -93,6 +94,7 @@ SET(PROJECT_SOURCES FeaturesPlugin_Intersection.cpp FeaturesPlugin_Partition.cpp FeaturesPlugin_Pipe.cpp + FeaturesPlugin_Loft.cpp FeaturesPlugin_Placement.cpp FeaturesPlugin_CompositeBoolean.cpp FeaturesPlugin_CompositeSketch.cpp @@ -150,6 +152,7 @@ SET(XML_RESOURCES placement_widget.xml intersection_widget.xml pipe_widget.xml + loft_widget.xml remove_subshapes_widget.xml union_widget.xml symmetry_widget.xml @@ -221,16 +224,16 @@ ADD_UNIT_TESTS( IF(${HAVE_SALOME}) enable_testing() set(TEST_INSTALL_DIRECTORY "${SALOME_SHAPER_INSTALL_TESTS}/FeaturesPlugin") - + install(FILES CTestTestfileInstall.cmake DESTINATION ${TEST_INSTALL_DIRECTORY} RENAME CTestTestfile.cmake) install(FILES tests.set DESTINATION ${TEST_INSTALL_DIRECTORY}) - + set(TMP_TESTS_NAMES) foreach(tfile ${TEST_NAMES}) list(APPEND TMP_TESTS_NAMES "Test/${tfile}") endforeach(tfile ${TEST_NAMES}) - + install(FILES ${TMP_TESTS_NAMES} DESTINATION ${TEST_INSTALL_DIRECTORY}) ENDIF(${HAVE_SALOME}) diff --git a/src/FeaturesPlugin/FeaturesPlugin_Loft.cpp b/src/FeaturesPlugin/FeaturesPlugin_Loft.cpp new file mode 100644 index 000000000..cb55099ec --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_Loft.cpp @@ -0,0 +1,188 @@ +// Copyright (C) 2014-2022 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 +// + +#include "FeaturesPlugin_Loft.h" +#include "FeaturesPlugin_Tools.h" + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +//================================================================================================== +FeaturesPlugin_Loft::FeaturesPlugin_Loft() +{ +} + +//================================================================================================== +void FeaturesPlugin_Loft::initAttributes() +{ + data()->addAttribute(FIRST_OBJECT_ID(), ModelAPI_AttributeSelection::typeId()); + data()->addAttribute(SECOND_OBJECT_ID(), ModelAPI_AttributeSelection::typeId()); +} + +//================================================================================================== +void FeaturesPlugin_Loft::execute() +{ + AttributeSelectionPtr aFirstSelection = selection(FIRST_OBJECT_ID()); + AttributeSelectionPtr aSecondelection = selection(SECOND_OBJECT_ID()); + + if (aFirstSelection->isInitialized() && aSecondelection->isInitialized()) { + + GeomShapePtr aFirstShape, aSecondShape; + + if (aFirstSelection && aSecondelection) { + aFirstShape = aFirstSelection->value(); + if (!aFirstShape && aFirstSelection->context()) + aFirstShape = aFirstSelection->context()->shape(); + + aSecondShape = aSecondelection->value(); + if (!aSecondShape && aSecondelection->context()) + aSecondShape = aSecondelection->context()->shape(); + + } + // Loft for two edges + if(aFirstShape->isEdge()) { + + std::shared_ptr aFilling( + new GeomAlgoAPI_Filling(2.0, 5.0, 0, 0.0001, 0.0001 )); + + // collect base shapes + GeomEdgePtr aFirstEdge = toEdge(aFirstShape); + if (!aFirstEdge) { + myLastEdgeStartPoint = GeomPointPtr(); + myLastEdgeEndPoint = GeomPointPtr(); + return; + } + aFilling->add(aFirstEdge); + + GeomEdgePtr aSecondEdge = toEdge(aSecondShape); + if (!aSecondEdge) { + myLastEdgeStartPoint = GeomPointPtr(); + myLastEdgeEndPoint = GeomPointPtr(); + return; + } + aFilling->add(aSecondEdge); + myLastEdgeStartPoint = GeomPointPtr(); + myLastEdgeEndPoint = GeomPointPtr(); + + // build result + aFilling->build(); + std::string anError; + if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aFilling, getKind(), anError)) { + setError(anError); + removeResults(0); + return; + } + + /// store result + GeomShapePtr aCreatedFace = aFilling->shape(); + ResultBodyPtr aResultBody = document()->createBody(data()); + aResultBody->store(aCreatedFace); + // store edges + for(GeomAPI_ShapeExplorer anExp(aCreatedFace, GeomAPI_Shape::EDGE); + anExp.more(); anExp.next()) { + GeomShapePtr anEdge = anExp.current(); + aResultBody->generated(anEdge, "Loft_Edge"); + } + setResult(aResultBody, 0); + + } else { + + std::shared_ptr aLoftAlgo(new GeomAlgoAPI_Loft(aFirstShape, aSecondShape)); + + std::string anError; + + if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aLoftAlgo, getKind(), anError)) { + setError(anError); + return; + } + ListOfShape theBoundaryShapes; + theBoundaryShapes.push_back(aFirstShape); + theBoundaryShapes.push_back(aSecondShape); + + // Create result body. + ResultBodyPtr aResultBody = document()->createBody(data()); + + aResultBody->store(aLoftAlgo->shape()); + // store Faces + for(GeomAPI_ShapeExplorer anExp(aLoftAlgo->shape(), GeomAPI_Shape::FACE); + anExp.more(); anExp.next()) { + GeomShapePtr anEdge = anExp.current(); + aResultBody->generated(anEdge, "Loft_Face"); + } + setResult(aResultBody, 0); + } + } +} + +//================================================================================================= +GeomEdgePtr FeaturesPlugin_Loft::toEdge(const GeomShapePtr& theShape) +{ + GeomEdgePtr anEdge = GeomEdgePtr(new GeomAPI_Edge(GeomAlgoAPI_Copy(theShape).shape())); + + if (!anEdge || anEdge->empty()) { + static const std::string aFeatureError = + "Error: incorrect type of input feature (edges are supported only)."; + setError(aFeatureError); + return anEdge; + } + + // correct edge orientation according to filling method + // check the distance to previous edge boundaries, reverse edge if necessary + GeomPointPtr aStartPnt = anEdge->firstPoint(); + GeomPointPtr aEndPnt = anEdge->lastPoint(); + if (anEdge->orientation() == GeomAPI_Shape::REVERSED) { + aStartPnt = anEdge->lastPoint(); + aEndPnt = anEdge->firstPoint(); + } + bool isReverse = false; + if (myLastEdgeStartPoint) { + double d1 = myLastEdgeStartPoint->distance(aStartPnt) + + myLastEdgeEndPoint->distance(aEndPnt); + double d2 = myLastEdgeStartPoint->distance(aEndPnt) + + myLastEdgeEndPoint->distance(aStartPnt); + if (fabs(d1 - d2) < 1.e-7) { + // undefined case => check distance to start point only + d1 = myLastEdgeStartPoint->distance(aStartPnt); + d2 = myLastEdgeStartPoint->distance(aEndPnt); + } + isReverse = d2 < d1; + } + + if (isReverse) { + anEdge->reverse(); + myLastEdgeStartPoint = aEndPnt; + myLastEdgeEndPoint = aStartPnt; + } else { + myLastEdgeStartPoint = aStartPnt; + myLastEdgeEndPoint = aEndPnt; + } + + return anEdge; +} diff --git a/src/FeaturesPlugin/FeaturesPlugin_Loft.h b/src/FeaturesPlugin/FeaturesPlugin_Loft.h new file mode 100644 index 000000000..a3fa5156e --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_Loft.h @@ -0,0 +1,101 @@ +// Copyright (C) 2014-2022 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 +// + +#ifndef FeaturesPlugin_Loft_H_ +#define FeaturesPlugin_Loft_H_ + +#include "FeaturesPlugin.h" + +#include + +#include +#include + +class GeomAPI_Pnt; + +/// \class FeaturesPlugin_Loft +/// \ingroup Plugins +/// \brief Feature for creation of extrusion along a path. +/// Pipe creates extrusion of objects along a path. +/// It produces the following results from objects:\n +/// Vertex -> Edge\n +/// Edge -> Face\n +/// Wire -> Shell\n +/// Face -> Solid +class FeaturesPlugin_Loft : public ModelAPI_Feature +{ +public: + /// Feature kind. + inline static const std::string& ID() + { + static const std::string MY_FEATURE_ID("Loft"); + return MY_FEATURE_ID; + } + + /// Attribute name for first object selected. + inline static const std::string& FIRST_OBJECT_ID() + { + static const std::string MY_FIRST_OBJECT("first_object"); + return MY_FIRST_OBJECT; + } + + /// Attribute name for second object selected. + inline static const std::string& SECOND_OBJECT_ID() + { + static const std::string MY_SECOND_OBJECT("second_object"); + return MY_SECOND_OBJECT; + } + + /// \return the kind of a feature. + FEATURESPLUGIN_EXPORT virtual const std::string& getKind() + { + static std::string MY_KIND = FeaturesPlugin_Loft::ID(); + return MY_KIND; + } + + /// Performs the algorithm and stores results it in the data structure. + FEATURESPLUGIN_EXPORT virtual void execute(); + + /// Request for initialization of data model of the feature: adding all attributes + FEATURESPLUGIN_EXPORT virtual void initAttributes(); + + /// Use plugin manager for features creation + FeaturesPlugin_Loft(); + + private: + + void storeResult(const std::shared_ptr theFirstShape, + const std::shared_ptr theSecondShape, + const std::shared_ptr theLoftAlgo, + const int theResultIndex = 0); + + void storeShapes(ResultBodyPtr theResultBody, + const GeomAPI_Shape::ShapeType theBaseShapeType, + const ListOfShape& theShapes, + const std::string theName); + private: + /// Convert shape to edge + std::shared_ptr toEdge(const std::shared_ptr& theShape); + + private: + std::shared_ptr myLastEdgeStartPoint; + std::shared_ptr myLastEdgeEndPoint; +}; + +#endif diff --git a/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp b/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp index 3d00700d6..cf8f39e87 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -85,7 +86,9 @@ FeaturesPlugin_Plugin::FeaturesPlugin_Plugin() aFactory->registerValidator("FeaturesPlugin_ValidatorPipeLocations", new FeaturesPlugin_ValidatorPipeLocations); aFactory->registerValidator("FeaturesPlugin_ValidatorPipeLocationsNumber", - new FeaturesPlugin_ValidatorPipeLocationsNumber); + new FeaturesPlugin_ValidatorLoftSameTypeShape); + aFactory->registerValidator("FeaturesPlugin_ValidatorLoftSameTypeShape", + new FeaturesPlugin_ValidatorLoftSameTypeShape); aFactory->registerValidator("FeaturesPlugin_ValidatorExtrusionDir", new FeaturesPlugin_ValidatorExtrusionDir); aFactory->registerValidator("FeaturesPlugin_ValidatorExtrusionBoundary", @@ -161,6 +164,8 @@ FeaturePtr FeaturesPlugin_Plugin::createFeature(std::string theFeatureID) return FeaturePtr(new FeaturesPlugin_Partition); } else if (theFeatureID == FeaturesPlugin_Pipe::ID()) { return FeaturePtr(new FeaturesPlugin_Pipe); + } else if (theFeatureID == FeaturesPlugin_Loft::ID()) { + return FeaturePtr(new FeaturesPlugin_Loft); } else if (theFeatureID == FeaturesPlugin_Placement::ID()) { return FeaturePtr(new FeaturesPlugin_Placement); } else if (theFeatureID == FeaturesPlugin_Recover::ID()) { diff --git a/src/FeaturesPlugin/FeaturesPlugin_Validators.cpp b/src/FeaturesPlugin/FeaturesPlugin_Validators.cpp index b5aa56afe..9500e0379 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Validators.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Validators.cpp @@ -228,6 +228,57 @@ bool FeaturesPlugin_ValidatorPipeLocationsNumber::isValid( } // LCOV_EXCL_STOP +//================================================================================================== +bool FeaturesPlugin_ValidatorLoftSameTypeShape::isValid( + const std::shared_ptr& theFeature, + const std::list& theArguments, + Events_InfoMessage& theError) const +{ + static const std::string aFirstObjetcID = "first_object"; + static const std::string aSecondObjetcID = "second_object"; + + if (theFeature->getKind() != "Loft") { + theError = "Error: Feature \"%1\" does not supported by this validator."; + theError.arg(theFeature->getKind()); + return false; + } + + AttributeSelectionPtr aFirstObjectsSelection = theFeature->selection(aFirstObjetcID); + if ( !aFirstObjectsSelection->isInitialized()) { + theError = "Error: Could not get \"%1\" attribute."; + theError.arg(aFirstObjetcID); + return false; + } + + AttributeSelectionPtr aSecondObjectsSelection = theFeature->selection(aSecondObjetcID); + if (!aSecondObjectsSelection->isInitialized()) { + theError = "Error: Could not get \"%1\" attribute."; + theError.arg(aSecondObjetcID); + return false; + } + + GeomShapePtr aFirstShape = aFirstObjectsSelection->value(); + if (!aFirstShape.get()) { + aFirstShape = aFirstObjectsSelection->context()->shape(); + } + GeomShapePtr aSecondShape = aSecondObjectsSelection->value(); + if (!aSecondShape.get()) { + aSecondShape = aSecondObjectsSelection->context()->shape(); + } + + if (aFirstShape->isEqual(aSecondShape)) { + theError = "Error: the shapes are equal"; + return false; + } + + if (aFirstShape->shapeType()!=aSecondShape->shapeType()) { + theError = "Error: the shapes have different type"; + return false; + } + + return true; +} + //================================================================================================== bool FeaturesPlugin_ValidatorBaseForGeneration::isValid(const AttributePtr& theAttribute, const std::list& theArguments, diff --git a/src/FeaturesPlugin/FeaturesPlugin_Validators.h b/src/FeaturesPlugin/FeaturesPlugin_Validators.h index 138ff80da..1c31440de 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Validators.h +++ b/src/FeaturesPlugin/FeaturesPlugin_Validators.h @@ -68,6 +68,21 @@ class FeaturesPlugin_ValidatorPipeLocationsNumber: public ModelAPI_FeatureValida Events_InfoMessage& theError) const; }; +/// \class FeaturesPlugin_ValidatorLoftSameTypeShape +/// \ingroup Validators +/// \brief Validator for the same type of shape. +class FeaturesPlugin_ValidatorLoftSameTypeShape: public ModelAPI_FeatureValidator +{ + public: + //! \return true if the type of selected are the same + //! \param theFeature the checked feature + //! \param theArguments arguments of the feature (not used) + //! \param theError error message + virtual bool isValid(const std::shared_ptr& theFeature, + const std::list& theArguments, + Events_InfoMessage& theError) const; +}; + /// \class FeaturesPlugin_ValidatorBaseForGeneration /// \ingroup Validators /// \brief A validator for selection base for generation. Allows to select faces on sketch, diff --git a/src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts b/src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts index 878c1f4d5..653d085b8 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts +++ b/src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts @@ -65,6 +65,10 @@ Pipe Tuyau + + Loft + Lissage + Recover Récupérer @@ -1384,6 +1388,28 @@ + + + Loft + + Loft + Lissage + + + + Loft:first_object + + First object: + Premier objet: + + + + Loft:second_object + + Second object: + Deuxième objet: + + Recover diff --git a/src/FeaturesPlugin/Test/TestLoft.py b/src/FeaturesPlugin/Test/TestLoft.py new file mode 100644 index 000000000..5a1f5d8e5 --- /dev/null +++ b/src/FeaturesPlugin/Test/TestLoft.py @@ -0,0 +1,143 @@ +# Copyright (C) 2018-2022 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() + +### Create Part +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() + +### Create Sketch +Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY")) + +### Create SketchLine +SketchLine_1 = Sketch_1.addLine(65.56914119359536, 34.84279475982533, -62.33478893740904, 34.84279475982533) + +### Create SketchLine +SketchLine_2 = Sketch_1.addLine(-62.33478893740904, 34.84279475982533, -62.33478893740904, -28.08005822416302) + +### Create SketchLine +SketchLine_3 = Sketch_1.addLine(-62.33478893740904, -28.08005822416302, 65.56914119359536, -28.08005822416302) + +### Create SketchLine +SketchLine_4 = Sketch_1.addLine(65.56914119359536, -28.08005822416302, 65.56914119359536, 34.84279475982533) +Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint()) +Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint()) +Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint()) +Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint()) +Sketch_1.setHorizontal(SketchLine_1.result()) +Sketch_1.setVertical(SketchLine_2.result()) +Sketch_1.setHorizontal(SketchLine_3.result()) +Sketch_1.setVertical(SketchLine_4.result()) +model.do() + +### Create Plane +Plane_4 = model.addPlane(Part_1_doc, model.selection("EDGE", "Sketch_1/SketchLine_4"), model.selection("VERTEX", "Sketch_1/SketchLine_3_StartVertex"), False) + +### Create Plane +Plane_5 = model.addPlane(Part_1_doc, model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_4f"), 100, False) + +### Create Sketch +Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("YOZ")) + +### Create SketchCircle +SketchCircle_1 = Sketch_2.addCircle(60.9581866489876, 39.76685108527785, 26.86156014153439) +model.do() + +### Create Plane +Plane_6 = model.addPlane(Part_1_doc, model.selection("FACE", "Sketch_2/Face-SketchCircle_1_2r"), 100, False) + +### Create Box +Box_1 = model.addBox(Part_1_doc, 10, 10, 10) + +### Create Box +Box_2 = model.addBox(Part_1_doc, 10, 10, 10) + +### Create Translation +Translation_1 = model.addTranslation(Part_1_doc, [model.selection("COMPOUND", "all-in-Box_2")], axis = model.selection("EDGE", "PartSet/OY"), distance = 100, keepSubResults = True) + +### Create Wire +Wire_1_objects = [model.selection("EDGE", "[Box_1_1/Front][Box_1_1/Right]"), + model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Top]"), + model.selection("EDGE", "[Box_1_1/Back][Box_1_1/Right]"), + model.selection("EDGE", "[Box_1_1/Right][Box_1_1/Bottom]")] +Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False) + +### Create Wire +Wire_2_objects = [model.selection("EDGE", "[Translation_1_1_1/MF:Translated&Box_2_1/Left][Translation_1_1_1/MF:Translated&Box_2_1/Top]"), + model.selection("EDGE", "[Translation_1_1_1/MF:Translated&Box_2_1/Front][Translation_1_1_1/MF:Translated&Box_2_1/Left]"), + model.selection("EDGE", "[Translation_1_1_1/MF:Translated&Box_2_1/Left][Translation_1_1_1/MF:Translated&Box_2_1/Bottom]"), + model.selection("EDGE", "[Translation_1_1_1/MF:Translated&Box_2_1/Back][Translation_1_1_1/MF:Translated&Box_2_1/Left]")] +Wire_2 = model.addWire(Part_1_doc, Wire_2_objects, False) + +### Create Box +Box_3 = model.addBox(Part_1_doc, 10, 10, 10) + +### Create Wire +Wire_3 = model.addWire(Part_1_doc, [model.selection("EDGE", "[Box_3_1/Left][Box_3_1/Top]"), model.selection("EDGE", "[Box_3_1/Front][Box_3_1/Left]")], False) + +### Create Box +Box_4 = model.addBox(Part_1_doc, 10, 10, 10) + +### Create Translation +Translation_2 = model.addTranslation(Part_1_doc, [model.selection("COMPOUND", "all-in-Box_4")], axis = model.selection("EDGE", "PartSet/OY"), distance = 40, keepSubResults = True) + +### Create Wire +Wire_4 = model.addWire(Part_1_doc, [model.selection("EDGE", "[Translation_2_1_1/MF:Translated&Box_4_1/Left][Translation_2_1_1/MF:Translated&Box_4_1/Top]"), model.selection("EDGE", "[Translation_2_1_1/MF:Translated&Box_4_1/Front][Translation_2_1_1/MF:Translated&Box_4_1/Left]")], False) + +### Create Loft +Loft_1 = model.addLoft(Part_1_doc, model.selection("FACE", "Plane_2"), model.selection("FACE", "Plane_1")) + +### Create Loft +Loft_2 = model.addLoft(Part_1_doc, model.selection("WIRE", "Wire_2_1"), model.selection("WIRE", "Wire_1_1")) + +### Create Loft +Loft_3 = model.addLoft(Part_1_doc, model.selection("WIRE", "Wire_3_1"), model.selection("WIRE", "Wire_4_1")) + +### Create Loft +Loft_4 = model.addLoft(Part_1_doc, model.selection("EDGE", "Sketch_1/SketchLine_2"), model.selection("EDGE", "Sketch_1/SketchLine_4")) + +model.end() + +from GeomAPI import GeomAPI_Shape + +#test loft with two face +model.testNbResults(Loft_1, 1) +model.testNbSubResults(Loft_1, [0]) +model.testNbSubShapes(Loft_1, GeomAPI_Shape.SOLID, [1]) + + +#test loft with two wire +model.testNbResults(Loft_2, 1) +model.testNbSubResults(Loft_2, [0]) +model.testNbSubShapes(Loft_2, GeomAPI_Shape.SHELL, [1]) + +#test loft with two wire +model.testNbResults(Loft_3, 1) +model.testNbSubResults(Loft_3, [0]) +model.testNbSubShapes(Loft_3, GeomAPI_Shape.SHELL, [1]) + +#test loft with two edge +model.testNbResults(Loft_4, 1) +model.testNbSubResults(Loft_4, [0]) +model.testNbSubShapes(Loft_4, GeomAPI_Shape.FACE, [1]) + diff --git a/src/FeaturesPlugin/doc/FeaturesPlugin.rst b/src/FeaturesPlugin/doc/FeaturesPlugin.rst index 6fc8177bd..ac4a0fd5b 100644 --- a/src/FeaturesPlugin/doc/FeaturesPlugin.rst +++ b/src/FeaturesPlugin/doc/FeaturesPlugin.rst @@ -25,6 +25,7 @@ Features plug-in provides a set of common topological operations. It implements geometryCalculationFeature.rst importResultFeature.rst linearCopyFeature.rst + loftFeature.rst measurementFeature.rst normalToFaceFeature.rst pipeFeature.rst diff --git a/src/FeaturesPlugin/doc/TUI_loftFeature.rst b/src/FeaturesPlugin/doc/TUI_loftFeature.rst new file mode 100644 index 000000000..c97cf3fc9 --- /dev/null +++ b/src/FeaturesPlugin/doc/TUI_loftFeature.rst @@ -0,0 +1,11 @@ + + .. _tui_loft: + +loft +==== + +.. literalinclude:: examples/loft.py + :linenos: + :language: python + +:download:`Download this script ` diff --git a/src/FeaturesPlugin/doc/examples/loft.py b/src/FeaturesPlugin/doc/examples/loft.py new file mode 100644 index 000000000..f3f9dfebe --- /dev/null +++ b/src/FeaturesPlugin/doc/examples/loft.py @@ -0,0 +1,45 @@ +from SketchAPI import * + +from salome.shaper import model + +model.begin() +partSet = model.moduleDocument() + +### Create Part +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() + +### Create Sketch +Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY")) + +### Create SketchLine +SketchLine_1 = Sketch_1.addLine(65.56914119359536, 34.84279475982533, -62.33478893740904, 34.84279475982533) + +### Create SketchLine +SketchLine_2 = Sketch_1.addLine(-62.33478893740904, 34.84279475982533, -62.33478893740904, -28.08005822416302) + +### Create SketchLine +SketchLine_3 = Sketch_1.addLine(-62.33478893740904, -28.08005822416302, 65.56914119359536, -28.08005822416302) + +### Create SketchLine +SketchLine_4 = Sketch_1.addLine(65.56914119359536, -28.08005822416302, 65.56914119359536, 34.84279475982533) +Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint()) +Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint()) +Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint()) +Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint()) +Sketch_1.setHorizontal(SketchLine_1.result()) +Sketch_1.setVertical(SketchLine_2.result()) +Sketch_1.setHorizontal(SketchLine_3.result()) +Sketch_1.setVertical(SketchLine_4.result()) +model.do() + +### Create Plane +Plane_1 = model.addPlane(Part_1_doc, model.selection("EDGE", "Sketch_1/SketchLine_4"), model.selection("VERTEX", "Sketch_1/SketchLine_3_StartVertex"), False) + +### Create Plane +Plane_2 = model.addPlane(Part_1_doc, model.selection("FACE", "Sketch_1/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f-SketchLine_4f"), 100, False) + +### Create Loft +Loft_1 = model.addLoft(Part_1_doc, model.selection("FACE", "Plane_1"), model.selection("FACE", "Plane_2")) + +model.end() diff --git a/src/FeaturesPlugin/doc/images/loft.png b/src/FeaturesPlugin/doc/images/loft.png new file mode 100644 index 000000000..892ead927 Binary files /dev/null and b/src/FeaturesPlugin/doc/images/loft.png differ diff --git a/src/FeaturesPlugin/doc/images/loftPropertyPanel.png b/src/FeaturesPlugin/doc/images/loftPropertyPanel.png new file mode 100644 index 000000000..760244331 Binary files /dev/null and b/src/FeaturesPlugin/doc/images/loftPropertyPanel.png differ diff --git a/src/FeaturesPlugin/doc/images/resultLoft.png b/src/FeaturesPlugin/doc/images/resultLoft.png new file mode 100644 index 000000000..acf0013cd Binary files /dev/null and b/src/FeaturesPlugin/doc/images/resultLoft.png differ diff --git a/src/FeaturesPlugin/doc/loftFeature.rst b/src/FeaturesPlugin/doc/loftFeature.rst new file mode 100644 index 000000000..dd017a948 --- /dev/null +++ b/src/FeaturesPlugin/doc/loftFeature.rst @@ -0,0 +1,45 @@ +.. |loft.icon| image:: images/loft.png + +Loft +==== + +**Loft** feature is used to create a face, shell or a solid shape from two or more objects. +The two objects can be edges, wires or faces. + +To create a Loft in the active part: + +#. select in the Main Menu *Features - > Loft* item or +#. click |loft.icon| **Loft** button in the toolbar + +The following property panel appears. + +.. figure:: images/loftPropertyPanel.png + :align: center + + Loft property panel + +Input fields: + +- **First object** defines the first shape (edge, wire, face) selected in 3D OCC viewer or object browser; +- **Second object** defines the second shape (edge, wire, face) selected in 3D OCC viewer or object browser; + +**TUI Command**: + +.. py:function:: model.addLoft(Part_doc, [shape], [shape]) + + :param part: The current part object. + :param object: A shape in format *model.selection(TYPE, shape)*. + :param object: A shape in format *model.selection(TYPE, shape)*. + :return: Created object. + +Result +"""""" + +Result of loft between two faces. + +.. figure:: images/resultLoft.png + :align: center + + Loft between two faces + +**See Also** a sample TUI Script of :ref:`tui_loft` operation. \ No newline at end of file diff --git a/src/FeaturesPlugin/icons/loft.png b/src/FeaturesPlugin/icons/loft.png new file mode 100644 index 000000000..892ead927 Binary files /dev/null and b/src/FeaturesPlugin/icons/loft.png differ diff --git a/src/FeaturesPlugin/loft_widget.xml b/src/FeaturesPlugin/loft_widget.xml new file mode 100644 index 000000000..21dc390d6 --- /dev/null +++ b/src/FeaturesPlugin/loft_widget.xml @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/src/FeaturesPlugin/plugin-Features.xml b/src/FeaturesPlugin/plugin-Features.xml index 87e47c378..59ec705fe 100644 --- a/src/FeaturesPlugin/plugin-Features.xml +++ b/src/FeaturesPlugin/plugin-Features.xml @@ -39,6 +39,10 @@ icon="icons/Features/pipe.png" helpfile="pipeFeature.html"> + + + + +#include "GeomAlgoAPI_DFLoader.h" +#include "GeomAlgoAPI_Loft.h" + +#include +#include +#include + +//================================================================================================== +GeomAlgoAPI_Loft::GeomAlgoAPI_Loft(const GeomShapePtr theFirstShape, + const GeomShapePtr theSecondShape) +{ + build(theFirstShape, theSecondShape); +} + +//================================================================================================== +void GeomAlgoAPI_Loft::build(const GeomShapePtr theFirstShape, + const GeomShapePtr theSecondShape) +{ + // Getting base shape. + if(!theFirstShape.get() || !theSecondShape.get()) { + return; + } + TopoDS_Shape aFirstShape = theFirstShape->impl(); + if(aFirstShape.IsNull()) { + return; + } + TopoDS_Shape aSecondShape= theSecondShape->impl(); + if(aSecondShape.IsNull()) { + return; + } + + bool anIsSolid = true; + + TopoDS_Shape aFirstShapeOut; + TopoDS_Shape aSecondShapeOut; + if (aFirstShape.ShapeType() == TopAbs_FACE) { + TopExp_Explorer anExp(aFirstShape, TopAbs_WIRE); + aFirstShapeOut = anExp.Current(); + TopExp_Explorer anExp2(aSecondShape, TopAbs_WIRE); + aSecondShapeOut = anExp2.Current(); + } + + if (aFirstShape.ShapeType() == TopAbs_WIRE) { + aFirstShapeOut = aFirstShape; + aSecondShapeOut = aSecondShape; + anIsSolid = false; + } + + // Initialize and build + BRepOffsetAPI_ThruSections * ThruSections = + new BRepOffsetAPI_ThruSections(anIsSolid, Standard_False, 1.0e-06); + ThruSections->AddWire( TopoDS::Wire( aFirstShapeOut ) ); + ThruSections->AddWire( TopoDS::Wire( aSecondShapeOut) ); + + try + { + ThruSections->Build(); + } + catch (Standard_Failure& aFail) + { + delete ThruSections; + return; + } + // Checking result. + if(!ThruSections->IsDone() || ThruSections->Shape().IsNull()) { + delete ThruSections; + return; + } + + this->initialize(ThruSections); + + // Setting result. + TopoDS_Shape aResult = ThruSections->Shape(); + aResult = GeomAlgoAPI_DFLoader::refineResult(aResult); + GeomShapePtr aGeomSh(new GeomAPI_Shape()); + aGeomSh->setImpl(new TopoDS_Shape(aResult)); + this->setShape(aGeomSh); + this->setDone(true); +} + +//================================================================================================== +void GeomAlgoAPI_Loft::generated(const GeomShapePtr theShape, + ListOfShape& theHistory) +{ + GeomAlgoAPI_MakeShape::generated(theShape, theHistory); +} diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Loft.h b/src/GeomAlgoAPI/GeomAlgoAPI_Loft.h new file mode 100644 index 000000000..82e3adf8f --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Loft.h @@ -0,0 +1,57 @@ +// Copyright (C) 2014-2022 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 +// + +#ifndef GeomAlgoAPI_Loft_H_ +#define GeomAlgoAPI_Loft__H_ + +#include "GeomAlgoAPI.h" + +#include "GeomAlgoAPI_MakeShape.h" + +#include + +/// \class GeomAlgoAPI_Loft +/// \ingroup DataAlgo +/// \brief Allows to create loft of two objects with same type. +/// It produces the following results from objects:\n +/// 2 edges -> Face\n +/// 2 Wire -> Shell\n +/// 2 Face -> Solid +class GeomAlgoAPI_Loft : public GeomAlgoAPI_MakeShape +{ +public: + /// \brief Creates loft for two given shape with same type. + /// \param[in] theFirstShape the first shape. + /// \param[in] theSecondShape the second shape. + GEOMALGOAPI_EXPORT GeomAlgoAPI_Loft(const GeomShapePtr theFirstShape, + const GeomShapePtr theSecondShape); + + /// \return the list of shapes generated from theShape. + /// \param[in] theShape base shape. + /// \param[out] theHistory generated shapes. + GEOMALGOAPI_EXPORT void generated(const GeomShapePtr theShape, + ListOfShape& theHistory); + +private: + void build(const GeomShapePtr theFirstShape, + const GeomShapePtr theSecondShape); + +}; + +#endif diff --git a/src/PythonAPI/model/features/__init__.py b/src/PythonAPI/model/features/__init__.py index 62a0ca1a8..f9d779762 100644 --- a/src/PythonAPI/model/features/__init__.py +++ b/src/PythonAPI/model/features/__init__.py @@ -23,7 +23,7 @@ from FeaturesAPI import addPlacement, addRotation, addScale, addSymmetry, addTra from FeaturesAPI import addMultiTranslation, addMultiRotation from FeaturesAPI import addExtrusion, addExtrusionCut, addExtrusionFuse from FeaturesAPI import addRevolution, addRevolutionCut, addRevolutionFuse -from FeaturesAPI import addPipe +from FeaturesAPI import addPipe, addLoft from FeaturesAPI import addCut, addFuse, addCommon, addSmash, addSplit from FeaturesAPI import addIntersection, addPartition, addUnion, addRemoveSubShapes from FeaturesAPI import addRecover