Salome HOME
Merge branch 'master' of newgeom:newgeom.git into BR_PYTHON_PLUGIN
authorsbh <sergey.belash@opencascade.com>
Tue, 25 Nov 2014 09:10:42 +0000 (12:10 +0300)
committersbh <sergey.belash@opencascade.com>
Tue, 25 Nov 2014 09:10:42 +0000 (12:10 +0300)
Conflicts:
src/ModelAPI/ModelAPI.i
src/ModelAPI/ModelAPI_Session.cpp

33 files changed:
CMakeLists.txt
linux_env.sh
msvc10_env.bat
src/Config/CMakeLists.txt
src/Config/Config_Keywords.h
src/Config/Config_ModuleReader.cpp
src/Config/Config_ModuleReader.h
src/Config/plugins.xml
src/ConstructionPlugin/ConstructionPlugin_Plugin.h
src/Events/Events_Loop.cpp
src/ExchangePlugin/ExchangePlugin_Plugin.h
src/FeaturesPlugin/FeaturesPlugin_Plugin.h
src/GeomAPI/CMakeLists.txt
src/GeomAlgoAPI/CMakeLists.txt
src/GeomDataAPI/CMakeLists.txt
src/Model/Model_Session.cpp
src/ModelAPI/CMakeLists.txt
src/ModelAPI/ModelAPI.i
src/ModelAPI/ModelAPI_Plugin.h
src/ModelAPI/ModelAPI_Session.cpp
src/ModelAPI/ModelAPI_Session.h
src/PartSetPlugin/PartSetPlugin_Plugin.h
src/PythonFeaturesPlugin/CMakeLists.txt [new file with mode: 0644]
src/PythonFeaturesPlugin/FeaturesAPI.py [new file with mode: 0644]
src/PythonFeaturesPlugin/PythonFeaturesPlugin.py [new file with mode: 0644]
src/PythonFeaturesPlugin/PythonFeaturesPlugin_Box.py [new file with mode: 0644]
src/PythonFeaturesPlugin/SketchResult.py [new file with mode: 0644]
src/PythonFeaturesPlugin/box_widget.xml [new file with mode: 0644]
src/PythonFeaturesPlugin/examples.py [new file with mode: 0644]
src/PythonFeaturesPlugin/extrusion.py [new file with mode: 0644]
src/PythonFeaturesPlugin/plugin-PythonFeatures.xml [new file with mode: 0644]
src/PythonFeaturesPlugin/sketch.py [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_Plugin.h

index 7f94b0fab1d610ac6ab09d88ebe60b5fe89e4f44..02ee3ea2c23557f0e36b913840b01e3aa671ea88 100644 (file)
@@ -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)
index fcbe77b868e98322647ced4401e595e1065a1a57..b58d16324ca82a3b78cf7a03151e1e651e710f94 100644 (file)
@@ -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
+
index ee0c3adc7fa43af1d5f6ee0ce2adee272039cc8f..9f018b720ee1c0ace401c0ae0eabfa54438d5d53 100644 (file)
@@ -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
index ab42ba19335b0d30ff217564b89743d9e5d35e1f..ecf41b60b7d200a699fc1faaffc412366003b178 100644 (file)
@@ -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})
index d7ed62fabf70872daefa2792218467617bb3cb64..62c5f59af88d6e1518de8a496badc71d3636faea 100644 (file)
@@ -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_ */
index f2fcda4b717278ae83d5787a0d497623b47bcb95..83b16f27d5afe166f58d15d66e602cb4a6b8a494 100644 (file)
@@ -14,6 +14,9 @@
 #include <libxml/parser.h>
 #include <libxml/tree.h>
 
+// Have to be included before std headers
+#include <Python.h>
+
 //Necessary for cerr
 #include <iostream>
 
 #include <dlfcn.h>
 #endif
 
+std::map<std::string, Config_ModuleReader::PluginType> 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<std::string> aFeatures = importPlugin(aPluginLibrary, aPluginConf);
+    std::string aPluginScript = getProperty(theNode, PLUGIN_SCRIPT);
+    std::string aPluginName = addPlugin(aPluginLibrary, aPluginScript, aPluginConf);
+
+    std::list<std::string> aFeatures = importPlugin(aPluginName, aPluginConf);
     std::list<std::string>::iterator it = aFeatures.begin();
     for (; it != aFeatures.end(); it++) {
       myFeaturesInFiles[*it] = aPluginConf;
@@ -70,19 +78,70 @@ bool Config_ModuleReader::processChildren(xmlNodePtr theNode)
 }
 
 std::list<std::string> 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<std::string>();
   }
 
-  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);
+  }
 }
 
index 18962f3488b9dbc03f7c41173fa143052e43946b..137afbeaeaa67f03d1667ebd8e9762613e156226 100644 (file)
 
 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<std::string, std::string>& 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<std::string> 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<std::string, std::string> myFeaturesInFiles;
