From 5297856d2148995c4dcb0561f895a6a22db7086b Mon Sep 17 00:00:00 2001 From: mpv Date: Wed, 15 Apr 2015 13:11:03 +0300 Subject: [PATCH] Added support of python high level API addons proposed by DBC as test of this approach. --- CMakeLists.txt | 3 +- env_Salome.bat | 9 +- linux_env.sh | 2 +- msvc10_env.bat | 10 +- salomeRun.bat | 2 +- src/Config/plugins.xml | 2 +- src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp | 10 +- src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.h | 2 - src/Model/Model_ResultConstruction.cpp | 2 +- src/PartSetPlugin/PartSetPlugin_Duplicate.cpp | 6 + src/PartSetPlugin/PartSetPlugin_Duplicate.h | 3 + src/PartSetPlugin/PartSetPlugin_Part.h | 1 + src/PythonAPI/CMakeLists.txt | 6 + src/PythonAPI/MakeBrick1.py | 74 ++++++ src/PythonAPI/MakeBrick2.py | 69 +++++ src/PythonAPI/MakeBrick3.py | 24 ++ src/PythonAPI/extension/__init__.py | 4 + src/PythonAPI/extension/box.py | 23 ++ src/PythonAPI/geom/__init__.py | 27 ++ src/PythonAPI/geom/missed.py | 25 ++ src/PythonAPI/modeler/__init__.py | 16 ++ src/PythonAPI/modeler/boolean.py | 48 ++++ src/PythonAPI/modeler/extrusion.py | 42 +++ src/PythonAPI/modeler/part.py | 19 ++ src/PythonAPI/modeler/roots.py | 41 +++ src/PythonAPI/modeler/services.py | 72 ++++++ src/PythonAPI/modeler/sketcher.py | 242 ++++++++++++++++++ src/PythonAddons/CMakeLists.txt | 10 + src/PythonAddons/__init__.py | 1 + .../addons_Features.py} | 16 +- src/PythonAddons/addons_Features.xml | 4 + src/PythonAddons/macros/__init__.py | 7 + src/PythonAddons/macros/box/__init__.py | 0 src/PythonAddons/macros/box/feature.py | 89 +++++++ src/PythonAddons/macros/box/widget.xml | 19 ++ src/PythonAddons/macros/cylinder/__init__.py | 0 src/PythonAddons/macros/cylinder/feature.py | 68 +++++ src/PythonAddons/macros/cylinder/widget.xml | 16 ++ src/PythonFeaturesPlugin/CMakeLists.txt | 17 -- src/PythonFeaturesPlugin/FeaturesAPI.py | 47 ---- .../PythonFeaturesPlugin_Box.py | 170 ------------ src/PythonFeaturesPlugin/SketchResult.py | 26 -- src/PythonFeaturesPlugin/box_widget.xml | 11 - src/PythonFeaturesPlugin/examples.py | 51 ---- src/PythonFeaturesPlugin/extrusion.py | 17 -- .../plugin-PythonFeatures.xml | 9 - src/PythonFeaturesPlugin/sketch.py | 134 ---------- 47 files changed, 988 insertions(+), 508 deletions(-) create mode 100644 src/PythonAPI/CMakeLists.txt create mode 100644 src/PythonAPI/MakeBrick1.py create mode 100644 src/PythonAPI/MakeBrick2.py create mode 100644 src/PythonAPI/MakeBrick3.py create mode 100644 src/PythonAPI/extension/__init__.py create mode 100644 src/PythonAPI/extension/box.py create mode 100644 src/PythonAPI/geom/__init__.py create mode 100644 src/PythonAPI/geom/missed.py create mode 100644 src/PythonAPI/modeler/__init__.py create mode 100644 src/PythonAPI/modeler/boolean.py create mode 100644 src/PythonAPI/modeler/extrusion.py create mode 100644 src/PythonAPI/modeler/part.py create mode 100644 src/PythonAPI/modeler/roots.py create mode 100644 src/PythonAPI/modeler/services.py create mode 100644 src/PythonAPI/modeler/sketcher.py create mode 100644 src/PythonAddons/CMakeLists.txt create mode 100644 src/PythonAddons/__init__.py rename src/{PythonFeaturesPlugin/PythonFeaturesPlugin.py => PythonAddons/addons_Features.py} (57%) create mode 100644 src/PythonAddons/addons_Features.xml create mode 100644 src/PythonAddons/macros/__init__.py create mode 100644 src/PythonAddons/macros/box/__init__.py create mode 100644 src/PythonAddons/macros/box/feature.py create mode 100644 src/PythonAddons/macros/box/widget.xml create mode 100644 src/PythonAddons/macros/cylinder/__init__.py create mode 100644 src/PythonAddons/macros/cylinder/feature.py create mode 100644 src/PythonAddons/macros/cylinder/widget.xml delete mode 100644 src/PythonFeaturesPlugin/CMakeLists.txt delete mode 100644 src/PythonFeaturesPlugin/FeaturesAPI.py delete mode 100644 src/PythonFeaturesPlugin/PythonFeaturesPlugin_Box.py delete mode 100644 src/PythonFeaturesPlugin/SketchResult.py delete mode 100644 src/PythonFeaturesPlugin/box_widget.xml delete mode 100644 src/PythonFeaturesPlugin/examples.py delete mode 100644 src/PythonFeaturesPlugin/extrusion.py delete mode 100644 src/PythonFeaturesPlugin/plugin-PythonFeatures.xml delete mode 100644 src/PythonFeaturesPlugin/sketch.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 0cf7163c2..6cb7b11d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,7 +55,6 @@ ADD_SUBDIRECTORY (src/PartSetPlugin) ADD_SUBDIRECTORY (src/ConstructionPlugin) ADD_SUBDIRECTORY (src/FeaturesPlugin) ADD_SUBDIRECTORY (src/SketcherPrs) -ADD_SUBDIRECTORY (src/PythonFeaturesPlugin) ADD_SUBDIRECTORY (src/SketchPlugin) ADD_SUBDIRECTORY (src/SketchSolver) ADD_SUBDIRECTORY (src/ModuleBase) @@ -67,6 +66,8 @@ ADD_SUBDIRECTORY (src/ExchangePlugin) ADD_SUBDIRECTORY (src/GeomValidators) ADD_SUBDIRECTORY (src/InitializationPlugin) ADD_SUBDIRECTORY (src/ParametersPlugin) +ADD_SUBDIRECTORY (src/PythonAddons) +ADD_SUBDIRECTORY (src/PythonAPI) IF(${HAVE_SALOME}) ADD_SUBDIRECTORY (src/NewGeom) diff --git a/env_Salome.bat b/env_Salome.bat index e7e3551a5..86b26cfbc 100644 --- a/env_Salome.bat +++ b/env_Salome.bat @@ -89,8 +89,9 @@ IF "%ARCH%" == "Win64" ( ) @SET NEW_GEOM_CONFIG_FILE=%ROOT_DIR%\install\plugins -@SET PATH=%ROOT_DIR%\install\swig;%ROOT_DIR%\install\plugins;%ROOT_DIR%\install\bin;%PATH% -@SET PYTHONPATH=%ROOT_DIR%\install\swig;%ROOT_DIR%\install\plugins;%PYTHONPATH% +@SET NEWGEOM_ROOT_DIR=%ROOT_DIR%\install +@SET PATH=%NEWGEOM_ROOT_DIR%\swig;%NEWGEOM_ROOT_DIR%\plugins;%NEWGEOM_ROOT_DIR%\bin;%PATH% +@SET PYTHONPATH=%NEWGEOM_ROOT_DIR%\swig;%NEWGEOM_ROOT_DIR%\plugins;%NEWGEOM_ROOT_DIR%\addons;%NEWGEOM_ROOT_DIR%\pythonAPI;%PYTHONPATH% -@SET LightAppConfig=%ROOT_DIR%\install\share\salome\resources\newgeom;%GUI_ROOT_DIR%\share\salome\resources\gui -@SET NewGeomResources=%ROOT_DIR%\install\resources +@SET LightAppConfig=%%NEWGEOM_ROOT_DIR%\share\salome\resources\newgeom;%GUI_ROOT_DIR%\share\salome\resources\gui +@SET NewGeomResources=%NEWGEOM_ROOT_DIR%\resources diff --git a/linux_env.sh b/linux_env.sh index b58d16324..917518588 100644 --- a/linux_env.sh +++ b/linux_env.sh @@ -37,7 +37,7 @@ export PATH=${CASROOT}:${PATH} #------ NewGEOM ------ export NEWGEOM_ROOT_DIR=${ROOT_DIR}/install export PATH=${NEWGEOM_ROOT_DIR}/bin:${NEWGEOM_ROOT_DIR}/plugins:${PATH} -export PYTHONPATH=${NEWGEOM_ROOT_DIR}/swig:${NEWGEOM_ROOT_DIR}/plugins:${PYTHONPATH} +export PYTHONPATH=${NEWGEOM_ROOT_DIR}/swig:${NEWGEOM_ROOT_DIR}/plugins:${NEWGEOM_ROOT_DIR}/addons:${NEWGEOM_ROOT_DIR}/pythonAPI:${PYTHONPATH} export LD_LIBRARY_PATH=${NEWGEOM_ROOT_DIR}/bin:${NEWGEOM_ROOT_DIR}/swig:${NEWGEOM_ROOT_DIR}/plugins:${LD_LIBRARY_PATH} export NEW_GEOM_CONFIG_FILE=${NEWGEOM_ROOT_DIR}/plugins export NewGeomResources=${NEWGEOM_ROOT_DIR}/resources diff --git a/msvc10_env.bat b/msvc10_env.bat index 30eb26a1c..e0f119ea8 100644 --- a/msvc10_env.bat +++ b/msvc10_env.bat @@ -153,11 +153,11 @@ set PATH=%CMAKEDIR%\bin;%PATH% @REM ------------------------- @REM OPENPARTS -@SET NEW_GEOM_CONFIG_FILE=%ROOT_DIR%\install\plugins -@SET PATH=%ROOT_DIR%\install\swig;%ROOT_DIR%\install\plugins;%ROOT_DIR%\install\bin;%PATH% -@SET PYTHONPATH=%ROOT_DIR%\install\swig;%ROOT_DIR%\install\plugins;%PYTHONPATH% -@SET NewGeomResources=%ROOT_DIR%\install\resources -@REM ------------------------- +@SET NEWGEOM_ROOT_DIR=%ROOT_DIR%\install +@SET NEW_GEOM_CONFIG_FILE=%NEWGEOM_ROOT_DIR%\plugins +@SET PATH=%NEWGEOM_ROOT_DIR%\swig;%NEWGEOM_ROOT_DIR%\plugins;%NEWGEOM_ROOT_DIR%\bin;%PATH% +@SET PYTHONPATH=%NEWGEOM_ROOT_DIR%\swig;%NEWGEOM_ROOT_DIR%\plugins;%NEWGEOM_ROOT_DIR%\addons;%NEWGEOM_ROOT_DIR%\pythonAPI;%PYTHONPATH% +@SET NewGeomResources=%NEWGEOM_ROOT_DIR%\resources rem -------- Visual Studio -------------------- rem Detect Visual Studio (either commercial or Express edition) diff --git a/salomeRun.bat b/salomeRun.bat index a73f0ce70..6d5ea04a7 100644 --- a/salomeRun.bat +++ b/salomeRun.bat @@ -3,6 +3,6 @@ call env_Salome.bat @SET NEWGEOM_ROOT_DIR=%ROOT_DIR%\install -@SET SalomeAppConfig=%ROOT_DIR%\install\share\salome\resources\newgeom;%GUI_ROOT_DIR%\share\salome\resources\gui +@SET SalomeAppConfig=%NEWGEOM_ROOT_DIR%\share\salome\resources\newgeom;%GUI_ROOT_DIR%\share\salome\resources\gui start %PYTHONBIN% "%KERNEL_ROOT_DIR%\bin\salome\envSalome.py" "%PYTHONBIN%" "%KERNEL_ROOT_DIR%\bin\salome\runSalome.py" %* diff --git a/src/Config/plugins.xml b/src/Config/plugins.xml index 65cdd3bee..70c0311a6 100644 --- a/src/Config/plugins.xml +++ b/src/Config/plugins.xml @@ -8,7 +8,7 @@ - + diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp index 065b27257..7e64d882c 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp @@ -82,8 +82,9 @@ static void removeWasteEdges(std::list::iterator& theStartVertex, void GeomAlgoAPI_SketchBuilder::createFaces( - const std::shared_ptr& theOrigin, const std::shared_ptr& theDirX, - const std::shared_ptr& theDirY, const std::shared_ptr& theNorm, + const std::shared_ptr& theOrigin, + const std::shared_ptr& theDirX, + const std::shared_ptr& theNorm, const std::list >& theFeatures, std::list >& theResultFaces, std::list >& theResultWires) @@ -132,8 +133,8 @@ void GeomAlgoAPI_SketchBuilder::createFaces( return; gp_Dir aDirX = theDirX->impl(); - gp_Dir aDirY = theDirY->impl(); gp_Dir aNorm = theNorm->impl(); + gp_Dir aDirY = aNorm.Crossed(aDirX); gp_Pln aPlane(theOrigin->impl(), aNorm); @@ -375,7 +376,6 @@ void GeomAlgoAPI_SketchBuilder::createFaces( void GeomAlgoAPI_SketchBuilder::createFaces(const std::shared_ptr& theOrigin, const std::shared_ptr& theDirX, - const std::shared_ptr& theDirY, const std::shared_ptr& theNorm, const std::shared_ptr& theWire, std::list >& theResultFaces) @@ -385,7 +385,7 @@ void GeomAlgoAPI_SketchBuilder::createFaces(const std::shared_ptr& return; // Filter wires, return only faces. std::list > aFilteredWires; - createFaces(theOrigin, theDirX, theDirY, theNorm, + createFaces(theOrigin, theDirX, theNorm, aWire->getEdges(), theResultFaces, aFilteredWires); } diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.h b/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.h index 0d471dd0f..a4da606b1 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.h @@ -38,7 +38,6 @@ class GEOMALGOAPI_EXPORT GeomAlgoAPI_SketchBuilder */ static void createFaces(const std::shared_ptr& theOrigin, const std::shared_ptr& theDirX, - const std::shared_ptr& theDirY, const std::shared_ptr& theNorm, const std::list >& theFeatures, std::list >& theResultFaces, @@ -58,7 +57,6 @@ class GEOMALGOAPI_EXPORT GeomAlgoAPI_SketchBuilder */ static void createFaces(const std::shared_ptr& theOrigin, const std::shared_ptr& theDirX, - const std::shared_ptr& theDirY, const std::shared_ptr& theNorm, const std::shared_ptr& theWire, std::list >& theResultFaces); diff --git a/src/Model/Model_ResultConstruction.cpp b/src/Model/Model_ResultConstruction.cpp index 1e2021c42..e614fd89c 100644 --- a/src/Model/Model_ResultConstruction.cpp +++ b/src/Model/Model_ResultConstruction.cpp @@ -61,7 +61,7 @@ int Model_ResultConstruction::facesNum() std::dynamic_pointer_cast(myShape); std::list > aFaces; GeomAlgoAPI_SketchBuilder::createFaces(aWirePtr->origin(), aWirePtr->dirX(), - aWirePtr->dirY(), aWirePtr->norm(), aWirePtr, aFaces); + aWirePtr->norm(), aWirePtr, aFaces); std::list >::iterator aFIter = aFaces.begin(); for(; aFIter != aFaces.end(); aFIter++) { std::shared_ptr aFace(new GeomAPI_Face(*aFIter)); diff --git a/src/PartSetPlugin/PartSetPlugin_Duplicate.cpp b/src/PartSetPlugin/PartSetPlugin_Duplicate.cpp index 35134c64b..462a7366b 100644 --- a/src/PartSetPlugin/PartSetPlugin_Duplicate.cpp +++ b/src/PartSetPlugin/PartSetPlugin_Duplicate.cpp @@ -46,3 +46,9 @@ void PartSetPlugin_Duplicate::execute() if (!data()->name().empty()) PartSetPlugin_Part::execute(); } + +const std::string& PartSetPlugin_Duplicate::documentToAdd() +{ + // part must be added only to the module document + return ModelAPI_Session::get()->moduleDocument()->kind(); +} diff --git a/src/PartSetPlugin/PartSetPlugin_Duplicate.h b/src/PartSetPlugin/PartSetPlugin_Duplicate.h index 5aa92ed1a..408d096e8 100644 --- a/src/PartSetPlugin/PartSetPlugin_Duplicate.h +++ b/src/PartSetPlugin/PartSetPlugin_Duplicate.h @@ -26,6 +26,9 @@ class PartSetPlugin_Duplicate : public PartSetPlugin_Part /// Makes a new part, copy of active PartSetPlugin_Duplicate(); + /// Part must be added only to PartSet + PARTSETPLUGIN_EXPORT virtual const std::string& documentToAdd(); + /// Request for initialization of data model of the feature: adding all attributes PARTSETPLUGIN_EXPORT virtual void initAttributes(); diff --git a/src/PartSetPlugin/PartSetPlugin_Part.h b/src/PartSetPlugin/PartSetPlugin_Part.h index e7f23387c..0a24df58e 100644 --- a/src/PartSetPlugin/PartSetPlugin_Part.h +++ b/src/PartSetPlugin/PartSetPlugin_Part.h @@ -43,6 +43,7 @@ class PartSetPlugin_Part : public ModelAPI_Feature /// Request for initialization of data model of the feature: adding all attributes PARTSETPLUGIN_EXPORT virtual void initAttributes(); + /// Part must be added only to PartSet PARTSETPLUGIN_EXPORT virtual const std::string& documentToAdd(); /// Returns true if this feature must be displayed in the history (top level of Part tree) diff --git a/src/PythonAPI/CMakeLists.txt b/src/PythonAPI/CMakeLists.txt new file mode 100644 index 000000000..c89a79868 --- /dev/null +++ b/src/PythonAPI/CMakeLists.txt @@ -0,0 +1,6 @@ +## Copyright (C) 2014-20xx OPEN CASCADE + + +SET(CMAKE_AUTOMOC ON) + +INSTALL(DIRECTORY extension geom modeler DESTINATION pythonAPI) diff --git a/src/PythonAPI/MakeBrick1.py b/src/PythonAPI/MakeBrick1.py new file mode 100644 index 000000000..349c47e52 --- /dev/null +++ b/src/PythonAPI/MakeBrick1.py @@ -0,0 +1,74 @@ +# Creation of a box using the end-user API +# Author: Daniel Brunier-Coulin +# ----------------------------- + +import modeler + + +# Initialisation + +modeler.begin() +mypartset = modeler.moduleDocument() + + +# Creating a new Part + +mypart = modeler.addPart(mypartset).document() + + +# Creating the base of the box + +mybase = modeler.addSketch( mypart, modeler.defaultPlane("XOY") ) + +l1 = mybase.addLine( 0, 0, 0, 1 ) +l2 = mybase.addLine( 0, 1, 1, 1 ) +l3 = mybase.addLine( 1, 1, 1, 0 ) +l4 = mybase.addLine( 1, 0, 0, 0 ) + +mybase.setCoincident( l1.endPointData(), l2.startPointData() ) +mybase.setCoincident( l2.endPointData(), l3.startPointData() ) +mybase.setCoincident( l3.endPointData(), l4.startPointData() ) +mybase.setCoincident( l4.endPointData(), l1.startPointData() ) + +mybase.setParallel( l1.result(), l3.result() ) +mybase.setParallel( l2.result(), l4.result() ) + +mybase.setPerpendicular( l1.result(), l4.result() ) + +mywidth = mybase.setLength( l1.result(), 50 ) +mylength = mybase.setDistance( l1.startPointData(), l3.result(), 50 ) + + +# Creating the extrusion + +mybox = modeler.addExtrusion( mypart, mybase.selectFace(), 50 ) + + +# Creating a cylinder on a face of the box + +thisface = "Extrusion_1/LateralFace_2" +thisxmin = "Extrusion_1/LateralFace_3|Extrusion_1/LateralFace_2" +thisxmax = "Extrusion_1/LateralFace_2|Extrusion_1/LateralFace_1" +thiszmin = "Sketch_1/Edge5_1" +thiszmax = "Extrusion_1/LateralFace_2|Extrusion_1/TopFace_1" + +mystand = modeler.addSketch( mypart, thisface ) +c1 = mystand.addCircle( 0, 25, 5) +mystand.setDistance( c1.centerData(), thisxmin, 10 ) +mystand.setDistance( c1.centerData(), thiszmax, 10 ) + +myboss = modeler.addExtrusion( mypart, mystand.selectFace(c1.result()), -5 ) + + +# Subtracting the cylinder to the box + +modeler.addSubtraction( mypart, mybox.result(), myboss.result() ) +modeler.end() + + +# Editing the box + +modeler.begin() +mybase.setValue( mylength, 100 ) +mybox.setSize( 20 ) +modeler.end() diff --git a/src/PythonAPI/MakeBrick2.py b/src/PythonAPI/MakeBrick2.py new file mode 100644 index 000000000..24865b532 --- /dev/null +++ b/src/PythonAPI/MakeBrick2.py @@ -0,0 +1,69 @@ +# Creation of a box using the end-user API +# Author: Daniel Brunier-Coulin +# ----------------------------- + +import modeler +import geom + + +# Initialisation + +modeler.begin() +mypartset = modeler.moduleDocument() + + +# Creating a new Part + +mypart = modeler.addPart(mypartset).document() + + +# Creating the base of the box + +mybase = modeler.addSketch( mypart, modeler.defaultPlane("XOY") ) + +p1 = geom.Pnt2d( 0, 0 ) +p2 = geom.Pnt2d( 0, 1 ) +p3 = geom.Pnt2d( 1, 1 ) +p4 = geom.Pnt2d( 1, 0 ) + +line = mybase.addPolygon(p1, p2, p3, p4) + +mybase.setParallel( line[0].result(), line[2].result() ) +mybase.setParallel( line[1].result(), line[3].result() ) +mybase.setPerpendicular( line[0].result(), line[3].result() ) + +mywidth = mybase.setLength( line[0].result(), 50 ) +mylength = mybase.setDistance( line[0].startPointData(),line[2].result(), 50 ) + + +# Creating the extrusion + +mybox = modeler.addExtrusion( mypart, mybase.selectFace(), 50 ) + + +# Creating a cylinder on a face of the box + +thisface = "Extrusion_1/LateralFace_2" +thisxmin = "Extrusion_1/LateralFace_3|Extrusion_1/LateralFace_2" +thiszmax = "Extrusion_1/LateralFace_2|Extrusion_1/TopFace_1" + +mystand = modeler.addSketch( mypart, thisface ) +circle = mystand.addCircle( 0, 25, 5) +mystand.setDistance( circle.centerData(), thisxmin, 10 ) +mystand.setDistance( circle.centerData(), thiszmax, 10 ) + +myboss = modeler.addExtrusion( mypart, mystand.selectFace(), -5 ) + + +# Subtracting the cylinder to the box + +modeler.addSubtraction( mypart, mybox.result(), myboss.result() ) +modeler.end() + + +# Editing the box + +modeler.begin() +mybase.setValue( mylength, 100 ) +mybox.setSize( 20 ) +modeler.end() diff --git a/src/PythonAPI/MakeBrick3.py b/src/PythonAPI/MakeBrick3.py new file mode 100644 index 000000000..c3147800e --- /dev/null +++ b/src/PythonAPI/MakeBrick3.py @@ -0,0 +1,24 @@ +# Creation of a box using the end-user API +# Author: Daniel Brunier-Coulin +# ----------------------------- + +import modeler +import extension + + +# Initialisation + +modeler.begin() +mypartset = modeler.moduleDocument() + + +# Creating a new Part + +mypart = modeler.addPart(mypartset).document() + + +# Creating the base of the box + +extension.addBox( mypart, 10, 20, 30 ) +modeler.end() + diff --git a/src/PythonAPI/extension/__init__.py b/src/PythonAPI/extension/__init__.py new file mode 100644 index 000000000..275cb5503 --- /dev/null +++ b/src/PythonAPI/extension/__init__.py @@ -0,0 +1,4 @@ +"""User-defined features. +""" + +from box import Box as addBox \ No newline at end of file diff --git a/src/PythonAPI/extension/box.py b/src/PythonAPI/extension/box.py new file mode 100644 index 000000000..957da5412 --- /dev/null +++ b/src/PythonAPI/extension/box.py @@ -0,0 +1,23 @@ +"""Box macro-feature Interface +Author: Daniel Brunier-Coulin +Copyright (C) 2014-20xx CEA/DEN, EDF R&D +""" + +import modeler +from macros.box.feature import BoxFeature as MY + + +class Box(modeler.Interface): + """Executes the macro-feature Box. + """ + def __init__(self, part, dx, dy, dz): + modeler.Interface.__init__(self, part, MY.ID()) + + self.setRealInput( MY.WIDTH_ID(), dx ) + self.setRealInput( MY.LENGTH_ID(), dy ) + self.setRealInput( MY.HEIGHT_ID(), dz ) + + if self.areInputValid(): + self.execute() + else: + raise Exception("cannot make the Box") \ No newline at end of file diff --git a/src/PythonAPI/geom/__init__.py b/src/PythonAPI/geom/__init__.py new file mode 100644 index 000000000..1ba89b9d9 --- /dev/null +++ b/src/PythonAPI/geom/__init__.py @@ -0,0 +1,27 @@ +"""This package defines the Direct Geometry API of the Modeler. +""" + +# Swigged interfaces to Modeling Data + +from GeomAPI import GeomAPI_Circ as Circ +from GeomAPI import GeomAPI_Circ2d as Circ2d +from GeomAPI import GeomAPI_Dir as Dir +from GeomAPI import GeomAPI_Lin as Lin +from GeomAPI import GeomAPI_Lin2d as Lin2d +from GeomAPI import GeomAPI_Pnt as Pnt +from GeomAPI import GeomAPI_Pnt2d as Pnt2d +from GeomAPI import GeomAPI_XY as XY +from GeomAPI import GeomAPI_XYZ as XYZ + +from GeomAPI import GeomAPI_Shape as Shape + + +# Swigged interfaces to Modeling Algorithms + +from GeomAlgoAPI import GeomAlgoAPI_Boolean as Boolean +from GeomAlgoAPI import GeomAlgoAPI_Extrusion as Extrusion + + +# Emulation of interfaces not yet swigged + +from missed import * \ No newline at end of file diff --git a/src/PythonAPI/geom/missed.py b/src/PythonAPI/geom/missed.py new file mode 100644 index 000000000..0aa6db1e3 --- /dev/null +++ b/src/PythonAPI/geom/missed.py @@ -0,0 +1,25 @@ +# Direct Geometry API not yet swigged +# Author: Daniel Brunier-Coulin +# ----------------------------- + +from GeomAPI import * + + +class Ax3: + + def __init__(self, origin, normal, dirx): + self.o = origin + self.n = normal + self.dx = dirx + + def location (self): + return self.o + + def direction (self): + return self.n + + def xDirection (self): + return self.dx + + def yDirection (self): + return self.n.cross(self.dx) diff --git a/src/PythonAPI/modeler/__init__.py b/src/PythonAPI/modeler/__init__.py new file mode 100644 index 000000000..8ffaa381e --- /dev/null +++ b/src/PythonAPI/modeler/__init__.py @@ -0,0 +1,16 @@ +"""This package defines the Parametric Geometry API of the Modeler. +""" + +# General purpose functions and abstract root classes + +from services import * +from roots import * + +# Built-in features + +from part import Part as addPart +from sketcher import Sketch as addSketch +from extrusion import Extrusion as addExtrusion +from boolean import Addition as addAddition +from boolean import Subtraction as addSubtraction +from boolean import Intersection as addIntersection \ No newline at end of file diff --git a/src/PythonAPI/modeler/boolean.py b/src/PythonAPI/modeler/boolean.py new file mode 100644 index 000000000..adc8d6613 --- /dev/null +++ b/src/PythonAPI/modeler/boolean.py @@ -0,0 +1,48 @@ +"""Boolean operations Interface +Author: Daniel Brunier-Coulin +Copyright (C) 2014-20xx CEA/DEN, EDF R&D +""" + +from ModelAPI import * +from GeomAlgoAPI import * + + +class Boolean(): + """Abstract root class of Boolean Features.""" + def __init__(self, part, object, tool, type): + self.my = part.addFeature("Boolean") + self.my.data().reference("main_object").setValue(object) + self.my.data().reference("tool_object").setValue(tool) + self.my.data().integer("bool_type").setValue(type) + + if ModelAPI_Session.get().validators().validate(self.my): + self.my.execute() + else: + raise Exception("cannot make the Boolean") + + +class Addition(Boolean): + + def __init__(self, part, object, tool): + """Inserts an addition to the given Part and executes the operation. + This operation adds tool to the given object. + """ + Boolean.__init__(self, part, object, tool, GeomAlgoAPI_Boolean.BOOL_FUSE) + + +class Subtraction(Boolean): + + def __init__(self, part, object, tool): + """Inserts a subtraction to the given Part and executes the operation. + This operation subtracts tool to the given object. + """ + Boolean.__init__(self, part, object, tool, GeomAlgoAPI_Boolean.BOOL_CUT) + + +class Intersection(Boolean): + + def __init__(self, part, object, tool): + """Inserts an intersection to the given Part and executes the operation. + This operation intersects tool to the given object. + """ + Boolean.__init__(self, part, object, tool, GeomAlgoAPI_Boolean.BOOL_COMMON) \ No newline at end of file diff --git a/src/PythonAPI/modeler/extrusion.py b/src/PythonAPI/modeler/extrusion.py new file mode 100644 index 000000000..ecb7fbe79 --- /dev/null +++ b/src/PythonAPI/modeler/extrusion.py @@ -0,0 +1,42 @@ +"""Extrusion Interface +Author: Daniel Brunier-Coulin with contribution by Mikhail Ponikarov +Copyright (C) 2014-20xx CEA/DEN, EDF R&D +""" + +from ModelAPI import * + + +class Extrusion(): + + def __init__ (self, part, sketch, size): + """Inserts an extrusion of the given Sketch to the given Part and executes the operation.""" + self.my = part.addFeature("Extrusion") + self.my.data().selectionList("base").append(sketch.result(), sketch.buildShape()) + if size < 0: + self.my.data().boolean("reverse").setValue(True) + size = -size + else: + self.my.data().boolean("reverse").setValue(False) + + self.my.data().real("size").setValue(size) + + if ModelAPI_Session.get().validators().validate(self.my): + self.my.execute() + else: + raise Exception("cannot make the Extrusion") + + + def setSize (self, size): + """Modifies the size of this extrusion according to the given size.""" + if size < 0: + self.my.data().boolean("reverse").setValue(True) + size = -size + else: + self.my.data().boolean("reverse").setValue(False) + + self.my.data().real("size").setValue(size) + self.my.execute() + + def result (self): + """Returns the result data of this Feature.""" + return self.my.firstResult() diff --git a/src/PythonAPI/modeler/part.py b/src/PythonAPI/modeler/part.py new file mode 100644 index 000000000..597d1cc75 --- /dev/null +++ b/src/PythonAPI/modeler/part.py @@ -0,0 +1,19 @@ +"""Part Feature Interface +Author: Daniel Brunier-Coulin +Copyright (C) 2014-20xx CEA/DEN, EDF R&D +""" + +import modeler # Required by the temporary implementation of result member function + + +class Part(): + + def __init__ (self, partset): + """Adds a new Part to the given Partset and activates the Part.""" + self.my = partset.addFeature("Part") + self.my.execute() + + def document (self): + """Returns the Part document created by this feature.""" + #TODO: Get the document referenced by this feature + return modeler.activeDocument() \ No newline at end of file diff --git a/src/PythonAPI/modeler/roots.py b/src/PythonAPI/modeler/roots.py new file mode 100644 index 000000000..62288ebb3 --- /dev/null +++ b/src/PythonAPI/modeler/roots.py @@ -0,0 +1,41 @@ +"""Abstract root classes of user-defined Python features producing a Body +Author: Daniel Brunier-Coulin +Copyright (C) 2014-20xx CEA/DEN, EDF R&D +""" + +from ModelAPI import * + + +class Feature(ModelAPI_Feature): + """Base class of user-defined Python features.""" + + def __init__(self): + ModelAPI_Feature.__init__(self) + + def addRealInput (self, inputid): + self.data().addAttribute(inputid, ModelAPI_AttributeDouble_typeId()) + + def getRealInput (self, inputid): + return self.data().real(inputid).value() + + def addResult (self, result): + shape = result.shape() + body = self.document().createBody( self.data() ) + body.store(shape) + self.setResult(body) + + +class Interface(): + """Base class of hight level Python interfaces to features.""" + + def __init__(self, container, fid): + self.my = container.addFeature(fid) + + def setRealInput (self, inputid, value): + self.my.data().real(inputid).setValue(value) + + def areInputValid (self): + return ModelAPI_Session.get().validators().validate(self.my) + + def execute (self): + self.my.execute() \ No newline at end of file diff --git a/src/PythonAPI/modeler/services.py b/src/PythonAPI/modeler/services.py new file mode 100644 index 000000000..d463c5951 --- /dev/null +++ b/src/PythonAPI/modeler/services.py @@ -0,0 +1,72 @@ +"""General purpose Interface +Author: Daniel Brunier-Coulin +Copyright (C) 2014-20xx CEA/DEN, EDF R&D +""" + +from ModelAPI import * +from GeomAPI import * +import geom # To be removed when gp_Ax3 will be Pythonized + + +def moduleDocument (): + """Returns the main document (the Partset) created or open from the Modeler. + This document is unique in the application session. + """ + return ModelAPI_Session.get().moduleDocument() + + +def activeDocument (): + """Returns the active document. + This document can be either the main application document (i.e. the Partset) or one of documents + referred to by the main document (a Part). + """ + return ModelAPI_Session.get().activeDocument() + + +def defaultPlane (name): + """Returns one of the three planes defined by the global coordinate system. + These planes are respectively referred to by name "XOY" (Z=0), "XOZ" (Y=0) or "YOZ" (X=0). + """ +# Temporary implementation before the availability of default planes. + + o = GeomAPI_Pnt( 0, 0, 0 ) + if name == "XOY": + n = GeomAPI_Dir( 0, 0, 1) + x = GeomAPI_Dir( 1, 0, 0) + elif name == "XOZ": + n = GeomAPI_Dir( 0, 1, 0) + x = GeomAPI_Dir( 1, 0, 0) + elif name == "YOZ": + n = GeomAPI_Dir( 1, 0, 0) + x = GeomAPI_Dir( 0, 1, 0) + + return geom.Ax3( o, n, x ) + + +def begin (): + """Starts a data structure transaction, as such making a control point for being able to discard or undo + all operations done during this transaction. + """ + ModelAPI_Session.get().startOperation() + + +def end (): + """Commits the data structure transaction and makes all operations done since the last control point undo-able.""" + ModelAPI_Session.get().finishOperation() + + +def do (): + """Commits the data structure transaction and makes all operations done since the last control point undo-able.""" + session = ModelAPI_Session.get() + session.finishOperation() + session.startOperation() + + +def undo (): + """Rolls-back the data structure to the previous control point.""" + ModelAPI_Session.get().undo() + + +def redo (): + """Restore the data structure rolled-back by the last undo.""" + ModelAPI_Session.get().redo() diff --git a/src/PythonAPI/modeler/sketcher.py b/src/PythonAPI/modeler/sketcher.py new file mode 100644 index 000000000..5aa7b54ad --- /dev/null +++ b/src/PythonAPI/modeler/sketcher.py @@ -0,0 +1,242 @@ +"""Sketch Feature Interface +Author: Daniel Brunier-Coulin with contribution by Mikhail Ponikarov +Copyright (C) 2014-20xx CEA/DEN, EDF R&D +""" + +from ModelAPI import * +from GeomDataAPI import * +from GeomAlgoAPI import * + + +class Sketch(): + + def __init__(self, doc, plane): + """Initializes a 2D Sketch on the given plane and adds the Sketch to the given Part or Partset. + The plane can be defined either by: + - a 3D axis system (geom.Ax3), + - an existing face identified by its topological name. + """ + self.my = featureToCompositeFeature( doc.addFeature("Sketch") ) + self.selection = None # Entities used for building the result shape +# self.resultype ="Face" # Type of Sketch result + if isinstance(plane, str): + self.__sketchOnFace(doc, plane) + else: + self.__sketchOnPlane(doc, plane) + + def __sketchOnPlane (self, doc, plane): + o = plane.location() + d = plane.direction() + dx = plane.xDirection() + geomDataAPI_Point( self.my.data().attribute("Origin") ).setValue( o.x(), o.y(), o.z() ) + geomDataAPI_Dir( self.my.data().attribute("DirX") ).setValue( dx.x(), dx.y(), dx.z() ) + geomDataAPI_Dir( self.my.data().attribute("Norm") ).setValue( d.x(), d.y(), d.z() ) + + def __sketchOnFace (self, doc, plane): + self.my.data().selection("External").selectSubShape("FACE", plane) + + +# Creation of Geometries + + def addPoint (self, *args): + """Adds a point to this Sketch.""" + return Point(self.my, *args) + + def addLine (self, *args): + """Adds a line to this Sketch.""" + return Line(self.my, *args) + + def addPolyline (self, *coords): + """Adds a poly-line to this Sketch. + The end of consecutive segments are defined as coincident. + """ + c0 = coords[0] + c1 = coords[1] + pl = [] + l1 = self.addLine(c0, c1) + pl.append(l1) + # Adding and connecting next lines + for c2 in coords[2:]: + l2 = self.addLine(c1, c2) + self.setCoincident( l1.endPointData(), l2.startPointData() ) + pl.append(l2) + c1 = c2 + l1 = l2 + return pl + + def addPolygon (self, *coords): + """Adds a polygon to this Sketch. + The end of consecutive segments are defined as coincident. + """ + pg = self.addPolyline(*coords) + # Closing the poly-line supposed being defined by at least 3 points + c0 = coords[0] + cn = coords[len(coords)-1] + ln = self.addLine(cn, c0) + self.setCoincident( pg[len(coords)-2].endPointData(), ln.startPointData() ) + self.setCoincident( ln.endPointData(), pg[0].startPointData() ) + pg.append(ln) + return pg + + def addCircle (self, *args): + """Adds a circle to this Sketch.""" + return Circle(self.my, *args) + + +# Creation of Geometrical and Dimensional Constraints + + def setCoincident (self, p1, p2): + """Sets coincident the two given points and adds the corresponding constraint to this Sketch.""" + constraint = self.my.addFeature("SketchConstraintCoincidence") + constraint.data().refattr("ConstraintEntityA").setAttr(p1) + constraint.data().refattr("ConstraintEntityB").setAttr(p2) + return constraint + + def setParallel (self, l1, l2): + """Sets parallel the two given lines and adds the corresponding constraint to this Sketch.""" + constraint = self.my.addFeature("SketchConstraintParallel") + constraint.data().refattr("ConstraintEntityA").setObject(l1) + constraint.data().refattr("ConstraintEntityB").setObject(l2) + return constraint + + def setPerpendicular (self, l1, l2): + """Sets perpendicular the two given lines and adds the corresponding constraint to this Sketch.""" + constraint = self.my.addFeature("SketchConstraintPerpendicular") + constraint.data().refattr("ConstraintEntityA").setObject(l1) + constraint.data().refattr("ConstraintEntityB").setObject(l2) + return constraint + + def setDistance (self, point, line, length): + """Sets the distance between the given point and line, and adds the corresponding constraint to this Sketch.""" + constraint = self.my.addFeature("SketchConstraintDistance") + if isinstance(line, str): + line = self.addLine(line).result() # Adds the edge identified by the given topological name to this Sketch + constraint.data().refattr("ConstraintEntityA").setAttr(point) + constraint.data().refattr("ConstraintEntityB").setObject(line) + constraint.data().real("ConstraintValue").setValue(length) + self.my.execute() + return constraint + + def setLength (self, line, length): + """Sets the length of the given line and adds the corresponding constraint to this Sketch.""" + constraint = self.my.addFeature("SketchConstraintLength") + constraint.data().refattr("ConstraintEntityA").setObject(line) + constraint.data().real("ConstraintValue").setValue(length) + return constraint + + def setRadius (self, circle, radius): + """Sets the radius of the given circle and adds the corresponding constraint to this Sketch.""" + constraint = self.my.addFeature("SketchConstraintRadius") + constraint.data().refattr("ConstraintEntityA").setObject(circle) + constraint.data().real("ConstraintValue").setValue(radius) + return constraint + + +# Edition of Dimensional Constraints + + def setValue (self, constraint, value): + """Modifies the value of the given dimensional constraint.""" + constraint.data().real("ConstraintValue").setValue(value) + + +# Getters + + def selectFace (self, *args): + """Selects the geometrical entities of this Sketch on which the result Face must be built. + When no entity is given, the face is based on all existing geometry of this Sketch. + """ + #self.resultype ="Face" + if len(args) == 0: + self.selection = modelAPI_ResultConstruction( self.my.firstResult() ).shape() + elif len(args) == 1: + self.selection = args[0].shape() + else: + raise Exception("not yet implemented") + return self + + def buildShape (self): + """Builds the result Shape of this Sketch according to the selected geometrical entities.""" + o = geomDataAPI_Point( self.my.data().attribute("Origin") ).pnt() + dx = geomDataAPI_Dir( self.my.data().attribute("DirX") ).dir() + n = geomDataAPI_Dir( self.my.data().attribute("Norm") ).dir() + + self.faces = ShapeList() # The faces are kept otherwise they are destroyed at exit + GeomAlgoAPI_SketchBuilder.createFaces(o, dx, n, self.selection, self.faces) +#TODO: Deal with several faces + return self.faces[0] + + def result (self): + """Returns the result data of this Feature.""" + return self.my.firstResult() + + +# Class definitions of Sketch features + +class Point(): + + def __init__(self, sketch, x, y): + self.my = sketch.addFeature("SketchPoint") + geomDataAPI_Point2D( self.my.data().attribute("PointCoordindates") ).setValue(x, y) + self.my.execute() + + def pointData (self): + return geomDataAPI_Point2D( self.my.data().attribute("PointCoordindates") ) + + def result (self): + return self.my.firstResult() + + +class Line(): + + def __init__(self, sketch, *args): + self.my = sketch.addFeature("SketchLine") + if len(args) == 4: + self.__createByCoordinates(*args) + elif len(args) == 2: + self.__createByPoints(*args) + elif len(args) == 1: + self.__createByName(sketch, *args) + else: + raise Exception("cannot create the Line") + + def __createByCoordinates(self, x1, y1, x2, y2): + geomDataAPI_Point2D( self.my.data().attribute("StartPoint") ).setValue(x1, y1) + geomDataAPI_Point2D( self.my.data().attribute("EndPoint") ).setValue(x2, y2) + self.my.execute() + + def __createByPoints(self, p1, p2): + geomDataAPI_Point2D( self.my.data().attribute("StartPoint") ).setValue(p1.x(), p1.y()) + geomDataAPI_Point2D( self.my.data().attribute("EndPoint") ).setValue(p2.x(), p2.y()) + self.my.execute() + + def __createByName(self, sketch, name): + self.my.data().selection("External").selectSubShape("EDGE", name) + self.my.execute() + rigid = sketch.addFeature("SketchConstraintRigid") + rigid.refattr("ConstraintEntityA").setObject( self.my.firstResult() ) + + def startPointData (self): + return geomDataAPI_Point2D( self.my.data().attribute("StartPoint") ) + + def endPointData (self): + return geomDataAPI_Point2D( self.my.data().attribute("EndPoint") ) + + def result (self): + return self.my.firstResult() + + +class Circle(): + + def __init__(self, sketch, x, y, r): + self.my = sketch.addFeature("SketchCircle") + geomDataAPI_Point2D( self.my.data().attribute("CircleCenter") ).setValue(x, y) + self.my.data().real("CircleRadius").setValue(r) + self.my.execute() + + def centerData (self): + return geomDataAPI_Point2D( self.my.data().attribute("CircleCenter") ) + + def result (self): + return self.my.lastResult() # Returns the circular line attribute + + diff --git a/src/PythonAddons/CMakeLists.txt b/src/PythonAddons/CMakeLists.txt new file mode 100644 index 000000000..37f3efc05 --- /dev/null +++ b/src/PythonAddons/CMakeLists.txt @@ -0,0 +1,10 @@ +## Copyright (C) 2014-20xx OPEN CASCADE + + +SET(CMAKE_AUTOMOC ON) + +INSTALL(FILES addons_Features.py addons_Features.xml DESTINATION plugins) + + +INSTALL(FILES __init__.py DESTINATION addons) +INSTALL(DIRECTORY macros DESTINATION addons) diff --git a/src/PythonAddons/__init__.py b/src/PythonAddons/__init__.py new file mode 100644 index 000000000..caf9c1cd4 --- /dev/null +++ b/src/PythonAddons/__init__.py @@ -0,0 +1 @@ +"""User-defined features""" \ No newline at end of file diff --git a/src/PythonFeaturesPlugin/PythonFeaturesPlugin.py b/src/PythonAddons/addons_Features.py similarity index 57% rename from src/PythonFeaturesPlugin/PythonFeaturesPlugin.py rename to src/PythonAddons/addons_Features.py index 890b3ae15..00c72b027 100644 --- a/src/PythonFeaturesPlugin/PythonFeaturesPlugin.py +++ b/src/PythonAddons/addons_Features.py @@ -1,8 +1,9 @@ -""" +"""Registration of all user-defined Python features """ import ModelAPI -from PythonFeaturesPlugin_Box import PythonFeaturesPlugin_Box +from macros.box.feature import BoxFeature +from macros.cylinder.feature import CylinderFeature class PythonFeaturesPlugin(ModelAPI.ModelAPI_Plugin): @@ -15,11 +16,16 @@ class PythonFeaturesPlugin(ModelAPI.ModelAPI_Plugin): def createFeature(self, theFeatureID): aFeature = None - if theFeatureID == PythonFeaturesPlugin_Box.ID(): - aCompositeFeature = PythonFeaturesPlugin_Box().__disown__() - aFeature = ModelAPI.compositeFeatureToFeature(aCompositeFeature) + + if theFeatureID == BoxFeature.ID(): + aFeature = BoxFeature().__disown__() + + elif theFeatureID == CylinderFeature.ID(): + aFeature = CylinderFeature().__disown__() + else: raise StandardError("No such feature %s" % theFeatureID) + return aFeature diff --git a/src/PythonAddons/addons_Features.xml b/src/PythonAddons/addons_Features.xml new file mode 100644 index 000000000..4fe748a5d --- /dev/null +++ b/src/PythonAddons/addons_Features.xml @@ -0,0 +1,4 @@ + + + + diff --git a/src/PythonAddons/macros/__init__.py b/src/PythonAddons/macros/__init__.py new file mode 100644 index 000000000..672545afc --- /dev/null +++ b/src/PythonAddons/macros/__init__.py @@ -0,0 +1,7 @@ +"""Python macro-features package +A macro-feature is a feature which executes a sequence of user actions. +Such feature is not registered in the application history. Instead, +only the operations it encapsulates are registered. +For editing the result of such feature, the user edits the operations +used in the macro-feature. +""" \ No newline at end of file diff --git a/src/PythonAddons/macros/box/__init__.py b/src/PythonAddons/macros/box/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/PythonAddons/macros/box/feature.py b/src/PythonAddons/macros/box/feature.py new file mode 100644 index 000000000..675b84c42 --- /dev/null +++ b/src/PythonAddons/macros/box/feature.py @@ -0,0 +1,89 @@ +"""Box macro-feature +Authors: Renaud Nedelec - Daniel Brunier-Coulin +Copyright (C) 2014-20xx CEA/DEN, EDF R&D +""" + +import modeler +import geom + + +class BoxFeature(modeler.Feature): + + +# Initializations + + def __init__(self): + modeler.Feature.__init__(self) + + @staticmethod + def ID(): + return "Box" + + @staticmethod + def WIDTH_ID(): + return "width" + + @staticmethod + def LENGTH_ID(): + return "length" + + @staticmethod + def HEIGHT_ID(): + return "height" + + def getKind(self): + return BoxFeature.ID() + + +# Creation of the box at default size + + def initAttributes(self): + + # Creating the input arguments of the feature + self.addRealInput( self.WIDTH_ID() ) + self.addRealInput( self.LENGTH_ID() ) + self.addRealInput( self.HEIGHT_ID() ) + + # Creating the base of the box with unit values + mypart = modeler.activeDocument() + xoy = modeler.defaultPlane("XOY") + + self.base = modeler.addSketch( mypart, xoy ) + + p1 = geom.Pnt2d( 0, 0 ) + p2 = geom.Pnt2d( 0, 1 ) + p3 = geom.Pnt2d( 1, 1 ) + p4 = geom.Pnt2d( 1, 0 ) + + line = self.base.addPolygon(p1, p2, p3, p4) + + self.base.setParallel( line[0].result(), line[2].result() ) + self.base.setParallel( line[1].result(), line[3].result() ) + self.base.setPerpendicular( line[0].result(), line[3].result() ) + + # Setting the size of the base with default values + self.width = self.base.setLength( line[0].result(), 50 ) # Keeps the constraint for edition + self.length = self.base.setLength( line[3].result(), 50 ) # Keeps the constraint for edition + + # Creating the extrusion (the box) at default size + self.box = modeler.addExtrusion( mypart, self.base.selectFace(), 50 ) + + +# Edition of the box at user size + + def execute(self): + # Retrieving the user inputs + width = self.getRealInput( self.WIDTH_ID() ) + length = self.getRealInput( self.LENGTH_ID() ) + height = self.getRealInput( self.HEIGHT_ID() ) + + # Editing the box + self.base.setValue( self.width, width ) + self.base.setValue( self.length, length ) + self.box.setSize( height ) + + # Publishing the result + self.addResult( self.box.result() ) + + + diff --git a/src/PythonAddons/macros/box/widget.xml b/src/PythonAddons/macros/box/widget.xml new file mode 100644 index 000000000..fc0bb3ba6 --- /dev/null +++ b/src/PythonAddons/macros/box/widget.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/PythonAddons/macros/cylinder/__init__.py b/src/PythonAddons/macros/cylinder/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/PythonAddons/macros/cylinder/feature.py b/src/PythonAddons/macros/cylinder/feature.py new file mode 100644 index 000000000..fd66f3836 --- /dev/null +++ b/src/PythonAddons/macros/cylinder/feature.py @@ -0,0 +1,68 @@ +"""Cylinder macro-feature +Authors: Daniel Brunier-Coulin +Copyright (C) 2014-20xx CEA/DEN, EDF R&D +""" + +import modeler +import geom + + +class CylinderFeature(modeler.Feature): + + +# Initializations + + def __init__(self): + modeler.Feature.__init__(self) + + @staticmethod + def ID(): + return "Cylinder" + + @staticmethod + def RADIUS_ID(): + return "radius" + + @staticmethod + def LENGTH_ID(): + return "length" + + def getKind(self): + return CylinderFeature.ID() + + +# Creation of the cylinder at default size + + def initAttributes(self): + + # Creating the input arguments of the feature + self.addRealInput( self.RADIUS_ID() ) + self.addRealInput( self.LENGTH_ID() ) + + # Creating the base of the cylinder with unit values + mypart = modeler.activeDocument() + xoy = modeler.defaultPlane("XOY") + + self.base = modeler.addSketch( mypart, xoy ) + circle = self.base.addCircle( 0, 0, 1) + + # Setting the radius of the base with default values + self.radius = self.base.setRadius( circle.result(), 10 ) # Keeps the constraint for edition + + # Creating the extrusion (the cylinder) at default size + self.cyl = modeler.addExtrusion( mypart, self.base.selectFace(), 50 ) + + +# Edition of the cylinder at user size + + def execute(self): + # Retrieving the user inputs + radius = self.getRealInput( self.RADIUS_ID() ) + length = self.getRealInput( self.LENGTH_ID() ) + + # Editing the cylinder + self.base.setValue( self.radius, radius ) + self.cyl.setSize( length ) + + # Publishing the result + self.addResult( self.cyl.result() ) \ No newline at end of file diff --git a/src/PythonAddons/macros/cylinder/widget.xml b/src/PythonAddons/macros/cylinder/widget.xml new file mode 100644 index 000000000..8b2101f9b --- /dev/null +++ b/src/PythonAddons/macros/cylinder/widget.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/PythonFeaturesPlugin/CMakeLists.txt b/src/PythonFeaturesPlugin/CMakeLists.txt deleted file mode 100644 index 1e600b3df..000000000 --- a/src/PythonFeaturesPlugin/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -INCLUDE(Common) - -SET(PYTHON_FILES - PythonFeaturesPlugin_Box.py - PythonFeaturesPlugin.py - sketch.py - extrusion.py - examples.py - SketchResult.py -) - -SET(XML_RESSOURCES - plugin-PythonFeatures.xml - box_widget.xml -) - -INSTALL(FILES ${PYTHON_FILES} ${XML_RESSOURCES} DESTINATION plugins) diff --git a/src/PythonFeaturesPlugin/FeaturesAPI.py b/src/PythonFeaturesPlugin/FeaturesAPI.py deleted file mode 100644 index f47ba3f70..000000000 --- a/src/PythonFeaturesPlugin/FeaturesAPI.py +++ /dev/null @@ -1,47 +0,0 @@ -from ModelAPI import * -from GeomDataAPI import * -from GeomAlgoAPI import * - -# NOTE : I think this style should be chosen -# for function as recommended by Python programming -# standards - - -def build_face_from_sketch(sketch, edges=None): - # If no edges have been selected, get the whole sketch - # edges - if edges == None: - result = sketch.firstResult() - edges = modelAPI_ResultConstruction(result).shape() - - # Build the face - origin = geomDataAPI_Point(sketch.attribute("Origin")).pnt() - dirX = geomDataAPI_Dir(sketch.attribute("DirX")).dir() - dirY = geomDataAPI_Dir(sketch.attribute("DirY")).dir() - normal = geomDataAPI_Dir(sketch.attribute("Norm")).dir() - faces = ShapeList() - GeomAlgoAPI_SketchBuilder.createFaces( - origin, dirX, dirY, normal, edges, faces) - return faces[0] - -# NOTE : with an optional argument it is not -# a so good idea to put part as last argument -# it would result in a mandatory argument -# put after an optionnal one - - -def addExtrusion(part, sketch, size, reverse=False, subshapes=None): - feature = part.addFeature("Extrusion") - - # Build apropriate face - face = build_face_from_sketch(sketch, subshapes) - # Get sketch result - sketchResult = sketch.firstResult() - - # Set attributes and execute the feature - feature.selection("extrusion_face").setValue(sketchResult, face) - feature.real("extrusion_size").setValue(size) - feature.boolean("extrusion_reverse").setValue(False) - feature.execute() - - return feature diff --git a/src/PythonFeaturesPlugin/PythonFeaturesPlugin_Box.py b/src/PythonFeaturesPlugin/PythonFeaturesPlugin_Box.py deleted file mode 100644 index fd5686355..000000000 --- a/src/PythonFeaturesPlugin/PythonFeaturesPlugin_Box.py +++ /dev/null @@ -1,170 +0,0 @@ -import ModelAPI - -from SketchResult import SketchResult -import extrusion -import sketch - - -class PythonFeaturesPlugin_Box(ModelAPI.ModelAPI_CompositeFeature): - """Feature to create a box by drawing a sketch and extruding it - """ - - def __init__(self): - ModelAPI.ModelAPI_CompositeFeature.__init__(self) - - @staticmethod - def ID(): - return "Box" - - @staticmethod - def WIDTH_ID(): - return "box_width" - - @staticmethod - def LENGTH_ID(): - return "box_length" - - @staticmethod - def HEIGHT_ID(): - return "box_height" - - @staticmethod - def WIDTH_REF_ID(): - return "box_ref_width" - - @staticmethod - def LENGTH_REF_ID(): - return "box_ref_length" - - @staticmethod - def HEIGHT_REF_ID(): - return "box_ref_height" - - def getKind(self): - return PythonFeaturesPlugin_Box.ID() - - def initAttributes(self): - # C++ static methods (in example "type()" of the ModelAPI_AttributeDouble - # should be called like this: moduleName.ClassName_staticMethod() - self.data().addAttribute(self.WIDTH_ID(), ModelAPI.ModelAPI_AttributeDouble_typeId()) - self.data().addAttribute(self.LENGTH_ID(), ModelAPI.ModelAPI_AttributeDouble_typeId()) - self.data().addAttribute(self.HEIGHT_ID(), ModelAPI.ModelAPI_AttributeDouble_typeId()) - self.data().addAttribute(self.WIDTH_REF_ID(), ModelAPI.ModelAPI_AttributeReference_typeId()) - self.data().addAttribute(self.LENGTH_REF_ID(), ModelAPI.ModelAPI_AttributeReference_typeId()) - self.data().addAttribute(self.HEIGHT_REF_ID(), ModelAPI.ModelAPI_AttributeReference_typeId()) - aSession = ModelAPI.ModelAPI_Session.get() - aSession.validators().registerNotObligatory(self.getKind(), self.WIDTH_REF_ID()) - aSession.validators().registerNotObligatory(self.getKind(), self.LENGTH_REF_ID()) - aSession.validators().registerNotObligatory(self.getKind(), self.HEIGHT_REF_ID()) - aSession.validators().registerConcealment(self.getKind(), self.HEIGHT_REF_ID()) - self.mySketch = None # not yet initialized - self.myExtrusion = None # not yet initialized - - def execute(self): - aWidth = self.real(self.WIDTH_ID()).value() - aLength = self.real(self.LENGTH_ID()).value() - aHeight = self.real(self.HEIGHT_ID()).value() - aWidthRefValue = self.reference(self.WIDTH_REF_ID()).value() - aLengthRefValue = self.reference(self.LENGTH_REF_ID()).value() - aHeightRefValue = self.reference(self.HEIGHT_REF_ID()).value() - aResult = None - if not all((aWidthRefValue, aLengthRefValue, aHeightRefValue)): - aResult = extrusion.getBody(self.makeBox(aLength, aWidth, aHeight)) - else: - aHeightProxyResult = ModelAPI.modelAPI_Result(aHeightRefValue) - aWidthFeature = ModelAPI.objectToFeature(aWidthRefValue) - aLengthFeature = ModelAPI.objectToFeature(aLengthRefValue) - aHeightResult = ModelAPI.modelAPI_ResultBody(aHeightProxyResult) - aWidthFeature.real("ConstraintValue").setValue(aWidth) - aLengthFeature.real("ConstraintValue").setValue(aLength) - if aHeightResult is not None: - aHeightFeature = aHeightResult.document().feature(aHeightResult) - aHeightFeature.real("extrusion_size").setValue(aHeight) - aResult = extrusion.getBody(aHeightFeature) - # create a new result with copied shape from extrusion - aResultBody = self.document().createBody(self.data()) - if not aResult is None: - aResultBody.store(aResult.shape()) - self.setResult(aResultBody) - pass - - def makeBox(self, aWidth, aLength, aHeight): - aSession = ModelAPI.ModelAPI_Session.get() - aPart = aSession.activeDocument() - # Starting the Sketch - aSketch = sketch.addTo(aPart) - self.mySketch = aSketch - sketch.setXOYPlane(aSketch) - # Creating the lines - l1 = sketch.addLine(10, 10, 10, 60, aSketch) - l2 = sketch.addLine(10, 60, 60, 60, aSketch) - l3 = sketch.addLine(60, 60, 60, 10, aSketch) - l4 = sketch.addLine(60, 10, 10, 10, aSketch) - aSketch.execute() - # Creating the constraints - sketch.makeCoincident(sketch.getEndPoint(l1), sketch.getStartPoint(l2), aSketch) - sketch.makeCoincident(sketch.getEndPoint(l2), sketch.getStartPoint(l3), aSketch) - sketch.makeCoincident(sketch.getEndPoint(l3), sketch.getStartPoint(l4), aSketch) - sketch.makeCoincident(sketch.getEndPoint(l4), sketch.getStartPoint(l1), aSketch) - sketch.makeParallel(sketch.getGeometry(l1), sketch.getGeometry(l3), aSketch) - sketch.makeParallel(sketch.getGeometry(l2), sketch.getGeometry(l4), aSketch) - sketch.makePerpendicular(sketch.getGeometry(l1), sketch.getGeometry(l4), aSketch) - # Set to 0X and 0Y lines defined length - aWidthFeature = sketch.makeConstantLength(sketch.getGeometry(l4), aWidth, aSketch) - aLengthFeature = sketch.makeConstantLength(sketch.getGeometry(l1), aLength, aSketch) - # Finalisation of the operation - builder = SketchResult(aSketch) - # Creating a feature Extrusion - aHeightFeature = extrusion.addNew(builder, aHeight, aPart) - self.myExtrusion = aHeightFeature - # Store features... - self.reference(self.WIDTH_REF_ID()).setValue(aWidthFeature) - self.reference(self.LENGTH_REF_ID()).setValue(aLengthFeature) - self.reference(self.HEIGHT_REF_ID()).setValue(aHeightFeature.firstResult()) - return aHeightFeature - - def addFeature(self, theID): - pass - - def numberOfSubs(self): - subsCount = 0 - if not self.mySketch is None: - subsCount += 1 - if not self.myExtrusion is None: - subsCount += 1 - # extrusion and sketch - return subsCount - - def subFeature(self, theIndex): - if theIndex == 0: # sketch - return ModelAPI.compositeFeatureToFeature(self.mySketch) - return self.myExtrusion - - def subFeatureId(self, theIndex): - return 0 - - def isSub(self, theFeature): - return theFeature == self.mySketch or theFeature == self.myExtrusion - - def attributeChanged(self, theAttrID): - # on update of attributes values, transfer them to sub-features immideately to see good preview - # otherwise these features will be executed before execute of "Box" and with old parameters - aWidthRefValue = self.reference(self.WIDTH_REF_ID()).value() - aLengthRefValue = self.reference(self.LENGTH_REF_ID()).value() - aHeightRefValue = self.reference(self.HEIGHT_REF_ID()).value() - if all((aWidthRefValue, aLengthRefValue, aHeightRefValue)): - self.execute() - -# TEST -""" -if __name__=='__main__': - session = ModelAPI.ModelAPI_Session.get() - part = session.activeDocument() - session.startOperation() - feature = part.addFeature('Box') - feature.real('box_width').setValue(10) - feature.real('box_length').setValue(10) - feature.real('box_height').setValue(10) - feature.execute() - session.finishOperation() -""" diff --git a/src/PythonFeaturesPlugin/SketchResult.py b/src/PythonFeaturesPlugin/SketchResult.py deleted file mode 100644 index 8d8b77a32..000000000 --- a/src/PythonFeaturesPlugin/SketchResult.py +++ /dev/null @@ -1,26 +0,0 @@ -from ModelAPI import * -from GeomDataAPI import * -from GeomAlgoAPI import * - - -class SketchResult: - - def __init__(self, sketch): - self.geom = sketch.firstResult() - self.faces = ShapeList() - self.edges = modelAPI_ResultConstruction(self.geom).shape() - self.origin = geomDataAPI_Point(sketch.attribute("Origin")).pnt() - self.dirX = geomDataAPI_Dir(sketch.attribute("DirX")).dir() - self.dirY = geomDataAPI_Dir(sketch.attribute("DirY")).dir() - self.normal = geomDataAPI_Dir(sketch.attribute("Norm")).dir() - - def setEdges(self, edges): - self.edges = edges - - def geometry(self): - return self.geom - - def face(self): - GeomAlgoAPI_SketchBuilder.createFaces( - self.origin, self.dirX, self.dirY, self.normal, self.edges, self.faces) - return self.faces[0] diff --git a/src/PythonFeaturesPlugin/box_widget.xml b/src/PythonFeaturesPlugin/box_widget.xml deleted file mode 100644 index 7c1a2c553..000000000 --- a/src/PythonFeaturesPlugin/box_widget.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/src/PythonFeaturesPlugin/examples.py b/src/PythonFeaturesPlugin/examples.py deleted file mode 100644 index 9f68e9234..000000000 --- a/src/PythonFeaturesPlugin/examples.py +++ /dev/null @@ -1,51 +0,0 @@ -from ModelAPI import * -from SketchResult import * -import sketch -import extrusion -# reload(sketch) # Pour tester plus facilement -# reload(extrusion) # Pour tester plus facilement - - -def makeBox(aLength, aWidth, aHeight): - # Getting the active document - session = ModelAPI_Session.get() - part = session.activeDocument() - - # Starting the Sketch - base = sketch.addTo(part) - sketch.setXOYPlane(base) - - # Creating the lines - l1 = sketch.addLine(10, 10, 10, 50, base) - l2 = sketch.addLine(10, 50, 60, 60, base) - l3 = sketch.addLine(60, 60, 50, 10, base) - l4 = sketch.addLine(50, 10, 10, 10, base) - base.execute() - - # Creating the constraints - sketch.makeCoincident(sketch.getEndPoint(l1), - sketch.getStartPoint(l2), base) - sketch.makeCoincident(sketch.getEndPoint(l2), - sketch.getStartPoint(l3), base) - sketch.makeCoincident(sketch.getEndPoint(l3), - sketch.getStartPoint(l4), base) - sketch.makeCoincident(sketch.getEndPoint(l4), - sketch.getStartPoint(l1), base) - - sketch.makeParallel(sketch.getGeometry(l1), sketch.getGeometry(l3), base) - sketch.makeParallel(sketch.getGeometry(l2), sketch.getGeometry(l4), base) - - sketch.makePerpendicular(sketch.getGeometry(l1), - sketch.getGeometry(l4), base) - # Set to 0X and 0Y lines defined length - sketch.makeConstantLength(sketch.getGeometry(l1), aLength, base) - sketch.makeConstantLength(sketch.getGeometry(l4), aWidth, base) - - # Finalisation of the operation - builder = SketchResult(base) - - # Creating a feature Extrusion - box = extrusion.addNew(builder, aHeight, part) - - # return base.lastResult() - return extrusion.getBody(box) diff --git a/src/PythonFeaturesPlugin/extrusion.py b/src/PythonFeaturesPlugin/extrusion.py deleted file mode 100644 index 225bd9e12..000000000 --- a/src/PythonFeaturesPlugin/extrusion.py +++ /dev/null @@ -1,17 +0,0 @@ -from ModelAPI import * - - -def addNew(builder, length, part, edges=None, reverse=False): - feature = part.addFeature("Extrusion") - feature.selection("extrusion_face").setValue(builder.geometry(), - builder.face()) - if length < 0.0000001: - length = 50 - feature.real("extrusion_size").setValue(length) - feature.boolean("extrusion_reverse").setValue(reverse) - feature.execute() - return feature - - -def getBody(extrusion): - return modelAPI_ResultBody(extrusion.firstResult()) diff --git a/src/PythonFeaturesPlugin/plugin-PythonFeatures.xml b/src/PythonFeaturesPlugin/plugin-PythonFeatures.xml deleted file mode 100644 index 2f7b97bc5..000000000 --- a/src/PythonFeaturesPlugin/plugin-PythonFeatures.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/src/PythonFeaturesPlugin/sketch.py b/src/PythonFeaturesPlugin/sketch.py deleted file mode 100644 index 39475c048..000000000 --- a/src/PythonFeaturesPlugin/sketch.py +++ /dev/null @@ -1,134 +0,0 @@ -from ModelAPI import * -from GeomDataAPI import * - - -# Initialization of the Sketch -# ---------------------------- - -def addTo(doc): - return featureToCompositeFeature(doc.addFeature("Sketch")) - - -def setXOYPlane(sketch): - geomDataAPI_Point(sketch.attribute("Origin")).setValue(0, 0, 0) - geomDataAPI_Dir(sketch.attribute("DirX")).setValue(1, 0, 0) - geomDataAPI_Dir(sketch.attribute("DirY")).setValue(0, 1, 0) - geomDataAPI_Dir(sketch.attribute("Norm")).setValue(0, 0, 1) - - -# Point geometry -# -------------- - -def addPoint(x, y, sketch): - point = sketch.addFeature("SketchPoint") - geomDataAPI_Point2D(point.attribute("PointCoordindates")).setValue(x, y) - # Required to get the result, if needed for creating constraints - point.execute() - return point - - -def getGeometry(point): - return geomDataAPI_Point2D(point.attribute("PointCoordindates")) - - -# Line geometry -# ------------- - -def addClosedBrokenLine(coords, sketch): - c0 = coords[0] - c1 = coords[1] - bl = [] - l1 = sketch.addFeature("SketchLine") - geomDataAPI_Point2D(l1.attribute("StartPoint")).setValue(c0.x(), c0.y()) - geomDataAPI_Point2D(l1.attribute("EndPoint")).setValue(c1.x(), c1.y()) - l1.execute() - bl.append(l1) - l0 = l1 - - for c2 in coords[2:]: - l2 = sketch.addFeature("SketchLine") - geomDataAPI_Point2D( - l2.attribute("StartPoint")).setValue(c1.x(), c1.y()) - geomDataAPI_Point2D(l2.attribute("EndPoint")).setValue(c2.x(), c2.y()) - l2.execute() - bl.append(l2) - constraint = sketch.addFeature("SketchConstraintCoincidence") - constraint.refattr("ConstraintEntityA").setAttr( - l1.attribute("EndPoint")) - constraint.refattr("ConstraintEntityB").setAttr( - l2.attribute("StartPoint")) - c1 = c2 - l1 = l2 - - if len(coords) > 2: - l2 = sketch.addFeature("SketchLine") - geomDataAPI_Point2D( - l2.attribute("StartPoint")).setValue(c1.x(), c1.y()) - geomDataAPI_Point2D(l2.attribute("EndPoint")).setValue(c0.x(), c0.y()) - l2.execute() - bl.append(l2) - constraint = sketch.addFeature("SketchConstraintCoincidence") - constraint.refattr("ConstraintEntityA").setAttr( - l1.attribute("EndPoint")) - constraint.refattr("ConstraintEntityB").setAttr( - l2.attribute("StartPoint")) - - constraint = sketch.addFeature("SketchConstraintCoincidence") - constraint.refattr("ConstraintEntityA").setAttr( - l2.attribute("EndPoint")) - constraint.refattr("ConstraintEntityB").setAttr( - l0.attribute("StartPoint")) - - return bl - - -def addLine(x1, y1, x2, y2, sketch): - line = sketch.addFeature("SketchLine") - geomDataAPI_Point2D(line.attribute("StartPoint")).setValue(x1, y1) - geomDataAPI_Point2D(line.attribute("EndPoint")).setValue(x2, y2) - # Required to get the result, if needed for creating constraints - line.execute() - return line - - -def getGeometry(line): - return modelAPI_ResultConstruction(line.firstResult()) - - -def getStartPoint(line): - return geomDataAPI_Point2D(line.attribute("StartPoint")) - - -def getEndPoint(line): - return geomDataAPI_Point2D(line.attribute("EndPoint")) - - -# Constraints -# ----------- - -def makeCoincident(p1, p2, sketch): - constraint = sketch.addFeature("SketchConstraintCoincidence") - constraint.refattr("ConstraintEntityA").setAttr(p1) - constraint.refattr("ConstraintEntityB").setAttr(p2) - return constraint - - -def makeParallel(l1, l2, sketch): - constraint = sketch.addFeature("SketchConstraintParallel") - constraint.refattr("ConstraintEntityA").setObject(l1) - constraint.refattr("ConstraintEntityB").setObject(l2) - return constraint - - -def makePerpendicular(l1, l2, sketch): - constraint = sketch.addFeature("SketchConstraintPerpendicular") - constraint.refattr("ConstraintEntityA").setObject(l1) - constraint.refattr("ConstraintEntityB").setObject(l2) - return constraint - - -def makeConstantLength(line, length, sketch): - constraint = sketch.addFeature("SketchConstraintLength") - constraint.refattr("ConstraintEntityA").setObject(line) - constraint.real("ConstraintValue").setValue(length) - return constraint -- 2.30.2