From: Jérôme Date: Wed, 21 Oct 2020 16:46:17 +0000 (+0200) Subject: Implementation of bounding box X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=43b500d35faa33754229b132a3e9f5429b4407b7;p=modules%2Fshaper.git Implementation of bounding box --- diff --git a/src/Config/Config_Keywords.h b/src/Config/Config_Keywords.h index 5be23a997..28783fd69 100644 --- a/src/Config/Config_Keywords.h +++ b/src/Config/Config_Keywords.h @@ -100,6 +100,7 @@ MAYBE_UNUSED const static char* ATTR_TOOLTIP = FEATURE_TOOLTIP; MAYBE_UNUSED const static char* ATTR_ICON = FEATURE_ICON; MAYBE_UNUSED const static char* ATTR_LABEL = "label"; MAYBE_UNUSED const static char* ATTR_STYLE_SHEET = "styleSheet"; +MAYBE_UNUSED const static char* ATTR_IS_SELECTABLE = "isSelectable"; MAYBE_UNUSED const static char* ATTR_HTML_STYLE = "isHTML"; MAYBE_UNUSED const static char* ATTR_DEFAULT = "default"; MAYBE_UNUSED const static char* ATTR_INTERNAL = "internal"; diff --git a/src/FeaturesAPI/CMakeLists.txt b/src/FeaturesAPI/CMakeLists.txt index 0b8e3055c..8294dd39e 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_BoundingBox.h FeaturesAPI_MultiRotation.h FeaturesAPI_MultiTranslation.h FeaturesAPI_Partition.h @@ -65,6 +66,7 @@ SET(PROJECT_SOURCES FeaturesAPI_Fillet.cpp FeaturesAPI_Intersection.cpp FeaturesAPI_Measurement.cpp + FeaturesAPI_BoundingBox.cpp FeaturesAPI_MultiRotation.cpp FeaturesAPI_MultiTranslation.cpp FeaturesAPI_Partition.cpp diff --git a/src/FeaturesAPI/FeaturesAPI.i b/src/FeaturesAPI/FeaturesAPI.i index b76fd2dc4..b4f0fbe87 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_BoundingBox) %shared_ptr(FeaturesAPI_Extrusion) %shared_ptr(FeaturesAPI_ExtrusionBoolean) %shared_ptr(FeaturesAPI_ExtrusionCut) @@ -211,6 +212,7 @@ %include "FeaturesAPI_Fillet.h" %include "FeaturesAPI_Intersection.h" %include "FeaturesAPI_Measurement.h" +%include "FeaturesAPI_BoundingBox.h" %include "FeaturesAPI_MultiRotation.h" %include "FeaturesAPI_MultiTranslation.h" %include "FeaturesAPI_Partition.h" diff --git a/src/FeaturesAPI/FeaturesAPI_BoundingBox.cpp b/src/FeaturesAPI/FeaturesAPI_BoundingBox.cpp new file mode 100644 index 000000000..cefac8ea0 --- /dev/null +++ b/src/FeaturesAPI/FeaturesAPI_BoundingBox.cpp @@ -0,0 +1,85 @@ +// Copyright (C) 2018-2020 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_BoundingBox.h" + +#include +#include +#include +#include + +#include +#include +#include + + +FeaturesAPI_BoundingBox:: + FeaturesAPI_BoundingBox(const std::shared_ptr& theFeature) + : ModelHighAPI_Interface(theFeature) +{ + initialize(); +} + +FeaturesAPI_BoundingBox::FeaturesAPI_BoundingBox( + const std::shared_ptr& theFeature, + const ModelHighAPI_Selection& theobject) +:ModelHighAPI_Interface(theFeature) +{ + if (initialize()) { + fillAttribute(theobject, myobjectselected); + execute(); + } +} + + +FeaturesAPI_BoundingBox::~FeaturesAPI_BoundingBox() +{ +} + +void FeaturesAPI_BoundingBox::dump(ModelHighAPI_Dumper& theDumper) const +{ + FeaturePtr aBase = feature(); + const std::string& aDocName = theDumper.name(aBase->document()); + + AttributeSelectionPtr anAttrObject; + anAttrObject = aBase->selection(FeaturesPlugin_BoundingBox::OBJECTS_LIST_ID()); + + theDumper << aBase << " = model.getBoundingBox(" << aDocName << ", " << anAttrObject; + + //if (!aBase->data()->version().empty()) + // theDumper << ", keepSubResults = True"; + + theDumper << ")" << std::endl; +} + +BoundingBoxPtr getBoundingBox(const std::shared_ptr& thePart, + const ModelHighAPI_Selection& theobject) +{ + FeaturePtr aBoundingBoxFeat = thePart->addFeature(FeaturesPlugin_BoundingBox::ID()); + + FeaturePtr aFeature = + thePart->addFeature(FeaturesAPI_BoundingBox::ID()); + + BoundingBoxPtr aBoundingBox; + + aBoundingBox.reset(new FeaturesAPI_BoundingBox(aFeature, theobject)); + + return aBoundingBox; +} + diff --git a/src/FeaturesAPI/FeaturesAPI_BoundingBox.h b/src/FeaturesAPI/FeaturesAPI_BoundingBox.h new file mode 100644 index 000000000..738c8f8ce --- /dev/null +++ b/src/FeaturesAPI/FeaturesAPI_BoundingBox.h @@ -0,0 +1,75 @@ +// Copyright (C) 2018-2020 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_BoundingBox_H_ +#define FeaturesAPI_BoundingBox_H_ + +#include "FeaturesAPI.h" + +#include "FeaturesPlugin_BoundingBox.h" + +#include +#include + +#include + +class ModelAPI_Document; +class ModelHighAPI_Selection; + +/// \class FeaturesAPI_NormalToFace +/// \ingroup CPPHighAPI +/// \brief Interface for NormalToface feature. +class FeaturesAPI_BoundingBox: public ModelHighAPI_Interface +{ +public: + /// Constructor without values. + FEATURESAPI_EXPORT + explicit FeaturesAPI_BoundingBox(const std::shared_ptr& theFeature); + + FEATURESAPI_EXPORT + explicit FeaturesAPI_BoundingBox(const std::shared_ptr& theFeature, + const ModelHighAPI_Selection& theobject); + + /// Destructor. + FEATURESAPI_EXPORT + virtual ~FeaturesAPI_BoundingBox(); + + INTERFACE_1(FeaturesPlugin_BoundingBox::ID(), + objectselected, FeaturesPlugin_BoundingBox::OBJECTS_LIST_ID(), + ModelAPI_AttributeSelection, + /** object selected*/) + + /// Dump wrapped feature + FEATURESAPI_EXPORT + virtual void dump(ModelHighAPI_Dumper& theDumper) const; + +}; + +/// Pointer on the NormalToface object. +typedef std::shared_ptr BoundingBoxPtr; + +/// \ingroup CPPHighAPI +/// \brief get the bounding Box +/// \param thePart the part +/// \param theobject the object selected +FEATURESAPI_EXPORT +BoundingBoxPtr getBoundingBox(const std::shared_ptr& thePart, + const ModelHighAPI_Selection& theobject); + +#endif // FeaturesAPI_BoundingBox_H_ diff --git a/src/FeaturesAPI/FeaturesAPI_swig.h b/src/FeaturesAPI/FeaturesAPI_swig.h index 17ada7187..232234267 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_BoundingBox.h" #include "FeaturesAPI_MultiRotation.h" #include "FeaturesAPI_MultiTranslation.h" #include "FeaturesAPI_Partition.h" diff --git a/src/FeaturesPlugin/BoundingBox_widget.xml b/src/FeaturesPlugin/BoundingBox_widget.xml new file mode 100644 index 000000000..0dc8a0d12 --- /dev/null +++ b/src/FeaturesPlugin/BoundingBox_widget.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/src/FeaturesPlugin/CMakeLists.txt b/src/FeaturesPlugin/CMakeLists.txt index c93c66a17..f4a79922b 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 FeaturesPlugin.h @@ -59,6 +70,7 @@ SET(PROJECT_HEADERS FeaturesPlugin_Fillet.h FeaturesPlugin_Fillet1D.h FeaturesPlugin_Measurement.h + FeaturesPlugin_BoundingBox.h FeaturesPlugin_FusionFaces.h FeaturesPlugin_RemoveResults.h FeaturesPlugin_Chamfer.h @@ -106,6 +118,7 @@ SET(PROJECT_SOURCES FeaturesPlugin_Fillet.cpp FeaturesPlugin_Fillet1D.cpp FeaturesPlugin_Measurement.cpp + FeaturesPlugin_BoundingBox.cpp FeaturesPlugin_FusionFaces.cpp FeaturesPlugin_RemoveResults.cpp FeaturesPlugin_Chamfer.cpp @@ -144,6 +157,7 @@ SET(XML_RESOURCES fillet_widget.xml fillet1d_widget.xml measurement_widget.xml + BoundingBox_widget.xml fusion_faces_widget.xml chamfer_widget.xml copy_widget.xml @@ -166,6 +180,7 @@ INCLUDE_DIRECTORIES( ../GeomAPI ../GeomAlgoAPI ../GeomValidators + ../ModuleBase ../Events ../Config ${OpenCASCADE_INCLUDE_DIR} @@ -182,7 +197,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}) @@ -682,6 +701,4 @@ ADD_UNIT_TESTS(TestExtrusion.py TestFillet1D_Wire_3.py TestFillet1D_Wire_4.py TestFillet1D_Wire_5.py - Test19931.py - Test20027.py ) diff --git a/src/FeaturesPlugin/FeaturesPlugin_BoundingBox.cpp b/src/FeaturesPlugin/FeaturesPlugin_BoundingBox.cpp new file mode 100644 index 000000000..f6d530c6a --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_BoundingBox.cpp @@ -0,0 +1,210 @@ +// Copyright (C) 2018-2020 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_BoundingBox.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +FeaturesPlugin_BoundingBox::FeaturesPlugin_BoundingBox() +{ +} + +void FeaturesPlugin_BoundingBox::initAttributes() +{ + // attribute for object selected + data()->addAttribute(OBJECTS_LIST_ID(), ModelAPI_AttributeSelection::typeId()); + // attributes for result message and values + data()->addAttribute(X_MIN_COOD_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(Y_MIN_COOD_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(Z_MIN_COOD_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(X_MAX_COOD_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(Y_MAX_COOD_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(Z_MAX_COOD_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(CREATEBOX_ID(), ModelAPI_AttributeBoolean::typeId()); + + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), X_MIN_COOD_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), Y_MIN_COOD_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), Z_MIN_COOD_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), X_MAX_COOD_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), Y_MAX_COOD_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), Z_MAX_COOD_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CREATEBOX_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), RESULT_VALUES_ID()); + + data()->addAttribute(RESULT_VALUES_ID(), ModelAPI_AttributeDoubleArray::typeId()); + + data()->realArray(RESULT_VALUES_ID())->setSize(6); + +} + +void FeaturesPlugin_BoundingBox::execute() +{ + if(boolean(CREATEBOX_ID())->value()) + { + updateValues(); + createBoxByTwoPoints(); + }else{ + eraseResults(); + } +} + +void FeaturesPlugin_BoundingBox::attributeChanged(const std::string& theID) +{ + if (theID == OBJECTS_LIST_ID()) { + updateValues(); + } +} + +void FeaturesPlugin_BoundingBox::updateValues() +{ + AttributeSelectionPtr aSelection = selection(OBJECTS_LIST_ID()); + AttributeDoubleArrayPtr aValues = + std::dynamic_pointer_cast(attribute(RESULT_VALUES_ID())); + std::stringstream streamxmin; + std::stringstream streamymin; + std::stringstream streamzmin; + std::stringstream streamxmax; + std::stringstream streamymax; + std::stringstream streamzmax; + GeomShapePtr aShape; + if (aSelection && aSelection->isInitialized()) { + aShape = aSelection->value(); + if (!aShape && aSelection->context()) + aShape = aSelection->context()->shape(); + } + if (aShape){ + double aXmin, aXmax, aYmin,aYmax,aZmin,aZmax; + std::string aError; + if( !GetBoundingBox(aShape, + true, + aXmin, aXmax, + aYmin,aYmax, + aZmin,aZmax, + aError)) + setError("Error in bounding box calculation :" + aError); + + streamxmin << std::setprecision(14) << aXmin; + aValues->setValue(0, aXmin); + streamxmax << std::setprecision(14) << aXmax; + aValues->setValue(1, aXmax); + streamymin << std::setprecision(14) << aYmin; + aValues->setValue(2, aYmin); + streamymax << std::setprecision(14) << aYmax; + aValues->setValue(3, aYmax); + streamzmin << std::setprecision(14) << aZmin; + aValues->setValue(4, aZmin); + streamzmax << std::setprecision(14) << aZmax; + aValues->setValue(5, aZmax); + } + + string(X_MIN_COOD_ID() )->setValue( "X = " + streamxmin.str() ); + string(Y_MIN_COOD_ID() )->setValue( "Y = " + streamymin.str() ); + string(Z_MIN_COOD_ID() )->setValue( "Z = " + streamzmin.str() ); + string(X_MAX_COOD_ID() )->setValue( "X = " + streamxmax.str() ); + string(Y_MAX_COOD_ID() )->setValue( "Y = " + streamymax.str() ); + string(Z_MAX_COOD_ID() )->setValue( "Z = " + streamzmax.str() ); +} + +//================================================================================================= +void FeaturesPlugin_BoundingBox::createBoxByTwoPoints() +{ + AttributeDoubleArrayPtr aValues = + std::dynamic_pointer_cast(attribute(RESULT_VALUES_ID())); + + GeomVertexPtr vertexFirst = + GeomAlgoAPI_PointBuilder::vertex( aValues->value(0), + aValues->value(2), + aValues->value(4)); + + GeomVertexPtr vertexSecond = + GeomAlgoAPI_PointBuilder::vertex( aValues->value(1), + aValues->value(3), + aValues->value(5)); + + std::shared_ptr aBoxAlgo; + + + aBoxAlgo = std::shared_ptr( + new GeomAlgoAPI_Box(vertexFirst->point(),vertexSecond->point())); + + + // These checks should be made to the GUI for the feature but + // the corresponding validator does not exist yet. + if (!aBoxAlgo->check()) { + setError(aBoxAlgo->getError()); + return; + } + + // Build the box + aBoxAlgo->build(); + + // Check if the creation of the box + if(!aBoxAlgo->isDone()) { + // The error is not displayed in a popup window. It must be in the message console. + setError(aBoxAlgo->getError()); + return; + } + if(!aBoxAlgo->checkValid("Box builder with two points")) { + // The error is not displayed in a popup window. It must be in the message console. + setError(aBoxAlgo->getError()); + return; + } + + int aResultIndex = 0; + ResultBodyPtr aResultBox = document()->createBody(data(), aResultIndex); + loadNamingDS(aBoxAlgo, aResultBox); + setResult(aResultBox, aResultIndex); +} + +//================================================================================================= +void FeaturesPlugin_BoundingBox::loadNamingDS(std::shared_ptr theBoxAlgo, + std::shared_ptr theResultBox) +{ + // Load the result + theResultBox->store(theBoxAlgo->shape()); + + // Prepare the naming + theBoxAlgo->prepareNamingFaces(); + + // Insert to faces + std::map< std::string, std::shared_ptr > listOfFaces = + theBoxAlgo->getCreatedFaces(); + for (std::map< std::string, std::shared_ptr >::iterator it = listOfFaces.begin(); + it != listOfFaces.end(); + ++it) + { + theResultBox->generated((*it).second, (*it).first); + } +} + diff --git a/src/FeaturesPlugin/FeaturesPlugin_BoundingBox.h b/src/FeaturesPlugin/FeaturesPlugin_BoundingBox.h new file mode 100644 index 000000000..997054858 --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_BoundingBox.h @@ -0,0 +1,133 @@ +// Copyright (C) 2018-2020 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_BoundingBox_H_ +#define FeaturesPlugin_BoundingBox_H_ + +#include "FeaturesPlugin.h" +#include + +#include +#include +#include + +/// \class FeaturesPlugin_BoundingBox +/// \ingroup Plugins +/// \brief Feature to view the Bounding Box. + +class FeaturesPlugin_BoundingBox : public ModelAPI_Feature +{ +public: + inline static const std::string& ID() + { + static const std::string MY_ID("BoundingBox"); + return MY_ID; + } + + /// \return the kind of a feature. + virtual const std::string& getKind() + { + return ID(); + } + + /// Attribute name for object selected. + inline static const std::string& OBJECTS_LIST_ID() + { + static const std::string MY_OBJECTS_LIST_ID("main_objects"); + return MY_OBJECTS_LIST_ID; + } + + /// Attribute name for x coodinate. + inline static const std::string& X_MIN_COOD_ID() + { + static const std::string MY_X_MIN_COOD_ID("xmincoordinate"); + return MY_X_MIN_COOD_ID; + } + + /// Attribute name for y coodinate. + inline static const std::string& Y_MIN_COOD_ID() + { + static const std::string MY_Y_MIN_COOD_ID("ymincoordinate"); + return MY_Y_MIN_COOD_ID; + } + + /// Attribute name for z coodinate. + inline static const std::string& Z_MIN_COOD_ID() + { + static const std::string MY_Z_MIN_COOD_ID("zmincoordinate"); + return MY_Z_MIN_COOD_ID; + } + + /// Attribute name for x max coodinate. + inline static const std::string& X_MAX_COOD_ID() + { + static const std::string MY_X_MAX_COOD_ID("xmaxcoordinate"); + return MY_X_MAX_COOD_ID; + } + + /// Attribute name for y max coodinate. + inline static const std::string& Y_MAX_COOD_ID() + { + static const std::string MY_Y_MAX_COOOD_ID("ymaxcoordinate"); + return MY_Y_MAX_COOOD_ID; + } + + /// Attribute name for z max coodinate. + inline static const std::string& Z_MAX_COOD_ID() + { + static const std::string MY_Z_MAX_COOD_ID("zmaxcoordinate"); + return MY_Z_MAX_COOD_ID; + } + + /// Attribute name for checkbox create box. + inline static const std::string& CREATEBOX_ID() + { + static const std::string MY_CREATEBOX_ID("createbox"); + return MY_CREATEBOX_ID; + } + + /// Attribute name for values of result. + inline static const std::string& RESULT_VALUES_ID() + { + static const std::string MY_RESULT_VALUES_ID("result_values"); + return MY_RESULT_VALUES_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_BoundingBox(); + + private: + void updateValues(); + void createBoxByTwoPoints(); + void loadNamingDS(std::shared_ptr theBoxAlgo, + std::shared_ptr theResultBox); + +}; + +#endif diff --git a/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp b/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp index 0d49dfe08..ba813cc08 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -187,6 +188,8 @@ 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_BoundingBox::ID()) { + return FeaturePtr(new FeaturesPlugin_BoundingBox); } else if (theFeatureID == FeaturesPlugin_RemoveResults::ID()) { return FeaturePtr(new FeaturesPlugin_RemoveResults); } else if (theFeatureID == FeaturesPlugin_Chamfer::ID()) { diff --git a/src/FeaturesPlugin/icons/bounding.png b/src/FeaturesPlugin/icons/bounding.png new file mode 100644 index 000000000..5a77a4542 Binary files /dev/null and b/src/FeaturesPlugin/icons/bounding.png differ diff --git a/src/FeaturesPlugin/plugin-Features.xml b/src/FeaturesPlugin/plugin-Features.xml index 08c08b775..ca556280d 100644 --- a/src/FeaturesPlugin/plugin-Features.xml +++ b/src/FeaturesPlugin/plugin-Features.xml @@ -134,7 +134,7 @@ + icon="icons/Features/fusion_faces.png" auto_preview="true" helpfile="FeaturesPlugin/fusionFacesFeature.html"> - + + + + diff --git a/src/GeomAlgoAPI/CMakeLists.txt b/src/GeomAlgoAPI/CMakeLists.txt index 95e749c10..ade5c32d5 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_BoundingBox.h GeomAlgoAPI_ThroughAll.h GeomAlgoAPI_Rotation.h GeomAlgoAPI_Translation.h @@ -98,6 +99,7 @@ SET(PROJECT_SOURCES GeomAlgoAPI_Prism.cpp GeomAlgoAPI_Revolution.cpp GeomAlgoAPI_Boolean.cpp + GeomAlgoAPI_BoundingBox.cpp GeomAlgoAPI_ThroughAll.cpp GeomAlgoAPI_Rotation.cpp GeomAlgoAPI_Translation.cpp @@ -176,6 +178,7 @@ INCLUDE_DIRECTORIES( ../GeomAlgoImpl ../ModelAPI ../XAO + ${PROJECT_SOURCE_DIR}/src/Locale ${OpenCASCADE_INCLUDE_DIR} ) diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_BoundingBox.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_BoundingBox.cpp new file mode 100644 index 000000000..5673eda4a --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_BoundingBox.cpp @@ -0,0 +1,396 @@ +// Copyright (C) 2014-2020 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_BoundingBox.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * This function constructs and returns modified shape from the original one + * for singular cases. It is used for the method GetMinDistanceSingular. + * + * \param theShape the original shape + * \param theModifiedShape output parameter. The modified shape. + * \param theAddDist output parameter. The added distance for modified shape. + * \retval true if the shape is modified; false otherwise. + * + * \internal + */ + Standard_Boolean ModifyShape(const TopoDS_Shape &theShape, + TopoDS_Shape &theModifiedShape, + Standard_Real &theAddDist) + { + TopExp_Explorer anExp; + int nbf = 0; + + theAddDist = 0.; + theModifiedShape.Nullify(); + + for ( anExp.Init( theShape, TopAbs_FACE ); anExp.More(); anExp.Next() ) { + nbf++; + theModifiedShape = anExp.Current(); + } + if(nbf==1) { + TopoDS_Shape sh = theShape; + while(sh.ShapeType()==TopAbs_COMPOUND) { + TopoDS_Iterator it(sh); + sh = it.Value(); + } + Handle(Geom_Surface) S = BRep_Tool::Surface(TopoDS::Face(theModifiedShape)); + if( S->IsKind(STANDARD_TYPE(Geom_SphericalSurface)) || + S->IsKind(STANDARD_TYPE(Geom_ToroidalSurface)) || + S->IsUPeriodic()) { + const Standard_Boolean isShell = + (sh.ShapeType()==TopAbs_SHELL || sh.ShapeType()==TopAbs_FACE); + + if ( !isShell && S->IsKind(STANDARD_TYPE(Geom_SphericalSurface)) ) { + Handle(Geom_SphericalSurface) SS = Handle(Geom_SphericalSurface)::DownCast(S); + gp_Pnt PC = SS->Location(); + BRep_Builder B; + TopoDS_Vertex V; + B.MakeVertex(V,PC,1.e-7); + theModifiedShape = V; + theAddDist = SS->Radius(); + return Standard_True; + } + if ( !isShell && S->IsKind(STANDARD_TYPE(Geom_ToroidalSurface)) ) { + Handle(Geom_ToroidalSurface) TS = Handle(Geom_ToroidalSurface)::DownCast(S); + gp_Ax3 ax3 = TS->Position(); + Handle(Geom_Circle) C = new Geom_Circle(ax3.Ax2(),TS->MajorRadius()); + BRep_Builder B; + TopoDS_Edge E; + B.MakeEdge(E,C,1.e-7); + theModifiedShape = E; + theAddDist = TS->MinorRadius(); + return Standard_True; + } + + // non solid case or any periodic surface (Mantis 22454). + double U1,U2,V1,V2; + // changes for 0020677: EDF 1219 GEOM: MinDistance gives 0 instead of 20.88 + //S->Bounds(U1,U2,V1,V2); changed by + ShapeAnalysis::GetFaceUVBounds(TopoDS::Face(theModifiedShape),U1,U2,V1,V2); + // end of changes for 020677 (dmv) + Handle(Geom_RectangularTrimmedSurface) TrS1 = + new Geom_RectangularTrimmedSurface(S,U1,(U1+U2)/2.,V1,V2); + Handle(Geom_RectangularTrimmedSurface) TrS2 = + new Geom_RectangularTrimmedSurface(S,(U1+U2)/2.,U2,V1,V2); + TopoDS_Shape aMShape; + + TopoDS_Face F1 = BRepBuilderAPI_MakeFace(TrS1, Precision::Confusion()); + TopoDS_Face F2 = BRepBuilderAPI_MakeFace(TrS2, Precision::Confusion()); + + if (isShell) { + BRep_Builder B; + B.MakeCompound(TopoDS::Compound(aMShape)); + B.Add(aMShape, F1); + B.Add(aMShape, F2); + } else { + // The original shape is a solid. + BRepBuilderAPI_Sewing aSewing (Precision::Confusion()*10.0); + aSewing.Add(F1); + aSewing.Add(F2); + aSewing.Perform(); + aMShape = aSewing.SewedShape(); + BRep_Builder B; + TopoDS_Solid aSolid; + B.MakeSolid(aSolid); + B.Add(aSolid, aMShape); + aMShape = aSolid; + } + + Handle(ShapeFix_Shape) sfs = new ShapeFix_Shape; + sfs->Init(aMShape); + sfs->SetPrecision(1.e-6); + sfs->SetMaxTolerance(1.0); + sfs->Perform(); + theModifiedShape = sfs->Shape(); + return Standard_True; + } + } + + theModifiedShape = theShape; + return Standard_False; + } + +//======================================================================= +//function : GetMinDistanceSingular +//======================================================================= +double GetMinDistanceSingular(const TopoDS_Shape& aSh1, + const TopoDS_Shape& aSh2, + gp_Pnt& Ptmp1, gp_Pnt& Ptmp2) +{ + TopoDS_Shape tmpSh1; + TopoDS_Shape tmpSh2; + Standard_Real AddDist1 = 0.; + Standard_Real AddDist2 = 0.; + Standard_Boolean IsChange1 = ModifyShape(aSh1, tmpSh1, AddDist1); + Standard_Boolean IsChange2 = ModifyShape(aSh2, tmpSh2, AddDist2); + + if( !IsChange1 && !IsChange2 ) + return -2.0; + + BRepExtrema_DistShapeShape dst(tmpSh1,tmpSh2); + if (dst.IsDone()) { + double MinDist = 1.e9; + gp_Pnt PMin1, PMin2, P1, P2; + for (int i = 1; i <= dst.NbSolution(); i++) { + P1 = dst.PointOnShape1(i); + P2 = dst.PointOnShape2(i); + Standard_Real Dist = P1.Distance(P2); + if (MinDist > Dist) { + MinDist = Dist; + PMin1 = P1; + PMin2 = P2; + } + } + if(MinDist<1.e-7) { + Ptmp1 = PMin1; + Ptmp2 = PMin2; + } + else { + gp_Dir aDir(gp_Vec(PMin1,PMin2)); + if( MinDist > (AddDist1+AddDist2) ) { + Ptmp1 = gp_Pnt( PMin1.X() + aDir.X()*AddDist1, + PMin1.Y() + aDir.Y()*AddDist1, + PMin1.Z() + aDir.Z()*AddDist1 ); + Ptmp2 = gp_Pnt( PMin2.X() - aDir.X()*AddDist2, + PMin2.Y() - aDir.Y()*AddDist2, + PMin2.Z() - aDir.Z()*AddDist2 ); + return (MinDist - AddDist1 - AddDist2); + } + else { + if( AddDist1 > 0 ) { + Ptmp1 = gp_Pnt( PMin1.X() + aDir.X()*AddDist1, + PMin1.Y() + aDir.Y()*AddDist1, + PMin1.Z() + aDir.Z()*AddDist1 ); + Ptmp2 = Ptmp1; + } + else { + Ptmp2 = gp_Pnt( PMin2.X() - aDir.X()*AddDist2, + PMin2.Y() - aDir.Y()*AddDist2, + PMin2.Z() - aDir.Z()*AddDist2 ); + Ptmp1 = Ptmp2; + } + } + } + double res = MinDist - AddDist1 - AddDist2; + if(res<0.) res = 0.0; + return res; + } + return -2.0; +} + +//function : GetMinDistance +//purpose : +//======================================================================= +Standard_Real GetMinDistance(const TopoDS_Shape& theShape1, + const TopoDS_Shape& theShape2, + gp_Pnt& thePnt1, gp_Pnt& thePnt2) +{ + Standard_Real aResult = 1.e9; + + // Issue 0020231: A min distance bug with torus and vertex. + // Make GetMinDistance() return zero if a sole VERTEX is inside any of SOLIDs + + // which of shapes consists of only one vertex? + TopExp_Explorer exp1(theShape1,TopAbs_VERTEX), exp2(theShape2,TopAbs_VERTEX); + TopoDS_Shape V1 = exp1.More() ? exp1.Current() : TopoDS_Shape(); + TopoDS_Shape V2 = exp2.More() ? exp2.Current() : TopoDS_Shape(); + exp1.Next(); exp2.Next(); + if ( exp1.More() ) V1.Nullify(); + if ( exp2.More() ) V2.Nullify(); + // vertex and container of solids + TopoDS_Shape V = V1.IsNull() ? V2 : V1; + TopoDS_Shape S = V1.IsNull() ? theShape1 : theShape2; + if ( !V.IsNull() ) { + // classify vertex against solids + gp_Pnt p = BRep_Tool::Pnt( TopoDS::Vertex( V ) ); + for ( exp1.Init( S, TopAbs_SOLID ); exp1.More(); exp1.Next() ) { + BRepClass3d_SolidClassifier classifier( exp1.Current(), p, 1e-6); + if ( classifier.State() == TopAbs_IN ) { + thePnt1 = p; + thePnt2 = p; + return 0.0; + } + } + } + + aResult = GetMinDistanceSingular(theShape1, theShape2, thePnt1, thePnt2); + + + BRepExtrema_DistShapeShape dst (theShape1, theShape2); + if (dst.IsDone()) { + gp_Pnt P1, P2; + + for (int i = 1; i <= dst.NbSolution(); i++) { + P1 = dst.PointOnShape1(i); + P2 = dst.PointOnShape2(i); + + Standard_Real Dist = P1.Distance(P2); + if (aResult < 0 || aResult > Dist) { + aResult = Dist; + thePnt1 = P1; + thePnt2 = P2; + } + } + } + + return aResult; +} + +//======================================================================= +//PreciseBoundingBox +//======================================================================= +Standard_Boolean PreciseBoundingBox + (const TopoDS_Shape &theShape, Bnd_Box &theBox) +{ + if ( theBox.IsVoid() ) BRepBndLib::Add( theShape, theBox ); + if ( theBox.IsVoid() ) return Standard_False; + + Standard_Real aBound[6]; + theBox.Get(aBound[0], aBound[2], aBound[4], aBound[1], aBound[3], aBound[5]); + + Standard_Integer i; + const gp_Pnt aMid(0.5*(aBound[1] + aBound[0]), // XMid + 0.5*(aBound[3] + aBound[2]), // YMid + 0.5*(aBound[5] + aBound[4])); // ZMid + const gp_XYZ aSize(aBound[1] - aBound[0], // DX + aBound[3] - aBound[2], // DY + aBound[5] - aBound[4]); // DZ + const gp_Pnt aPnt[6] = + { + gp_Pnt(aBound[0] - (aBound[1] - aBound[0]), aMid.Y(), aMid.Z()), // XMin + gp_Pnt(aBound[1] + (aBound[1] - aBound[0]), aMid.Y(), aMid.Z()), // XMax + gp_Pnt(aMid.X(), aBound[2] - (aBound[3] - aBound[2]), aMid.Z()), // YMin + gp_Pnt(aMid.X(), aBound[3] + (aBound[3] - aBound[2]), aMid.Z()), // YMax + gp_Pnt(aMid.X(), aMid.Y(), aBound[4] - (aBound[5] - aBound[4])), // ZMin + gp_Pnt(aMid.X(), aMid.Y(), aBound[5] + (aBound[5] - aBound[4])) // ZMax + }; + const gp_Dir aDir[3] = { gp::DX(), gp::DY(), gp::DZ() }; + const Standard_Real aPlnSize[3] = + { + 0.5*Max(aSize.Y(), aSize.Z()), // XMin, XMax planes + 0.5*Max(aSize.X(), aSize.Z()), // YMin, YMax planes + 0.5*Max(aSize.X(), aSize.Y()) // ZMin, ZMax planes + }; + gp_Pnt aPMin[2]; + + for (i = 0; i < 6; i++) { + const Standard_Integer iHalf = i/2; + const gp_Pln aPln(aPnt[i], aDir[iHalf]); + BRepBuilderAPI_MakeFace aMkFace(aPln, -aPlnSize[iHalf], aPlnSize[iHalf], + -aPlnSize[iHalf], aPlnSize[iHalf]); + + if (!aMkFace.IsDone()) { + return Standard_False; + } + + TopoDS_Shape aFace = aMkFace.Shape(); + + // Get minimal distance between planar face and shape. + Standard_Real aMinDist = GetMinDistance(aFace, theShape, aPMin[0], aPMin[1]); + + if (aMinDist < 0.) { + return Standard_False; + } + + aBound[i] = aPMin[1].Coord(iHalf + 1); + } + + // Update Bounding box with the new values. + theBox.SetVoid(); + theBox.Update(aBound[0], aBound[2], aBound[4], aBound[1], aBound[3], aBound[5]); + + return Standard_True; +} + +//================================================================================================= +bool GetBoundingBox( const std::shared_ptr& theShape, + const bool thePrecise, + Standard_Real& theXmin,Standard_Real& theXmax, + Standard_Real& theYmin,Standard_Real& theYmax, + Standard_Real& theZmin,Standard_Real& theZmax, + std::string& theError) +{ + + #ifdef _DEBUG + std::cout << "GetBoundingBox " << std::endl; + #endif + + if (!theShape.get()) { + theError = "GetBasicProperties : An invalid argument"; + return false; + } + + TopoDS_Shape aShape = theShape->impl(); + //Compute the parameters + Bnd_Box B; + + try { + OCC_CATCH_SIGNALS; + BRepBuilderAPI_Copy aCopyTool (aShape); + if (!aCopyTool.IsDone()) { + theError = "GetBoundingBox Error: Bad shape detected"; + return false; + } + + aShape = aCopyTool.Shape(); + + // remove triangulation to obtain more exact boundaries + BRepTools::Clean(aShape); + + BRepBndLib::Add(aShape, B); + + if (thePrecise) { + if (!PreciseBoundingBox(aShape, B)) { + theError = "GetBoundingBox Error: Bounding box cannot be precised"; + return false; + } + } + + B.Get(theXmin, theYmin, theZmin, theXmax, theYmax, theZmax); + } + catch (Standard_Failure& aFail) { + theError = aFail.GetMessageString(); + return false; + } + return true; +} + diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_BoundingBox.h b/src/GeomAlgoAPI/GeomAlgoAPI_BoundingBox.h new file mode 100644 index 000000000..be6e548b6 --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_BoundingBox.h @@ -0,0 +1,45 @@ +// Copyright (C) 2014-2020 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_BoundingBox_H_ +#define GeomAlgoAPI_BoundingBox_H_ + +#include +#include +#include + +/// get the boundin box of theshape. + /// \param theShape the shape + /// \param thePrecise precise TRUE for precise computation; FALSE for fast one. + /// \param theXmin X min of the box + /// \param theXmax X max of the box + /// \param theYmin Y min of the box + /// \param theYmax Y max of the box + /// \param theZmin Z min of the box + /// \param theZmax Z max of the box + /// \param theError error +GEOMALGOAPI_EXPORT +bool GetBoundingBox( const std::shared_ptr& theShape, + const bool thePrecise, + Standard_Real& theXmin,Standard_Real& theXmax, + Standard_Real& theYmin,Standard_Real& theYmax, + Standard_Real& theZmin,Standard_Real& theZmax, + std::string& theError); + +#endif diff --git a/src/ModelAPI/CMakeLists.txt b/src/ModelAPI/CMakeLists.txt index dd2f4acd9..7b7876165 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} ) @@ -265,6 +269,4 @@ ADD_UNIT_TESTS(TestConstants.py Test19707.py Test19726.py Test19912.py - Test19932.py - Test19989.py ) diff --git a/src/ModuleBase/ModuleBase_WidgetLabel.cpp b/src/ModuleBase/ModuleBase_WidgetLabel.cpp index 7a47835c8..7e3f86de0 100644 --- a/src/ModuleBase/ModuleBase_WidgetLabel.cpp +++ b/src/ModuleBase/ModuleBase_WidgetLabel.cpp @@ -61,6 +61,10 @@ ModuleBase_WidgetLabel::ModuleBase_WidgetLabel(QWidget* theParent, std::string aStyleSheet = theData->getProperty(ATTR_STYLE_SHEET); if (!aStyleSheet.empty()) myLabel->setStyleSheet(QString("QLabel {%1}").arg(aStyleSheet.c_str())); + + aStyleSheet = theData->getProperty(ATTR_IS_SELECTABLE); + if ( aStyleSheet == "true") + myLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); } ModuleBase_WidgetLabel::~ModuleBase_WidgetLabel() diff --git a/src/PythonAPI/model/features/__init__.py b/src/PythonAPI/model/features/__init__.py index 772dc05c2..4232d37b7 100644 --- a/src/PythonAPI/model/features/__init__.py +++ b/src/PythonAPI/model/features/__init__.py @@ -30,6 +30,7 @@ from FeaturesAPI import addRecover from FeaturesAPI import addFillet, addChamfer from FeaturesAPI import addFusionFaces from FeaturesAPI import measureLength, measureDistance, measureRadius, measureAngle +from FeaturesAPI import getBoundingBox from FeaturesAPI import addRemoveResults from FeaturesAPI import addCopy, addImportResult from FeaturesAPI import addDefeaturing