+  static std::map<std::string, PluginType> myPluginTypes;
   const char* myEventGenerated;
 
 };
index 396f565a9f20fdf8a5c3f866270fa508a8056e51..474b0ba07def5ac985f424b14efbaefc4d0094ec 100644 (file)
@@ -4,7 +4,8 @@
   <plugin library="ConstructionPlugin" configuration="plugin-Construction.xml"/>
   <plugin library="FeaturesPlugin" configuration="plugin-Features.xml"/>
   <plugin library="ExchangePlugin" configuration="plugin-Exchange.xml"/>
+  <plugin script="PythonFeaturesPlugin" configuration="plugin-PythonFeatures.xml"/>
   <plugin library="SketchSolver"/>
   <plugin library="GeomValidators"/>
-  <plugin library="DFBrowser"/>
+  <plugin library="DFBrowser" internal="true"/>
 </plugins>
index 143b786e55d931542e4350dd2b0ab72753680755..79f48abe5cd6e375891d1b573ed9565d1c9c5e6d 100644 (file)
@@ -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();
 };
 
index 9447c376b97c6a4f017be8206e8c13f41325fed6..f9ccd81eca3e7857cf3b5849e261fa93d823db3c 100644 (file)
@@ -122,7 +122,9 @@ void Events_Loop::flush(const Events_ID& theID)
     std::shared_ptr<Events_Message> aGroup = aMyGroup->second;
     myGroups.erase(aMyGroup);
     send(aGroup, false);
-    myFlushed.erase(myFlushed.find(theID.myID));
+    std::set<char*>::iterator anIt = myFlushed.find(theID.myID);
+    if (anIt != myFlushed.end())
+      myFlushed.erase(myFlushed.find(theID.myID));
   }
 }
 
index 5cb5f20f0ac5793fea1fb08f9703f4f2f70d4fe9..d614028f1296f5b8ea3eca822af3fea11dbcc8a1 100644 (file)
@@ -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();
 };
 
index 560a2242a88e73a25f8747e802a716ac2029be75..e56ac83ea77c79afc93639bfa4a2af8c994c871b 100644 (file)
@@ -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();
 };
 
index 2718fa98007c81bd5db0b61caf66488bbcedebf1..9ee8694c8cac79d3c34eeac641b6c7a16f4d98c2 100644 (file)
@@ -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")
index 5656a0ad8a5e0227eaa10d12050708099e3a7f12..ef36a838e3b4c70ff2ab0ab5ad9f4f7962132227 100644 (file)
@@ -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")
index d956835d1a388204c223cbd41387214ea46e8623..b9e1488b7ffda88869b9855292b5276310b8fbe6 100644 (file)
@@ -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")
index d8e5166986f5a7cfb9329ccf7747ba2e0993dfde..d742dd9306451cebd46893011453e1b451f2e3f3 100644 (file)
@@ -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);
index bbc99cbb1543d004c3504af482afb9439aa07577..5df84da6a5185d7ad0027cc0fcf07d3b6bc505c4 100644 (file)
@@ -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
index 3017bac28f2df63cc839566b92a669091918014b..d1ffd5643561aae44863ce92451cad2ad1f295ca 100644 (file)
@@ -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"
 %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)
 %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"
 %template(ObjectList) std::list<std::shared_ptr<ModelAPI_Object> >;
 %template(ResultList) std::list<std::shared_ptr<ModelAPI_Result> >;
 
+template<class T1, class T2> boost::shared_ptr<T1> boost_cast(boost::shared_ptr<T2> theObject);
+
+// Feature casts
+%template(modelAPI_Feature)          shared_ptr_cast<ModelAPI_Feature, ModelAPI_Object>;
+%template(modelAPI_CompositeFeature) shared_ptr_cast<ModelAPI_CompositeFeature, ModelAPI_Feature>;
 template<class T1, class T2> std::shared_ptr<T1> shared_ptr_cast(std::shared_ptr<T2> theObject);
 %template(modelAPI_CompositeFeature) shared_ptr_cast<ModelAPI_CompositeFeature, ModelAPI_Feature>;
 %template(modelAPI_ResultConstruction) shared_ptr_cast<ModelAPI_ResultConstruction, ModelAPI_Result>;
 %template(modelAPI_ResultBody) shared_ptr_cast<ModelAPI_ResultBody, ModelAPI_Result>;
 %template(modelAPI_ResultPart) shared_ptr_cast<ModelAPI_ResultPart, ModelAPI_Result>;
 
+// Result casts
+%template(modelAPI_ResultConstruction) boost_cast<ModelAPI_ResultConstruction, ModelAPI_Result>;
+%template(modelAPI_ResultBody)         boost_cast<ModelAPI_ResultBody, ModelAPI_Result>;
+%template(modelAPI_ResultPart)         boost_cast<ModelAPI_ResultPart, ModelAPI_Result>;
 
