From 114b72cd99a3a4be9e851be1c4b271b554808897 Mon Sep 17 00:00:00 2001 From: Clarisse Genrault Date: Tue, 21 Jun 2016 15:23:48 +0200 Subject: [PATCH] Add the primitive 3D "Box". --- src/GeomAlgoAPI/CMakeLists.txt | 8 + src/GeomAlgoAPI/GeomAlgoAPI.i | 4 + src/GeomAlgoAPI/GeomAlgoAPI_Box.cpp | 94 +++++++++++ src/GeomAlgoAPI/GeomAlgoAPI_Box.h | 44 +++++ src/GeomAlgoAPI/GeomAlgoAPI_BoxPoints.cpp | 65 ++++++++ src/GeomAlgoAPI/GeomAlgoAPI_BoxPoints.h | 38 +++++ src/GeomAlgoAPI/GeomAlgoAPI_swig.h | 6 +- src/PrimitivesPlugin/CMakeLists.txt | 50 ++++++ src/PrimitivesPlugin/PrimitivesPlugin.h | 20 +++ src/PrimitivesPlugin/PrimitivesPlugin_Box.cpp | 153 ++++++++++++++++++ src/PrimitivesPlugin/PrimitivesPlugin_Box.h | 108 +++++++++++++ .../PrimitivesPlugin_Plugin.cpp | 37 +++++ .../PrimitivesPlugin_Plugin.h | 29 ++++ src/PrimitivesPlugin/Test/APIDirectTestBox.py | 27 ++++ src/PrimitivesPlugin/Test/UnitTestBox.py | 150 +++++++++++++++++ src/PrimitivesPlugin/box_widget.xml | 55 +++++++ src/PrimitivesPlugin/icons/box.png | Bin 0 -> 405 bytes src/PrimitivesPlugin/icons/box_2pt_32x32.png | Bin 0 -> 2196 bytes src/PrimitivesPlugin/icons/box_dxyz_32x32.png | Bin 0 -> 2254 bytes src/PrimitivesPlugin/icons/point.png | Bin 0 -> 486 bytes src/PrimitivesPlugin/plugin-Primitives.xml | 13 ++ 21 files changed, 900 insertions(+), 1 deletion(-) create mode 100644 src/GeomAlgoAPI/GeomAlgoAPI_Box.cpp create mode 100644 src/GeomAlgoAPI/GeomAlgoAPI_Box.h create mode 100644 src/GeomAlgoAPI/GeomAlgoAPI_BoxPoints.cpp create mode 100644 src/GeomAlgoAPI/GeomAlgoAPI_BoxPoints.h create mode 100644 src/PrimitivesPlugin/CMakeLists.txt create mode 100644 src/PrimitivesPlugin/PrimitivesPlugin.h create mode 100644 src/PrimitivesPlugin/PrimitivesPlugin_Box.cpp create mode 100644 src/PrimitivesPlugin/PrimitivesPlugin_Box.h create mode 100644 src/PrimitivesPlugin/PrimitivesPlugin_Plugin.cpp create mode 100644 src/PrimitivesPlugin/PrimitivesPlugin_Plugin.h create mode 100644 src/PrimitivesPlugin/Test/APIDirectTestBox.py create mode 100644 src/PrimitivesPlugin/Test/UnitTestBox.py create mode 100644 src/PrimitivesPlugin/box_widget.xml create mode 100644 src/PrimitivesPlugin/icons/box.png create mode 100644 src/PrimitivesPlugin/icons/box_2pt_32x32.png create mode 100644 src/PrimitivesPlugin/icons/box_dxyz_32x32.png create mode 100755 src/PrimitivesPlugin/icons/point.png create mode 100644 src/PrimitivesPlugin/plugin-Primitives.xml diff --git a/src/GeomAlgoAPI/CMakeLists.txt b/src/GeomAlgoAPI/CMakeLists.txt index 7d05409ac..ee42e2a90 100644 --- a/src/GeomAlgoAPI/CMakeLists.txt +++ b/src/GeomAlgoAPI/CMakeLists.txt @@ -39,6 +39,10 @@ SET(PROJECT_HEADERS GeomAlgoAPI_WireBuilder.h GeomAlgoAPI_Sewing.h GeomAlgoAPI_ShapeBuilder.h + GeomAlgoAPI_DirectAPI.h + GeomAlgoAPI_Exception.h + GeomAlgoAPI_Box.h + GeomAlgoAPI_BoxPoints.h GeomAlgoAPI_XAOExport.h GeomAlgoAPI_XAOImport.h ) @@ -76,6 +80,10 @@ SET(PROJECT_SOURCES GeomAlgoAPI_WireBuilder.cpp GeomAlgoAPI_Sewing.cpp GeomAlgoAPI_ShapeBuilder.cpp + GeomAlgoAPI_DirectAPI.cpp + GeomAlgoAPI_Exception.cpp + GeomAlgoAPI_Box.cpp + GeomAlgoAPI_BoxPoints.cpp GeomAlgoAPI_XAOExport.cpp GeomAlgoAPI_XAOImport.cpp ) diff --git a/src/GeomAlgoAPI/GeomAlgoAPI.i b/src/GeomAlgoAPI/GeomAlgoAPI.i index c6d4d7953..9391a720c 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI.i +++ b/src/GeomAlgoAPI/GeomAlgoAPI.i @@ -33,6 +33,8 @@ %shared_ptr(GeomAlgoAPI_ShapeBuilder) %shared_ptr(GeomAlgoAPI_Translation) %shared_ptr(GeomAlgoAPI_Transform) +%shared_ptr(GeomAlgoAPI_Box) +%shared_ptr(GeomAlgoAPI_BoxPoints) // all supported interfaces %include "GeomAlgoAPI_MakeShape.h" @@ -66,6 +68,8 @@ %include "GeomAlgoAPI_WireBuilder.h" %include "GeomAlgoAPI_Sewing.h" %include "GeomAlgoAPI_ShapeBuilder.h" +%include "GeomAlgoAPI_Exception.h" +%include "GeomAlgoAPI_DirectAPI.h" %typemap(out) std::list< std::shared_ptr< GeomAPI_Shape > >::value_type & { $result = SWIG_NewPointerObj(SWIG_as_voidptr(new std::shared_ptr(*$1)), $descriptor(std::shared_ptr *), SWIG_POINTER_OWN | 0 ); diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Box.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_Box.cpp new file mode 100644 index 000000000..ee03a2224 --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Box.cpp @@ -0,0 +1,94 @@ +// Copyright (C) 2014-2016 CEA/DEN, EDF R&D + +// File: GeomAlgoAPI_Box.cpp +// Created: 10 Mar 2016 +// Author: Clarisse Genrault (CEA) + +#include + +#include +#include + +//================================================================================================= +GeomAlgoAPI_Box::GeomAlgoAPI_Box() +{ +} + +//================================================================================================= +GeomAlgoAPI_Box::GeomAlgoAPI_Box(const double theDx, const double theDy, const double theDz) +{ + myDx = theDx; + myDy = theDy; + myDz = theDz; +} + +//================================================================================================= +bool GeomAlgoAPI_Box::check() +{ + if (myDx < Precision::Confusion()) { + myError = "Box builder with dimensions :: Dx is null."; + return false; + } else if (myDy < Precision::Confusion()) { + myError = "Box builder with dimensions :: Dy is null."; + return false; + } else if (myDz < Precision::Confusion()) { + myError = "Box builder with dimensions :: Dz is null."; + return false; + } + return true; +} + +//================================================================================================= +void GeomAlgoAPI_Box::build() +{ + myCreatedFaces.clear(); + + // Construct the box + BRepPrimAPI_MakeBox *aBoxMaker = new BRepPrimAPI_MakeBox(myDx, myDy, myDz); + aBoxMaker->Build(); + + // Test the algorithm + if (!aBoxMaker->IsDone()) { + myError = "Box builder with dimensions :: algorithm failed."; + return; + } + + TopoDS_Shape aResult = aBoxMaker->Shape(); + std::shared_ptr aShape(new GeomAPI_Shape()); + aShape->setImpl(new TopoDS_Shape(aResult)); + setShape(aShape); + + // Test on the shapes + if (!aShape.get() || aShape->isNull()) { + myError = "Box builder with dimensions :: resulting shape is null."; + return; + } + + setImpl(aBoxMaker); + + setDone(true); +} + +//================================================================================================= +void GeomAlgoAPI_Box::prepareNamingFaces() +{ + BRepPrimAPI_MakeBox aBoxMaker = impl(); + std::shared_ptr aShapeFront(new GeomAPI_Shape); + aShapeFront->setImpl(new TopoDS_Shape(aBoxMaker.FrontFace())); + myCreatedFaces["Front"] = aShapeFront; + std::shared_ptr aShapeBack(new GeomAPI_Shape); + aShapeBack->setImpl(new TopoDS_Shape(aBoxMaker.BackFace())); + myCreatedFaces["Back"] = aShapeBack; + std::shared_ptr aShapeTop(new GeomAPI_Shape); + aShapeTop->setImpl(new TopoDS_Shape(aBoxMaker.TopFace())); + myCreatedFaces["Top"] = aShapeTop; + std::shared_ptr aShapeBottom(new GeomAPI_Shape); + aShapeBottom->setImpl(new TopoDS_Shape(aBoxMaker.BottomFace())); + myCreatedFaces["Bottom"] = aShapeBottom; + std::shared_ptr aShapeLeft(new GeomAPI_Shape); + aShapeLeft->setImpl(new TopoDS_Shape(aBoxMaker.LeftFace())); + myCreatedFaces["Left"] = aShapeLeft; + std::shared_ptr aShapeRight(new GeomAPI_Shape); + aShapeRight->setImpl(new TopoDS_Shape(aBoxMaker.RightFace())); + myCreatedFaces["Right"] = aShapeRight; +} diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Box.h b/src/GeomAlgoAPI/GeomAlgoAPI_Box.h new file mode 100644 index 000000000..23bcb8d35 --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Box.h @@ -0,0 +1,44 @@ +// Copyright (C) 2014-2016 CEA/DEN, EDF R&D + +// File: GeomAlgoAPI_Box.h +// Created: 17 Mar 2016 +// Author: Clarisse Genrault (CEA) + +#ifndef GeomAlgoAPI_Box_H_ +#define GeomAlgoAPI_Box_H_ + +#include +#include + +/**\class GeomAlgoAPI_Box + * \ingroup DataAlgo + * \brief Allows to create Box Primitives + */ +class GeomAlgoAPI_Box : public GeomAlgoAPI_MakeShape +{ + public: + GEOMALGOAPI_EXPORT GeomAlgoAPI_Box(); + + /// Creates a box using the dimensions. + /// \param theDx The dimension on X + /// \param theDy The dimension on Y + /// \param theDz The dimension on Z + GEOMALGOAPI_EXPORT GeomAlgoAPI_Box(const double theDx, const double theDy, const double theDz); + + /// Checks if each dimension "Dx", Dy" and "Dz" for the box construction is OK. + GEOMALGOAPI_EXPORT bool check(); + + /// Builds the box with the dimensions "Dx", "Dy" and "Dz". + GEOMALGOAPI_EXPORT void build(); + + /// Prepare the naming (redifined because it is specific for a box). + GEOMALGOAPI_EXPORT void prepareNamingFaces(); + + private: + double myDx; /// Dimension on X to create a box. + double myDy; /// Dimension on Y to create a box. + double myDz; /// Dimension Z to create a box. +}; + + +#endif diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_BoxPoints.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_BoxPoints.cpp new file mode 100644 index 000000000..dcfd835c5 --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_BoxPoints.cpp @@ -0,0 +1,65 @@ +// Copyright (C) 2014-2016 CEA/DEN, EDF R&D + +// File: GeomAlgoAPI_BoxPoints.cpp +// Created: 17 Mar 2016 +// Author: Clarisse Genrault (CEA) + +#include + +#include +#include + +#include + +//================================================================================================= +GeomAlgoAPI_BoxPoints::GeomAlgoAPI_BoxPoints(std::shared_ptr theFirstPoint, + std::shared_ptr theSecondPoint) +:GeomAlgoAPI_Box() +{ + myFirstPoint = theFirstPoint; + mySecondPoint = theSecondPoint; +} + +//================================================================================================= +bool GeomAlgoAPI_BoxPoints::check() +{ + // The distance between myFirstPoint and mySecondPoint must not be null. + if (myFirstPoint->distance(mySecondPoint) < Precision::Confusion()) + return false; + return true; +} + +//================================================================================================= +void GeomAlgoAPI_BoxPoints::build() +{ + myCreatedFaces.clear(); + + const gp_Pnt& aFirstPoint = myFirstPoint->impl(); + const gp_Pnt& aSecondPoint = mySecondPoint->impl(); + + // Construct the box + BRepPrimAPI_MakeBox *aBoxMaker = new BRepPrimAPI_MakeBox(aFirstPoint, aSecondPoint); + aBoxMaker->Build(); + + // Test the algorithm + if(!aBoxMaker->IsDone()) { + myError = "Box builder with two points :: algorithm failed."; + return; + } + + TopoDS_Shape aResult = aBoxMaker->Shape(); + + std::shared_ptr aShape(new GeomAPI_Shape()); + aShape->setImpl(new TopoDS_Shape(aResult)); + setShape(aShape); + + // Tests on the shape + if (!aShape.get() || aShape->isNull()) { + myError = "Box builder with two points :: resulting shape is null."; + return; + } + + setImpl(aBoxMaker); + + setDone(true); +} diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_BoxPoints.h b/src/GeomAlgoAPI/GeomAlgoAPI_BoxPoints.h new file mode 100644 index 000000000..159715f21 --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_BoxPoints.h @@ -0,0 +1,38 @@ +// Copyright (C) 2014-2016 CEA/DEN, EDF R&D + +// File: GeomAlgoAPI_BoxPoints.h +// Created: 17 Mar 2016 +// Author: Clarisse Genrault (CEA) + +#ifndef GeomAlgoAPI_BoxPoints_H_ +#define GeomAlgoAPI_BoxPoints_H_ + +#include +#include + +/**\class GeomAlgoAPI_BoxPoints + * \ingroup DataAlgo + * \brief Allows to create Box Primitives using the two points that defined a diagonal. + */ +class GeomAlgoAPI_BoxPoints : public GeomAlgoAPI_Box +{ + public: + /// Creates a box using the two points that defined a diagonal. + /// \param theFirstPoint One extermity of the diagonal + /// \param theSecondPoint The other extremity of the diagonal + GEOMALGOAPI_EXPORT GeomAlgoAPI_BoxPoints(std::shared_ptr theFirstPoint, + std::shared_ptr theSecondPoint); + + /// \return true if the data of the construction of the box were correct. + GEOMALGOAPI_EXPORT bool check(); + + /// Builds the box. + GEOMALGOAPI_EXPORT void build(); + + private: + std::shared_ptr myFirstPoint; /// First point to create a box. + std::shared_ptr mySecondPoint; /// Second point to create a box. +}; + + +#endif diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_swig.h b/src/GeomAlgoAPI/GeomAlgoAPI_swig.h index 226338bf4..b742d88e8 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_swig.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_swig.h @@ -40,7 +40,11 @@ #include "GeomAlgoAPI_Pipe.h" #include "GeomAlgoAPI_WireBuilder.h" #include "GeomAlgoAPI_Sewing.h" - #include "GeomAlgoAPI_ShapeBuilder.h" + #include "GeomAlgoAPI_ShapeBuilder.h" + #include "GeomAlgoAPI_Exception.h" + #include "GeomAlgoAPI_DirectAPI.h" + #include "GeomAlgoAPI_Box.h" + #include "GeomAlgoAPI_BoxPoints.h" #include #include diff --git a/src/PrimitivesPlugin/CMakeLists.txt b/src/PrimitivesPlugin/CMakeLists.txt new file mode 100644 index 000000000..86a5f1683 --- /dev/null +++ b/src/PrimitivesPlugin/CMakeLists.txt @@ -0,0 +1,50 @@ +# Copyright (C) 2015-2016 CEA/DEN, EDF R&D + +# File: CMakeLists.txt +# Created: 07 Apr 2016 +# Author: CEA (delegation to Alyotech) + +INCLUDE(UnitTest) + +SET(PROJECT_HEADERS + PrimitivesPlugin.h + PrimitivesPlugin_Plugin.h + PrimitivesPlugin_Box.h +) + +SET(PROJECT_SOURCES + PrimitivesPlugin_Plugin.cpp + PrimitivesPlugin_Box.cpp +) + +SET(XML_RESOURCES + plugin-Primitives.xml + box_widget.xml +) + +INCLUDE_DIRECTORIES( + ../ModelAPI + ../GeomAPI + ../GeomAlgoAPI + ../Events +) + +SET(PROJECT_LIBRARIES + Events + ModelAPI + GeomAPI + GeomAlgoAPI +) + +ADD_DEFINITIONS(-DPRIMITIVESPLUGIN_EXPORTS) +ADD_LIBRARY(PrimitivesPlugin MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${XML_RESOURCES}) +TARGET_LINK_LIBRARIES(PrimitivesPlugin ${PROJECT_LIBRARIES}) + +INSTALL(TARGETS PrimitivesPlugin DESTINATION ${SHAPER_INSTALL_PLUGIN_FILES}) +INSTALL(FILES ${XML_RESOURCES} DESTINATION ${SHAPER_INSTALL_XML_RESOURCES}) +INSTALL(DIRECTORY icons/ DESTINATION ${SHAPER_INSTALL_XML_RESOURCES}/icons/Primitives) + +ADD_UNIT_TESTS(UnitTestBox.py + APIDirectTestBox.py +) + diff --git a/src/PrimitivesPlugin/PrimitivesPlugin.h b/src/PrimitivesPlugin/PrimitivesPlugin.h new file mode 100644 index 000000000..a2996d38d --- /dev/null +++ b/src/PrimitivesPlugin/PrimitivesPlugin.h @@ -0,0 +1,20 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> + +#ifndef PRIMITIVESPLUGIN_H +#define PRIMITIVESPLUGIN_H + +#if defined PRIMITIVESPLUGIN_EXPORTS +#if defined WIN32 +#define PRIMITIVESPLUGIN_EXPORT __declspec( dllexport ) +#else +#define PRIMITIVESPLUGIN_EXPORT +#endif +#else +#if defined WIN32 +#define PRIMITIVESPLUGIN_EXPORT __declspec( dllimport ) +#else +#define PRIMITIVESPLUGIN_EXPORT +#endif +#endif + +#endif diff --git a/src/PrimitivesPlugin/PrimitivesPlugin_Box.cpp b/src/PrimitivesPlugin/PrimitivesPlugin_Box.cpp new file mode 100644 index 000000000..734d87d8f --- /dev/null +++ b/src/PrimitivesPlugin/PrimitivesPlugin_Box.cpp @@ -0,0 +1,153 @@ +// Copyright (C) 2014-2016 CEA/DEN, EDF R&D + +// File: PrimitivesPlugin_Box.cpp +// Created: 10 Mar 2016 +// Author: Clarisse Genrault (CEA) + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +//================================================================================================= +PrimitivesPlugin_Box::PrimitivesPlugin_Box() // Nothing to do during instantiation +{ +} + +//================================================================================================= +void PrimitivesPlugin_Box::initAttributes() +{ + data()->addAttribute(PrimitivesPlugin_Box::METHOD(), ModelAPI_AttributeString::typeId()); + + data()->addAttribute(PrimitivesPlugin_Box::DX(), ModelAPI_AttributeDouble::typeId()); + data()->addAttribute(PrimitivesPlugin_Box::DY(), ModelAPI_AttributeDouble::typeId()); + data()->addAttribute(PrimitivesPlugin_Box::DZ(), ModelAPI_AttributeDouble::typeId()); + + data()->addAttribute(PrimitivesPlugin_Box::POINT_FIRST(), ModelAPI_AttributeSelection::typeId()); + data()->addAttribute(PrimitivesPlugin_Box::POINT_SECOND(), ModelAPI_AttributeSelection::typeId()); +} + +//================================================================================================= +void PrimitivesPlugin_Box::execute() +{ + AttributeStringPtr aMethodTypeAttr = string(PrimitivesPlugin_Box::METHOD()); + std::string aMethodType = aMethodTypeAttr->value(); + + if (aMethodType == "BoxByDimensions") + createBoxByDimensions(); + + if (aMethodType == "BoxByTwoPoints") + createBoxByTwoPoints(); +} + +//================================================================================================= +void PrimitivesPlugin_Box::createBoxByDimensions() +{ + double aDx = real(PrimitivesPlugin_Box::DX())->value(); + double aDy = real(PrimitivesPlugin_Box::DY())->value(); + double aDz = real(PrimitivesPlugin_Box::DZ())->value(); + + std::shared_ptr aBoxAlgo(new GeomAlgoAPI_Box(aDx,aDy,aDz)); + + // These checks should be made to the GUI for the feature but the corresponding validator does not exist yet. + if (!aBoxAlgo->check()) { + // The error is not displayed in a popup window. It must be in the status bar. + setError(aBoxAlgo->getError(), false); + return; + } + + // Build the box + aBoxAlgo->build(); + + // Check if the creation of the box + if(!aBoxAlgo->isDone()) { + setError(aBoxAlgo->getError()); + return; + } + if(!aBoxAlgo->checkValid("Box builder with dimensions")) { + setError(aBoxAlgo->getError()); + return; + } + + int aResultIndex = 0; + ResultBodyPtr aResultBox = document()->createBody(data(), aResultIndex); + loadNamingDS(aBoxAlgo, aResultBox); + setResult(aResultBox, aResultIndex); +} + +//================================================================================================= +void PrimitivesPlugin_Box::createBoxByTwoPoints() +{ + AttributeSelectionPtr aRef1 = data()->selection(PrimitivesPlugin_Box::POINT_FIRST()); + AttributeSelectionPtr aRef2 = data()->selection(PrimitivesPlugin_Box::POINT_SECOND()); + + std::shared_ptr aBoxAlgo; + + if ((aRef1.get() != NULL) && (aRef2.get() != NULL)) { + GeomShapePtr aShape1 = aRef1->value(); + if (!aShape1.get()) //If we can't get the points directly, try getting them from the context + aShape1 = aRef1->context()->shape(); + GeomShapePtr aShape2 = aRef2->value(); + if (!aShape2.get()) + aShape2 = aRef2->context()->shape(); + if (aShape1 && aShape2){ + std::shared_ptr aFirstPoint = GeomAlgoAPI_PointBuilder::point(aShape1); + std::shared_ptr aSecondPoint = GeomAlgoAPI_PointBuilder::point(aShape2); + aBoxAlgo = std::shared_ptr(new GeomAlgoAPI_BoxPoints(aFirstPoint,aSecondPoint)); + } + } + + // These checks should be made to the GUI for the feature but the corresponding validator does not exist yet. + if (!aBoxAlgo->check()) { + // The error is not displayed in a popup window. It must be in the message console. + setError(aBoxAlgo->getError(), false); + 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(), false); + 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(), false); + return; + } + + int aResultIndex = 0; + ResultBodyPtr aResultBox = document()->createBody(data(), aResultIndex); + loadNamingDS(aBoxAlgo, aResultBox); + setResult(aResultBox, aResultIndex); +} + +//================================================================================================= +void PrimitivesPlugin_Box::loadNamingDS(std::shared_ptr theBoxAlgo, + std::shared_ptr theResultBox) +{ + // Load the result + theResultBox->store(theBoxAlgo->shape()); + + // Prepare the naming + theBoxAlgo->prepareNamingFaces(); + + // Insert to faces + int num = 1; + 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) { + std::shared_ptr aFace = (*it).second; + theResultBox->generated(aFace, (*it).first, num++); + } +} + diff --git a/src/PrimitivesPlugin/PrimitivesPlugin_Box.h b/src/PrimitivesPlugin/PrimitivesPlugin_Box.h new file mode 100644 index 000000000..7672d2fb8 --- /dev/null +++ b/src/PrimitivesPlugin/PrimitivesPlugin_Box.h @@ -0,0 +1,108 @@ +// Copyright (C) 2014-2016 CEA/DEN, EDF R&D + +// File: PrimitivesPlugin_Box.h +// Created: 10 Mar 2016 +// Author: Clarisse Genrault (CEA) + +#ifndef PrimitivesPlugin_Box_H_ +#define PrimitivesPlugin_Box_H_ + +#include +#include +#include +#include + +class GeomAPI_Shape; +class ModelAPI_ResultBody; + +/**\class PrimitivesPlugin_Box + * \ingroup Plugins + * \brief Feature for creation of a box primitive using various methods. + * + * Box creates a cuboid - Parallelepiped with 6 rectangular faces. It can be built via two + * methods : using two points that define a diagonal, or using 3 lengths that define the + * rectangular dimensions. + */ +class PrimitivesPlugin_Box : public ModelAPI_Feature +{ + public: + /// Box kind + inline static const std::string& ID() + { + static const std::string MY_BOX_ID("Box"); + return MY_BOX_ID; + } + + /// attribute name for creation method + inline static const std::string& METHOD() + { + static const std::string METHOD_ATTR("CreationMethod"); + return METHOD_ATTR; + } + + /// attribute name of first point + inline static const std::string& POINT_FIRST() + { + static const std::string MY_POINT_FIRST("FirstPoint"); + return MY_POINT_FIRST; + } + + /// attribute name of second point + inline static const std::string& POINT_SECOND() + { + static const std::string MY_POINT_SECOND("SecondPoint"); + return MY_POINT_SECOND; + } + + /// attribute first coordinate + inline static const std::string& DX() + { + static const std::string MY_DX("dx"); + return MY_DX; + } + + /// attribute second coordinate + inline static const std::string& DY() + { + static const std::string MY_DY("dy"); + return MY_DY; + } + + /// attribute third coordinate + inline static const std::string& DZ() + { + static const std::string MY_DZ("dz"); + return MY_DZ; + } + + /// Returns the kind of a feature + PRIMITIVESPLUGIN_EXPORT virtual const std::string& getKind() + { + static std::string MY_KIND = PrimitivesPlugin_Box::ID(); + return MY_KIND; + } + + /// Creates a new part document if needed + PRIMITIVESPLUGIN_EXPORT virtual void execute(); + + /// Request for initialization of data model of the feature: adding all attributes + PRIMITIVESPLUGIN_EXPORT virtual void initAttributes(); + + /// Use plugin manager for features creation + PrimitivesPlugin_Box(); + + private: + /// Load Naming data structure of the feature to the document + void loadNamingDS(std::shared_ptr theBoxAlgo, + std::shared_ptr theResultBox); + + ///Perform the creation of the box using two points defining a diagonal + void createBoxByTwoPoints(); + + ///Perform the creation of the box using three cordinates + void createBoxByDimensions(); + +}; + + +#endif diff --git a/src/PrimitivesPlugin/PrimitivesPlugin_Plugin.cpp b/src/PrimitivesPlugin/PrimitivesPlugin_Plugin.cpp new file mode 100644 index 000000000..b4281ea41 --- /dev/null +++ b/src/PrimitivesPlugin/PrimitivesPlugin_Plugin.cpp @@ -0,0 +1,37 @@ +// Copyright (C) 2014-2016 CEA/DEN, EDF R&D --> + +// File: PrimitivesPlugin_Plugin.hxx +// Created: 29 Mar 2016 +// Author: Clarisse Genrault (CEA) + +#include + +#include + +#include + +#include + +#include + +#include + +using namespace std; + +// the only created instance of this plugin +static PrimitivesPlugin_Plugin* MY_PRIMITIVES_INSTANCE = new PrimitivesPlugin_Plugin(); + +PrimitivesPlugin_Plugin::PrimitivesPlugin_Plugin() +{ + // register this plugin + ModelAPI_Session::get()->registerPlugin(this); +} + +FeaturePtr PrimitivesPlugin_Plugin::createFeature(string theFeatureID) +{ + if (theFeatureID == PrimitivesPlugin_Box::ID()) { + return FeaturePtr(new PrimitivesPlugin_Box); + } + // feature of such kind is not found + return FeaturePtr(); +} diff --git a/src/PrimitivesPlugin/PrimitivesPlugin_Plugin.h b/src/PrimitivesPlugin/PrimitivesPlugin_Plugin.h new file mode 100644 index 000000000..819913bfd --- /dev/null +++ b/src/PrimitivesPlugin/PrimitivesPlugin_Plugin.h @@ -0,0 +1,29 @@ +// Copyright (C) 2014-2016 CEA/DEN, EDF R&D --> + +// File: PrimitivesPlugin_Plugin.hxx +// Created: 29 Mar 2016 +// Author: Clarisse Genrault (CEA) + +#ifndef PrimitivesPlugin_Plugin_H_ +#define PrimitivesPlugin_Plugin_H_ + +#include "PrimitivesPlugin.h" +#include +#include + +/**\class PrimitivesPlugin_Plugin + * \ingroup Plugins + * \brief The main class managing Primitive Features as plugins. + */ +class PRIMITIVESPLUGIN_EXPORT PrimitivesPlugin_Plugin : public ModelAPI_Plugin +{ + public: + /// Creates the feature object of this plugin by the feature string ID + virtual FeaturePtr createFeature(std::string theFeatureID); + + public: + /// Default constructor + PrimitivesPlugin_Plugin(); +}; + +#endif diff --git a/src/PrimitivesPlugin/Test/APIDirectTestBox.py b/src/PrimitivesPlugin/Test/APIDirectTestBox.py new file mode 100644 index 000000000..247a3f82e --- /dev/null +++ b/src/PrimitivesPlugin/Test/APIDirectTestBox.py @@ -0,0 +1,27 @@ +from GeomAlgoAPI import GeomAlgoAPI_DirectAPI as shaperpy +from GeomAlgoAPI import GeomAlgoAPI_Exception as myExcept +from GeomAPI import GeomAPI_Pnt as pnt + +# Create a box with dimensions +try : + box1 = shaperpy.makeBox(5.,15.,5.) + +except myExcept,ec: + print ec.what() + +# Create a box with two points defining the diagonal +try : + pnt1 = pnt(0.,0.,0.) + pnt2 = pnt(10.,10.,10.) + box2 = shaperpy.makeBox(pnt1,pnt2) + +except myExcept,ec: + print ec.what() + + +# Create a box with null dimensions +try : + box3 = shaperpy.makeBox(0.,0.,0.) + +except myExcept,ec: + print ec.what() \ No newline at end of file diff --git a/src/PrimitivesPlugin/Test/UnitTestBox.py b/src/PrimitivesPlugin/Test/UnitTestBox.py new file mode 100644 index 000000000..3245a09c6 --- /dev/null +++ b/src/PrimitivesPlugin/Test/UnitTestBox.py @@ -0,0 +1,150 @@ +""" + UnitTestBox.py + Unit Test of PrimitivesPlugin_Box class + +class PrimitivesPlugin_Box : public ModelAPI_Feature + static const std::string MY_BOX_ID("Box"); + static const std::string METHOD_ATTR("CreationMethod"); + static const std::string MY_POINT_FIRST("FirstPoint"); + static const std::string MY_POINT_SECOND("SecondPoint"); + static const std::string MY_DX("dx"); + static const std::string MY_DY("dy"); + static const std::string MY_DZ("dz"); + + data()->addAttribute(METHOD(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(POINT_FIRST(), ModelAPI_AttributeSelection::typeId()); + data()->addAttribute(POINT_SECOND(), ModelAPI_AttributeSelection::typeId()); + data()->addAttribute(DX(), ModelAPI_AttributeDouble::typeId()); + data()->addAttribute(DY(), ModelAPI_AttributeDouble::typeId()); + data()->addAttribute(DZ(), ModelAPI_AttributeDouble::typeId()); + +""" + +#========================================================================= +# Initialization of the test +#========================================================================= +from ModelAPI import * +from GeomDataAPI import * +from GeomAlgoAPI import * +from GeomAPI import * +import math + +__updated__ = "2016-01-04" + +aSession = ModelAPI_Session.get() +aDocument = aSession.moduleDocument() +# Create a part for creation of a box +aSession.startOperation() +aPartFeature = aDocument.addFeature("Part") +aSession.finishOperation() +assert (len(aPartFeature.results()) == 1) + +aPartResult = modelAPI_ResultPart(aPartFeature.firstResult()) +aPart = aPartResult.partDoc() +#========================================================================= +# Creation of a Box by coordinates +#========================================================================= +aSession.startOperation() +aBoxBy3Dims = aPart.addFeature("Box") +assert (aBoxBy3Dims.getKind() == "Box") + +aBoxBy3Dims.string("CreationMethod").setValue("BoxByDimensions") +aBoxBy3Dims.real("dx").setValue(1.6) +aBoxBy3Dims.real("dy").setValue(1.6) +aBoxBy3Dims.real("dz").setValue(1.6) +aBoxBy3Dims.execute() + +# Check box results +assert (len(aBoxBy3Dims.results()) > 0) +aBoxResult = modelAPI_ResultBody(aBoxBy3Dims.firstResult()) +assert (aBoxResult is not None) + +# Check box volume +aRefVolume = 1.6 * 1.6 * 1.6 +aResVolume = GeomAlgoAPI_ShapeTools_volume(aBoxResult.shape()) +assert (math.fabs(aResVolume - aRefVolume) < 10 ** -5) + + +#Check the naming by selecting a face and making a plane out of it +aPlaneTop = aPart.addFeature("Plane") +assert(aPlaneTop.getKind() == "Plane") +aPlaneTop.string("CreationMethod").setValue("PlaneByFaceAndDistance") +aSelectionAttr = aPlaneTop.selection("planeFace") +aSelectionAttr.selectSubShape("face", "Box_1_1/Top_1") +aPlaneTop.real("distance").setValue(0.4) +aPlaneTop.execute() + +#The face should be at 1.6, so the plane should be at 1.6 + 0.4 = 2. +aRefPlaneTopLocation = 2. + +#location() is a method from GeomAPI_Face that returns a GeomAPI_Pnt, from which we can extract the z coordinate +aPlaneTopResult = aPlaneTop.firstResult() +aPlaneTopFace = GeomAPI_Face(aPlaneTopResult.shape()) +aPlaneTestLocation = aPlaneTopFace.getPlane() +aPlaneLocation = aPlaneTestLocation.location().z() +assert(math.fabs(aPlaneLocation - aRefPlaneTopLocation) < 10 ** -5) + +aSession.finishOperation() + +#========================================================================= +# Creation of a Box by two points +#========================================================================= + +aSession.startOperation() + +#Create two points +aPoint1 = aPart.addFeature("Point") +aPoint2 = aPart.addFeature("Point") +assert(aPoint1.getKind() == "Point") +assert(aPoint2.getKind() == "Point") +aPoint1.real("x").setValue(2.0) +aPoint1.real("y").setValue(2.0) +aPoint1.real("z").setValue(2.0) +aPoint2.real("x").setValue(2.5) +aPoint2.real("y").setValue(2.5) +aPoint2.real("z").setValue(2.5) +aPoint1.execute() +aPoint2.execute() +aPoint1Result = aPoint1.firstResult() +aPoint2Result = aPoint2.firstResult() +aPoint1Vertex = aPoint1Result.shape() +aPoint2Vertex = aPoint2Result.shape() + +aBoxBy2Pts = aPart.addFeature("Box") +assert (aBoxBy2Pts.getKind() == "Box") +aBoxBy2Pts.string("CreationMethod").setValue("BoxByTwoPoints") +aBoxBy2Pts.selection("FirstPoint").setValue(aPoint1Result, aPoint1Vertex) +aBoxBy2Pts.selection("SecondPoint").setValue(aPoint2Result, aPoint2Vertex) +aBoxBy2Pts.execute() + +# Check box volume +aBoxResult2 = modelAPI_ResultBody(aBoxBy2Pts.firstResult()) +aRefVolume2 = 0.5 * 0.5 * 0.5 +aResVolume2 = GeomAlgoAPI_ShapeTools_volume(aBoxResult2.shape()) +assert (math.fabs(aResVolume2 - aRefVolume2) < 10 ** -5) + +#Check the naming by selecting a face and making a plane out of it +aPlaneRight = aPart.addFeature("Plane") +assert(aPlaneRight.getKind() == "Plane") +aPlaneRight.string("CreationMethod").setValue("PlaneByFaceAndDistance") +aSelectionAttr = aPlaneRight.selection("planeFace") +aSelectionAttr.selectSubShape("face", "Box_2_1/Right_1") +aPlaneRight.real("distance").setValue(0.5) +aPlaneRight.execute() + +#The face should be at 2.5, so the plane should be at 2.5 + 0.5 = 3. +aRefPlaneRightLocation = 3. + +#location() is a method from GeomAPI_Face that returns a GeomAPI_Pnt, +#from which we can extract the y coordinate +aPlaneRightResult = aPlaneRight.firstResult() +aPlaneRightFace = GeomAPI_Face(aPlaneRightResult.shape()) +aPlaneTestLocation = aPlaneRightFace.getPlane() +aPlaneLocation = aPlaneTestLocation.location().y() +assert(math.fabs(aPlaneLocation - aRefPlaneRightLocation) < 10 ** -5) + +aSession.finishOperation() + +#========================================================================= +# End of test +#========================================================================= diff --git a/src/PrimitivesPlugin/box_widget.xml b/src/PrimitivesPlugin/box_widget.xml new file mode 100644 index 000000000..9da6966c1 --- /dev/null +++ b/src/PrimitivesPlugin/box_widget.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/PrimitivesPlugin/icons/box.png b/src/PrimitivesPlugin/icons/box.png new file mode 100644 index 0000000000000000000000000000000000000000..104a1edde755dae03a8348b40b4667b0e70d860c GIT binary patch literal 405 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 literal 0 HcmV?d00001 diff --git a/src/PrimitivesPlugin/icons/point.png b/src/PrimitivesPlugin/icons/point.png new file mode 100755 index 0000000000000000000000000000000000000000..96149ebf38492cc735949b52e2f0233e28cb8a6d GIT binary patch literal 486 zcmV@P)r|oM}L_)mw{R1YGm^+A96WV99nutv- zVj-INF|ZiKU@_R5#v)C-86+kN|AOEdbV9YhW8gJaRg${NH=KL#Ip6)xmrF_LBtjjr z|3e_sDj9b(NstQ+>cTU_+`22|uA6(=?17V-UI9!`tk$>o5-Cqnx_y4*Rn+39gbTlz zJN!bBR6hwf?Z(~AYJlyr^l`%VHUb=X(+AGz!w)3Fk zSiPQ;@{#~Ras<$zlk&PhZeU(StdUTkfFuFQ7}`d%jbuZJ0*D2eAq_N7RTq#XfH6Ng zyziItGkz&QBj_C9Nq{S`3Lsuv3VfPy6hFIM`pJVRs_O=3uQB)S8x!N+mJG@d{nobq zSe>WQO_%9AeF~Seq;Bqt`Q5ex0N}XO69Q&Q)dYk<3I;p(rQCUQZ%cuCk)(dvwzdL) ciH?`)9SSJ2sp2ZYhyVZp07*qoM6N<$f=AuWpa1{> literal 0 HcmV?d00001 diff --git a/src/PrimitivesPlugin/plugin-Primitives.xml b/src/PrimitivesPlugin/plugin-Primitives.xml new file mode 100644 index 000000000..22a4b366a --- /dev/null +++ b/src/PrimitivesPlugin/plugin-Primitives.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + -- 2.39.2