From: azv Date: Wed, 3 Aug 2016 06:43:53 +0000 (+0300) Subject: Dump Python in the High Level Parameterized Geometry API (issue #1648) X-Git-Tag: V_2.5.0~137^2~88 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=483750cc09178e5fa392706e5d73820b1fe5ecfb;p=modules%2Fshaper.git Dump Python in the High Level Parameterized Geometry API (issue #1648) 1. Dumper base functionality. 2. Feature to dump model into Python script. 3. Dump parameters, parts, sketches and points on sketches. 4. Uncompleted dump for point from ConstructionPlugin. --- diff --git a/src/ConstructionAPI/ConstructionAPI_Point.cpp b/src/ConstructionAPI/ConstructionAPI_Point.cpp index c503c16fa..76be0f73b 100644 --- a/src/ConstructionAPI/ConstructionAPI_Point.cpp +++ b/src/ConstructionAPI/ConstructionAPI_Point.cpp @@ -8,6 +8,7 @@ #include +#include #include #include @@ -133,6 +134,21 @@ void ConstructionAPI_Point::setByLineAndPlaneIntersection(const ModelHighAPI_Sel execute(); }*/ +//================================================================================================== +void ConstructionAPI_Point::dump(ModelHighAPI_Dumper& theDumper) const +{ + // TODO: all types of points + + FeaturePtr aBase = feature(); + const std::string& aDocName = theDumper.name(aBase->document()); + + AttributeDoublePtr anAttrX = aBase->real(ConstructionPlugin_Point::X()); + AttributeDoublePtr anAttrY = aBase->real(ConstructionPlugin_Point::Y()); + AttributeDoublePtr anAttrZ = aBase->real(ConstructionPlugin_Point::Z()); + theDumper << aBase << " = model.addPoint(" << aDocName << ", " + << anAttrX << ", " << anAttrY << ", " << anAttrZ << ")" << std::endl; +} + //================================================================================================== PointPtr addPoint(const std::shared_ptr& thePart, const ModelHighAPI_Double& theX, diff --git a/src/ConstructionAPI/ConstructionAPI_Point.h b/src/ConstructionAPI/ConstructionAPI_Point.h index c27ea76d5..6c2b295bb 100644 --- a/src/ConstructionAPI/ConstructionAPI_Point.h +++ b/src/ConstructionAPI/ConstructionAPI_Point.h @@ -102,6 +102,10 @@ public: CONSTRUCTIONAPI_EXPORT void setByLineAndPlaneIntersection(const ModelHighAPI_Selection& theEdge, const ModelHighAPI_Selection& theFace);*/ + + /// Dump wrapped feature + CONSTRUCTIONAPI_EXPORT + virtual void dump(ModelHighAPI_Dumper& theDumper) const; }; /// Pointer on Point object. diff --git a/src/ExchangePlugin/CMakeLists.txt b/src/ExchangePlugin/CMakeLists.txt index 0745869ce..2e11f0375 100644 --- a/src/ExchangePlugin/CMakeLists.txt +++ b/src/ExchangePlugin/CMakeLists.txt @@ -6,6 +6,7 @@ INCLUDE(UnitTest) INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/Events ${PROJECT_SOURCE_DIR}/src/Config ${PROJECT_SOURCE_DIR}/src/ModelAPI + ${PROJECT_SOURCE_DIR}/src/ModelHighAPI ${PROJECT_SOURCE_DIR}/src/GeomAPI ${PROJECT_SOURCE_DIR}/src/GeomAlgoAPI ${PROJECT_SOURCE_DIR}/src/XAO @@ -18,6 +19,7 @@ SET(PROJECT_HEADERS ExchangePlugin_ExportFeature.h ExchangePlugin_Validators.h ExchangePlugin_Tools.h + ExchangePlugin_Dump.h ) SET(PROJECT_SOURCES @@ -26,6 +28,7 @@ SET(PROJECT_SOURCES ExchangePlugin_ExportFeature.cpp ExchangePlugin_Validators.cpp ExchangePlugin_Tools.cpp + ExchangePlugin_Dump.cpp ) SET(XML_RESOURCES @@ -41,6 +44,7 @@ SET(PROJECT_LIBRARIES Events Config ModelAPI + ModelHighAPI GeomAPI GeomAlgoAPI XAO diff --git a/src/ExchangePlugin/ExchangePlugin_Dump.cpp b/src/ExchangePlugin/ExchangePlugin_Dump.cpp new file mode 100644 index 000000000..d89f6d98a --- /dev/null +++ b/src/ExchangePlugin/ExchangePlugin_Dump.cpp @@ -0,0 +1,52 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: ExchangePlugin_ExportFeature.cpp +// Created: May 14, 2015 +// Author: Sergey POKHODENKO + +#include + +#include +#include +#include + +#include + +#include + + +ExchangePlugin_Dump::ExchangePlugin_Dump() +{ +} + +ExchangePlugin_Dump::~ExchangePlugin_Dump() +{ +} + +void ExchangePlugin_Dump::initAttributes() +{ + data()->addAttribute(ExchangePlugin_Dump::FILE_PATH_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(ExchangePlugin_Dump::FILE_FORMAT_ID(), ModelAPI_AttributeString::typeId()); +} + +void ExchangePlugin_Dump::execute() +{ + AttributeStringPtr aFilePathAttr = + this->string(ExchangePlugin_Dump::FILE_PATH_ID()); + std::string aFilePath = aFilePathAttr->value(); + if (aFilePath.empty()) + return; + + dump(aFilePath); +} + +void ExchangePlugin_Dump::dump(const std::string& theFileName) +{ + // load DumpAssistant from Python side + Config_ModuleReader::loadScript("model.dump"); + + ModelHighAPI_Dumper* aDumper = ModelHighAPI_Dumper::getInstance(); + DocumentPtr aDoc = ModelAPI_Session::get()->moduleDocument(); + if (!aDumper || !aDumper->process(aDoc, theFileName)) + setError("An error occured while dumping to " + theFileName); +} diff --git a/src/ExchangePlugin/ExchangePlugin_Dump.h b/src/ExchangePlugin/ExchangePlugin_Dump.h new file mode 100644 index 000000000..dc4096505 --- /dev/null +++ b/src/ExchangePlugin/ExchangePlugin_Dump.h @@ -0,0 +1,69 @@ +// Copyright (C) 2016-20xx CEA/DEN, EDF R&D + +// File: ExchangePlugin_Dump.h +// Created: August 1, 2016 +// Author: Artem ZHIDKOV + +#ifndef EXCHANGEPLUGIN_DUMP_H_ +#define EXCHANGEPLUGIN_DUMP_H_ + +#include + +#include + +/** + * \class ExchangePlugin_Dump + * \ingroup Plugins + * \brief Store full model as a Python script + */ +class ExchangePlugin_Dump : public ModelAPI_Feature +{ +public: + /// Feature kind + inline static const std::string& ID() + { + static const std::string MY_DUMP_ID("Dump"); + return MY_DUMP_ID; + } + /// attribute name of file path + inline static const std::string& FILE_PATH_ID() + { + static const std::string MY_FILE_PATH_ID("file_path"); + return MY_FILE_PATH_ID; + } + /// attribute name of file format + inline static const std::string& FILE_FORMAT_ID() + { + static const std::string MY_FILE_FORMAT_ID("file_format"); + return MY_FILE_FORMAT_ID; + } + + /// Default constructor + EXCHANGEPLUGIN_EXPORT ExchangePlugin_Dump(); + /// Default destructor + EXCHANGEPLUGIN_EXPORT virtual ~ExchangePlugin_Dump(); + + /// Returns the unique kind of a feature + EXCHANGEPLUGIN_EXPORT virtual const std::string& getKind() + { + return ExchangePlugin_Dump::ID(); + } + + /// Request for initialization of data model of the feature: adding all attributes + EXCHANGEPLUGIN_EXPORT virtual void initAttributes(); + + /// Computes or recomputes the results + EXCHANGEPLUGIN_EXPORT virtual void execute(); + + /// Reimplemented from ModelAPI_Feature::isMacro(). Returns true. + EXCHANGEPLUGIN_EXPORT virtual bool isMacro() const { return true; } + + /// Reimplemented from ModelAPI_Feature::isPreviewNeeded(). Returns false. + EXCHANGEPLUGIN_EXPORT virtual bool isPreviewNeeded() const { return false; } + +protected: + /// Performs dump to the file + EXCHANGEPLUGIN_EXPORT void dump(const std::string& theFileName); +}; + +#endif diff --git a/src/ExchangePlugin/ExchangePlugin_Plugin.cpp b/src/ExchangePlugin/ExchangePlugin_Plugin.cpp index e731309c3..af3018145 100644 --- a/src/ExchangePlugin/ExchangePlugin_Plugin.cpp +++ b/src/ExchangePlugin/ExchangePlugin_Plugin.cpp @@ -5,6 +5,7 @@ // Author: Sergey BELASH #include +#include #include #include #include @@ -40,6 +41,9 @@ FeaturePtr ExchangePlugin_Plugin::createFeature(string theFeatureID) } else if (theFeatureID == ExchangePlugin_ExportFeature::ID()) { return FeaturePtr(new ExchangePlugin_ExportFeature); + } else + if (theFeatureID == ExchangePlugin_Dump::ID()) { + return FeaturePtr(new ExchangePlugin_Dump); } // feature of such kind is not found return FeaturePtr(); diff --git a/src/ExchangePlugin/icons/dump.png b/src/ExchangePlugin/icons/dump.png new file mode 100644 index 000000000..196cf55dd Binary files /dev/null and b/src/ExchangePlugin/icons/dump.png differ diff --git a/src/ExchangePlugin/plugin-Exchange.xml b/src/ExchangePlugin/plugin-Exchange.xml index f428938d9..abd5f75ba 100755 --- a/src/ExchangePlugin/plugin-Exchange.xml +++ b/src/ExchangePlugin/plugin-Exchange.xml @@ -11,6 +11,15 @@ + + + + + \ No newline at end of file diff --git a/src/ModelHighAPI/CMakeLists.txt b/src/ModelHighAPI/CMakeLists.txt index dfd97daaf..d92154841 100644 --- a/src/ModelHighAPI/CMakeLists.txt +++ b/src/ModelHighAPI/CMakeLists.txt @@ -5,6 +5,7 @@ INCLUDE(Common) SET(PROJECT_HEADERS ModelHighAPI.h ModelHighAPI_Double.h + ModelHighAPI_Dumper.h ModelHighAPI_Integer.h ModelHighAPI_Interface.h ModelHighAPI_Macro.h @@ -17,6 +18,7 @@ SET(PROJECT_HEADERS SET(PROJECT_SOURCES ModelHighAPI_Double.cpp + ModelHighAPI_Dumper.cpp ModelHighAPI_Integer.cpp ModelHighAPI_Interface.cpp ModelHighAPI_RefAttr.cpp @@ -34,7 +36,7 @@ SET(PROJECT_LIBRARIES ModelAPI ) -ADD_DEFINITIONS(-DMODELHIGHAPI_EXPORTS) +ADD_DEFINITIONS(-DMODELHIGHAPI_EXPORTS -DWNT) ADD_LIBRARY(ModelHighAPI SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS}) #TODO(spo): is it necessary? SET_TARGET_PROPERTIES(ModelHighAPI PROPERTIES LINKER_LANGUAGE CXX) @@ -57,6 +59,8 @@ INCLUDE_DIRECTORIES( ${PROJECT_SOURCE_DIR}/src/GeomAPI ${PROJECT_SOURCE_DIR}/src/GeomDataAPI ${PROJECT_SOURCE_DIR}/src/ModelAPI + ${PROJECT_SOURCE_DIR}/src/PartSetPlugin + ${CAS_INCLUDE_DIRS} ) set(SWIG_MODULE_ModelHighAPI_EXTRA_DEPS diff --git a/src/ModelHighAPI/ModelHighAPI.i b/src/ModelHighAPI/ModelHighAPI.i index 1dd6be785..4f4312e23 100644 --- a/src/ModelHighAPI/ModelHighAPI.i +++ b/src/ModelHighAPI/ModelHighAPI.i @@ -1,5 +1,12 @@ /* ModelHighAPI.i */ -%module ModelHighAPI +%module(directors="1") ModelHighAPI +%feature("director:except") { + if ($error != NULL) { + PyErr_Print(); + std::cerr << std::endl; + throw Swig::DirectorMethodException(); + } +} %{ #include "ModelHighAPI_swig.h" @@ -24,6 +31,9 @@ %include "std_string.i" %include "std_shared_ptr.i" +// directors +%feature("director") ModelHighAPI_Dumper; + // shared pointers %shared_ptr(ModelHighAPI_Interface) @@ -180,6 +190,7 @@ // all supported interfaces %include "ModelHighAPI_Double.h" +%include "ModelHighAPI_Dumper.h" %include "ModelHighAPI_Integer.h" %include "ModelHighAPI_Interface.h" %include "ModelHighAPI_RefAttr.h" diff --git a/src/ModelHighAPI/ModelHighAPI_Dumper.cpp b/src/ModelHighAPI/ModelHighAPI_Dumper.cpp new file mode 100644 index 000000000..5bff806d8 --- /dev/null +++ b/src/ModelHighAPI/ModelHighAPI_Dumper.cpp @@ -0,0 +1,368 @@ +// Copyright (C) 2016-20xx CEA/DEN, EDF R&D --> + +// File: ModelHighAPI_Dumper.cpp +// Created: 1 August 2016 +// Author: Artem ZHIDKOV + +//-------------------------------------------------------------------------------------- +#include "ModelHighAPI_Dumper.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +//#define DUMP_USER_DEFINED_NAMES + +ModelHighAPI_Dumper* ModelHighAPI_Dumper::mySelf = 0; + +ModelHighAPI_Dumper::ModelHighAPI_Dumper() +{ + clear(); +} + +void ModelHighAPI_Dumper::setInstance(ModelHighAPI_Dumper* theDumper) +{ + if (mySelf == 0) + mySelf = theDumper; +} + +ModelHighAPI_Dumper* ModelHighAPI_Dumper::getInstance() +{ + return mySelf; +} + +void ModelHighAPI_Dumper::clear() +{ + myDumpBuffer = std::ostringstream(); + myDumpBuffer << std::setprecision(16); +} + +const std::string& ModelHighAPI_Dumper::name(const EntityPtr& theEntity) +{ + EntityNameMap::const_iterator aFound = myNames.find(theEntity); + if (aFound != myNames.end()) + return aFound->second.first; + + // entity is not found, store it + std::string aName; + bool isNameDefined = false; + FeaturePtr aFeature = std::dynamic_pointer_cast(theEntity); + if (aFeature) { + aName = aFeature->name(); + isNameDefined = !aName.empty(); + + if (!isNameDefined) { + static long anIndex = 0; + // set default name: feature ID + index + std::ostringstream aConverter; + aConverter << aFeature->getKind() << "_" << ++anIndex; + aName = aConverter.str(); + std::transform(aName.begin(), aName.end(), aName.begin(), ::tolower); + } + } + + myNames[theEntity] = std::pair(aName, isNameDefined); + return myNames[theEntity].first; +} + +const std::string& ModelHighAPI_Dumper::parentName(const FeaturePtr& theEntity) +{ + const std::set& aRefs = theEntity->data()->refsToMe(); + std::set::const_iterator aRefIt = aRefs.begin(); + for (; aRefIt != aRefs.end(); ++aRefIt) { + CompositeFeaturePtr anOwner = std::dynamic_pointer_cast( + ModelAPI_Feature::feature((*aRefIt)->owner())); + if (anOwner) + return name(anOwner); + } + + static const std::string DUMMY; + return DUMMY; +} + +bool ModelHighAPI_Dumper::process(const std::shared_ptr& theDoc, + const std::string& theFileName) +{ + // dump top level document feature + static const std::string aDocName("partSet"); + myNames[theDoc] = std::pair(aDocName, false); + *this << aDocName << " = model.moduleDocument()" << std::endl; + + // dump subfeatures and store result to file + return process(theDoc) && exportTo(theFileName); +} + +bool ModelHighAPI_Dumper::process(const std::shared_ptr& theDoc) +{ + bool isOk = true; + // dump all features + std::list aFeatures = theDoc->allFeatures(); + std::list::const_iterator aFeatIt = aFeatures.begin(); + for (; aFeatIt != aFeatures.end(); ++aFeatIt) { + dumpFeature(*aFeatIt); + // iteratively process composite features + CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast(*aFeatIt); + if (!aCompFeat) + continue; + + // sub-part is processed independently, because it provides separate document + if ((*aFeatIt)->getKind() == PartSetPlugin_Part::ID()) { + ResultPartPtr aPartResult = + std::dynamic_pointer_cast((*aFeatIt)->lastResult()); + if (!aPartResult) + continue; + DocumentPtr aSubDoc = aPartResult->partDoc(); + // set name of document equal to part name + myNames[aSubDoc] = myNames[*aFeatIt]; + + isOk = process(aSubDoc) && isOk; + } else + isOk = process(aCompFeat) && isOk; + } + return isOk; +} + +bool ModelHighAPI_Dumper::process(const std::shared_ptr& theComposite) +{ + // dump all sub-features; + int aNbSubs = theComposite->numberOfSubs(); + for (int anIndex = 0; anIndex < aNbSubs; ++anIndex) { + FeaturePtr aFeature = theComposite->subFeature(anIndex); + dumpFeature(aFeature, true); + } + // dump command to update model + myDumpBuffer << "model.do()" << std::endl; + return true; +} + +bool ModelHighAPI_Dumper::exportTo(const std::string& theFileName) +{ + std::ofstream aFile; + OSD_OpenStream(aFile, theFileName.c_str(), std::ofstream::out); + if (!aFile.is_open()) + return false; + + // standard header + for (ModulesMap::const_iterator aModIt = myModules.begin(); + aModIt != myModules.end(); ++aModIt) { + aFile << "from " << aModIt->first << " import "; + if (aModIt->second.empty() || + aModIt->second.find(std::string()) != aModIt->second.end()) + aFile << "*"; // import whole module + else { + // import specific features + std::set::const_iterator anObjIt = aModIt->second.begin(); + aFile << *anObjIt; + for (++anObjIt; anObjIt != aModIt->second.end(); ++anObjIt) + aFile << ", " << *anObjIt; + } + aFile << std::endl; + } + if (!myModules.empty()) + aFile << std::endl; + + aFile << "import model" << std::endl << std::endl; + aFile << "model.begin()" << std::endl; + + // dump collected data + aFile << myDumpBuffer.str(); + + // standard footer + aFile << "model.end()" << std::endl; + + aFile.close(); + clear(); + + return true; +} + +void ModelHighAPI_Dumper::importModule(const std::string& theModuleName, + const std::string& theObject) +{ + myModules[theModuleName].insert(theObject); +} + +void ModelHighAPI_Dumper::dumpEntitySetName() +{ + if (!myLastEntityWithName) + return; + +#ifdef DUMP_USER_DEFINED_NAMES + const std::string& aName = name(myLastEntityWithName); + myDumpBuffer << aName; + FeaturePtr aFeature = std::dynamic_pointer_cast(myLastEntityWithName); + if (aFeature) + myDumpBuffer << ".feature()"; + myDumpBuffer << ".data().setName(\"" << aName << "\")" << std::endl; +#endif + myLastEntityWithName = EntityPtr(); +} + +ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const char theChar) +{ + myDumpBuffer << theChar; + return *this; +} + +ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const char* theString) +{ + myDumpBuffer << theString; + return *this; +} + +ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const std::string& theString) +{ + myDumpBuffer << theString; + return *this; +} + +ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const int theValue) +{ + myDumpBuffer << theValue; + return *this; +} + +ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const double theValue) +{ + myDumpBuffer << theValue; + return *this; +} + +ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const std::shared_ptr& thePoint) +{ + importModule("GeomAPI", "GeomAPI_Pnt"); + myDumpBuffer << "GeomAPI_Pnt(" << thePoint->x() << ", " + << thePoint->y() << ", " << thePoint->z() << ")"; + return *this; +} + +ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const std::shared_ptr& theDir) +{ + importModule("GeomAPI", "GeomAPI_Dir"); + myDumpBuffer << "GeomAPI_Dir(" << theDir->x() << ", " + << theDir->y() << ", " << theDir->z() << ")"; + return *this; +} + +ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( + const std::shared_ptr& theDir) +{ + myDumpBuffer << theDir->x() << ", " << theDir->y() << ", " << theDir->z(); + return *this; +} + +static void dumpArray(std::ostringstream& theOutput, int theSize, + double* theValues, std::string* theTexts) +{ + for (int i = 0; i < theSize; ++i) { + if (i > 0) + theOutput << ", "; + if (theTexts[i].empty()) + theOutput << theValues[i]; + else + theOutput << "\"" << theTexts[i] << "\""; + } +} + +ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( + const std::shared_ptr& thePoint) +{ + static const int aSize = 3; + double aValues[aSize] = {thePoint->x(), thePoint->y(), thePoint->z()}; + std::string aTexts[aSize] = {thePoint->textX(), thePoint->textY(), thePoint->textZ()}; + dumpArray(myDumpBuffer, aSize, aValues, aTexts); + return *this; +} + +ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( + const std::shared_ptr& thePoint) +{ + static const int aSize = 2; + double aValues[aSize] = {thePoint->x(), thePoint->y()}; + std::string aTexts[aSize] = {thePoint->textX(), thePoint->textY()}; + dumpArray(myDumpBuffer, aSize, aValues, aTexts); + return *this; +} + +ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( + const std::shared_ptr& theAttrBool) +{ + myDumpBuffer << theAttrBool->value(); + return *this; +} + +ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( + const std::shared_ptr& theAttrInt) +{ + std::string aText = theAttrInt->text(); + if (aText.empty()) + myDumpBuffer << theAttrInt->value(); + else + myDumpBuffer << "\"" << aText << "\""; + return *this; +} + +ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( + const std::shared_ptr& theAttrReal) +{ + std::string aText = theAttrReal->text(); + if (aText.empty()) + myDumpBuffer << theAttrReal->value(); + else + myDumpBuffer << "\"" << aText << "\""; + return *this; +} + +ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( + const std::shared_ptr& theAttrStr) +{ + myDumpBuffer << "\"" << theAttrStr->value() << "\""; + return *this; +} + +ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const EntityPtr& theEntity) +{ + myDumpBuffer << name(theEntity); + if (myNames[theEntity].second) + myLastEntityWithName = theEntity; + return *this; +} + +ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( + const std::shared_ptr& theAttrSelect) +{ + myDumpBuffer << "\"" << theAttrSelect->namingName() << "\""; + return *this; +} + +/// Dump std::endl +MODELHIGHAPI_EXPORT +ModelHighAPI_Dumper& operator<<(ModelHighAPI_Dumper& theDumper, + std::basic_ostream& (*theEndl)(std::basic_ostream&)) +{ + theDumper.myDumpBuffer << theEndl; + theDumper.dumpEntitySetName(); + return theDumper; +} diff --git a/src/ModelHighAPI/ModelHighAPI_Dumper.h b/src/ModelHighAPI/ModelHighAPI_Dumper.h new file mode 100644 index 000000000..675228960 --- /dev/null +++ b/src/ModelHighAPI/ModelHighAPI_Dumper.h @@ -0,0 +1,179 @@ +// Copyright (C) 2016-20xx CEA/DEN, EDF R&D --> + +// File: ModelHighAPI_Dumper.h +// Created: 1 August 2016 +// Author: Artem ZHIDKOV + +#ifndef ModelHighAPI_Dumper_H_ +#define ModelHighAPI_Dumper_H_ + +#include "ModelHighAPI.h" + +#include +#include +#include +#include +#include + +class GeomAPI_Pnt; +class GeomAPI_Dir; + +class GeomDataAPI_Dir; +class GeomDataAPI_Point; +class GeomDataAPI_Point2D; + +class ModelAPI_AttributeBoolean; +class ModelAPI_AttributeDouble; +class ModelAPI_AttributeInteger; +class ModelAPI_AttributeSelection; +class ModelAPI_AttributeString; +class ModelAPI_CompositeFeature; +class ModelAPI_Document; +class ModelAPI_Entity; +class ModelAPI_Feature; + +typedef std::shared_ptr EntityPtr; +typedef std::shared_ptr FeaturePtr; + +/**\class ModelHighAPI_Dumper + * \ingroup CPPHighAPI + * \brief Dump engine for the model + */ +class ModelHighAPI_Dumper +{ +public: + /// Default constructor + MODELHIGHAPI_EXPORT + ModelHighAPI_Dumper(); + + /// Sets instance of a dumper + MODELHIGHAPI_EXPORT + static void setInstance(ModelHighAPI_Dumper* theDumper); + + /// Returns instance of a dumper + MODELHIGHAPI_EXPORT + static ModelHighAPI_Dumper* getInstance(); + + /// Destructor + virtual ~ModelHighAPI_Dumper() {} + + /// Dump given document into the file + /// \return \c true, if succeed + MODELHIGHAPI_EXPORT + bool process(const std::shared_ptr& theDoc, const std::string& theFileName); + + /// Add module to list of imported modules + /// \param theModuleName name of the module to be imported + /// \param theObject name of the entity to be imported from the module (if empty, while module will be imported) + MODELHIGHAPI_EXPORT + void importModule(const std::string& theModuleName, + const std::string& theObject = std::string()); + + /// Returns name of specified entity + MODELHIGHAPI_EXPORT + const std::string& name(const EntityPtr& theEntity); + + /// Returns name of parent composite feature for specified entity + MODELHIGHAPI_EXPORT + const std::string& parentName(const FeaturePtr& theFeature); + + /// Dump given feature + virtual void dumpFeature(const FeaturePtr& theFeature, const bool theForce = false) = 0; + + /// Save all dumps into specified file + MODELHIGHAPI_EXPORT + bool exportTo(const std::string& theFileName); + + /// Dump character + MODELHIGHAPI_EXPORT + ModelHighAPI_Dumper& operator<<(const char theChar); + /// Dump string + MODELHIGHAPI_EXPORT + ModelHighAPI_Dumper& operator<<(const char* theString); + /// Dump string + MODELHIGHAPI_EXPORT + ModelHighAPI_Dumper& operator<<(const std::string& theString); + /// Dump integer + MODELHIGHAPI_EXPORT + ModelHighAPI_Dumper& operator<<(const int theValue); + /// Dump real + MODELHIGHAPI_EXPORT + ModelHighAPI_Dumper& operator<<(const double theValue); + /// Dump std::endl + friend + MODELHIGHAPI_EXPORT + ModelHighAPI_Dumper& operator<<(ModelHighAPI_Dumper& theDumper, + std::basic_ostream& (*theEndl)(std::basic_ostream&)); + + /// Dump GeomAPI_Pnt in the following form: + /// "GeomAPI_Pnt(X, Y, Z)" + MODELHIGHAPI_EXPORT + ModelHighAPI_Dumper& operator<<(const std::shared_ptr& thePoint); + /// Dump GeomAPI_Dir + /// "GeomAPI_Dir(X, Y, Z)" + MODELHIGHAPI_EXPORT + ModelHighAPI_Dumper& operator<<(const std::shared_ptr& theDir); + + /// Dump GeomDataAPI_Dir in the following form: + /// "X, Y, Z" + MODELHIGHAPI_EXPORT + ModelHighAPI_Dumper& operator<<(const std::shared_ptr& theDir); + /// Dump GeomDataAPI_Point in the following form: + /// "X, Y, Z" + MODELHIGHAPI_EXPORT + ModelHighAPI_Dumper& operator<<(const std::shared_ptr& thePoint); + /// Dump GeomDataAPI_Point2D in the following form: + /// "X, Y" + MODELHIGHAPI_EXPORT + ModelHighAPI_Dumper& operator<<(const std::shared_ptr& thePoint); + + /// Dump AttributeBoolean + MODELHIGHAPI_EXPORT + ModelHighAPI_Dumper& operator<<(const std::shared_ptr& theAttrBool); + /// Dump AttributeInteger + MODELHIGHAPI_EXPORT + ModelHighAPI_Dumper& operator<<(const std::shared_ptr& theAttrInt); + /// Dump AttributeDouble + MODELHIGHAPI_EXPORT + ModelHighAPI_Dumper& operator<<(const std::shared_ptr& theAttrReal); + /// Dump AttributeString + MODELHIGHAPI_EXPORT + ModelHighAPI_Dumper& operator<<(const std::shared_ptr& theAttrStr); + /// Dump name of entity and remember to dump "setName" if the entity has user-defined name + MODELHIGHAPI_EXPORT + ModelHighAPI_Dumper& operator<<(const EntityPtr& theEntity); + + /// Dump AttributeSelection + MODELHIGHAPI_EXPORT + ModelHighAPI_Dumper& operator<<(const std::shared_ptr& theAttrSelect); + +protected: + /// Dump "setName" command if last entity had user-defined name + MODELHIGHAPI_EXPORT void dumpEntitySetName(); + + /// Clear dump buffer + void clear(); + +private: + ModelHighAPI_Dumper(const ModelHighAPI_Dumper&); + const ModelHighAPI_Dumper& operator=(const ModelHighAPI_Dumper&); + + /// Iterate all features in document and dump them into intermediate buffer + bool process(const std::shared_ptr& theDoc); + + /// Iterate all features in composite feature and dump them into intermediate buffer + bool process(const std::shared_ptr& theComposite); + +private: + typedef std::map > EntityNameMap; + typedef std::map > ModulesMap; + + static ModelHighAPI_Dumper* mySelf; + + std::ostringstream myDumpBuffer; ///< intermediate buffer to store dumping data + ModulesMap myModules; ///< modules and entities to be imported + EntityNameMap myNames; ///< names of the entities + EntityPtr myLastEntityWithName; ///< not null, if last dumped entity had user defined name +}; + +#endif diff --git a/src/ModelHighAPI/ModelHighAPI_Interface.h b/src/ModelHighAPI/ModelHighAPI_Interface.h index 7d61ffbfb..143be4e53 100644 --- a/src/ModelHighAPI/ModelHighAPI_Interface.h +++ b/src/ModelHighAPI/ModelHighAPI_Interface.h @@ -18,6 +18,7 @@ class ModelAPI_Feature; class ModelAPI_Result; class ModelHighAPI_Selection; +class ModelHighAPI_Dumper; //-------------------------------------------------------------------------------------- /**\class ModelHighAPI_Interface * \ingroup CPPHighAPI @@ -58,6 +59,10 @@ public: MODELHIGHAPI_EXPORT void throwException(const std::string & theDescription); + /// Dump wrapped feature + MODELHIGHAPI_EXPORT + virtual void dump(ModelHighAPI_Dumper& theDumper) const {} + protected: std::shared_ptr myFeature; }; diff --git a/src/ModelHighAPI/ModelHighAPI_Services.cpp b/src/ModelHighAPI/ModelHighAPI_Services.cpp index 09be73726..80f466e5e 100644 --- a/src/ModelHighAPI/ModelHighAPI_Services.cpp +++ b/src/ModelHighAPI/ModelHighAPI_Services.cpp @@ -11,6 +11,8 @@ #include #include +#include + //-------------------------------------------------------------------------------------- std::shared_ptr moduleDocument() { @@ -42,6 +44,32 @@ std::shared_ptr defaultPlane( const std::string& theName ) return std::shared_ptr(new GeomAPI_Ax3(o, x, n)); } +std::string defaultPlane(const std::shared_ptr& theOrigin, + const std::shared_ptr& theNormal, + const std::shared_ptr& theDirX) +{ + static const double aTol = 1.e-10; + + if (fabs(theOrigin->x()) > aTol || fabs(theOrigin->y()) > aTol || fabs(theOrigin->z()) > aTol) + return std::string(); + + // XOY or XOZ + if (fabs(theNormal->x()) < aTol && + fabs(theDirX->x() - 1.0) < aTol && fabs(theDirX->y()) < aTol && fabs(theDirX->z()) < aTol) { + // XOY + if (fabs(theNormal->y()) < aTol && fabs(theNormal->z() - 1.0) < aTol) + return std::string("XOY"); + else if (fabs(theNormal->y() + 1.0) < aTol && fabs(theNormal->z()) < aTol) + return std::string("XOZ"); + } + // YOZ + else if (fabs(theNormal->x() - 1.0) < aTol && fabs(theNormal->y()) < aTol && fabs(theNormal->z()) < aTol && + fabs(theDirX->x()) < aTol && fabs(theDirX->y() - 1.0) < aTol && fabs(theDirX->z()) < aTol) + return std::string("YOZ"); + + return std::string(); +} + //-------------------------------------------------------------------------------------- void begin() { diff --git a/src/ModelHighAPI/ModelHighAPI_Services.h b/src/ModelHighAPI/ModelHighAPI_Services.h index 4d0578382..fa500e5de 100644 --- a/src/ModelHighAPI/ModelHighAPI_Services.h +++ b/src/ModelHighAPI/ModelHighAPI_Services.h @@ -14,6 +14,8 @@ #include //-------------------------------------------------------------------------------------- class GeomAPI_Ax3; +class GeomAPI_Dir; +class GeomAPI_Pnt; class ModelAPI_Document; //-------------------------------------------------------------------------------------- /// Return the main document (the Partset) created or open from the Modeler. @@ -35,6 +37,12 @@ std::shared_ptr activeDocument(); MODELHIGHAPI_EXPORT std::shared_ptr defaultPlane(const std::string & theName); +/// Return name of coordinate plane ("XOY", "XOZ" or "YOZ") or empty string for other planes. +MODELHIGHAPI_EXPORT +std::string defaultPlane(const std::shared_ptr& theOrigin, + const std::shared_ptr& theNormal, + const std::shared_ptr& theDirX); + /** Start a data structure transaction. * * Make a control point for being able to discard or undo diff --git a/src/ModelHighAPI/ModelHighAPI_swig.h b/src/ModelHighAPI/ModelHighAPI_swig.h index d430240cc..c9230d49e 100644 --- a/src/ModelHighAPI/ModelHighAPI_swig.h +++ b/src/ModelHighAPI/ModelHighAPI_swig.h @@ -13,6 +13,7 @@ #include "ModelHighAPI.h" #include "ModelHighAPI_Double.h" + #include "ModelHighAPI_Dumper.h" #include "ModelHighAPI_Integer.h" #include "ModelHighAPI_Interface.h" #include "ModelHighAPI_Macro.h" diff --git a/src/ParametersAPI/ParametersAPI_Parameter.cpp b/src/ParametersAPI/ParametersAPI_Parameter.cpp index 0faa1346a..8781004a0 100644 --- a/src/ParametersAPI/ParametersAPI_Parameter.cpp +++ b/src/ParametersAPI/ParametersAPI_Parameter.cpp @@ -7,6 +7,7 @@ //-------------------------------------------------------------------------------------- #include "ParametersAPI_Parameter.h" //-------------------------------------------------------------------------------------- +#include #include //-------------------------------------------------------------------------------------- ParametersAPI_Parameter::ParametersAPI_Parameter( @@ -36,6 +37,21 @@ ParametersAPI_Parameter::~ParametersAPI_Parameter() { } +void ParametersAPI_Parameter::dump(ModelHighAPI_Dumper& theDumper) const +{ + FeaturePtr aBase = feature(); + const std::string& aDocName = theDumper.name(aBase->document()); + const std::string& aParamName = theDumper.name(aBase); + + AttributeStringPtr anExpr = aBase->string(ParametersPlugin_Parameter::EXPRESSION_ID()); + AttributeStringPtr aComment = aBase->string(ParametersPlugin_Parameter::COMMENT_ID()); + + theDumper << "model.addParameter(" << aDocName << ", \"" << aParamName << "\", " << anExpr; + if (aComment->isInitialized() && !aComment->value().empty()) + theDumper << ", " << aComment; + theDumper << ")" << std::endl; +} + //-------------------------------------------------------------------------------------- ParameterPtr addParameter(const std::shared_ptr & thePart, const std::string & theName, diff --git a/src/ParametersAPI/ParametersAPI_Parameter.h b/src/ParametersAPI/ParametersAPI_Parameter.h index f3e92af18..526267099 100644 --- a/src/ParametersAPI/ParametersAPI_Parameter.h +++ b/src/ParametersAPI/ParametersAPI_Parameter.h @@ -43,6 +43,10 @@ public: comment, ParametersPlugin_Parameter::COMMENT_ID(), ModelAPI_AttributeString, /** Comment */ ) + /// Dump wrapped feature + PARAMETERSAPI_EXPORT + virtual void dump(ModelHighAPI_Dumper& theDumper) const; + }; //! Pointer on Parameter object diff --git a/src/PartSetAPI/PartSetAPI_Part.cpp b/src/PartSetAPI/PartSetAPI_Part.cpp index e55cc920f..acda463d3 100644 --- a/src/PartSetAPI/PartSetAPI_Part.cpp +++ b/src/PartSetAPI/PartSetAPI_Part.cpp @@ -8,6 +8,7 @@ #include "PartSetAPI_Part.h" //-------------------------------------------------------------------------------------- #include +#include //-------------------------------------------------------------------------------------- #include #include @@ -29,6 +30,14 @@ std::shared_ptr PartSetAPI_Part::document() const return std::dynamic_pointer_cast(defaultResult())->partDoc(); } +void PartSetAPI_Part::dump(ModelHighAPI_Dumper& theDumper) const +{ + FeaturePtr aBase = feature(); + const std::string& aDocName = theDumper.name(aBase->document()); + + theDumper << aBase << " = model.addPart(" << aDocName << ").document()" << std::endl; +} + //-------------------------------------------------------------------------------------- PartPtr addPart(const std::shared_ptr & thePart) { diff --git a/src/PartSetAPI/PartSetAPI_Part.h b/src/PartSetAPI/PartSetAPI_Part.h index b65fce9b9..46b1dd558 100644 --- a/src/PartSetAPI/PartSetAPI_Part.h +++ b/src/PartSetAPI/PartSetAPI_Part.h @@ -36,6 +36,10 @@ public: /// Return document PARTSETAPI_EXPORT std::shared_ptr document() const; + + /// Dump wrapped feature + PARTSETAPI_EXPORT + virtual void dump(ModelHighAPI_Dumper& theDumper) const; }; //! Pointer on Part object diff --git a/src/PythonAPI/model/dump/DumpAssistant.py b/src/PythonAPI/model/dump/DumpAssistant.py new file mode 100644 index 000000000..457c7116d --- /dev/null +++ b/src/PythonAPI/model/dump/DumpAssistant.py @@ -0,0 +1,49 @@ +"""Package for dumping purposes. +""" + +import ModelHighAPI + +import ModelAPI + +import sys +import inspect + +def singleton(cls): + instance = cls() + instance.__call__ = lambda: instance + return instance + + +## @ingroup CPPHighAPI +# Collect information about features that may be dumped and stores the model as a Python script +@singleton +class DumpAssistant(ModelHighAPI.ModelHighAPI_Dumper): + + ## Constructor + def __init__(self): + ModelHighAPI.ModelHighAPI_Dumper.__init__(self) + ModelHighAPI.ModelHighAPI_Dumper.setInstance(self) + self.collectFeatures() + + ## Collect feature wrappers, which allow dumping (have method dump) + def collectFeatures(self): + self.myFeatures = {} + for aModule in sys.modules: + for aName, anObj in inspect.getmembers(sys.modules[aModule], inspect.isclass): + if issubclass(anObj, ModelHighAPI.ModelHighAPI_Interface) and hasattr(anObj, "ID") and anObj.dump != ModelHighAPI.ModelHighAPI_Interface.dump: + self.myFeatures[anObj.ID()] = anObj + + ## Create wrapper for a given feature and dump it + def dumpFeature(self, theFeature, theForce): + aFeatureKind = theFeature.getKind() + if aFeatureKind in self.myFeatures: + # Dump only feature created by user (in history). + # For all other features, just keep their name. + if theForce or aFeatureKind == "Parameter" or theFeature.isInHistory(): + self.myFeatures[aFeatureKind](theFeature).dump(self) + else: + self.name(theFeature) + + +# Instance of dumper +dumper = DumpAssistant \ No newline at end of file diff --git a/src/PythonAPI/model/dump/__init__.py b/src/PythonAPI/model/dump/__init__.py new file mode 100644 index 000000000..78a1de4e5 --- /dev/null +++ b/src/PythonAPI/model/dump/__init__.py @@ -0,0 +1,4 @@ +"""Package for dumping purposes. +""" + +from DumpAssistant import * diff --git a/src/SketchAPI/SketchAPI_Point.cpp b/src/SketchAPI/SketchAPI_Point.cpp index c133a74c0..08df487e4 100644 --- a/src/SketchAPI/SketchAPI_Point.cpp +++ b/src/SketchAPI/SketchAPI_Point.cpp @@ -9,6 +9,7 @@ //-------------------------------------------------------------------------------------- #include //-------------------------------------------------------------------------------------- +#include #include #include //-------------------------------------------------------------------------------------- @@ -96,3 +97,20 @@ void SketchAPI_Point::setByExternalName(const std::string & theExternalName) } //-------------------------------------------------------------------------------------- + +void SketchAPI_Point::dump(ModelHighAPI_Dumper& theDumper) const +{ + FeaturePtr aBase = feature(); + const std::string& aSketchName = theDumper.parentName(aBase); + + AttributeSelectionPtr anExternal = aBase->selection(SketchPlugin_SketchEntity::EXTERNAL_ID()); + if (anExternal->value()) { + // point is external + theDumper << aBase << " = " << aSketchName << ".addPoint(" << anExternal << ")" << std::endl; + } else { + // point given by coordinates + std::shared_ptr aPoint = std::dynamic_pointer_cast( + aBase->attribute(SketchPlugin_Point::COORD_ID())); + theDumper << aBase << " = " << aSketchName << ".addPoint(" << aPoint << ")" << std::endl; + } +} diff --git a/src/SketchAPI/SketchAPI_Point.h b/src/SketchAPI/SketchAPI_Point.h index 1596b0f9b..a680aacc6 100644 --- a/src/SketchAPI/SketchAPI_Point.h +++ b/src/SketchAPI/SketchAPI_Point.h @@ -68,6 +68,10 @@ public: /// Set by external name SKETCHAPI_EXPORT void setByExternalName(const std::string & theExternalName); + + /// Dump wrapped feature + SKETCHAPI_EXPORT + virtual void dump(ModelHighAPI_Dumper& theDumper) const; }; //! Pointer on Point object diff --git a/src/SketchAPI/SketchAPI_Sketch.cpp b/src/SketchAPI/SketchAPI_Sketch.cpp index 2a8e7e141..32ed616d3 100644 --- a/src/SketchAPI/SketchAPI_Sketch.cpp +++ b/src/SketchAPI/SketchAPI_Sketch.cpp @@ -27,8 +27,10 @@ //-------------------------------------------------------------------------------------- #include #include +#include #include #include +#include #include //-------------------------------------------------------------------------------------- #include "SketchAPI_Arc.h" @@ -572,3 +574,46 @@ std::shared_ptr SketchAPI_Sketch::setVertical( } //-------------------------------------------------------------------------------------- + +void SketchAPI_Sketch::dump(ModelHighAPI_Dumper& theDumper) const +{ + FeaturePtr aBase = feature(); + const std::string& aDocName = theDumper.name(aBase->document()); + + AttributeSelectionPtr anExternal = aBase->selection(SketchPlugin_SketchEntity::EXTERNAL_ID()); + if (anExternal->value()) { + FeaturePtr aPlnFeature = ModelAPI_Feature::feature(anExternal->context()->data()->owner()); + const std::string& aPlaneName = theDumper.name(aPlnFeature); + theDumper << aBase << " = model.addSketch(" << aDocName << ", \"" << aPlaneName << "\")" << std::endl; + } else { + // Sketch is base on a plane. + std::shared_ptr anOrigin = std::dynamic_pointer_cast( + aBase->attribute(SketchPlugin_Sketch::ORIGIN_ID()))->pnt(); + std::shared_ptr aNormal = std::dynamic_pointer_cast( + aBase->attribute(SketchPlugin_Sketch::NORM_ID()))->dir(); + std::shared_ptr aDirX = std::dynamic_pointer_cast( + aBase->attribute(SketchPlugin_Sketch::DIRX_ID()))->dir(); + + // Check the plane is coordinate plane + std::string aPlaneName = defaultPlane(anOrigin, aNormal, aDirX); + if (aPlaneName.empty()) { + // needs import additional module + theDumper.importModule("GeomAPI"); + // dump plane parameters + const std::string& aSketchName = theDumper.name(aBase); + std::string anOriginName = aSketchName + "_origin"; + std::string aNormalName = aSketchName + "_norm"; + std::string aDirXName = aSketchName + "_dirx"; + theDumper << anOriginName << " = " << anOrigin << std::endl + << aNormalName << " = " << aNormal << std::endl + << aDirXName << " = " << aDirX << std::endl; + // dump sketch based on arbitrary plane + theDumper << aBase << " = model.addSketch(" << aDocName << ", GeomAPI_Ax3(" + << anOriginName << ", " << aDirXName << ", " << aNormalName << "))" << std::endl; + } else { + // dump sketch based on coordinate plane + theDumper << aBase << " = model.addSketch(" << aDocName + << ", model.defaultPlane(\"" << aPlaneName << "\"))" << std::endl; + } + } +} diff --git a/src/SketchAPI/SketchAPI_Sketch.h b/src/SketchAPI/SketchAPI_Sketch.h index e23f9dd90..e74096348 100644 --- a/src/SketchAPI/SketchAPI_Sketch.h +++ b/src/SketchAPI/SketchAPI_Sketch.h @@ -333,6 +333,10 @@ public: SKETCHAPI_EXPORT std::list selectFace() const; + /// Dump wrapped feature + SKETCHAPI_EXPORT + virtual void dump(ModelHighAPI_Dumper& theDumper) const; + protected: std::shared_ptr compositeFeature() const;