From 64a1c2eb2f69296ef63245d3a777797918e79376 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me?= Date: Wed, 21 Oct 2020 19:26:35 +0200 Subject: [PATCH] Integration : { Code from : Jerome LUCAS } + Implementation create normal to face + Modification for "create normal" functionality + Add documentation and test unit + Refactoring code + Copyright update to 2021 --- src/FeaturesAPI/CMakeLists.txt | 2 + src/FeaturesAPI/FeaturesAPI.i | 2 + src/FeaturesAPI/FeaturesAPI_NormalToFace.cpp | 119 +++++++++ src/FeaturesAPI/FeaturesAPI_NormalToFace.h | 88 +++++++ src/FeaturesAPI/FeaturesAPI_swig.h | 1 + src/FeaturesPlugin/CMakeLists.txt | 29 ++- .../FeaturesPlugin_CreateNormalToFace.cpp | 114 +++++++++ .../FeaturesPlugin_CreateNormalToFace.h | 84 +++++++ .../FeaturesPlugin_NormalToFace.cpp | 165 ++++++++++++ .../FeaturesPlugin_NormalToFace.h | 102 ++++++++ src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp | 6 + src/FeaturesPlugin/Test/TestNormalToFace.py | 66 +++++ .../create_normal_to_face_widget.xml | 20 ++ src/FeaturesPlugin/doc/FeaturesPlugin.rst | 1 + .../doc/TUI_normalToFaceFeature.rst | 22 ++ .../doc/examples/createNormalToFace.py | 15 ++ .../examples/createNormalToFaceAtVertex.py | 17 ++ src/FeaturesPlugin/doc/images/normal.png | Bin 0 -> 655 bytes .../doc/images/normalToFacePropertyPanel.png | Bin 0 -> 10808 bytes .../doc/images/normalToFaceResult.png | Bin 0 -> 2777 bytes .../images/normalToFaceResultwithVertex.png | Bin 0 -> 2685 bytes .../doc/normalToFaceFeature.rst | 71 ++++++ src/FeaturesPlugin/icons/normale.png | Bin 0 -> 655 bytes src/FeaturesPlugin/normal_to_face_widget.xml | 21 ++ src/FeaturesPlugin/plugin-Features.xml | 14 +- src/FeaturesPlugin/tests.set | 3 +- src/GeomAlgoAPI/CMakeLists.txt | 2 + src/GeomAlgoAPI/GeomAlgoAPI_NormalToFace.cpp | 235 ++++++++++++++++++ src/GeomAlgoAPI/GeomAlgoAPI_NormalToFace.h | 46 ++++ src/ModelAPI/CMakeLists.txt | 12 +- src/PythonAPI/model/features/__init__.py | 1 + 31 files changed, 1247 insertions(+), 11 deletions(-) create mode 100644 src/FeaturesAPI/FeaturesAPI_NormalToFace.cpp create mode 100644 src/FeaturesAPI/FeaturesAPI_NormalToFace.h create mode 100644 src/FeaturesPlugin/FeaturesPlugin_CreateNormalToFace.cpp create mode 100644 src/FeaturesPlugin/FeaturesPlugin_CreateNormalToFace.h create mode 100644 src/FeaturesPlugin/FeaturesPlugin_NormalToFace.cpp create mode 100644 src/FeaturesPlugin/FeaturesPlugin_NormalToFace.h create mode 100644 src/FeaturesPlugin/Test/TestNormalToFace.py create mode 100644 src/FeaturesPlugin/create_normal_to_face_widget.xml create mode 100644 src/FeaturesPlugin/doc/TUI_normalToFaceFeature.rst create mode 100644 src/FeaturesPlugin/doc/examples/createNormalToFace.py create mode 100644 src/FeaturesPlugin/doc/examples/createNormalToFaceAtVertex.py create mode 100644 src/FeaturesPlugin/doc/images/normal.png create mode 100644 src/FeaturesPlugin/doc/images/normalToFacePropertyPanel.png create mode 100644 src/FeaturesPlugin/doc/images/normalToFaceResult.png create mode 100644 src/FeaturesPlugin/doc/images/normalToFaceResultwithVertex.png create mode 100644 src/FeaturesPlugin/doc/normalToFaceFeature.rst create mode 100644 src/FeaturesPlugin/icons/normale.png create mode 100644 src/FeaturesPlugin/normal_to_face_widget.xml create mode 100644 src/GeomAlgoAPI/GeomAlgoAPI_NormalToFace.cpp create mode 100644 src/GeomAlgoAPI/GeomAlgoAPI_NormalToFace.h diff --git a/src/FeaturesAPI/CMakeLists.txt b/src/FeaturesAPI/CMakeLists.txt index 9cb86e10b..6cd9ba368 100644 --- a/src/FeaturesAPI/CMakeLists.txt +++ b/src/FeaturesAPI/CMakeLists.txt @@ -32,6 +32,7 @@ SET(PROJECT_HEADERS FeaturesAPI_Fillet.h FeaturesAPI_Intersection.h FeaturesAPI_Measurement.h + FeaturesAPI_NormalToFace.h FeaturesAPI_MultiRotation.h FeaturesAPI_MultiTranslation.h FeaturesAPI_Partition.h @@ -68,6 +69,7 @@ SET(PROJECT_SOURCES FeaturesAPI_Fillet.cpp FeaturesAPI_Intersection.cpp FeaturesAPI_Measurement.cpp + FeaturesAPI_NormalToFace.cpp FeaturesAPI_MultiRotation.cpp FeaturesAPI_MultiTranslation.cpp FeaturesAPI_Partition.cpp diff --git a/src/FeaturesAPI/FeaturesAPI.i b/src/FeaturesAPI/FeaturesAPI.i index 01804317a..d9fa7c0b5 100644 --- a/src/FeaturesAPI/FeaturesAPI.i +++ b/src/FeaturesAPI/FeaturesAPI.i @@ -63,6 +63,7 @@ %shared_ptr(FeaturesAPI_BooleanSmash) %shared_ptr(FeaturesAPI_BooleanFill) %shared_ptr(FeaturesAPI_Chamfer) +%shared_ptr(FeaturesAPI_NormalToFace) %shared_ptr(FeaturesAPI_Extrusion) %shared_ptr(FeaturesAPI_ExtrusionBoolean) %shared_ptr(FeaturesAPI_ExtrusionCut) @@ -212,6 +213,7 @@ %include "FeaturesAPI_Fillet.h" %include "FeaturesAPI_Intersection.h" %include "FeaturesAPI_Measurement.h" +%include "FeaturesAPI_NormalToFace.h" %include "FeaturesAPI_MultiRotation.h" %include "FeaturesAPI_MultiTranslation.h" %include "FeaturesAPI_Partition.h" diff --git a/src/FeaturesAPI/FeaturesAPI_NormalToFace.cpp b/src/FeaturesAPI/FeaturesAPI_NormalToFace.cpp new file mode 100644 index 000000000..8cbf7bf9e --- /dev/null +++ b/src/FeaturesAPI/FeaturesAPI_NormalToFace.cpp @@ -0,0 +1,119 @@ +// Copyright (C) 2014-2021 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_NormalToFace.h" + +#include + +#include +#include +#include + +//================================================================================================= +FeaturesAPI_NormalToFace::FeaturesAPI_NormalToFace( + const std::shared_ptr& theFeature) + : ModelHighAPI_Interface(theFeature) +{ + initialize(); +} + +//================================================================================================= +FeaturesAPI_NormalToFace::FeaturesAPI_NormalToFace( + const std::shared_ptr& theFeature, + const ModelHighAPI_Selection& theBaseFace, + const ModelHighAPI_Selection& theOptionnelPoint) +:ModelHighAPI_Interface(theFeature) +{ + if (initialize()) { + fillAttribute(theBaseFace, myfaceSelected); + fillAttribute(theOptionnelPoint, myvertexSelected); + feature()->string(FeaturesPlugin_CreateNormalToFace::VERTEX_OPTION_ID())->setValue("true"); + execute(); + } +} + +//================================================================================================= +FeaturesAPI_NormalToFace::FeaturesAPI_NormalToFace( + const std::shared_ptr& theFeature, + const ModelHighAPI_Selection& theBaseFace) +:ModelHighAPI_Interface(theFeature) +{ + if (initialize()) { + fillAttribute(theBaseFace, myfaceSelected); + feature()->string(FeaturesPlugin_CreateNormalToFace::VERTEX_OPTION_ID())->setValue(""); + execute(); + } +} + +//================================================================================================= +FeaturesAPI_NormalToFace::~FeaturesAPI_NormalToFace() +{ +} + +//================================================================================================= +void FeaturesAPI_NormalToFace::dump(ModelHighAPI_Dumper& theDumper) const +{ + FeaturePtr aBase = feature(); + const std::string& aDocName = theDumper.name(aBase->document()); + + AttributeSelectionPtr anAttrObject; + anAttrObject = aBase->selection(FeaturesPlugin_CreateNormalToFace::FACE_SELECTED_ID()); + + theDumper << aBase << " = model.getNormal(" << aDocName << ", " << anAttrObject; + + if (!aBase->string(FeaturesPlugin_CreateNormalToFace::VERTEX_OPTION_ID())->value().empty()){ + + AttributeSelectionPtr anAttrVertex = + aBase->selection(FeaturesPlugin_CreateNormalToFace::VERTEX_SELECTED_ID()); + + theDumper << ", " << anAttrVertex; + } + + theDumper << ")" << std::endl; +} + +//================================================================================================== +NormalPtr getNormal(const std::shared_ptr& thePart, + const ModelHighAPI_Selection& theBaseFace, + const ModelHighAPI_Selection& theOptionnelPoint) +{ + + FeaturePtr aFeature = thePart->addFeature(FeaturesPlugin_CreateNormalToFace::ID()); + + NormalPtr aNormalToface; + + aNormalToface.reset(new FeaturesAPI_NormalToFace(aFeature, theBaseFace, theOptionnelPoint)); + + return aNormalToface; +} + +//================================================================================================= +NormalPtr getNormal(const std::shared_ptr& thePart, + const ModelHighAPI_Selection& theBaseFace) +{ + + FeaturePtr aFeature = thePart->addFeature(FeaturesPlugin_CreateNormalToFace::ID()); + + NormalPtr aNormalToface; + + aNormalToface.reset(new FeaturesAPI_NormalToFace(aFeature, theBaseFace)); + + return aNormalToface; +} + diff --git a/src/FeaturesAPI/FeaturesAPI_NormalToFace.h b/src/FeaturesAPI/FeaturesAPI_NormalToFace.h new file mode 100644 index 000000000..d305cdec2 --- /dev/null +++ b/src/FeaturesAPI/FeaturesAPI_NormalToFace.h @@ -0,0 +1,88 @@ +// Copyright (C) 2014-2021 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_NormalToFace_H_ +#define FeaturesAPI_NormalToFace_H_ + +#include "FeaturesAPI.h" + +#include + +#include +#include + + +class ModelHighAPI_Selection; + +/// \class FeaturesAPI_NormalToFace +/// \ingroup CPPHighAPI +/// \brief Interface for NormalToface feature. +class FeaturesAPI_NormalToFace: public ModelHighAPI_Interface +{ +public: + /// Constructor without values. + FEATURESAPI_EXPORT + explicit FeaturesAPI_NormalToFace(const std::shared_ptr& theFeature); + + FEATURESAPI_EXPORT + explicit FeaturesAPI_NormalToFace(const std::shared_ptr& theFeature, + const ModelHighAPI_Selection& theBaseFace, + const ModelHighAPI_Selection& theOptionnelPoint); + + FEATURESAPI_EXPORT + explicit FeaturesAPI_NormalToFace(const std::shared_ptr& theFeature, + const ModelHighAPI_Selection& theBaseFace); + /// Destructor. + FEATURESAPI_EXPORT + virtual ~FeaturesAPI_NormalToFace(); + + INTERFACE_3(FeaturesPlugin_CreateNormalToFace::ID(), + faceSelected, FeaturesPlugin_CreateNormalToFace::FACE_SELECTED_ID(), + ModelAPI_AttributeSelection, + /** base face */, + vertexSelected, FeaturesPlugin_CreateNormalToFace::VERTEX_SELECTED_ID(), + ModelAPI_AttributeSelection, + /** vetex option */, + vertexOption, FeaturesPlugin_CreateNormalToFace::VERTEX_OPTION_ID(), + ModelAPI_AttributeString, + /** option */) + + /// Dump wrapped feature + FEATURESAPI_EXPORT + virtual void dump(ModelHighAPI_Dumper& theDumper) const; + +}; + +/// Pointer on the NormalToface object. +typedef std::shared_ptr NormalPtr; + +/// \ingroup CPPHighAPI +/// \brief Create NormalToFace feature. +FEATURESAPI_EXPORT +NormalPtr getNormal(const std::shared_ptr& thePart, + const ModelHighAPI_Selection& theBaseFace, + const ModelHighAPI_Selection& theOptionnelPoint); + +/// \ingroup CPPHighAPI +/// \brief Create NormalToFace feature. +FEATURESAPI_EXPORT +NormalPtr getNormal(const std::shared_ptr& thePart, + const ModelHighAPI_Selection& theBaseFace); + +#endif // FeaturesAPI_Fillet_H_ diff --git a/src/FeaturesAPI/FeaturesAPI_swig.h b/src/FeaturesAPI/FeaturesAPI_swig.h index ce4a8887e..ede8f2c11 100644 --- a/src/FeaturesAPI/FeaturesAPI_swig.h +++ b/src/FeaturesAPI/FeaturesAPI_swig.h @@ -35,6 +35,7 @@ #include "FeaturesAPI_Fillet.h" #include "FeaturesAPI_Intersection.h" #include "FeaturesAPI_Measurement.h" + #include "FeaturesAPI_NormalToFace.h" #include "FeaturesAPI_MultiRotation.h" #include "FeaturesAPI_MultiTranslation.h" #include "FeaturesAPI_Partition.h" diff --git a/src/FeaturesPlugin/CMakeLists.txt b/src/FeaturesPlugin/CMakeLists.txt index 4d52c6119..bf435e301 100644 --- a/src/FeaturesPlugin/CMakeLists.txt +++ b/src/FeaturesPlugin/CMakeLists.txt @@ -19,6 +19,17 @@ INCLUDE(Common) INCLUDE(UnitTest) +INCLUDE(UseQtExt) + +# additional include directories +INCLUDE_DIRECTORIES( ${PROJECT_SOURCE_DIR}/src/GeomDataAPI + ${PROJECT_SOURCE_DIR}/src/Locale + ${PROJECT_SOURCE_DIR}/src/PrimitivesPlugin + ${QT_INCLUDES}) + +# additional preprocessor / compiler flags +ADD_DEFINITIONS(${QT_DEFINITIONS}) + SET(PROJECT_HEADERS @@ -60,6 +71,8 @@ SET(PROJECT_HEADERS FeaturesPlugin_Fillet.h FeaturesPlugin_Fillet1D.h FeaturesPlugin_Measurement.h + FeaturesPlugin_NormalToFace.h + FeaturesPlugin_CreateNormalToFace.h FeaturesPlugin_FusionFaces.h FeaturesPlugin_RemoveResults.h FeaturesPlugin_Chamfer.h @@ -112,6 +125,8 @@ SET(PROJECT_SOURCES FeaturesPlugin_Fillet.cpp FeaturesPlugin_Fillet1D.cpp FeaturesPlugin_Measurement.cpp + FeaturesPlugin_NormalToFace.cpp + FeaturesPlugin_CreateNormalToFace.cpp FeaturesPlugin_FusionFaces.cpp FeaturesPlugin_RemoveResults.cpp FeaturesPlugin_Chamfer.cpp @@ -155,6 +170,8 @@ SET(XML_RESOURCES fillet_widget.xml fillet1d_widget.xml measurement_widget.xml + normal_to_face_widget.xml + create_normal_to_face_widget.xml fusion_faces_widget.xml chamfer_widget.xml copy_widget.xml @@ -198,7 +215,11 @@ SET(PROJECT_LIBRARIES ) ADD_DEFINITIONS(-DFEATURESPLUGIN_EXPORTS) -ADD_LIBRARY(FeaturesPlugin MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${XML_RESOURCES} ${TEXT_RESOURCES}) +ADD_LIBRARY(FeaturesPlugin MODULE + ${PROJECT_SOURCES} + ${PROJECT_HEADERS} + ${XML_RESOURCES} + ${TEXT_RESOURCES}) TARGET_LINK_LIBRARIES(FeaturesPlugin ${PROJECT_LIBRARIES}) INSTALL(TARGETS FeaturesPlugin DESTINATION ${SHAPER_INSTALL_PLUGIN_FILES}) @@ -215,16 +236,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_CreateNormalToFace.cpp b/src/FeaturesPlugin/FeaturesPlugin_CreateNormalToFace.cpp new file mode 100644 index 000000000..f0b944b53 --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_CreateNormalToFace.cpp @@ -0,0 +1,114 @@ +// Copyright (C) 2014-2021 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_CreateNormalToFace.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +//================================================================================================= +FeaturesPlugin_CreateNormalToFace::FeaturesPlugin_CreateNormalToFace() +{ +} + +//================================================================================================= +void FeaturesPlugin_CreateNormalToFace::initAttributes() +{ + // attribute for object selected + data()->addAttribute(FACE_SELECTED_ID(), ModelAPI_AttributeSelection::typeId()); + data()->addAttribute(VERTEX_SELECTED_ID(), ModelAPI_AttributeSelection::typeId()); + // attributes for result message and values + data()->addAttribute(VERTEX_OPTION_ID(), ModelAPI_AttributeString::typeId()); + + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), VERTEX_SELECTED_ID()); + +} + +//================================================================================================= +void FeaturesPlugin_CreateNormalToFace::execute() +{ + + AttributeSelectionPtr aSelectionFace = selection(FACE_SELECTED_ID()); + AttributeSelectionPtr aSelectionPoint = selection(VERTEX_SELECTED_ID()); + + GeomShapePtr aShape; + GeomShapePtr aShapePoint; + if (!string(VERTEX_OPTION_ID())->value().empty()) { + if (aSelectionPoint && aSelectionPoint->isInitialized()) { + aShapePoint = aSelectionPoint->value(); + if (!aShapePoint && aSelectionPoint->context()) + aShapePoint = aSelectionPoint->context()->shape(); + } + } + + if (aSelectionFace && aSelectionFace->isInitialized()) { + aShape = aSelectionFace->value(); + if (!aShape && aSelectionFace->context()) + aShape = aSelectionFace->context()->shape(); + } + + if (aShape) { + std::string aError; + std::shared_ptr theNormal(new GeomAPI_Edge); + if (!GeomAlgoAPI_NormalToFace::normal(aShape, + aShapePoint, + theNormal, + aError)) + setError("Error in bounding box calculation :" + aError); + + GeomDirPtr theDir; + std::shared_ptr aPnt = theNormal->lastPoint(); + if (theNormal.get()) { + if (theNormal->isLine()) { + theDir = theNormal->line()->direction(); + } + } + aPnt->translate(theDir, 100); + + std::shared_ptr anEdge = + GeomAlgoAPI_EdgeBuilder::line(theNormal->firstPoint(), + aPnt); + + ResultConstructionPtr aConstr = document()->createConstruction(data()); + aConstr->setInfinite(true); + aConstr->setShape(anEdge); + setResult(aConstr); + } +} + +//================================================================================================= +void FeaturesPlugin_CreateNormalToFace::attributeChanged(const std::string& theID) +{ +} + + diff --git a/src/FeaturesPlugin/FeaturesPlugin_CreateNormalToFace.h b/src/FeaturesPlugin/FeaturesPlugin_CreateNormalToFace.h new file mode 100644 index 000000000..b3a356770 --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_CreateNormalToFace.h @@ -0,0 +1,84 @@ +// Copyright (C) 2014-2021 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_CreateNormalToFace_H_ +#define FeaturesPlugin_CreateNormalToFace_H_ + +#include "FeaturesPlugin.h" +#include + +#include +#include + +/// \class FeaturesPlugin_CreateNormalToFace +/// \ingroup Plugins +/// \brief Feature for construct normal to face + +class FeaturesPlugin_CreateNormalToFace : public ModelAPI_Feature +{ +public: + inline static const std::string& ID() + { + static const std::string MY_ID("Normal"); + return MY_ID; + } + + /// Attribute name for face selected. + inline static const std::string& FACE_SELECTED_ID() + { + static const std::string MY_FACE_ID("face"); + return MY_FACE_ID; + } + + /// Attribute name for vertex selected. + inline static const std::string& VERTEX_SELECTED_ID() + { + static const std::string MY_VERTEX_SELECTED_ID("vertex"); + return MY_VERTEX_SELECTED_ID; + } + + /// Attribute name of vertex option. + inline static const std::string& VERTEX_OPTION_ID() + { + static const std::string MY_VERTEX_OPTION_ID("vertex_option"); + return MY_VERTEX_OPTION_ID; + } + + /// \return the kind of a feature. + virtual const std::string& getKind() + { + return ID(); + } + + /// 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(); + + /// Called on change of any argument-attribute of this object + /// \param theID identifier of changed attribute + FEATURESPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID); + + /// Use plugin manager for features creation + FeaturesPlugin_CreateNormalToFace(); + +}; + +#endif diff --git a/src/FeaturesPlugin/FeaturesPlugin_NormalToFace.cpp b/src/FeaturesPlugin/FeaturesPlugin_NormalToFace.cpp new file mode 100644 index 000000000..853c26c1d --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_NormalToFace.cpp @@ -0,0 +1,165 @@ +// Copyright (C) 2014-2021 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_NormalToFace.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +//================================================================================================= +FeaturesPlugin_NormalToFace::FeaturesPlugin_NormalToFace() +{ +} + +//================================================================================================= +void FeaturesPlugin_NormalToFace::initAttributes() +{ + // attribute for object selected + data()->addAttribute(FACE_SELECTED_ID(), ModelAPI_AttributeSelection::typeId()); + data()->addAttribute(VERTEX_SELECTED_ID(), ModelAPI_AttributeSelection::typeId()); + // attributes for result message and values + data()->addAttribute(CREATENORMAL_ID(), ModelAPI_AttributeBoolean::typeId()); + data()->addAttribute(VERTEX_OPTION_ID(), ModelAPI_AttributeString::typeId()); + + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), VERTEX_SELECTED_ID()); + +} + +//================================================================================================= +void FeaturesPlugin_NormalToFace::execute() +{ + AttributeSelectionPtr aSelectionFace = selection(FACE_SELECTED_ID()); + AttributeSelectionPtr aSelectionPoint = selection(VERTEX_SELECTED_ID()); + + GeomShapePtr aShape; + GeomShapePtr aShapePoint; + if (!string(VERTEX_OPTION_ID())->value().empty()) { + if (aSelectionPoint && aSelectionPoint->isInitialized()) { + aShapePoint = aSelectionPoint->value(); + if (!aShapePoint && aSelectionPoint->context()) + aShapePoint = aSelectionPoint->context()->shape(); + } + } + + if (aSelectionFace && aSelectionFace->isInitialized()) { + aShape = aSelectionFace->value(); + if (!aShape && aSelectionFace->context()) + aShape = aSelectionFace->context()->shape(); + } + + if (aShape) { + std::string aError; + std::shared_ptr theNormal(new GeomAPI_Edge); + if (!GeomAlgoAPI_NormalToFace::normal(aShape, + aShapePoint, + theNormal, + aError)) + setError("Error in bounding box calculation :" + aError); + + GeomDirPtr theDir; + std::shared_ptr aPnt = theNormal->lastPoint(); + if (theNormal.get()) { + if (theNormal->isLine()) { + theDir = theNormal->line()->direction(); + } + } + aPnt->translate(theDir, 100); + + std::shared_ptr anEdge = + GeomAlgoAPI_EdgeBuilder::line(theNormal->firstPoint(), aPnt); + + ResultConstructionPtr aConstr = document()->createConstruction(data()); + aConstr->setInfinite(true); + aConstr->setShape(anEdge); + setResult(aConstr); + } + + if (boolean(CREATENORMAL_ID())->value()) { + if (!myCreateFeature.get()) + createNormal(); + updateNormal(); + } else { + if (myCreateFeature.get()) { + myCreateFeature->eraseResults(); + SessionPtr aSession = ModelAPI_Session::get(); + DocumentPtr aDoc = aSession->activeDocument(); + aDoc->removeFeature(myCreateFeature); + myCreateFeature.reset(); + } + } +} + +//================================================================================================= +void FeaturesPlugin_NormalToFace::attributeChanged(const std::string& theID) +{ + if (theID == FACE_SELECTED_ID()) { + if (myCreateFeature.get()) + updateNormal(); + } +} + +//================================================================================================= +void FeaturesPlugin_NormalToFace::createNormal() +{ + SessionPtr aSession = ModelAPI_Session::get(); + + DocumentPtr aDoc = aSession->activeDocument(); + + if (aDoc.get()) { + myCreateFeature = aDoc->addFeature(FeaturesPlugin_CreateNormalToFace::ID()); + } +} + +//================================================================================================= +void FeaturesPlugin_NormalToFace::updateNormal() +{ + myCreateFeature->selection(FeaturesPlugin_CreateNormalToFace::FACE_SELECTED_ID()) + ->setValue(selection(FACE_SELECTED_ID())->context() , + selection(FACE_SELECTED_ID())->value()); + + myCreateFeature->string(FeaturesPlugin_CreateNormalToFace::VERTEX_OPTION_ID()) + ->setValue(string(VERTEX_OPTION_ID())->value()); + + if (!string(VERTEX_OPTION_ID())->value().empty()) { + myCreateFeature->selection(FeaturesPlugin_CreateNormalToFace::VERTEX_SELECTED_ID()) + ->setValue(selection(VERTEX_SELECTED_ID())->context() , + selection(VERTEX_SELECTED_ID())->value()); + } + + myCreateFeature->execute(); +} diff --git a/src/FeaturesPlugin/FeaturesPlugin_NormalToFace.h b/src/FeaturesPlugin/FeaturesPlugin_NormalToFace.h new file mode 100644 index 000000000..ce6f72bb1 --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_NormalToFace.h @@ -0,0 +1,102 @@ +// Copyright (C) 2014-2021 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_NormalToFace_H_ +#define FeaturesPlugin_NormalToFace_H_ + +#include "FeaturesPlugin.h" +#include + +#include +#include + +/// \class FeaturesPlugin_NormalToFace +/// \ingroup Plugins +/// \brief Feature for construct normal to face + +class FeaturesPlugin_NormalToFace : public ModelAPI_Feature +{ +public: + inline static const std::string& ID() + { + static const std::string MY_ID("NormalMacro"); + return MY_ID; + } + + /// Attribute name for face selected. + inline static const std::string& FACE_SELECTED_ID() + { + static const std::string MY_FACE_SELECTED_ID("face"); + return MY_FACE_SELECTED_ID; + } + + /// Attribute name for vertex selected. + inline static const std::string& VERTEX_SELECTED_ID() + { + static const std::string MY_VERTEX_SELECTED_ID("vertex"); + return MY_VERTEX_SELECTED_ID; + } + + /// Attribute name for checkbox create box. + inline static const std::string& CREATENORMAL_ID() + { + static const std::string MY_CREATENORMAL_ID("createnormal"); + return MY_CREATENORMAL_ID; + } + + /// Attribute name of vertex option. + inline static const std::string& VERTEX_OPTION_ID() + { + static const std::string MY_VERTEX_OPTION_ID("vertex_option"); + return MY_VERTEX_OPTION_ID; + } + + /// \return the kind of a feature. + virtual const std::string& getKind() + { + return ID(); + } + + /// 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(); + + /// Called on change of any argument-attribute of this object + /// \param theID identifier of changed attribute + FEATURESPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID); + + /// Reimplemented from ModelAPI_Feature::isMacro(). Returns true. + FEATURESPLUGIN_EXPORT virtual bool isMacro() const { return true; } + + /// Use plugin manager for features creation + FeaturesPlugin_NormalToFace(); + + private: + /// Create normal in feature + void createNormal(); + /// Update normal in feature + void updateNormal(); + /// Feature to create normal + FeaturePtr myCreateFeature; + +}; + +#endif diff --git a/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp b/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp index 63d0241e3..b7c824d51 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include #include #include @@ -191,6 +193,10 @@ FeaturePtr FeaturesPlugin_Plugin::createFeature(std::string theFeatureID) return FeaturePtr(new FeaturesPlugin_Fillet1D); } else if (theFeatureID == FeaturesPlugin_Measurement::ID()) { return FeaturePtr(new FeaturesPlugin_Measurement); + } else if (theFeatureID == FeaturesPlugin_NormalToFace::ID()) { + return FeaturePtr(new FeaturesPlugin_NormalToFace); + } else if (theFeatureID == FeaturesPlugin_CreateNormalToFace::ID()) { + return FeaturePtr(new FeaturesPlugin_CreateNormalToFace); } else if (theFeatureID == FeaturesPlugin_RemoveResults::ID()) { return FeaturePtr(new FeaturesPlugin_RemoveResults); } else if (theFeatureID == FeaturesPlugin_Chamfer::ID()) { diff --git a/src/FeaturesPlugin/Test/TestNormalToFace.py b/src/FeaturesPlugin/Test/TestNormalToFace.py new file mode 100644 index 000000000..ad70044d9 --- /dev/null +++ b/src/FeaturesPlugin/Test/TestNormalToFace.py @@ -0,0 +1,66 @@ +# Copyright (C) 2014-2021 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 +# + +""" + Unit test of ... +""" +#========================================================================= +# Initialization of the test +#========================================================================= + + +import os +import math + +from ModelAPI import * +from salome.shaper import model + + +__updated__ = "2020-11-12" + + +#========================================================================= +# test creating normal to face +#========================================================================= +def test_Normal_to_face(): + + model.begin() + file_path = os.path.join(os.getenv("DATA_DIR"),"Shapes","Brep","box1.brep") + partSet = model.moduleDocument() + Part_1 = model.addPart(partSet) + Part_1_doc = Part_1.document() + Import_1 = model.addImport(Part_1_doc,file_path) + model.do() + ### Create Normal + Normal_1 = model.getNormal(Part_1_doc, model.selection("FACE", "box1_1/Shape_6")) + model.end() + + assert (len(Normal_1.results()) > 0) + assert(Normal_1.feature().error() == "") + anAxisResult = modelAPI_ResultConstruction(Normal_1.feature().firstResult()) + assert (anAxisResult is not None) + + +if __name__ == '__main__': + + test_Normal_to_face() + + #========================================================================= + # End of test + #========================================================================= diff --git a/src/FeaturesPlugin/create_normal_to_face_widget.xml b/src/FeaturesPlugin/create_normal_to_face_widget.xml new file mode 100644 index 000000000..82ee3be95 --- /dev/null +++ b/src/FeaturesPlugin/create_normal_to_face_widget.xml @@ -0,0 +1,20 @@ + + + + + + + + + + diff --git a/src/FeaturesPlugin/doc/FeaturesPlugin.rst b/src/FeaturesPlugin/doc/FeaturesPlugin.rst index 34e8fea42..6fc8177bd 100644 --- a/src/FeaturesPlugin/doc/FeaturesPlugin.rst +++ b/src/FeaturesPlugin/doc/FeaturesPlugin.rst @@ -26,6 +26,7 @@ Features plug-in provides a set of common topological operations. It implements importResultFeature.rst linearCopyFeature.rst measurementFeature.rst + normalToFaceFeature.rst pipeFeature.rst placementFeature.rst pointCoordinatesFeature.rst diff --git a/src/FeaturesPlugin/doc/TUI_normalToFaceFeature.rst b/src/FeaturesPlugin/doc/TUI_normalToFaceFeature.rst new file mode 100644 index 000000000..2ae1c6dc3 --- /dev/null +++ b/src/FeaturesPlugin/doc/TUI_normalToFaceFeature.rst @@ -0,0 +1,22 @@ + + .. _tui_create_normal_to_face: + +Create normal to a face +======================= + +.. literalinclude:: examples/createNormalToFace.py + :linenos: + :language: python + +:download:`Download this script ` + + .. _tui_create_normal_to_face_at_vertex: + +Create normal to a face at vertex +================================= + +.. literalinclude:: examples/createNormalToFaceAtVertex.py + :linenos: + :language: python + +:download:`Download this script ` \ No newline at end of file diff --git a/src/FeaturesPlugin/doc/examples/createNormalToFace.py b/src/FeaturesPlugin/doc/examples/createNormalToFace.py new file mode 100644 index 000000000..a1f973011 --- /dev/null +++ b/src/FeaturesPlugin/doc/examples/createNormalToFace.py @@ -0,0 +1,15 @@ +from salome.shaper import model +import os + +model.begin() +file_path = os.path.join(os.getenv("DATA_DIR"),"Shapes","Brep","box1.brep") +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +Import_1 = model.addImport(Part_1_doc,file_path) +model.do() + +### Create BoundingBox +Normal_1 = model.getNormal(Part_1_doc, model.selection("FACE", "box1_1/Shape_6")) +model.do() +model.end() diff --git a/src/FeaturesPlugin/doc/examples/createNormalToFaceAtVertex.py b/src/FeaturesPlugin/doc/examples/createNormalToFaceAtVertex.py new file mode 100644 index 000000000..c59aa67c5 --- /dev/null +++ b/src/FeaturesPlugin/doc/examples/createNormalToFaceAtVertex.py @@ -0,0 +1,17 @@ + +from salome.shaper import model +import os + +model.begin() +file_path = os.path.join(os.getenv("DATA_DIR"),"Shapes","Brep","box1.brep") +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +Import_1 = model.addImport(Part_1_doc,file_path) +model.do() + +### Create BoundingBox +Normal_1 = model.getNormal(Part_1_doc, model.selection("FACE", "box1_1/Shape_6"), + model.selection("VERTEX", "[box1_1/Shape_2][box1_1/Shape_4][box1_1/Shape_6]")) +model.do() +model.end() diff --git a/src/FeaturesPlugin/doc/images/normal.png b/src/FeaturesPlugin/doc/images/normal.png new file mode 100644 index 0000000000000000000000000000000000000000..16080764e8d275a433c96cfb3c849a9d1bd931e0 GIT binary patch literal 655 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 literal 0 HcmV?d00001 diff --git a/src/FeaturesPlugin/doc/images/normalToFaceResult.png b/src/FeaturesPlugin/doc/images/normalToFaceResult.png new file mode 100644 index 0000000000000000000000000000000000000000..ecfb260ab9a0efbf3924a3c16b59c7754bea6b1d GIT binary patch literal 2777 zcmZWr2~<g#_%G4c_W!rmTkpPm?>_sSbJsa{bEzKA zYDirq003&PE|hNoKnV)ICU6)yQ#(VL20zO24z50M@JWV;alrr03`akPcT5E13_UI! zI2IjqD%>nSG%h?mI{tVJV;M8h1Pgz!RWl;Fya6+UR<^z-cC2 z`yPUN5I{Qwz`sFI%7~i**JLk*sXI)uRfR*=%u{N6 zni|)&Y}~aQL?#xI^XsSWN;v&qhoR3qKN)?m&)MOxny?$RA_7cBfC~;r9@SFJ zEjSuy`>Xoi`C7rw`Coj_ChG_@pUyA0cClrGB66q^{}~aF$Q6m z#?ve}dh>6ltIu&okUU}fj1A=G6|Y1YS%W}E5ysvQNbPha z-N~tUQI|~5=R-x88gEM@NA?VD+v;lYed}Za%ISnD+OH?*=|(S%J_%D;?nLvoM6!wM zAw=BaBwGbG><|W#v&nhn*L^PwU>*yDy`!F+hBU0ndc2!PIf5JE+P^+sB5T9i_R`C4 z@ptphgbn?r(^LCY*hFjyk?36v3ko}67qHe;(Pc-%aEfqUJ=Zify(aT8i#5IQ8qJI~ zeeL3l6+03)?j*%$zTR1x0{ZzDEVmFofrfi`_drjYrD1!p>nK zQt<^gb|xD$QxMOZ{W(EmR!Sbcbh46l&2PvinScxo-6h$DmgKx!Y6gE^W*rKQo86C| zJZOn5O$jHJW_Hk2Z#7Ggl*ND<-PK;f+f1@j5es-bs+7GX9H>a`hz`p>@ItGhBi)RU zw!0zPji@^-V|;9e+WVzpYC851gXBl?Q7c2t6}oW*dl*&e6m5^OXJgxL1#7dmC7C0G z8(95grLEd)k+4x1}q0Ill!I`s{h!Ky*;#RivOHV{$@F#+6GqpVYU4-)q1|g6Knq5raN+I zx$!%hD2&(ITdrQQZX4`llTrJSaY}myIj5B;RF&AcXDz>J6VcQvh|w?Vm#oOPP$}Z& z?M`@iY-s^%?}#n^y|QdZL_2s-{o(jW$<-=^6pwt!Tj*J1!m@{nL#YjX(i8X^t66S2icF=Pi(-jW3G0!uIp8Z0V@Jc9IIm z$YOjUy*#MztRg(8sN;c|R@4%Y>h-9z8(%s~wL$!zq@Pa5d#% zbbFQL4SMUJyWaTE zdaEtFX5+=IxnxR6+gSHWJim4BTIXZpU>mi|pY{O4>-#U9GmeGtl2GNn zbH~@a_hkbo7N_e!kX5@Q@*U~LSHyzr879hs6Ts<5b2XIFj^UE=#u)zmLax(~7s#@t zfck-B#XOTU24-)6$>F=_Hm$6D#pYG^zXwVC_?+b}{J`hmsm+Jlx5RB08$h%s%?ZSA2) z>t8`9jvUUu!0n)kqWAm#=YdVlwsQH2(R@U-@dj^)--ESFieVUi6^_>FJ5{E4(Z|DoVgIkh5yjNR;O<+GX{Cqp%IG5b49z7VG*w+zr zNSjg?M1baU0Cf!(C>XHZb*+t`wNnO^g5`DqrnaDL`7D;?o4$w$=PdFlfOZKfR!FE% z%EC2n@{AEw4*OJ}@&YR*Dx#d7({}&|=%=G{O literal 0 HcmV?d00001 diff --git a/src/FeaturesPlugin/doc/images/normalToFaceResultwithVertex.png b/src/FeaturesPlugin/doc/images/normalToFaceResultwithVertex.png new file mode 100644 index 0000000000000000000000000000000000000000..98f1aa8ed9875d7a6cc11a010fc5ebe019a46b56 GIT binary patch literal 2685 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 literal 0 HcmV?d00001 diff --git a/src/FeaturesPlugin/doc/normalToFaceFeature.rst b/src/FeaturesPlugin/doc/normalToFaceFeature.rst new file mode 100644 index 000000000..cf498b72d --- /dev/null +++ b/src/FeaturesPlugin/doc/normalToFaceFeature.rst @@ -0,0 +1,71 @@ +.. |normalToFace.icon| image:: images/normal.png + +Normal to a face +================ + +The **Normal to a face** feature displays the normal to a face. A vertex can be specified to indicate the position of the normal else the center of face is used. + +the resulting normal can be created via a dedicated check-box **Create normal**. If this last is checked corresponding result and feature would be created. + +If the check-box **Create normal** isn't checked, **Apply** button does not generate any result and has the same effect as **Cancel** for this feature. + +To display the normal to a face in the active part: + +#. select in the Main Menu *Inspection - > Normal to a face* item or +#. click |normalToFace.icon| **Normal to a face** button in the toolbar + +The property panel is shown below. + +.. figure:: images/normalToFacePropertyPanel.png + :align: center + + Normal to a face + + +Input fields: + +- **Face** contains face selected in 3D OCC viewer or object browser. +- **Vertex** contains optionnal vertex selected in 3D OCC viewer or object browser. +- **Create normal** check-box allow the creation of the normal (result and feature). + +**TUI Command**: + +.. py:function:: model.getNormal(Part, face) + + :param part: The current part object. + :param object: A face in format *model.selection("FACE", face)*. + :return: Created normal to a face at center. + +Result +"""""" + +Result of **Normal to a face**. + +.. figure:: images/normalToFaceResult.png + :align: center + + Normal to a face + +**See Also** a sample TUI Script of :ref:`tui_create_normal_to_face` operation. + + +**TUI Command**: + +.. py:function:: model.getNormal(Part, face, vertex) + + :param part: The current part object. + :param object: A face in format *model.selection("FACE", face)*. + :param object: A vertex in format *model.selection("VERTEX", vertex)*. + :return: Created normal to a face at vertex. + +Result +"""""" + +Result of **Normal to aface** where **Vertex** is selecteted. + +.. figure:: images/normalToFaceResultwithVertex.png + :align: center + + Normal to a face at vertex + +**See Also** a sample TUI Script of :ref:`tui_create_normal_to_face_at_vertex` operation. \ No newline at end of file diff --git a/src/FeaturesPlugin/icons/normale.png b/src/FeaturesPlugin/icons/normale.png new file mode 100644 index 0000000000000000000000000000000000000000..16080764e8d275a433c96cfb3c849a9d1bd931e0 GIT binary patch literal 655 zcmV;A0&x9_P)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ;1xZ9fRCwBA{Qv(y12q9a05LI882|(jQ3hU9S0~yV z00G3r$jHb*2!jAI>OdGEfT-?efB+(B;8iuX|41|kA@u+OM5+q~2q^#vAVy+bhYYlD z-NLH}Ab^NL98iM;f!KhMw*dl(7%y`mc~_8-fdB!-LclO&FV7=nvzV9|13&=bGw}b! z4ObYx|N6tgP!q;bGUp`2-@pGD{`~vT@ay+KhHpQAGra%ui{bO<&kVo5ePp<`x{Tq~ zt5=Eu0ffuI|C2XeW%&Bz4;X{M=Wo9me*XRow%`+x{q5@)hM%9`GW`7dp5gws4u%gO zJ|qE^SpozQwix^0v-T3$pwHiaF(h`!!6kBo`Wb$I2fFCXJBFWM-ZK0G8us|$Y>+FP zfzm&K_&z`Yp&R(WYQbrS&)X&M03jRrKW)-shL2x=F}wvD^yABWpbI`Q`~e#B=jS(uzrVf# z* + + + + + + + + + + diff --git a/src/FeaturesPlugin/plugin-Features.xml b/src/FeaturesPlugin/plugin-Features.xml index 7fb18f31f..9092142dc 100644 --- a/src/FeaturesPlugin/plugin-Features.xml +++ b/src/FeaturesPlugin/plugin-Features.xml @@ -126,7 +126,7 @@ + icon="icons/Features/fillet.png" auto_preview="false" helpfile="filletFeature.html"> + icon="icons/Features/fusion_faces.png" auto_preview="true" helpfile="FeaturesPlugin/fusionFacesFeature.html"> + + + + + + + + diff --git a/src/FeaturesPlugin/tests.set b/src/FeaturesPlugin/tests.set index 404476a40..75e619ded 100644 --- a/src/FeaturesPlugin/tests.set +++ b/src/FeaturesPlugin/tests.set @@ -177,7 +177,7 @@ SET(TEST_NAMES TestMeasurementAngle3Points.py TestMeasurementPresentation.py TestFusionFaces.py - TestFusionFaces2697.py + TestFusionFaces2697.py Test1379.py Test1922.py Test1942.py @@ -521,4 +521,5 @@ SET(TEST_NAMES TestGeometryCalculation.py TestBoundingBox.py Test23885.py + TestNormalToFace.py ) diff --git a/src/GeomAlgoAPI/CMakeLists.txt b/src/GeomAlgoAPI/CMakeLists.txt index 0c549a45b..4a04f03f8 100644 --- a/src/GeomAlgoAPI/CMakeLists.txt +++ b/src/GeomAlgoAPI/CMakeLists.txt @@ -33,6 +33,7 @@ SET(PROJECT_HEADERS GeomAlgoAPI_Prism.h GeomAlgoAPI_Revolution.h GeomAlgoAPI_Boolean.h + GeomAlgoAPI_NormalToFace.h GeomAlgoAPI_ThroughAll.h GeomAlgoAPI_Rotation.h GeomAlgoAPI_Translation.h @@ -103,6 +104,7 @@ SET(PROJECT_SOURCES GeomAlgoAPI_Prism.cpp GeomAlgoAPI_Revolution.cpp GeomAlgoAPI_Boolean.cpp + GeomAlgoAPI_NormalToFace.cpp GeomAlgoAPI_ThroughAll.cpp GeomAlgoAPI_Rotation.cpp GeomAlgoAPI_Translation.cpp diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_NormalToFace.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_NormalToFace.cpp new file mode 100644 index 000000000..bd65e01df --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_NormalToFace.cpp @@ -0,0 +1,235 @@ +// Copyright (C) 2014-2021 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 "GeomAlgoAPI_NormalToFace.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + /*! + * \brief Return type of shape for explode. In case of compound it will be a type of its first sub shape. + * \param theShape The shape to get type of. + * \retval TopAbs_ShapeEnum Return type of shape for explode. + */ +TopAbs_ShapeEnum GetTypeOfSimplePart(const TopoDS_Shape& theShape) +{ + TopAbs_ShapeEnum aType = theShape.ShapeType(); + if (aType == TopAbs_VERTEX) return TopAbs_VERTEX; + else if (aType == TopAbs_EDGE || aType == TopAbs_WIRE) return TopAbs_EDGE; + else if (aType == TopAbs_FACE || aType == TopAbs_SHELL) return TopAbs_FACE; + else if (aType == TopAbs_SOLID || aType == TopAbs_COMPSOLID) return TopAbs_SOLID; + else if (aType == TopAbs_COMPOUND) { + // Only the iType of the first shape in the compound is taken into account + TopoDS_Iterator It (theShape, Standard_False, Standard_False); + if (It.More()) { + return GetTypeOfSimplePart(It.Value()); + } + } + return TopAbs_SHAPE; +} + + /*! + * \brief Get Local Coordinate System, corresponding to the given shape. + * + * Origin of the LCS is situated at the shape's center of mass. + * Axes of the LCS are obtained from shape's location or, + * if the shape is a planar face, from position of its plane. + */ +gp_Ax3 GetPosition(const TopoDS_Shape& theShape) +{ + gp_Ax3 aResult; + + if (theShape.IsNull()) + return aResult; + + // Axes + aResult.Transform(theShape.Location().Transformation()); + if (theShape.ShapeType() == TopAbs_FACE) { + Handle(Geom_Surface) aGS = BRep_Tool::Surface(TopoDS::Face(theShape)); + if (!aGS.IsNull() && aGS->IsKind(STANDARD_TYPE(Geom_Plane))) { + Handle(Geom_Plane) aGPlane = Handle(Geom_Plane)::DownCast(aGS); + gp_Pln aPln = aGPlane->Pln(); + aResult = aPln.Position(); + // In case of reverse orinetation of the face invert the plane normal + // (the face's normal does not mathc the plane's normal in this case) + if (theShape.Orientation() == TopAbs_REVERSED) { + gp_Dir Vx = aResult.XDirection(); + gp_Dir N = aResult.Direction().Mirrored(Vx); + gp_Pnt P = aResult.Location(); + aResult = gp_Ax3(P, N, Vx); + } + } + } + + // Origin + gp_Pnt aPnt; + + TopAbs_ShapeEnum aShType = theShape.ShapeType(); + + if (aShType == TopAbs_VERTEX) { + aPnt = BRep_Tool::Pnt(TopoDS::Vertex(theShape)); + } else { + if (aShType == TopAbs_COMPOUND) { + aShType = GetTypeOfSimplePart(theShape); + } + + GProp_GProps aSystem; + if (aShType == TopAbs_EDGE || aShType == TopAbs_WIRE) + BRepGProp::LinearProperties(theShape, aSystem); + else if (aShType == TopAbs_FACE || aShType == TopAbs_SHELL) + BRepGProp::SurfaceProperties(theShape, aSystem); + else + BRepGProp::VolumeProperties(theShape, aSystem); + + aPnt = aSystem.CentreOfMass(); + } + + aResult.SetLocation(aPnt); + + return aResult; +} + +//================================================================================================= +static bool GeomAlgoAPI_NormalToFace::normal(GeomShapePtr theFace, + GeomShapePtr theOptionnelPoint, + GeomEdgePtr theNormal, + std::string& theError){ + + #ifdef _DEBUG + std::cout << "GeomAlgoAPI_NormalToFace::normal" << std::endl; + #endif + + if (!theFace.get()) { + theError = "Face for normale calculation is null"; + return false; + } + + TopoDS_Shape aShape = theFace->impl(); + + if (aShape.ShapeType() != TopAbs_FACE) { + theError = "Shape for normale calculation is not a face"; + return false; + } + + TopoDS_Face aFace = TopoDS::Face(aShape); + + // Point + gp_Pnt p1 (0,0,0); + + if (theOptionnelPoint.get()) { + TopoDS_Shape anOptPnt = theOptionnelPoint->impl(); + if (anOptPnt.IsNull()) { + theError = "Invalid shape given for point argument"; + return false; + } + p1 = BRep_Tool::Pnt(TopoDS::Vertex(anOptPnt)); + } else { + gp_Ax3 aPos = GetPosition(aFace); + p1 = aPos.Location(); + } + + // Point parameters on surface + Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace); + Handle(ShapeAnalysis_Surface) aSurfAna = new ShapeAnalysis_Surface (aSurf); + gp_Pnt2d pUV = aSurfAna->ValueOfUV(p1, Precision::Confusion()); + + // Normal direction + gp_Vec Vec1,Vec2; + BRepAdaptor_Surface SF (aFace); + SF.D1(pUV.X(), pUV.Y(), p1, Vec1, Vec2); + if (Vec1.Magnitude() < Precision::Confusion()) { + gp_Vec tmpV; + gp_Pnt tmpP; + SF.D1(pUV.X(), pUV.Y()-0.1, tmpP, Vec1, tmpV); + } + else if (Vec2.Magnitude() < Precision::Confusion()) { + gp_Vec tmpV; + gp_Pnt tmpP; + SF.D1(pUV.X()-0.1, pUV.Y(), tmpP, tmpV, Vec2); + } + + gp_Vec V = Vec1.Crossed(Vec2); + Standard_Real mod = V.Magnitude(); + if (mod < Precision::Confusion()) + Standard_NullObject::Raise("Normal vector of a face has null magnitude"); + + // Set length of normal vector to average radius of curvature + Standard_Real radius = 0.0; + GeomLProp_SLProps aProperties (aSurf, pUV.X(), pUV.Y(), 2, Precision::Confusion()); + if (aProperties.IsCurvatureDefined()) { + Standard_Real radius1 = Abs(aProperties.MinCurvature()); + Standard_Real radius2 = Abs(aProperties.MaxCurvature()); + if (Abs(radius1) > Precision::Confusion()) { + radius = 1.0 / radius1; + if (Abs(radius2) > Precision::Confusion()) { + radius = (radius + 1.0 / radius2) / 2.0; + } + } else { + if (Abs(radius2) > Precision::Confusion()) { + radius = 1.0 / radius2; + } + } + } + + // Set length of normal vector to average dimension of the face + // (only if average radius of curvature is not appropriate) + if (radius < Precision::Confusion()) { + Bnd_Box B; + Standard_Real Xmin, Xmax, Ymin, Ymax, Zmin, Zmax; + BRepBndLib::Add(aFace, B); + B.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax); + radius = ((Xmax - Xmin) + (Ymax - Ymin) + (Zmax - Zmin)) / 3.0; + } + + if (radius < Precision::Confusion()) + radius = 1.0; + + V *= radius / mod; + + // consider the face orientation + if (aFace.Orientation() == TopAbs_REVERSED || + aFace.Orientation() == TopAbs_INTERNAL) { + V = - V; + } + + // Edge + gp_Pnt p2 = p1.Translated(V); + BRepBuilderAPI_MakeEdge aBuilder (p1, p2); + if (!aBuilder.IsDone()) + Standard_NullObject::Raise("Vector construction failed"); + aShape = aBuilder.Shape(); + + theNormal->setImpl(new TopoDS_Shape(aShape)); + + return true; +} + diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_NormalToFace.h b/src/GeomAlgoAPI/GeomAlgoAPI_NormalToFace.h new file mode 100644 index 000000000..6c54e4488 --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_NormalToFace.h @@ -0,0 +1,46 @@ +// Copyright (C) 2014-2021 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_NormalToFace_H_ +#define GeomAlgoAPI_NormalToFace_H_ + +#include +#include +#include + +/**\class GeomAlgoAPI_NormalToFace + * \ingroup DataAlgo + * \brief Allows to create normal to face-shapes + */ + +class GEOMALGOAPI_EXPORT GeomAlgoAPI_NormalToFace +{ + public: + /// get the normal to face-shapes + /// \param theface the face + /// \param theOptionnelPoint the optionnel point + /// \param theNormal the normal + /// \param theError the error + static bool GeomAlgoAPI_NormalToFace::normal(GeomShapePtr theFace, + GeomShapePtr theOptionnelPoint, + GeomEdgePtr theNormal, + std::string& theError); +}; + +#endif diff --git a/src/ModelAPI/CMakeLists.txt b/src/ModelAPI/CMakeLists.txt index c6a298461..e495fe850 100644 --- a/src/ModelAPI/CMakeLists.txt +++ b/src/ModelAPI/CMakeLists.txt @@ -117,7 +117,7 @@ SET(PROJECT_SOURCES SET(PROJECT_LIBRARIES Config GeomAPI - Locale + ${OpenCASCADE_ApplicationFramework_LIBRARIES} ) SET(CMAKE_SWIG_FLAGS -threads -w325,321,362,383,302,403,451,473) ADD_DEFINITIONS(-DMODELAPI_EXPORTS) @@ -131,6 +131,10 @@ INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/Config ${PROJECT_SOURCE_DIR}/src/GeomAPI ${PROJECT_SOURCE_DIR}/src/GeomAlgoAPI ${PROJECT_SOURCE_DIR}/src/Locale + ${OpenCASCADE_INCLUDE_DIR} + ${OpenCASCADE_DataExchange_LIBRARIES} + ${OpenCASCADE_ModelingAlgorithms_LIBRARIES} + ${OpenCASCADE_ApplicationFramework_LIBRARIES} ) @@ -172,16 +176,16 @@ ADD_UNIT_TESTS(${TEST_NAMES}) if(${HAVE_SALOME}) enable_testing() set(TEST_INSTALL_DIRECTORY "${SALOME_SHAPER_INSTALL_TESTS}/ModelAPI") - + 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/PythonAPI/model/features/__init__.py b/src/PythonAPI/model/features/__init__.py index 5ce684790..62a0ca1a8 100644 --- a/src/PythonAPI/model/features/__init__.py +++ b/src/PythonAPI/model/features/__init__.py @@ -31,6 +31,7 @@ from FeaturesAPI import addFillet, addChamfer from FeaturesAPI import addFusionFaces from FeaturesAPI import measureLength, measureDistance, measureRadius, measureAngle from FeaturesAPI import getPointCoordinates, getGeometryCalculation, getBoundingBox +from FeaturesAPI import getNormal from FeaturesAPI import addRemoveResults from FeaturesAPI import addCopy, addImportResult from FeaturesAPI import addDefeaturing -- 2.39.2