From: Clarisse Genrault Date: Fri, 16 Sep 2016 07:20:36 +0000 (+0200) Subject: Add primitive Sphere. X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=07e7474315356b82f35e486d3dcd1106d32dc7a0;p=modules%2Fshaper.git Add primitive Sphere. --- diff --git a/src/GeomAlgoAPI/CMakeLists.txt b/src/GeomAlgoAPI/CMakeLists.txt index 697f8012a..e762850e8 100644 --- a/src/GeomAlgoAPI/CMakeLists.txt +++ b/src/GeomAlgoAPI/CMakeLists.txt @@ -4,6 +4,7 @@ FIND_PACKAGE(SWIG REQUIRED) INCLUDE(${SWIG_USE_FILE}) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) +INCLUDE(UnitTest) SET(PROJECT_HEADERS GeomAlgoAPI.h @@ -42,6 +43,7 @@ SET(PROJECT_HEADERS GeomAlgoAPI_ShapeAPI.h GeomAlgoAPI_Exception.h GeomAlgoAPI_Box.h + GeomAlgoAPI_Sphere.h GeomAlgoAPI_XAOExport.h GeomAlgoAPI_XAOImport.h GeomAlgoAPI_Copy.h @@ -83,6 +85,7 @@ SET(PROJECT_SOURCES GeomAlgoAPI_ShapeAPI.cpp GeomAlgoAPI_Exception.cpp GeomAlgoAPI_Box.cpp + GeomAlgoAPI_Sphere.cpp GeomAlgoAPI_XAOExport.cpp GeomAlgoAPI_XAOImport.cpp GeomAlgoAPI_Copy.cpp @@ -149,3 +152,7 @@ ENDIF(WIN32) INSTALL(TARGETS _GeomAlgoAPI DESTINATION ${SHAPER_INSTALL_SWIG}) INSTALL(TARGETS GeomAlgoAPI DESTINATION ${SHAPER_INSTALL_BIN}) INSTALL(FILES ${SWIG_SCRIPTS} DESTINATION ${SHAPER_INSTALL_SWIG}) + +ADD_UNIT_TESTS(TestAPI_Box.py + TestAPI_Sphere.py +) diff --git a/src/GeomAlgoAPI/GeomAlgoAPI.i b/src/GeomAlgoAPI/GeomAlgoAPI.i index 7e6272505..4c416ac49 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI.i +++ b/src/GeomAlgoAPI/GeomAlgoAPI.i @@ -34,7 +34,7 @@ %shared_ptr(GeomAlgoAPI_Translation) %shared_ptr(GeomAlgoAPI_Transform) %shared_ptr(GeomAlgoAPI_Box) -%shared_ptr(GeomAlgoAPI_BoxPoints) +%shared_ptr(GeomAlgoAPI_Sphere) %shared_ptr(GeomAlgoAPI_Copy) // all supported interfaces diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeAPI.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeAPI.cpp index a2e1184e6..fc13554ed 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeAPI.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeAPI.cpp @@ -6,6 +6,7 @@ #include "GeomAlgoAPI_ShapeAPI.h" #include +#include #include #include @@ -56,4 +57,46 @@ namespace GeomAlgoAPI_ShapeAPI } return aBoxAlgo.shape(); } + + //========================================================================================================= + std::shared_ptr GeomAlgoAPI_ShapeAPI::makeSphere(const double theRadius) throw (GeomAlgoAPI_Exception) + { + std::shared_ptr anOrigin = std::shared_ptr(new GeomAPI_Pnt(0., 0., 0.)); + GeomAlgoAPI_Sphere aSphereAlgo(anOrigin, theRadius); + + if (!aSphereAlgo.check()) { + throw GeomAlgoAPI_Exception(aSphereAlgo.getError()); + } + + aSphereAlgo.build(); + + if(!aSphereAlgo.isDone()) { + throw GeomAlgoAPI_Exception(aSphereAlgo.getError()); + } + if (!aSphereAlgo.checkValid("Sphere builder with radius at origin")) { + throw GeomAlgoAPI_Exception(aSphereAlgo.getError()); + } + return aSphereAlgo.shape(); + } + + //========================================================================================================= + std::shared_ptr GeomAlgoAPI_ShapeAPI::makeSphere(std::shared_ptr theCenterPoint, + const double theRadius) throw (GeomAlgoAPI_Exception) + { + GeomAlgoAPI_Sphere aSphereAlgo(theCenterPoint, theRadius); + + if (!aSphereAlgo.check()) { + throw GeomAlgoAPI_Exception(aSphereAlgo.getError()); + } + + aSphereAlgo.build(); + + if(!aSphereAlgo.isDone()) { + throw GeomAlgoAPI_Exception(aSphereAlgo.getError()); + } + if (!aSphereAlgo.checkValid("Sphere builder with center and radius")) { + throw GeomAlgoAPI_Exception(aSphereAlgo.getError()); + } + return aSphereAlgo.shape(); + } } diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeAPI.h b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeAPI.h index 02ebef9dd..b5bf72755 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeAPI.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeAPI.h @@ -35,6 +35,18 @@ public: /// \return a shape static std::shared_ptr makeBox(std::shared_ptr theFirstPoint, std::shared_ptr theSecondPoint) throw (GeomAlgoAPI_Exception); + + /// Creates a sphere centered around the origin using a radius. + /// \param theRadius Radius of the sphere + /// \return a shape + static std::shared_ptr makeSphere(const double theRadius) throw (GeomAlgoAPI_Exception); + + /// Creates a sphere using a center and a radius. + /// \param theCenterPoint Center of the sphere + /// \param theRadius Radius of the sphere + /// \return a shape + static std::shared_ptr makeSphere(std::shared_ptr theCenterPoint, + const double theRadius) throw (GeomAlgoAPI_Exception); }; } #endif diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Sphere.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_Sphere.cpp new file mode 100644 index 000000000..68d4c1093 --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Sphere.cpp @@ -0,0 +1,67 @@ +// Copyright (C) 2014-2016 CEA/DEN, EDF R&D + +// File: GeomAlgoAPI_Sphere.cpp +// Created: 29 Mar 2016 +// Author: CEA (delegation to Alyotech) + +#include + +#include +#include + +//================================================================================================= +GeomAlgoAPI_Sphere::GeomAlgoAPI_Sphere() +{ +} + + +//================================================================================================= +GeomAlgoAPI_Sphere::GeomAlgoAPI_Sphere(std::shared_ptr theCenter, const double theRadius) +{ + myCenter = theCenter; + myRadius = theRadius; +} + +//================================================================================================= +bool GeomAlgoAPI_Sphere::check() +{ + if (myRadius < Precision::Confusion()) { + myError = "Sphere builder with center and radius :: radius is less than or equal to zero."; + return false; + } + return true; +} + +//================================================================================================= +void GeomAlgoAPI_Sphere::build() +{ + myCreatedFaces.clear(); + + // Convert the point given as argument to OCCT object + const gp_Pnt& aCenter = myCenter->impl(); + + // We need the OCCT sphere-making engine. And we need it as a regular pointer so we can add it to the list of MakeShape + BRepPrimAPI_MakeSphere *aSphereMaker = new BRepPrimAPI_MakeSphere(aCenter, myRadius); + aSphereMaker->Build(); //Let the OCCT sphere-maker make the sphere + + // Test the algorithm + if (!aSphereMaker->IsDone()) { + return; + } + + TopoDS_Shape aResult = aSphereMaker->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 = "Sphere builder with center and radius :: resulting shape is null."; + return; + } + + setImpl(aSphereMaker); + setBuilderType(OCCT_BRepBuilderAPI_MakeShape); + + setDone(true); +} diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Sphere.h b/src/GeomAlgoAPI/GeomAlgoAPI_Sphere.h new file mode 100644 index 000000000..b94f8eaf3 --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Sphere.h @@ -0,0 +1,39 @@ +// Copyright (C) 2014-2016 CEA/DEN, EDF R&D + +// File: GeomAlgoAPI_Sphere.h +// Created: 29 Mar 2016 +// Author: CEA (delegation to Alyotech) + +#ifndef GeomAlgoAPI_Sphere_H_ +#define GeomAlgoAPI_Sphere_H_ + +#include +#include + +/**\class GeomAlgoAPI_Sphere + * \ingroup DataAlgo + * \brief Allows to create Sphere Primitives + */ +class GeomAlgoAPI_Sphere : public GeomAlgoAPI_MakeShape +{ + public: + GEOMALGOAPI_EXPORT GeomAlgoAPI_Sphere(); + + /// Creates a Sphere using a center and a radius + /// \param theCenter the center + /// \param theRadius the radius of the sphere + GEOMALGOAPI_EXPORT GeomAlgoAPI_Sphere(std::shared_ptr theCenter, const double theRadius); + + /// Checks if the center myCenter and radius myRadius are OK. + GEOMALGOAPI_EXPORT bool check(); + + /// Builds the sphere with the center myCenter and radius myRadius + GEOMALGOAPI_EXPORT void build(); + + private: + std::shared_ptr myCenter; /// attribute point defining the center of the sphere + double myRadius; /// attribute radius of the sphere +}; + + +#endif diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_swig.h b/src/GeomAlgoAPI/GeomAlgoAPI_swig.h index df537f620..0a2174e0b 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_swig.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_swig.h @@ -44,6 +44,7 @@ #include "GeomAlgoAPI_Exception.h" #include "GeomAlgoAPI_ShapeAPI.h" #include "GeomAlgoAPI_Box.h" + #include "GeomAlgoAPI_Sphere.h" #include "GeomAlgoAPI_Copy.h" #include diff --git a/src/GeomAlgoAPI/Test/TestAPI_Sphere.py b/src/GeomAlgoAPI/Test/TestAPI_Sphere.py new file mode 100644 index 000000000..c6a16c1fb --- /dev/null +++ b/src/GeomAlgoAPI/Test/TestAPI_Sphere.py @@ -0,0 +1,32 @@ +# Copyright (C) 2014-2016 CEA/DEN, EDF R&D + +# File: APIDirectTestSphere.py +# Created: 15 Apr 2016 +# Author: CEA (delegation to Alyotech) + +from GeomAlgoAPI import GeomAlgoAPI_ShapeAPI as shaperpy +from GeomAlgoAPI import GeomAlgoAPI_Exception as myExcept +from GeomAPI import GeomAPI_Pnt as pnt + +# Create a sphere with radius 5. at origin +try : + sphere1 = shaperpy.makeSphere(5.) + +except myExcept,ec: + print ec.what() + +# Create a sphere with a point defining the center and radius 8. +try : + center = pnt(10.,0.,0.) + sphere2 = shaperpy.makeSphere(center, 8.) + +except myExcept,ec: + print ec.what() + + +# Create a sphere with null radius +try : + sphere3 = shaperpy.makeSphere(0.) + +except myExcept,ec: + print ec.what() diff --git a/src/PrimitivesPlugin/CMakeLists.txt b/src/PrimitivesPlugin/CMakeLists.txt index 86a5f1683..0bfd4fbf5 100644 --- a/src/PrimitivesPlugin/CMakeLists.txt +++ b/src/PrimitivesPlugin/CMakeLists.txt @@ -10,16 +10,19 @@ SET(PROJECT_HEADERS PrimitivesPlugin.h PrimitivesPlugin_Plugin.h PrimitivesPlugin_Box.h + PrimitivesPlugin_Sphere.h ) SET(PROJECT_SOURCES PrimitivesPlugin_Plugin.cpp PrimitivesPlugin_Box.cpp + PrimitivesPlugin_Sphere.cpp ) SET(XML_RESOURCES plugin-Primitives.xml box_widget.xml + sphere_widget.xml ) INCLUDE_DIRECTORIES( @@ -44,7 +47,7 @@ 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 +ADD_UNIT_TESTS(TestBox.py + TestSphere.py ) diff --git a/src/PrimitivesPlugin/PrimitivesPlugin_Plugin.cpp b/src/PrimitivesPlugin/PrimitivesPlugin_Plugin.cpp index b4281ea41..98b5b402a 100644 --- a/src/PrimitivesPlugin/PrimitivesPlugin_Plugin.cpp +++ b/src/PrimitivesPlugin/PrimitivesPlugin_Plugin.cpp @@ -7,6 +7,7 @@ #include #include +#include #include @@ -31,6 +32,8 @@ FeaturePtr PrimitivesPlugin_Plugin::createFeature(string theFeatureID) { if (theFeatureID == PrimitivesPlugin_Box::ID()) { return FeaturePtr(new PrimitivesPlugin_Box); + } else if (theFeatureID == PrimitivesPlugin_Sphere::ID()) { + return FeaturePtr(new PrimitivesPlugin_Sphere); } // feature of such kind is not found return FeaturePtr(); diff --git a/src/PrimitivesPlugin/PrimitivesPlugin_Sphere.cpp b/src/PrimitivesPlugin/PrimitivesPlugin_Sphere.cpp new file mode 100644 index 000000000..d4a474bd9 --- /dev/null +++ b/src/PrimitivesPlugin/PrimitivesPlugin_Sphere.cpp @@ -0,0 +1,109 @@ +// Copyright (C) 2014-2016 CEA/DEN, EDF R&D + +// File: PrimitivesPlugin_Sphere.cpp +// Created: 29 Mar 2016 +// Author: CEA (delegation to Alyotech) + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +//================================================================================================= +PrimitivesPlugin_Sphere::PrimitivesPlugin_Sphere() // Nothing to do during instantiation +{ +} + +//================================================================================================= +void PrimitivesPlugin_Sphere::initAttributes() +{ + + // The center of the sphere + data()->addAttribute(CENTER(), ModelAPI_AttributeSelection::typeId()); + AttributeSelectionPtr aBase = data()->selection(CENTER()); + if (!aBase->isInitialized()) { // on restore (undo, open), this may be already defined + ObjectPtr aPointObj = ModelAPI_Session::get()->moduleDocument()->objectByName(ModelAPI_ResultConstruction::group(), "Origin"); + if (aPointObj.get()) { // if initialization plugin performed well + ResultPtr aPointRes = std::dynamic_pointer_cast(aPointObj); + // second argument is null: just point result, without sub-shape selection + aBase->setValue(aPointRes, std::shared_ptr()); + } + } + + // The radius needed to create a sphere by radius at origin and by the center + data()->addAttribute(RADIUS(), ModelAPI_AttributeDouble::typeId()); +} + +//================================================================================================= +void PrimitivesPlugin_Sphere::execute(){ + +//Get the point and the radius from the input parameters, check their soudness, then instantiate a sphere builder with these elements + AttributeSelectionPtr aRef = data()->selection(CENTER()); + double aRadius = real(RADIUS())->value(); + + std::shared_ptr aCenter = GeomAlgoAPI_PointBuilder::point(aRef->context()->shape()); + + std::shared_ptr aSphereAlgo; + + if ((aRef.get() != NULL)) { + GeomShapePtr aShape = aRef->value(); + if (!aShape.get()) //If we can't get the points directly, try getting them from the context + aShape = aRef->context()->shape(); + if (aShape){ + std::shared_ptr aCenter = GeomAlgoAPI_PointBuilder::point(aShape); + aSphereAlgo = std::shared_ptr(new GeomAlgoAPI_Sphere(aCenter, aRadius)); + } + } + + // We need to check that everything went smoothly with GeomAlgoAPI_Sphere + if (!aSphereAlgo->check()){ + setError(aSphereAlgo->getError(), false); + return; + } + + // Build the sphere + aSphereAlgo->build(); + + // Check if the creation of the sphere went well + if(!aSphereAlgo->isDone()) { + setError(aSphereAlgo->getError()); + return; + } + if(!aSphereAlgo->checkValid("Sphere builder")) { + setError(aSphereAlgo->getError()); + return; + } + + int aResultIndex = 0; // There's only going to be one result : the sphere + ResultBodyPtr aResultSphere = document()->createBody(data(), aResultIndex); + loadNamingDS(aSphereAlgo, aResultSphere); + setResult(aResultSphere, aResultIndex); +} + +//================================================================================================= + void PrimitivesPlugin_Sphere::loadNamingDS(std::shared_ptr theSphereAlgo, + std::shared_ptr theResultSphere) +{ + // Load the result + theResultSphere->store(theSphereAlgo->shape()); + + // Prepare the naming + theSphereAlgo->prepareNamingFaces(); + + // Insert to faces + int num = 1; + std::map< std::string, std::shared_ptr > listOfFaces = theSphereAlgo->getCreatedFaces(); + for (std::map< std::string, std::shared_ptr >::iterator it=listOfFaces.begin(); it!=listOfFaces.end(); ++it){ + std::shared_ptr aFace = (*it).second; + theResultSphere->generated(aFace, (*it).first, num++); + } +} diff --git a/src/PrimitivesPlugin/PrimitivesPlugin_Sphere.h b/src/PrimitivesPlugin/PrimitivesPlugin_Sphere.h new file mode 100644 index 000000000..6914dd6ed --- /dev/null +++ b/src/PrimitivesPlugin/PrimitivesPlugin_Sphere.h @@ -0,0 +1,71 @@ +// Copyright (C) 2014-2016 CEA/DEN, EDF R&D + +// File: PrimitivesPlugin_Sphere.h +// Created: 29 Mar 2016 +// Author: CEA (delegation to Alyotech) + +#ifndef PrimitivesPlugin_Sphere_H_ +#define PrimitivesPlugin_Sphere_H_ + +#include +#include +#include + +class GeomAPI_Shape; +class ModelAPI_ResultBody; + +/**\class PrimitivesPlugin_Sphere + * \ingroup Plugins + * \brief Feature for creation of a sphere. + * + * Sphere creates a sphere from a radius and a center point, defaulting to + * the origin. + */ +class PrimitivesPlugin_Sphere : public ModelAPI_Feature +{ + public: + /// Sphere kind + inline static const std::string& ID() + { + static const std::string MY_SPHERE_ID("Sphere"); + return MY_SPHERE_ID; + } + + /// attribute name of the center + inline static const std::string& CENTER() + { + static const std::string MY_CENTER("center"); + return MY_CENTER; + } + + /// attribute name of the radius + inline static const std::string& RADIUS() + { + static const std::string MY_RADIUS("radius"); + return MY_RADIUS; + } + + /// Returns the kind of a feature + PRIMITIVESPLUGIN_EXPORT virtual const std::string& getKind() + { + static std::string MY_KIND = PrimitivesPlugin_Sphere::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_Sphere(); + + private: + /// Load Naming data structure of the feature to the document + void loadNamingDS(std::shared_ptr theSphereAlgo, + std::shared_ptr theResultSphere); + +}; + +#endif diff --git a/src/PrimitivesPlugin/Test/TestSphere.py b/src/PrimitivesPlugin/Test/TestSphere.py new file mode 100644 index 000000000..84d63ad6b --- /dev/null +++ b/src/PrimitivesPlugin/Test/TestSphere.py @@ -0,0 +1,83 @@ +# Copyright (C) 2014-2016 CEA/DEN, EDF R&D + +# File: UnitTestSphere.py +# Created: 31 Mar 2016 +# Author: CEA (delegation to Alyotech) + +""" + UnitTestSphere.py + Unit Test of PrimitivesPlugin_Sphere class + +class PrimitivesPlugin_Sphere : public ModelAPI_Feature + static const std::string MY_SPHERE_ID("Sphere"); + static const std::string METHOD_ATTR("CreationMethod"); + static const std::string MY_CENTER("center"); + static const std::string MY_RADIUS("radius"); + + + data()->addAttribute(METHOD(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(CENTER(), ModelAPI_AttributeSelection::typeId()); + data()->addAttribute(RADIUS(), 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 sphere +aSession.startOperation() +aPartFeature = aDocument.addFeature("Part") +aSession.finishOperation() +assert (len(aPartFeature.results()) == 1) + +aPartResult = modelAPI_ResultPart(aPartFeature.firstResult()) +aPart = aPartResult.partDoc() + +#========================================================================= +# Creation of a Sphere by a point and a radius +#========================================================================= + +aSession.startOperation() + +#Create the center +aCenter = aPart.addFeature("Point") +assert(aCenter.getKind() == "Point") +aCenter.real("x").setValue(10.0) +aCenter.real("y").setValue(10.0) +aCenter.real("z").setValue(10.0) +aCenter.execute() +aCenterResult = aCenter.firstResult() +aCenterVertex = aCenterResult.shape() + +aSphereByCenter = aPart.addFeature("Sphere") +assert (aSphereByCenter.getKind() == "Sphere") +aSphereByCenter.selection("center").setValue(aCenterResult, aCenterVertex) +aSphereByCenter.real("radius").setValue(5.) +aSphereByCenter.execute() + +# Check sphere results +assert (len(aSphereByCenter.results()) > 0) +aSphereCenterResult = modelAPI_ResultBody(aSphereByCenter.firstResult()) +assert (aSphereCenterResult is not None) + +# Check sphere volume +aRefVolumeSphereCenter = (4. * math.pi * 5. ** 3 ) / 3. +aResVolumeSphereCenter = GeomAlgoAPI_ShapeTools_volume(aSphereCenterResult.shape()) +assert (math.fabs(aResVolumeSphereCenter - aRefVolumeSphereCenter) < 10. ** -5) + +aSession.finishOperation() + +#========================================================================= +# End of test +#========================================================================= diff --git a/src/PrimitivesPlugin/icons/sphere.png b/src/PrimitivesPlugin/icons/sphere.png new file mode 100644 index 000000000..000d658ab Binary files /dev/null and b/src/PrimitivesPlugin/icons/sphere.png differ diff --git a/src/PrimitivesPlugin/plugin-Primitives.xml b/src/PrimitivesPlugin/plugin-Primitives.xml index 22a4b366a..aca019c88 100644 --- a/src/PrimitivesPlugin/plugin-Primitives.xml +++ b/src/PrimitivesPlugin/plugin-Primitives.xml @@ -8,6 +8,9 @@ + + + diff --git a/src/PrimitivesPlugin/sphere_widget.xml b/src/PrimitivesPlugin/sphere_widget.xml new file mode 100644 index 000000000..f1011b7e5 --- /dev/null +++ b/src/PrimitivesPlugin/sphere_widget.xml @@ -0,0 +1,23 @@ + + + + + + + + + +