From: sbh Date: Tue, 25 Nov 2014 09:10:42 +0000 (+0300) Subject: Merge branch 'master' of newgeom:newgeom.git into BR_PYTHON_PLUGIN X-Git-Tag: V_0.7.0_rc1~57^2~3^2~7 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=35a88fdd724349275bbff32b9596a44e7cd422e2;hp=1264006edf1221473f3a70ef31bcee6bbf78d23b;p=modules%2Fshaper.git Merge branch 'master' of newgeom:newgeom.git into BR_PYTHON_PLUGIN Conflicts: src/ModelAPI/ModelAPI.i src/ModelAPI/ModelAPI_Session.cpp --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f94b0fab..02ee3ea2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,7 @@ ADD_SUBDIRECTORY (src/GeomDataAPI) ADD_SUBDIRECTORY (src/PartSetPlugin) ADD_SUBDIRECTORY (src/ConstructionPlugin) ADD_SUBDIRECTORY (src/FeaturesPlugin) +ADD_SUBDIRECTORY (src/PythonFeaturesPlugin) ADD_SUBDIRECTORY (src/SketchPlugin) ADD_SUBDIRECTORY (src/SketchSolver) ADD_SUBDIRECTORY (src/ModuleBase) diff --git a/linux_env.sh b/linux_env.sh index fcbe77b86..b58d16324 100644 --- a/linux_env.sh +++ b/linux_env.sh @@ -37,7 +37,8 @@ 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:${PYTHONPATH} +export PYTHONPATH=${NEWGEOM_ROOT_DIR}/swig:${NEWGEOM_ROOT_DIR}/plugins:${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 ee0c3adc7..9f018b720 100644 --- a/msvc10_env.bat +++ b/msvc10_env.bat @@ -127,7 +127,7 @@ set PATH=%CMAKEDIR%\bin;%PATH% @SET NEW_GEOM_CONFIG_FILE=%ROOT_DIR%\install\plugins @SET PATH=%ROOT_DIR%\install\plugins;%ROOT_DIR%\install\bin;%PATH% -@SET PYTHONPATH=%ROOT_DIR%\install\swig;%PYTHONPATH% +@SET PYTHONPATH=%ROOT_DIR%\install\swig;%ROOT_DIR%\install\plugins;%PYTHONPATH% @REM ------------------------- @REM PTHREAD diff --git a/src/Config/CMakeLists.txt b/src/Config/CMakeLists.txt index ab42ba193..ecf41b60b 100644 --- a/src/Config/CMakeLists.txt +++ b/src/Config/CMakeLists.txt @@ -1,7 +1,8 @@ INCLUDE(Common) INCLUDE(XMLProcessing) -INCLUDE_DIRECTORIES (${PROJECT_SOURCE_DIR}/src/Events) +INCLUDE_DIRECTORIES (${PROJECT_SOURCE_DIR}/src/Events + ${PYTHON_INCLUDE_DIRS}) SET(PROJECT_HEADERS Config_def.h @@ -42,6 +43,7 @@ SET(XML_RESOURCES SET(PROJECT_LIBRARIES Events ${LIBXML2_LIBRARIES} + ${PYTHON_LIBRARIES} ) SOURCE_GROUP ("Resource Files" FILES ${XML_RESOURCES}) diff --git a/src/Config/Config_Keywords.h b/src/Config/Config_Keywords.h index d7ed62fab..62c5f59af 100644 --- a/src/Config/Config_Keywords.h +++ b/src/Config/Config_Keywords.h @@ -77,11 +77,14 @@ const static char* CONTAINER_PAGE_NAME = "title"; /* * Hardcoded xml entities of plugins.xml */ + +const static char* PLUGIN_FILE = "plugins.xml"; const static char* NODE_PLUGIN = "plugin"; const static char* NODE_PLUGINS = "plugins"; const static char* PLUGINS_MODULE = "module"; const static char* PLUGIN_CONFIG = "configuration"; const static char* PLUGIN_LIBRARY = "library"; +const static char* PLUGIN_SCRIPT = "script"; #endif /* CONFIG_KEYWORDS_H_ */ diff --git a/src/Config/Config_ModuleReader.cpp b/src/Config/Config_ModuleReader.cpp index f2fcda4b7..83b16f27d 100644 --- a/src/Config/Config_ModuleReader.cpp +++ b/src/Config/Config_ModuleReader.cpp @@ -14,6 +14,9 @@ #include #include +// Have to be included before std headers +#include + //Necessary for cerr #include @@ -23,8 +26,10 @@ #include #endif +std::map Config_ModuleReader::myPluginTypes; + Config_ModuleReader::Config_ModuleReader(const char* theEventGenerated) - : Config_XMLReader("plugins.xml"), + : Config_XMLReader(PLUGIN_FILE), myEventGenerated(theEventGenerated) { } @@ -56,7 +61,10 @@ void Config_ModuleReader::processNode(xmlNodePtr theNode) if (isNode(theNode, NODE_PLUGIN, NULL)) { std::string aPluginConf = getProperty(theNode, PLUGIN_CONFIG); std::string aPluginLibrary = getProperty(theNode, PLUGIN_LIBRARY); - std::list aFeatures = importPlugin(aPluginLibrary, aPluginConf); + std::string aPluginScript = getProperty(theNode, PLUGIN_SCRIPT); + std::string aPluginName = addPlugin(aPluginLibrary, aPluginScript, aPluginConf); + + std::list aFeatures = importPlugin(aPluginName, aPluginConf); std::list::iterator it = aFeatures.begin(); for (; it != aFeatures.end(); it++) { myFeaturesInFiles[*it] = aPluginConf; @@ -70,19 +78,70 @@ bool Config_ModuleReader::processChildren(xmlNodePtr theNode) } std::list Config_ModuleReader::importPlugin(const std::string& thePluginLibrary, - const std::string& thePluginFile) + const std::string& thePluginXmlConf) { - if (thePluginFile.empty()) { //probably a third party library + if (thePluginXmlConf.empty()) { //probably a third party library loadLibrary(thePluginLibrary); return std::list(); } - Config_FeatureReader aReader = Config_FeatureReader(thePluginFile, thePluginLibrary, + Config_FeatureReader aReader = Config_FeatureReader(thePluginXmlConf, + thePluginLibrary, myEventGenerated); aReader.readAll(); return aReader.features(); } +std::string Config_ModuleReader::addPlugin(const std::string& aPluginLibrary, + const std::string& aPluginScript, + const std::string& aPluginConf) +{ + PluginType aType = PluginType::Binary; + std::string aPluginName; + if (!aPluginLibrary.empty()) { + aPluginName = aPluginLibrary; + if (aPluginConf.empty()) { + aType = PluginType::Intrenal; + } + } else if (!aPluginScript.empty()) { + aPluginName = aPluginScript; + aType = PluginType::Python; + } + if(!aPluginName.empty()) { + myPluginTypes[aPluginName] = aType; + + } + return aPluginName; +} + +void Config_ModuleReader::loadPlugin(const std::string thePluginName) +{ + PluginType aType = PluginType::Binary; + if(myPluginTypes.find(thePluginName) != myPluginTypes.end()) { + aType = myPluginTypes.at(thePluginName); + } + switch (aType) { + case PluginType::Python: + loadScript(thePluginName); + break; + case PluginType::Binary: + case PluginType::Intrenal: + default: + loadLibrary(thePluginName); + break; + } +} + +void Config_ModuleReader::loadScript(const std::string theFileName) +{ + std::string aPythonFile = theFileName + ".py"; + /* aquire python thread */ + PyGILState_STATE gstate = PyGILState_Ensure(); + PyObject* module = PyImport_ImportModule(aPythonFile.c_str()); + /* release python thread */ + PyGILState_Release(gstate); +} + void Config_ModuleReader::loadLibrary(const std::string theLibName) { std::string aFileName = library(theLibName); @@ -91,16 +150,15 @@ void Config_ModuleReader::loadLibrary(const std::string theLibName) #ifdef WIN32 HINSTANCE aModLib = ::LoadLibrary(aFileName.c_str()); - if (!aModLib && theLibName != "DFBrowser") { // don't shor error for internal debugging tool - std::string errorMsg = "Failed to load " + aFileName; - std::cerr << errorMsg << std::endl; - Events_Error::send(errorMsg); - } #else void* aModLib = dlopen( aFileName.c_str(), RTLD_LAZY | RTLD_GLOBAL ); - if ( !aModLib && theLibName != "DFBrowser") { // don't shor error for internal debugging tool - std::cerr << "Failed to load " << aFileName.c_str() << std::endl; - } #endif + if(!aModLib && theLibName != "DFBrowser") { // don't show error for internal debugging tool + std::string anErrorMsg = "Failed to load " + aFileName; + #ifndef WIN32 + anErrorMsg += ": " + std::string(dlerror()); + #endif + Events_Error::send(anErrorMsg); + } } diff --git a/src/Config/Config_ModuleReader.h b/src/Config/Config_ModuleReader.h index 18962f348..137afbeae 100644 --- a/src/Config/Config_ModuleReader.h +++ b/src/Config/Config_ModuleReader.h @@ -17,16 +17,25 @@ class Config_ModuleReader : public Config_XMLReader { + enum PluginType { + Binary = 0, + Intrenal = 1, + Python = 2 + }; public: - CONFIG_EXPORT Config_ModuleReader(const char* theEventGenerated = 0);CONFIG_EXPORT virtual ~Config_ModuleReader(); + CONFIG_EXPORT Config_ModuleReader(const char* theEventGenerated = 0); + CONFIG_EXPORT virtual ~Config_ModuleReader(); CONFIG_EXPORT const std::map& featuresInFiles() const; CONFIG_EXPORT std::string getModuleName(); + CONFIG_EXPORT static void loadPlugin(const std::string thePluginName); /// loads the library with specific name, appends "lib*.dll" or "*.so" depending on the platform CONFIG_EXPORT static void loadLibrary(const std::string theLibName); + /// loads the python module with specified name + CONFIG_EXPORT static void loadScript(const std::string theFileName); protected: void processNode(xmlNodePtr aNode); @@ -34,9 +43,13 @@ class Config_ModuleReader : public Config_XMLReader std::list importPlugin(const std::string& thePluginLibrary, const std::string& thePluginFile); + std::string addPlugin(const std::string& aPluginLibrary, + const std::string& aPluginScript, + const std::string& aPluginConf); private: std::map myFeaturesInFiles; + static std::map myPluginTypes; const char* myEventGenerated; }; diff --git a/src/Config/plugins.xml b/src/Config/plugins.xml index 396f565a9..474b0ba07 100644 --- a/src/Config/plugins.xml +++ b/src/Config/plugins.xml @@ -4,7 +4,8 @@ + - + diff --git a/src/ConstructionPlugin/ConstructionPlugin_Plugin.h b/src/ConstructionPlugin/ConstructionPlugin_Plugin.h index 143b786e5..79f48abe5 100644 --- a/src/ConstructionPlugin/ConstructionPlugin_Plugin.h +++ b/src/ConstructionPlugin/ConstructionPlugin_Plugin.h @@ -16,7 +16,6 @@ class CONSTRUCTIONPLUGIN_EXPORT ConstructionPlugin_Plugin : public ModelAPI_Plug virtual FeaturePtr createFeature(std::string theFeatureID); public: - /// Is needed for python wrapping by swig ConstructionPlugin_Plugin(); }; diff --git a/src/Events/Events_Loop.cpp b/src/Events/Events_Loop.cpp index 9447c376b..f9ccd81ec 100644 --- a/src/Events/Events_Loop.cpp +++ b/src/Events/Events_Loop.cpp @@ -122,7 +122,9 @@ void Events_Loop::flush(const Events_ID& theID) std::shared_ptr aGroup = aMyGroup->second; myGroups.erase(aMyGroup); send(aGroup, false); - myFlushed.erase(myFlushed.find(theID.myID)); + std::set::iterator anIt = myFlushed.find(theID.myID); + if (anIt != myFlushed.end()) + myFlushed.erase(myFlushed.find(theID.myID)); } } diff --git a/src/ExchangePlugin/ExchangePlugin_Plugin.h b/src/ExchangePlugin/ExchangePlugin_Plugin.h index 5cb5f20f0..d614028f1 100644 --- a/src/ExchangePlugin/ExchangePlugin_Plugin.h +++ b/src/ExchangePlugin/ExchangePlugin_Plugin.h @@ -16,7 +16,6 @@ class EXCHANGEPLUGIN_EXPORT ExchangePlugin_Plugin : public ModelAPI_Plugin virtual FeaturePtr createFeature(std::string theFeatureID); public: - /// Is needed for python wrapping by swig ExchangePlugin_Plugin(); }; diff --git a/src/FeaturesPlugin/FeaturesPlugin_Plugin.h b/src/FeaturesPlugin/FeaturesPlugin_Plugin.h index 560a2242a..e56ac83ea 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Plugin.h +++ b/src/FeaturesPlugin/FeaturesPlugin_Plugin.h @@ -16,7 +16,6 @@ class FEATURESPLUGIN_EXPORT FeaturesPlugin_Plugin : public ModelAPI_Plugin virtual FeaturePtr createFeature(std::string theFeatureID); public: - /// Is needed for python wrapping by swig FeaturesPlugin_Plugin(); }; diff --git a/src/GeomAPI/CMakeLists.txt b/src/GeomAPI/CMakeLists.txt index 2718fa980..9ee8694c8 100644 --- a/src/GeomAPI/CMakeLists.txt +++ b/src/GeomAPI/CMakeLists.txt @@ -58,7 +58,7 @@ SET(PROJECT_LIBRARIES ADD_DEFINITIONS(-DGEOMAPI_EXPORTS ${CAS_DEFINITIONS}) ADD_LIBRARY(GeomAPI SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS}) -SET(CMAKE_SWIG_FLAGS "") +SET(CMAKE_SWIG_FLAGS -threads -Wall) SET_SOURCE_FILES_PROPERTIES(GeomAPI.i PROPERTIES CPLUSPLUS ON) SET_SOURCE_FILES_PROPERTIES(GeomAPI.i PROPERTIES SWIG_DEFINITIONS "-shadow") diff --git a/src/GeomAlgoAPI/CMakeLists.txt b/src/GeomAlgoAPI/CMakeLists.txt index 5656a0ad8..ef36a838e 100644 --- a/src/GeomAlgoAPI/CMakeLists.txt +++ b/src/GeomAlgoAPI/CMakeLists.txt @@ -41,7 +41,7 @@ SET(PROJECT_LIBRARIES ADD_DEFINITIONS(-DGEOMALGOAPI_EXPORTS ${CAS_DEFINITIONS}) ADD_LIBRARY(GeomAlgoAPI SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS}) -SET(CMAKE_SWIG_FLAGS "") +SET(CMAKE_SWIG_FLAGS "-Wall") SET_SOURCE_FILES_PROPERTIES(GeomAlgoAPI.i PROPERTIES CPLUSPLUS ON) SET_SOURCE_FILES_PROPERTIES(GeomAlgoAPI.i PROPERTIES SWIG_DEFINITIONS "-shadow") diff --git a/src/GeomDataAPI/CMakeLists.txt b/src/GeomDataAPI/CMakeLists.txt index d956835d1..b9e1488b7 100644 --- a/src/GeomDataAPI/CMakeLists.txt +++ b/src/GeomDataAPI/CMakeLists.txt @@ -10,7 +10,7 @@ SET(PROJECT_HEADERS GeomDataAPI_Point2D.h ) -SET(CMAKE_SWIG_FLAGS "") +SET(CMAKE_SWIG_FLAGS "-Wall") SET_SOURCE_FILES_PROPERTIES(GeomDataAPI.i PROPERTIES CPLUSPLUS ON) SET_SOURCE_FILES_PROPERTIES(GeomDataAPI.i PROPERTIES SWIG_DEFINITIONS "-shadow") diff --git a/src/Model/Model_Session.cpp b/src/Model/Model_Session.cpp index d8e516698..d742dd930 100644 --- a/src/Model/Model_Session.cpp +++ b/src/Model/Model_Session.cpp @@ -98,8 +98,9 @@ void Model_Session::redo() FeaturePtr Model_Session::createFeature(string theFeatureID) { - if (this != myImpl) + if (this != myImpl) { return myImpl->createFeature(theFeatureID); + } // load all information about plugins, features and attributes LoadPluginsInfo(); @@ -115,7 +116,7 @@ FeaturePtr Model_Session::createFeature(string theFeatureID) myCurrentPluginName = aPlugin.first; if (myPluginObjs.find(myCurrentPluginName) == myPluginObjs.end()) { // load plugin library if not yet done - Config_ModuleReader::loadLibrary(myCurrentPluginName); + Config_ModuleReader::loadPlugin(myCurrentPluginName); } if (myPluginObjs.find(myCurrentPluginName) != myPluginObjs.end()) { FeaturePtr aCreated = myPluginObjs[myCurrentPluginName]->createFeature(theFeatureID); diff --git a/src/ModelAPI/CMakeLists.txt b/src/ModelAPI/CMakeLists.txt index bbc99cbb1..5df84da6a 100644 --- a/src/ModelAPI/CMakeLists.txt +++ b/src/ModelAPI/CMakeLists.txt @@ -47,8 +47,9 @@ SET(PROJECT_SOURCES SET(PROJECT_LIBRARIES Config ) +SET(CMAKE_SWIG_FLAGS -threads -Wall) +ADD_DEFINITIONS(-DMODELAPI_EXPORTS -DSWIG_TYPE_TABLE=ModelAPI) -ADD_DEFINITIONS(-DMODELAPI_EXPORTS) ADD_LIBRARY(ModelAPI SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS}) SET_TARGET_PROPERTIES(ModelAPI PROPERTIES LINKER_LANGUAGE CXX) TARGET_LINK_LIBRARIES(ModelAPI ${PROJECT_LIBRARIES}) @@ -60,7 +61,6 @@ INCLUDE_DIRECTORIES( ../GeomAlgoAPI ) -SET(CMAKE_SWIG_FLAGS "") SET_SOURCE_FILES_PROPERTIES(ModelAPI.i PROPERTIES CPLUSPLUS ON) # "-includeall" is not needed: it starts to follow the standard inludes (like "string") without success diff --git a/src/ModelAPI/ModelAPI.i b/src/ModelAPI/ModelAPI.i index 3017bac28..d1ffd5643 100644 --- a/src/ModelAPI/ModelAPI.i +++ b/src/ModelAPI/ModelAPI.i @@ -1,5 +1,13 @@ /* ModelAPI.i */ -%module ModelAPI +%module(directors="1") ModelAPI +%feature("director:except") { + if ($error != NULL) { + PyErr_Print(); + std::cerr << std::endl; + throw Swig::DirectorMethodException(); + } +} + %{ #include "GeomAPI_Interface.h" #include "GeomAPI_Shape.h" @@ -8,6 +16,7 @@ #include "ModelAPI_Session.h" #include "ModelAPI_Object.h" #include "ModelAPI_Feature.h" + #include "ModelAPI_Plugin.h" #include "ModelAPI_CompositeFeature.h" #include "ModelAPI_Data.h" #include "ModelAPI_Attribute.h" @@ -50,12 +59,18 @@ %include "std_list.i" %include "std_shared_ptr.i" +// directors +%feature("director") ModelAPI_Plugin; +%feature("director") ModelAPI_Object; +%feature("director") ModelAPI_Feature; + // shared pointers // For ModelAPI_ResultConstruction.shape() %shared_ptr(GeomAPI_Interface) %shared_ptr(GeomAPI_Shape) %shared_ptr(ModelAPI_Document) %shared_ptr(ModelAPI_Session) +%shared_ptr(ModelAPI_Plugin) %shared_ptr(ModelAPI_Object) %shared_ptr(ModelAPI_Feature) %shared_ptr(ModelAPI_CompositeFeature) @@ -86,6 +101,7 @@ %include "GeomAPI_Shape.h" %include "ModelAPI_Document.h" %include "ModelAPI_Session.h" +%include "ModelAPI_Plugin.h" %include "ModelAPI_Object.h" %include "ModelAPI_Feature.h" %include "ModelAPI_CompositeFeature.h" @@ -115,10 +131,30 @@ %template(ObjectList) std::list >; %template(ResultList) std::list >; +template boost::shared_ptr boost_cast(boost::shared_ptr theObject); + +// Feature casts +%template(modelAPI_Feature) shared_ptr_cast; +%template(modelAPI_CompositeFeature) shared_ptr_cast; template std::shared_ptr shared_ptr_cast(std::shared_ptr theObject); %template(modelAPI_CompositeFeature) shared_ptr_cast; %template(modelAPI_ResultConstruction) shared_ptr_cast; %template(modelAPI_ResultBody) shared_ptr_cast; %template(modelAPI_ResultPart) shared_ptr_cast; +// Result casts +%template(modelAPI_ResultConstruction) boost_cast; +%template(modelAPI_ResultBody) boost_cast; +%template(modelAPI_ResultPart) boost_cast; +// Attribute casts +%template(modelAPI_AttributeDocRef) boost_cast; +%template(modelAPI_AttributeDouble) boost_cast; +%template(modelAPI_AttributeInteger) boost_cast; +%template(modelAPI_AttributeString) boost_cast; +%template(modelAPI_AttributeReference) boost_cast; +%template(modelAPI_AttributeRefAttr) boost_cast; +%template(modelAPI_AttributeBoolean) boost_cast; +%template(modelAPI_AttributeSelection) boost_cast; +%template(modelAPI_AttributeSelectionList) boost_cast; +%template(modelAPI_AttributeRefList) boost_cast; diff --git a/src/ModelAPI/ModelAPI_Plugin.h b/src/ModelAPI/ModelAPI_Plugin.h index 0e910ae1f..5b107d5a4 100644 --- a/src/ModelAPI/ModelAPI_Plugin.h +++ b/src/ModelAPI/ModelAPI_Plugin.h @@ -26,13 +26,6 @@ class MODELAPI_EXPORT ModelAPI_Plugin virtual ~ModelAPI_Plugin() { } - - protected: - /// Is needed for python wrapping by swig - ModelAPI_Plugin() - { - } - ; }; #endif diff --git a/src/ModelAPI/ModelAPI_Session.cpp b/src/ModelAPI/ModelAPI_Session.cpp index c7b784d3a..29c251031 100644 --- a/src/ModelAPI/ModelAPI_Session.cpp +++ b/src/ModelAPI/ModelAPI_Session.cpp @@ -44,10 +44,6 @@ using namespace std; /// Manager that will be initialized from Model package, one per application std::shared_ptr MY_MANAGER; -ModelAPI_Session::ModelAPI_Session() -{ -} - void ModelAPI_Session::setSession(std::shared_ptr theManager) { MY_MANAGER = theManager; diff --git a/src/ModelAPI/ModelAPI_Session.h b/src/ModelAPI/ModelAPI_Session.h index 811174e7c..02449b6ce 100644 --- a/src/ModelAPI/ModelAPI_Session.h +++ b/src/ModelAPI/ModelAPI_Session.h @@ -91,9 +91,6 @@ class MODELAPI_EXPORT ModelAPI_Session /// Returns the validators factory: the only one instance per application virtual ModelAPI_ValidatorsFactory* validators() = 0; - /// Is needed for python wrapping by swig, call Get to get an instance - ModelAPI_Session(); - /// To virtually destroy the fields of successors virtual ~ModelAPI_Session() { diff --git a/src/PartSetPlugin/PartSetPlugin_Plugin.h b/src/PartSetPlugin/PartSetPlugin_Plugin.h index e8e9e702b..5d91f7d46 100644 --- a/src/PartSetPlugin/PartSetPlugin_Plugin.h +++ b/src/PartSetPlugin/PartSetPlugin_Plugin.h @@ -16,7 +16,6 @@ class PARTSETPLUGIN_EXPORT PartSetPlugin_Plugin : public ModelAPI_Plugin virtual FeaturePtr createFeature(std::string theFeatureID); public: - /// Is needed for python wrapping by swig PartSetPlugin_Plugin(); }; diff --git a/src/PythonFeaturesPlugin/CMakeLists.txt b/src/PythonFeaturesPlugin/CMakeLists.txt new file mode 100644 index 000000000..1e600b3df --- /dev/null +++ b/src/PythonFeaturesPlugin/CMakeLists.txt @@ -0,0 +1,17 @@ +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 new file mode 100644 index 000000000..f47ba3f70 --- /dev/null +++ b/src/PythonFeaturesPlugin/FeaturesAPI.py @@ -0,0 +1,47 @@ +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.py b/src/PythonFeaturesPlugin/PythonFeaturesPlugin.py new file mode 100644 index 000000000..ca671e144 --- /dev/null +++ b/src/PythonFeaturesPlugin/PythonFeaturesPlugin.py @@ -0,0 +1,20 @@ +import ModelAPI +from PythonFeaturesPlugin_Box import PythonFeaturesPlugin_Box + + +class PythonFeaturesPlugin(ModelAPI.ModelAPI_Plugin): + + def __init__(self): + ModelAPI.ModelAPI_Plugin.__init__(self) + pass + + def createFeature(self, theFeatureID): + if theFeatureID == PythonFeaturesPlugin_Box.ID(): + return PythonFeaturesPlugin_Box().__disown__() + else: + raise StandardError("No such feature %s" % theFeatureID) + +plugin = PythonFeaturesPlugin() +aSession = ModelAPI.ModelAPI_Session.get() +print "Module loaded. Session", aSession +aSession.registerPlugin(plugin) diff --git a/src/PythonFeaturesPlugin/PythonFeaturesPlugin_Box.py b/src/PythonFeaturesPlugin/PythonFeaturesPlugin_Box.py new file mode 100644 index 000000000..05f6460d6 --- /dev/null +++ b/src/PythonFeaturesPlugin/PythonFeaturesPlugin_Box.py @@ -0,0 +1,64 @@ +import ModelAPI +import examples + + +class PythonFeaturesPlugin_Box(ModelAPI.ModelAPI_Feature): + + "Feature to create a box by drawing a sketch and extruding it" + + def __init__(self): + ModelAPI.ModelAPI_Feature.__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" + + 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(PythonFeaturesPlugin_Box.WIDTH_ID(), + ModelAPI.ModelAPI_AttributeDouble_type()) + self.data().addAttribute(PythonFeaturesPlugin_Box.LENGTH_ID(), + ModelAPI.ModelAPI_AttributeDouble_type()) + self.data().addAttribute(PythonFeaturesPlugin_Box.HEIGHT_ID(), + ModelAPI.ModelAPI_AttributeDouble_type()) + + def execute(self): + aWidth = self.real(PythonFeaturesPlugin_Box.WIDTH_ID()).value() + aLength = self.real(PythonFeaturesPlugin_Box.LENGTH_ID()).value() + aHeight = self.real(PythonFeaturesPlugin_Box.HEIGHT_ID()).value() + print ("Box W:{0} L:{1} H:{2}".format(aWidth, aLength, aHeight)) + aResultBody = self.document().createBody(self.data()) + aResult = examples.makeBox(aLength, aWidth, aHeight) + #aShape = modelAPI_ResultConstruction(aResult).shape() + # aResultBody.store(aShape) + self.setResult(aResultBody) + +# 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 new file mode 100644 index 000000000..8d8b77a32 --- /dev/null +++ b/src/PythonFeaturesPlugin/SketchResult.py @@ -0,0 +1,26 @@ +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 new file mode 100644 index 000000000..f35231580 --- /dev/null +++ b/src/PythonFeaturesPlugin/box_widget.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/PythonFeaturesPlugin/examples.py b/src/PythonFeaturesPlugin/examples.py new file mode 100644 index 000000000..3da0d6f57 --- /dev/null +++ b/src/PythonFeaturesPlugin/examples.py @@ -0,0 +1,45 @@ +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 + # NOTE : the following lines are currently not working in BR_PYTHON_PLUGIN + # branch + # 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)) + # sketch.makeParallel(sketch.getGeometry(l2), sketch.getGeometry(l4)) + # + # sketch.makePerpendicular(sketch.getGeometry(l1), sketch.getGeometry(l4)) + + # Finalisation of the operation + builder = SketchResult(base) + + # Creating a feature Extrusion + box = extrusion.addNew(builder, 50, part) + + # return base.lastResult() + return extrusion.getBody(box) diff --git a/src/PythonFeaturesPlugin/extrusion.py b/src/PythonFeaturesPlugin/extrusion.py new file mode 100644 index 000000000..2ce035dca --- /dev/null +++ b/src/PythonFeaturesPlugin/extrusion.py @@ -0,0 +1,15 @@ +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()) + feature.real("extrusion_size").setValue(length) + feature.boolean("extrusion_reverse").setValue(reverse) + feature.execute() + return feature + + +def getBody(extrusion): + return extrusion.firstResult() diff --git a/src/PythonFeaturesPlugin/plugin-PythonFeatures.xml b/src/PythonFeaturesPlugin/plugin-PythonFeatures.xml new file mode 100644 index 000000000..2f7b97bc5 --- /dev/null +++ b/src/PythonFeaturesPlugin/plugin-PythonFeatures.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/PythonFeaturesPlugin/sketch.py b/src/PythonFeaturesPlugin/sketch.py new file mode 100644 index 000000000..f60fbc16e --- /dev/null +++ b/src/PythonFeaturesPlugin/sketch.py @@ -0,0 +1,130 @@ +from ModelAPI import * +from GeomDataAPI import * + + +# Initialization of the Sketch +# ---------------------------- + +def addTo(doc): + return modelAPI_CompositeFeature(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) + + +def makeParallel(l1, l2, sketch): + constraint = sketch.addFeature("SketchConstraintParallel") + constraint.refattr("ConstraintEntityA").setObject(l1) + constraint.refattr("ConstraintEntityB").setObject(l2) + + +def makePerpendicular(l1, l2, sketch): + constraint = sketch.addFeature("SketchConstraintPerpendicular") + constraint.refattr("ConstraintEntityA").setObject(l1) + constraint.refattr("ConstraintEntityB").setObject(l2) + + +def makeConstantLength(line, length, sketch): + constraint = sketch.addFeature("SketchConstraintLength") + constraint.refattr("ConstraintEntityA").setObject(line) + constraint.real("ConstraintValue").setValue(length) diff --git a/src/SketchPlugin/SketchPlugin_Plugin.h b/src/SketchPlugin/SketchPlugin_Plugin.h index bb81ba781..3b480410b 100644 --- a/src/SketchPlugin/SketchPlugin_Plugin.h +++ b/src/SketchPlugin/SketchPlugin_Plugin.h @@ -16,7 +16,6 @@ class SKETCHPLUGIN_EXPORT SketchPlugin_Plugin : public ModelAPI_Plugin virtual FeaturePtr createFeature(std::string theFeatureID); public: - /// Is needed for python wrapping by swig SketchPlugin_Plugin(); };