+// Attribute casts
+%template(modelAPI_AttributeDocRef)        boost_cast<ModelAPI_AttributeDocRef, ModelAPI_Attribute>;
+%template(modelAPI_AttributeDouble)        boost_cast<ModelAPI_AttributeDouble, ModelAPI_Attribute>;
+%template(modelAPI_AttributeInteger)       boost_cast<ModelAPI_AttributeInteger, ModelAPI_Attribute>;
+%template(modelAPI_AttributeString)        boost_cast<ModelAPI_AttributeString, ModelAPI_Attribute>;
+%template(modelAPI_AttributeReference)     boost_cast<ModelAPI_AttributeReference, ModelAPI_Attribute>;
+%template(modelAPI_AttributeRefAttr)       boost_cast<ModelAPI_AttributeRefAttr, ModelAPI_Attribute>;
+%template(modelAPI_AttributeBoolean)       boost_cast<ModelAPI_AttributeBoolean, ModelAPI_Attribute>;
+%template(modelAPI_AttributeSelection)     boost_cast<ModelAPI_AttributeSelection, ModelAPI_Attribute>;
+%template(modelAPI_AttributeSelectionList) boost_cast<ModelAPI_AttributeSelectionList, ModelAPI_Attribute>;
+%template(modelAPI_AttributeRefList)       boost_cast<ModelAPI_AttributeRefList, ModelAPI_Attribute>;
index 0e910ae1f4cc9d2f829a9867d5bb67b51e98b738..5b107d5a4730287c40d55d5c004a75887baa06da 100644 (file)
@@ -26,13 +26,6 @@ class MODELAPI_EXPORT ModelAPI_Plugin
   virtual ~ModelAPI_Plugin()
   {
   }
-
- protected:
-  /// Is needed for python wrapping by swig
-  ModelAPI_Plugin()
-  {
-  }
-  ;
 };
 
 #endif
index c7b784d3ac7f51fc2e63277450b4aad6cc7fc071..29c251031c4d43bf25fa7663dbd09b277b849b83 100644 (file)
@@ -44,10 +44,6 @@ using namespace std;
 /// Manager that will be initialized from Model package, one per application
 std::shared_ptr<ModelAPI_Session> MY_MANAGER;
 
-ModelAPI_Session::ModelAPI_Session()
-{
-}
-
 void ModelAPI_Session::setSession(std::shared_ptr<ModelAPI_Session> theManager)
 {
   MY_MANAGER = theManager;
index 811174e7c235b4614f323824b07cacaba0a7c116..02449b6ce8c60b3eb412087dcea9a6516ce051e0 100644 (file)
@@ -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()
   {
index e8e9e702b405575131d7604756660c5b2052972e..5d91f7d46fb0b44cbcf183ed501ba6950d6b44ab 100644 (file)
@@ -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 (file)
index 0000000..1e600b3
--- /dev/null
@@ -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 (file)
index 0000000..f47ba3f
--- /dev/null
@@ -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 (file)
index 0000000..ca671e1
--- /dev/null
@@ -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 (file)
index 0000000..05f6460
--- /dev/null
@@ -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 (file)
index 0000000..8d8b77a
--- /dev/null
@@ -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 (file)
index 0000000..f352315
--- /dev/null
@@ -0,0 +1,11 @@
+<source>
+  <doublevalue id="box_width" label="Width" min="0" step="1.0" default="10" icon=":icons/dimension_v.png" tooltip="Set width of the box">
+    <validator id="GeomValidators_Positive"/>
+  </doublevalue>
+  <doublevalue id="box_length" label="Length" min="0" step="1.0" default="10" icon=":icons/dimension_v.png" tooltip="Set length of the box">
+    <validator id="GeomValidators_Positive"/>
+  </doublevalue>
+  <doublevalue id="box_height" label="Height" min="0" step="1.0" default="10" icon=":icons/dimension_v.png" tooltip="Set height of the box">
+    <validator id="GeomValidators_Positive"/>
+  </doublevalue>
+</source>
diff --git a/src/PythonFeaturesPlugin/examples.py b/src/PythonFeaturesPlugin/examples.py
new file mode 100644 (file)
index 0000000..3da0d6f
--- /dev/null
@@ -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 (file)
index 0000000..2ce035d
--- /dev/null
@@ -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 (file)
index 0000000..2f7b97b
--- /dev/null
@@ -0,0 +1,9 @@
+<plugin>
+  <workbench id="Features" document="Part">
+    <group id="Basic">
+      <feature id="Box" title="Box" tooltip="Create a box" icon=":pictures/part_ico.png">
+          <source path="box_widget.xml"/>
+      </feature>
+    </group>
+  </workbench>  
+</plugin>
diff --git a/src/PythonFeaturesPlugin/sketch.py b/src/PythonFeaturesPlugin/sketch.py
new file mode 100644 (file)
index 0000000..f60fbc1
--- /dev/null
@@ -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)
index bb81ba781212d882e113cd32646eda725832af99..3b480410b8b169b23ccdbddfb98faf7455e59dc6 100644 (file)
@@ -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();
 };