From: cg246364 Date: Tue, 19 Jan 2021 14:46:17 +0000 (+0100) Subject: CEA : Lot2 - Bounding box X-Git-Tag: V9_7_0a1~44^2~1 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=8f29b823e6a1a407252eea9dbf110ad695c7121c;p=modules%2Fshaper.git CEA : Lot2 - Bounding box --- diff --git a/src/FeaturesAPI/CMakeLists.txt b/src/FeaturesAPI/CMakeLists.txt index 844baeb00..1ebde42d0 100644 --- a/src/FeaturesAPI/CMakeLists.txt +++ b/src/FeaturesAPI/CMakeLists.txt @@ -53,6 +53,7 @@ SET(PROJECT_HEADERS FeaturesAPI_Defeaturing.h FeaturesAPI_PointCoordinates.h FeaturesAPI_GeometryCalculation.h + FeaturesAPI_BoundingBox.h ) SET(PROJECT_SOURCES @@ -88,6 +89,7 @@ SET(PROJECT_SOURCES FeaturesAPI_Defeaturing.cpp FeaturesAPI_PointCoordinates.cpp FeaturesAPI_GeometryCalculation.cpp + FeaturesAPI_BoundingBox.cpp ) SET(PROJECT_LIBRARIES diff --git a/src/FeaturesAPI/FeaturesAPI.i b/src/FeaturesAPI/FeaturesAPI.i index 4a63d049b..6f89d07cf 100644 --- a/src/FeaturesAPI/FeaturesAPI.i +++ b/src/FeaturesAPI/FeaturesAPI.i @@ -92,6 +92,7 @@ %shared_ptr(FeaturesAPI_Copy) %shared_ptr(FeaturesAPI_ImportResult) %shared_ptr(FeaturesAPI_Defeaturing) +%shared_ptr(FeaturesAPI_BoundingBox) %typecheck(SWIG_TYPECHECK_POINTER) std::pair, bool>, const std::pair, bool> & { @@ -231,3 +232,4 @@ %include "FeaturesAPI_ImportResult.h" %include "FeaturesAPI_PointCoordinates.h" %include "FeaturesAPI_GeometryCalculation.h" +%include "FeaturesAPI_BoundingBox.h" diff --git a/src/FeaturesAPI/FeaturesAPI_BoundingBox.cpp b/src/FeaturesAPI/FeaturesAPI_BoundingBox.cpp new file mode 100644 index 000000000..d72009d39 --- /dev/null +++ b/src/FeaturesAPI/FeaturesAPI_BoundingBox.cpp @@ -0,0 +1,84 @@ +// 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_CreateBoundingBox::OBJECT_ID()); + + theDumper << aBase << " = model.getBoundingBox(" << aDocName << ", " << anAttrObject; + + theDumper << ")" << std::endl; +} + +//================================================================================================= +BoundingBoxPtr getBoundingBox(const std::shared_ptr& thePart, + const ModelHighAPI_Selection& theObject) +{ + + FeaturePtr aFeature = + thePart->addFeature(FeaturesPlugin_CreateBoundingBox::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..cc45aa4af --- /dev/null +++ b/src/FeaturesAPI/FeaturesAPI_BoundingBox.h @@ -0,0 +1,74 @@ +// 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_CreateBoundingBox.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_CreateBoundingBox::ID(), + objectSelected, FeaturesPlugin_CreateBoundingBox::OBJECT_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 1ad19edc1..6bd15c3c0 100644 --- a/src/FeaturesAPI/FeaturesAPI_swig.h +++ b/src/FeaturesAPI/FeaturesAPI_swig.h @@ -55,5 +55,6 @@ #include "FeaturesAPI_ImportResult.h" #include "FeaturesAPI_PointCoordinates.h" #include "FeaturesAPI_GeometryCalculation.h" + #include "FeaturesAPI_BoundingBox.h" #endif // FeaturesAPI_swig_H_ diff --git a/src/FeaturesPlugin/CMakeLists.txt b/src/FeaturesPlugin/CMakeLists.txt index 1e14a6289..7a793e03b 100644 --- a/src/FeaturesPlugin/CMakeLists.txt +++ b/src/FeaturesPlugin/CMakeLists.txt @@ -69,6 +69,9 @@ SET(PROJECT_HEADERS FeaturesPlugin_VersionedChFi.h FeaturesPlugin_PointCoordinates.h FeaturesPlugin_GeometryCalculation.h + FeaturesPlugin_BoundingBox.h + FeaturesPlugin_CommonBoundingBox.h + FeaturesPlugin_CreateBoundingBox.h ) SET(PROJECT_SOURCES @@ -118,6 +121,9 @@ SET(PROJECT_SOURCES FeaturesPlugin_VersionedChFi.cpp FeaturesPlugin_PointCoordinates.cpp FeaturesPlugin_GeometryCalculation.cpp + FeaturesPlugin_BoundingBox.cpp + FeaturesPlugin_CommonBoundingBox.cpp + FeaturesPlugin_CreateBoundingBox.cpp ) SET(XML_RESOURCES @@ -156,6 +162,8 @@ SET(XML_RESOURCES defeaturing_widget.xml point_coordinates_widget.xml geometry_calculation_widget.xml + bounding_box_widget.xml + create_bounding_box_widget.xml ) SET(TEXT_RESOURCES @@ -698,4 +706,5 @@ ADD_UNIT_TESTS(TestExtrusion.py Test20247.py TestPointCoordinates.py TestGeometryCalculation.py + TestBoundingBox.py ) diff --git a/src/FeaturesPlugin/FeaturesPlugin_BoundingBox.cpp b/src/FeaturesPlugin/FeaturesPlugin_BoundingBox.cpp new file mode 100644 index 000000000..6e30b6f54 --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_BoundingBox.cpp @@ -0,0 +1,195 @@ +// 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 + +//================================================================================================= +FeaturesPlugin_BoundingBox::FeaturesPlugin_BoundingBox() +{ +} + +//================================================================================================= +void FeaturesPlugin_BoundingBox::initAttributes() +{ + // attribute for object selected + data()->addAttribute(OBJECT_ID(), ModelAPI_AttributeSelection::typeId()); + + // attributes for result message and values + data()->addAttribute(X_MIN_COORD_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(Y_MIN_COORD_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(Z_MIN_COORD_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(X_MAX_COORD_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(Y_MAX_COORD_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(Z_MAX_COORD_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(CREATEBOX_ID(), ModelAPI_AttributeBoolean::typeId()); + + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), X_MIN_COORD_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), Y_MIN_COORD_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), Z_MIN_COORD_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), X_MAX_COORD_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), Y_MAX_COORD_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), Z_MAX_COORD_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() +{ + updateValues(); + createBoxByTwoPoints(); + + if (boolean(CREATEBOX_ID())->value()) { + if (!myCreateFeature.get()) + createBox(); + updateBox(); + } else { + if (myCreateFeature.get()) { + myCreateFeature->eraseResults(); + SessionPtr aSession = ModelAPI_Session::get(); + DocumentPtr aDoc = aSession->activeDocument(); + aDoc->removeFeature(myCreateFeature); + myCreateFeature.reset(); + } + } +} + +//================================================================================================= +void FeaturesPlugin_BoundingBox::attributeChanged(const std::string& theID) +{ + if (theID == OBJECT_ID()) { + if (myCreateFeature.get()) + updateBox(); + } +} + +//================================================================================================= +AttributePtr FeaturesPlugin_BoundingBox::attributResultValues() +{ + return attribute(RESULT_VALUES_ID()); +} + +//================================================================================================= +void FeaturesPlugin_BoundingBox::updateValues() +{ + AttributeSelectionPtr aSelection = selection(OBJECT_ID()); + if (aSelection->isInitialized()) { + 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 && !aShape->isEqual(myShape)) { + 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); + + myShape = aShape; + 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_COORD_ID() )->setValue( "X = " + streamxmin.str() ); + string(Y_MIN_COORD_ID() )->setValue( "Y = " + streamymin.str() ); + string(Z_MIN_COORD_ID() )->setValue( "Z = " + streamzmin.str() ); + string(X_MAX_COORD_ID() )->setValue( "X = " + streamxmax.str() ); + string(Y_MAX_COORD_ID() )->setValue( "Y = " + streamymax.str() ); + string(Z_MAX_COORD_ID() )->setValue( "Z = " + streamzmax.str() ); + } + } +} + +//================================================================================================= +void FeaturesPlugin_BoundingBox::createBox() +{ + SessionPtr aSession = ModelAPI_Session::get(); + + DocumentPtr aDoc = aSession->activeDocument(); + + if (aDoc.get()) { + myCreateFeature = aDoc->addFeature(FeaturesPlugin_CreateBoundingBox::ID()); + } +} + +//================================================================================================= +void FeaturesPlugin_BoundingBox::updateBox() +{ + myCreateFeature->boolean(FeaturesPlugin_CreateBoundingBox::COMPUTE_ID())->setValue(false); + myCreateFeature->selection(FeaturesPlugin_CreateBoundingBox::OBJECT_ID()) + ->setValue(selection(OBJECT_ID())->context(), + selection(OBJECT_ID())->value()); + + AttributeDoubleArrayPtr aValuesFeatures = + std::dynamic_pointer_cast + (myCreateFeature->attribute(RESULT_VALUES_ID())); + AttributeDoubleArrayPtr aValues = + std::dynamic_pointer_cast(attribute(RESULT_VALUES_ID())); + for (int anI=0; anI < 6; anI++) + aValuesFeatures->setValue(anI,aValues->value(anI)); + + myCreateFeature->execute(); + myCreateFeature->boolean(FeaturesPlugin_CreateBoundingBox::COMPUTE_ID())->setValue(true); +} diff --git a/src/FeaturesPlugin/FeaturesPlugin_BoundingBox.h b/src/FeaturesPlugin/FeaturesPlugin_BoundingBox.h new file mode 100644 index 000000000..ef12a579f --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_BoundingBox.h @@ -0,0 +1,140 @@ +// 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 + +/// \class FeaturesPlugin_BoundingBox +/// \ingroup Plugins +/// \brief Feature to view the Bounding Box. + +class FeaturesPlugin_BoundingBox : public FeaturesPlugin_CommonBoundingBox +{ +public: + /// Bounding box macro kind. + inline static const std::string& ID() + { + static const std::string MY_ID("BoundingBoxMacro"); + return MY_ID; + } + + /// Attribute name for object selected. + inline static const std::string& OBJECT_ID() + { + static const std::string MY_OBJECT_ID("main_object"); + return MY_OBJECT_ID; + } + + /// Attribute name for x coodinate. + inline static const std::string& X_MIN_COORD_ID() + { + static const std::string MY_X_MIN_COORD_ID("xmincoordinate"); + return MY_X_MIN_COORD_ID; + } + + /// Attribute name for y coodinate. + inline static const std::string& Y_MIN_COORD_ID() + { + static const std::string MY_Y_MIN_COORD_ID("ymincoordinate"); + return MY_Y_MIN_COORD_ID; + } + + /// Attribute name for z coodinate. + inline static const std::string& Z_MIN_COORD_ID() + { + static const std::string MY_Z_MIN_COORD_ID("zmincoordinate"); + return MY_Z_MIN_COORD_ID; + } + + /// Attribute name for x max coodinate. + inline static const std::string& X_MAX_COORD_ID() + { + static const std::string MY_X_MAX_COORD_ID("xmaxcoordinate"); + return MY_X_MAX_COORD_ID; + } + + /// Attribute name for y max coodinate. + inline static const std::string& Y_MAX_COORD_ID() + { + static const std::string MY_Y_MAX_COORD_ID("ymaxcoordinate"); + return MY_Y_MAX_COORD_ID; + } + + /// Attribute name for z max coodinate. + inline static const std::string& Z_MAX_COORD_ID() + { + static const std::string MY_Z_MAX_COORD_ID("zmaxcoordinate"); + return MY_Z_MAX_COORD_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; + } + + /// \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_BoundingBox(); + +private: + /// Return Attribut values of result. + virtual AttributePtr attributResultValues(); + + /// Update values displayed. + void updateValues(); + /// Create Box + void createBox(); + /// Update Box + void updateBox(); + + /// Feature to create box + FeaturePtr myCreateFeature; + +}; + +#endif diff --git a/src/FeaturesPlugin/FeaturesPlugin_CommonBoundingBox.cpp b/src/FeaturesPlugin/FeaturesPlugin_CommonBoundingBox.cpp new file mode 100644 index 000000000..9a3784aa8 --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_CommonBoundingBox.cpp @@ -0,0 +1,115 @@ +// 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_CommonBoundingBox.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + + + +//================================================================================================= +void FeaturesPlugin_CommonBoundingBox::createBoxByTwoPoints() +{ + AttributeDoubleArrayPtr aValues = + std::dynamic_pointer_cast(attributResultValues()); + + SessionPtr aSession = ModelAPI_Session::get(); + + DocumentPtr aDoc = aSession->activeDocument(); + + 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_CommonBoundingBox::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_CommonBoundingBox.h b/src/FeaturesPlugin/FeaturesPlugin_CommonBoundingBox.h new file mode 100644 index 000000000..c28392d47 --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_CommonBoundingBox.h @@ -0,0 +1,59 @@ +// 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_CommonBoundingBox_H_ +#define FeaturesPlugin_CommonBoundingBox_H_ + +#include "FeaturesPlugin.h" +#include + +#include + +#include +#include + +#include + +/// \class FeaturesPlugin_CommonBoundingBox +/// \ingroup Plugins +/// \brief Feature to view the Bounding Box. + +class FeaturesPlugin_CommonBoundingBox : public ModelAPI_Feature +{ +public: + /// Performs the algorithm and stores results it in the data structure. + FEATURESPLUGIN_EXPORT virtual void execute(){}; + + /// Return Attribut values of result. + virtual AttributePtr attributResultValues() = 0; + +protected: + FeaturesPlugin_CommonBoundingBox() {} + + /// Create box with two points + void createBoxByTwoPoints(); + + /// Create namming + void loadNamingDS(std::shared_ptr theBoxAlgo, + std::shared_ptr theResultBox); + + GeomShapePtr myShape; +}; + +#endif diff --git a/src/FeaturesPlugin/FeaturesPlugin_CreateBoundingBox.cpp b/src/FeaturesPlugin/FeaturesPlugin_CreateBoundingBox.cpp new file mode 100644 index 000000000..f59d98b94 --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_CreateBoundingBox.cpp @@ -0,0 +1,158 @@ +// 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_CreateBoundingBox.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include + +//================================================================================================= +FeaturesPlugin_CreateBoundingBox::FeaturesPlugin_CreateBoundingBox() +{ +} + +//================================================================================================= +void FeaturesPlugin_CreateBoundingBox::initAttributes() +{ + // attribute for object selected + data()->addAttribute(OBJECT_ID(), ModelAPI_AttributeSelection::typeId()); + + // attributes for result message and values + data()->addAttribute(X_MIN_COORD_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(Y_MIN_COORD_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(Z_MIN_COORD_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(X_MAX_COORD_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(Y_MAX_COORD_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(Z_MAX_COORD_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(COMPUTE_ID(), ModelAPI_AttributeBoolean::typeId()); + + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), X_MIN_COORD_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), Y_MIN_COORD_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), Z_MIN_COORD_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), X_MAX_COORD_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), Y_MAX_COORD_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), Z_MAX_COORD_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), COMPUTE_ID()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), OBJECT_ID()); + data()->addAttribute(RESULT_VALUES_ID(), ModelAPI_AttributeDoubleArray::typeId()); + + data()->realArray(RESULT_VALUES_ID())->setSize(6); + data()->boolean(COMPUTE_ID())->setValue(true); +} + +//================================================================================================= +void FeaturesPlugin_CreateBoundingBox::execute() +{ + updateValues(); + createBoxByTwoPoints(); +} + +//================================================================================================= +void FeaturesPlugin_CreateBoundingBox::attributeChanged(const std::string& theID) +{ +} + +//================================================================================================= +void FeaturesPlugin_CreateBoundingBox::updateValues() +{ + AttributeSelectionPtr aSelection = selection(OBJECT_ID()); + AttributeDoubleArrayPtr aValues = + std::dynamic_pointer_cast(attribute(RESULT_VALUES_ID())); + + if (aSelection->isInitialized()) { + 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(); + } + + AttributeBooleanPtr anIsCompute = boolean(COMPUTE_ID()); + if (!anIsCompute->value()) { + myShape = aShape; + anIsCompute->setValue(true); + } + + if (aShape && !aShape->isEqual(myShape)) { + 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); + myShape = aShape; + 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); + } else { + streamxmin << std::setprecision(14) << aValues->value(0); + streamxmax << std::setprecision(14) << aValues->value(1); + streamymin << std::setprecision(14) << aValues->value(2); + streamymax << std::setprecision(14) << aValues->value(3); + streamzmin << std::setprecision(14) << aValues->value(4); + streamzmax << std::setprecision(14) << aValues->value(5); + } + + string(X_MIN_COORD_ID() )->setValue( "X = " + streamxmin.str() ); + string(Y_MIN_COORD_ID() )->setValue( "Y = " + streamymin.str() ); + string(Z_MIN_COORD_ID() )->setValue( "Z = " + streamzmin.str() ); + string(X_MAX_COORD_ID() )->setValue( "X = " + streamxmax.str() ); + string(Y_MAX_COORD_ID() )->setValue( "Y = " + streamymax.str() ); + string(Z_MAX_COORD_ID() )->setValue( "Z = " + streamzmax.str() ); + } +} + +//================================================================================================= +AttributePtr FeaturesPlugin_CreateBoundingBox::attributResultValues() +{ + return attribute(RESULT_VALUES_ID()); +} diff --git a/src/FeaturesPlugin/FeaturesPlugin_CreateBoundingBox.h b/src/FeaturesPlugin/FeaturesPlugin_CreateBoundingBox.h new file mode 100644 index 000000000..6884ac0db --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_CreateBoundingBox.h @@ -0,0 +1,130 @@ +// 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_CreateBoundingBox_H_ +#define FeaturesPlugin_CreateBoundingBox_H_ + +#include + +/// \class FeaturesPlugin_BoundingBox +/// \ingroup Plugins +/// \brief Feature to view the Bounding Box. + +class FeaturesPlugin_CreateBoundingBox : public FeaturesPlugin_CommonBoundingBox +{ +public: + /// Bounding box kind. + inline static const std::string& ID() + { + static const std::string MY_ID("BoundingBox"); + return MY_ID; + } + + /// Attribute name for object selected. + inline static const std::string& OBJECT_ID() + { + static const std::string MY_OBJECT_ID("main_object"); + return MY_OBJECT_ID; + } + + /// Attribute name for x coodinate. + inline static const std::string& X_MIN_COORD_ID() + { + static const std::string MY_X_MIN_COORD_ID("xmincoordinate"); + return MY_X_MIN_COORD_ID; + } + + /// Attribute name for y coodinate. + inline static const std::string& Y_MIN_COORD_ID() + { + static const std::string MY_Y_MIN_COORD_ID("ymincoordinate"); + return MY_Y_MIN_COORD_ID; + } + + /// Attribute name for z coodinate. + inline static const std::string& Z_MIN_COORD_ID() + { + static const std::string MY_Z_MIN_COORD_ID("zmincoordinate"); + return MY_Z_MIN_COORD_ID; + } + + /// Attribute name for x max coodinate. + inline static const std::string& X_MAX_COORD_ID() + { + static const std::string MY_X_MAX_COORD_ID("xmaxcoordinate"); + return MY_X_MAX_COORD_ID; + } + + /// Attribute name for y max coodinate. + inline static const std::string& Y_MAX_COORD_ID() + { + static const std::string MY_Y_MAX_COORD_ID("ymaxcoordinate"); + return MY_Y_MAX_COORD_ID; + } + + /// Attribute name for z max coodinate. + inline static const std::string& Z_MAX_COORD_ID() + { + static const std::string MY_Z_MAX_COORD_ID("zmaxcoordinate"); + return MY_Z_MAX_COORD_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; + } + + /// Attribute name for indicate to compute the bounding box. + inline static const std::string& COMPUTE_ID() + { + static const std::string MY_COMPUTE_ID("compute"); + return MY_COMPUTE_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); + + /// Return Attribut values of result. + FEATURESPLUGIN_EXPORT virtual AttributePtr attributResultValues(); + + /// Use plugin manager for features creation + FeaturesPlugin_CreateBoundingBox(); + +private: + /// Update values displayed. + void updateValues(); + +}; + +#endif diff --git a/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp b/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp index 8419057e2..d3332d14f 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp @@ -24,7 +24,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -203,6 +205,10 @@ FeaturePtr FeaturesPlugin_Plugin::createFeature(std::string theFeatureID) return FeaturePtr(new FeaturesPlugin_PointCoordinates); } else if (theFeatureID == FeaturesPlugin_GeometryCalculation::ID()) { return FeaturePtr(new FeaturesPlugin_GeometryCalculation); + } else if (theFeatureID == FeaturesPlugin_BoundingBox::ID()) { + return FeaturePtr(new FeaturesPlugin_BoundingBox); + } else if (theFeatureID == FeaturesPlugin_CreateBoundingBox::ID()) { + return FeaturePtr(new FeaturesPlugin_CreateBoundingBox); } diff --git a/src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts b/src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts index ff2645663..878c1f4d5 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts +++ b/src/FeaturesPlugin/FeaturesPlugin_msg_fr.ts @@ -131,6 +131,10 @@ Geometry calculation Calcul de la géométrie + + Bounding box + Boîte englobante + Placement Placement @@ -149,6 +153,30 @@ + + + BoundingBox + + BoundingBox + Boîte englobante + + + Create box + Créer la boîte + + + + BoundingBoxMacro + + BoundingBox + Boîte englobante + + + Create box + Créer la boîte + + + Chamfer @@ -4462,14 +4490,44 @@ Deuxième direction - + + - PointCoordinates + BoundingBoxMacro - Point coordinates - Coordonnées d'un point + Bounding box + Boîte englobante + + + + BoundingBoxMacro:main_object + + Object + Objet + + BoundingBoxMacro:createbox + + Create box + Créer la boîte + + + + BoundingBox + + Bounding box + Boîte englobante + + + + BoundingBox:main_object + + Object + Objet + + + GeometryCalculation @@ -4500,6 +4558,7 @@ Volume = + Measurement @@ -4771,6 +4830,15 @@ + + + PointCoordinates + + Point coordinates + Coordonnées d'un point + + + Rotation diff --git a/src/FeaturesPlugin/Test/TestBoundingBox.py b/src/FeaturesPlugin/Test/TestBoundingBox.py new file mode 100644 index 000000000..673445e86 --- /dev/null +++ b/src/FeaturesPlugin/Test/TestBoundingBox.py @@ -0,0 +1,81 @@ +# 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 +# + +""" + Unit test of ... +""" +#========================================================================= +# Initialization of the test +#========================================================================= + + +import os +import math + +from ModelAPI import * +from salome.shaper import model + + +__updated__ = "2020-11-12" + + +#========================================================================= +# test Bounding Box +#========================================================================= +def test_Bounding_Box(): + + model.begin() + file_path = os.path.join(os.getenv("DATA_DIR"),"Shapes","Step","screw.step") + 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 + BoundingBox_1 = model.getBoundingBox(Part_1_doc, model.selection("SOLID", "screw_1")) + model.end() + + myDelta = 1e-6 + Props = model.getGeometryCalculation(Part_1_doc,model.selection("SOLID", "BoundingBox_1_1")) + + print(" Basic Properties:") + print(" Wires length: ", Props[0]) + print(" Surface area: ", Props[1]) + print(" Volume : ", Props[2]) + + aReflength = 0.32855301948678 + aReslength = Props[0] + assert (math.fabs(aReslength - aReflength) < myDelta), "The surface is wrong: expected = {0}, real = {1}".format(aReflength, aReslength) + + aRefSurface = 0.0041640657342782 + aResSurface = Props[1] + assert (math.fabs(aResSurface - aRefSurface) < myDelta), "The surface is wrong: expected = {0}, real = {1}".format(aRefSurface, aResSurface) + + aRefVolume = 1.6785355394103e-05 + aResVolume = Props[2] + assert (math.fabs(aResVolume - aRefVolume) < myDelta), "The volume is wrong: expected = {0}, real = {1}".format(aRefVolume, aResVolume) + + +if __name__ == '__main__': + + test_Bounding_Box() + + #========================================================================= + # End of test + #========================================================================= diff --git a/src/FeaturesPlugin/bounding_box_widget.xml b/src/FeaturesPlugin/bounding_box_widget.xml new file mode 100644 index 000000000..199c2a111 --- /dev/null +++ b/src/FeaturesPlugin/bounding_box_widget.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/src/FeaturesPlugin/create_bounding_box_widget.xml b/src/FeaturesPlugin/create_bounding_box_widget.xml new file mode 100644 index 000000000..39e494f92 --- /dev/null +++ b/src/FeaturesPlugin/create_bounding_box_widget.xml @@ -0,0 +1,21 @@ + + + + + + + + + + diff --git a/src/FeaturesPlugin/doc/FeaturesPlugin.rst b/src/FeaturesPlugin/doc/FeaturesPlugin.rst index 23cfb1f5c..34e8fea42 100644 --- a/src/FeaturesPlugin/doc/FeaturesPlugin.rst +++ b/src/FeaturesPlugin/doc/FeaturesPlugin.rst @@ -12,6 +12,7 @@ Features plug-in provides a set of common topological operations. It implements booleanOperations.rst angularCopyFeature.rst + boundingBoxFeature.rst chamferFeature.rst copyFeature.rst defeaturingFeature.rst diff --git a/src/FeaturesPlugin/doc/TUI_boundingBoxFeature.rst b/src/FeaturesPlugin/doc/TUI_boundingBoxFeature.rst new file mode 100644 index 000000000..bb73b2234 --- /dev/null +++ b/src/FeaturesPlugin/doc/TUI_boundingBoxFeature.rst @@ -0,0 +1,11 @@ + + .. _tui_create_Bounding_Box: + +Create bounding box +=================== + +.. literalinclude:: examples/create_bounding_box.py + :linenos: + :language: python + +:download:`Download this script ` diff --git a/src/FeaturesPlugin/doc/boundingBoxFeature.rst b/src/FeaturesPlugin/doc/boundingBoxFeature.rst new file mode 100644 index 000000000..9a1222d73 --- /dev/null +++ b/src/FeaturesPlugin/doc/boundingBoxFeature.rst @@ -0,0 +1,51 @@ +.. |boundingBox.icon| image:: images/bounding.png + +Bounding box +============ + +The **Bounding box** feature displays the bounding box of sub-elements of a geometrical object (shape). + +The property panel displays the coordinates of inferior (**Min**) and superior (**Max**) points. +the resulting bounding box can be created via a dedicated check-box **Create Box**. If this last is checked corresponding result and feature would be created. + +If the check-box **Create Box** isn't checked, **Apply** button does not generate any result and has the same effect as **Cancel** for this feature. + +To display the bounding box in the active part: + +#. select in the Main Menu *Inspection - > Bounding box* item or +#. click |boundingBox.icon| **Bounding box** button in the toolbar + +Coordinates of the two points (inferior and superior) of the bounding box can be displayed for a selected object in the property panel : + +.. figure:: images/boundingBoxPropertyPanel.png + :align: center + + Bounding Box + + +Input fields: + +- **Object** contains object selected in 3D OCC viewer or object browser. +- **Create box** check-box allow the creation of the bounding box (result and feature). + +Note, the coordinates of two points displayed can be selected. + +**TUI Command**: + +.. py:function:: model.getBoundingBox(Part_doc, shape) + + :param part: The current part object. + :param object: A shape in format *model.selection("Type", shape)*. + :return: Created bounding box. + +Result +"""""" + +Result of **Bounding box** where **Create box** is checked. + +.. figure:: images/BoundingBoxResult.png + :align: center + + Object selected + +**See Also** a sample TUI Script of :ref:`tui_create_Bounding_Box` operation. diff --git a/src/FeaturesPlugin/doc/examples/create_bounding_box.py b/src/FeaturesPlugin/doc/examples/create_bounding_box.py new file mode 100644 index 000000000..d904006ae --- /dev/null +++ b/src/FeaturesPlugin/doc/examples/create_bounding_box.py @@ -0,0 +1,13 @@ +from salome.shaper import model +import os + +model.begin() +file_path = os.path.join(os.getenv("DATA_DIR"),"Shapes","Step","screw.step") +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 +BoundingBox_1 = model.getBoundingBox(Part_1_doc, model.selection("SOLID", "screw_1")) +model.end() diff --git a/src/FeaturesPlugin/doc/images/BoundingBoxResult.png b/src/FeaturesPlugin/doc/images/BoundingBoxResult.png new file mode 100644 index 000000000..89eb1278d Binary files /dev/null and b/src/FeaturesPlugin/doc/images/BoundingBoxResult.png differ diff --git a/src/FeaturesPlugin/doc/images/bounding.png b/src/FeaturesPlugin/doc/images/bounding.png new file mode 100644 index 000000000..5a77a4542 Binary files /dev/null and b/src/FeaturesPlugin/doc/images/bounding.png differ diff --git a/src/FeaturesPlugin/doc/images/boundingBoxPropertyPanel.png b/src/FeaturesPlugin/doc/images/boundingBoxPropertyPanel.png new file mode 100644 index 000000000..0da9ddae8 Binary files /dev/null and b/src/FeaturesPlugin/doc/images/boundingBoxPropertyPanel.png differ 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 2ee033977..7fb18f31f 100644 --- a/src/FeaturesPlugin/plugin-Features.xml +++ b/src/FeaturesPlugin/plugin-Features.xml @@ -183,6 +183,14 @@ icon="icons/Features/geometryCalculation.png" helpfile="geometryCalculationFeature.html" abort_confirmation="false"> + + + + + + diff --git a/src/GeomAlgoAPI/CMakeLists.txt b/src/GeomAlgoAPI/CMakeLists.txt index 0aaebb219..e3ea735fb 100644 --- a/src/GeomAlgoAPI/CMakeLists.txt +++ b/src/GeomAlgoAPI/CMakeLists.txt @@ -89,6 +89,7 @@ SET(PROJECT_HEADERS GeomAlgoAPI_Chamfer.h GeomAlgoAPI_Defeaturing.h GeomAlgoAPI_GeometryCalculation.h + GeomAlgoAPI_BoundingBox.h ) SET(PROJECT_SOURCES @@ -157,6 +158,7 @@ SET(PROJECT_SOURCES GeomAlgoAPI_Chamfer.cpp GeomAlgoAPI_Defeaturing.cpp GeomAlgoAPI_GeometryCalculation.cpp + GeomAlgoAPI_BoundingBox.cpp ) SET(PROJECT_LIBRARIES diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_BoundingBox.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_BoundingBox.cpp new file mode 100644 index 000000000..856b2eb4d --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_BoundingBox.cpp @@ -0,0 +1,395 @@ +// 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 +//======================================================================= +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; +} + +//======================================================================= +// function : 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 = "GetBoundingBox : 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..010c3a30b --- /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/PythonAPI/model/features/__init__.py b/src/PythonAPI/model/features/__init__.py index 84b7b6562..81ba70cc0 100644 --- a/src/PythonAPI/model/features/__init__.py +++ b/src/PythonAPI/model/features/__init__.py @@ -30,7 +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 getPointCoordinates, getGeometryCalculation +from FeaturesAPI import getPointCoordinates, getGeometryCalculation, getBoundingBox from FeaturesAPI import addRemoveResults from FeaturesAPI import addCopy, addImportResult from FeaturesAPI import addDefeaturing