Salome HOME
Dump Python in the High Level Parameterized Geometry API (issue #1648)
[modules/shaper.git] / src / ModelHighAPI / ModelHighAPI_Dumper.cpp
1 // Copyright (C) 2016-20xx CEA/DEN, EDF R&D -->
2
3 // File:        ModelHighAPI_Dumper.cpp
4 // Created:     1 August 2016
5 // Author:      Artem ZHIDKOV
6
7 //--------------------------------------------------------------------------------------
8 #include "ModelHighAPI_Dumper.h"
9
10 #include <GeomAPI_Pnt.h>
11 #include <GeomAPI_Dir.h>
12
13 #include <GeomDataAPI_Dir.h>
14 #include <GeomDataAPI_Point.h>
15 #include <GeomDataAPI_Point2D.h>
16
17 #include <ModelAPI_AttributeBoolean.h>
18 #include <ModelAPI_AttributeDouble.h>
19 #include <ModelAPI_AttributeInteger.h>
20 #include <ModelAPI_AttributeRefAttr.h>
21 #include <ModelAPI_AttributeSelection.h>
22 #include <ModelAPI_AttributeString.h>
23 #include <ModelAPI_CompositeFeature.h>
24 #include <ModelAPI_Document.h>
25 #include <ModelAPI_Entity.h>
26 #include <ModelAPI_Feature.h>
27 #include <ModelAPI_Result.h>
28 #include <ModelAPI_ResultPart.h>
29
30 #include <PartSetPlugin_Part.h>
31
32 #include <OSD_OpenFile.hxx>
33
34 #include <algorithm>
35 #include <fstream>
36
37 //#define DUMP_USER_DEFINED_NAMES
38
39 ModelHighAPI_Dumper* ModelHighAPI_Dumper::mySelf = 0;
40
41 ModelHighAPI_Dumper::ModelHighAPI_Dumper()
42 {
43   clear();
44 }
45
46 void ModelHighAPI_Dumper::setInstance(ModelHighAPI_Dumper* theDumper)
47 {
48   if (mySelf == 0)
49     mySelf = theDumper;
50 }
51
52 ModelHighAPI_Dumper* ModelHighAPI_Dumper::getInstance()
53 {
54   return mySelf;
55 }
56
57 void ModelHighAPI_Dumper::clear()
58 {
59   myDumpBuffer = std::ostringstream();
60   myDumpBuffer << std::setprecision(16);
61 }
62
63 const std::string& ModelHighAPI_Dumper::name(const EntityPtr& theEntity)
64 {
65   EntityNameMap::const_iterator aFound = myNames.find(theEntity);
66   if (aFound != myNames.end())
67     return aFound->second.first;
68
69   // entity is not found, store it
70   std::string aName;
71   bool isNameDefined = false;
72   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theEntity);
73   if (aFeature) {
74     aName = aFeature->name();
75     isNameDefined = !aName.empty();
76
77     if (!isNameDefined) {
78       static long anIndex = 0;
79       // set default name: feature ID + index
80       std::ostringstream aConverter;
81       aConverter << aFeature->getKind() << "_" << ++anIndex;
82       aName = aConverter.str();
83       std::transform(aName.begin(), aName.end(), aName.begin(), ::tolower);
84     }
85   }
86
87   myNames[theEntity] = std::pair<std::string, bool>(aName, isNameDefined);
88   return myNames[theEntity].first;
89 }
90
91 const std::string& ModelHighAPI_Dumper::parentName(const FeaturePtr& theEntity)
92 {
93   const std::set<AttributePtr>& aRefs = theEntity->data()->refsToMe();
94   std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
95   for (; aRefIt != aRefs.end(); ++aRefIt) {
96     CompositeFeaturePtr anOwner = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(
97         ModelAPI_Feature::feature((*aRefIt)->owner()));
98     if (anOwner)
99       return name(anOwner);
100   }
101
102   static const std::string DUMMY;
103   return DUMMY;
104 }
105
106 bool ModelHighAPI_Dumper::process(const std::shared_ptr<ModelAPI_Document>& theDoc,
107                                   const std::string& theFileName)
108 {
109   // dump top level document feature
110   static const std::string aDocName("partSet");
111   myNames[theDoc] = std::pair<std::string, bool>(aDocName, false);
112   *this << aDocName << " = model.moduleDocument()" << std::endl;
113
114   // dump subfeatures and store result to file
115   return process(theDoc) && exportTo(theFileName);
116 }
117
118 bool ModelHighAPI_Dumper::process(const std::shared_ptr<ModelAPI_Document>& theDoc)
119 {
120   bool isOk = true;
121   CompositeFeaturePtr aLastComposite;
122   // dump all features
123   std::list<FeaturePtr> aFeatures = theDoc->allFeatures();
124   std::list<FeaturePtr>::const_iterator aFeatIt = aFeatures.begin();
125   for (; aFeatIt != aFeatures.end(); ++aFeatIt) {
126     // dump feature if and only if it is not a sub-feature of last composite feature
127     // (all subs of composite are dumped in special method)
128     if (!aLastComposite || !aLastComposite->isSub(*aFeatIt))
129       dumpFeature(*aFeatIt);
130
131     // iteratively process composite features
132     CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aFeatIt);
133     if (!aCompFeat)
134       continue;
135
136     // sub-part is processed independently, because it provides separate document
137     if ((*aFeatIt)->getKind() == PartSetPlugin_Part::ID()) {
138       ResultPartPtr aPartResult =
139           std::dynamic_pointer_cast<ModelAPI_ResultPart>((*aFeatIt)->lastResult());
140       if (!aPartResult)
141         continue;
142       DocumentPtr aSubDoc = aPartResult->partDoc();
143       // set name of document equal to part name
144       myNames[aSubDoc] = myNames[*aFeatIt];
145
146       isOk = process(aSubDoc) && isOk;
147     } else {
148       isOk = process(aCompFeat) && isOk;
149       aLastComposite = aCompFeat;
150     }
151   }
152   return isOk;
153 }
154
155 bool ModelHighAPI_Dumper::process(const std::shared_ptr<ModelAPI_CompositeFeature>& theComposite)
156 {
157   // dump all sub-features;
158   int aNbSubs = theComposite->numberOfSubs();
159   for (int anIndex = 0; anIndex < aNbSubs; ++anIndex) {
160     FeaturePtr aFeature = theComposite->subFeature(anIndex);
161     dumpFeature(aFeature, true);
162   }
163   // dump command to update model
164   myDumpBuffer << "model.do()" << std::endl;
165   return true;
166 }
167
168 bool ModelHighAPI_Dumper::exportTo(const std::string& theFileName)
169 {
170   std::ofstream aFile;
171   OSD_OpenStream(aFile, theFileName.c_str(), std::ofstream::out);
172   if (!aFile.is_open())
173     return false;
174
175   // standard header
176   for (ModulesMap::const_iterator aModIt = myModules.begin();
177        aModIt != myModules.end(); ++aModIt) {
178     aFile << "from " << aModIt->first << " import ";
179     if (aModIt->second.empty() || 
180         aModIt->second.find(std::string()) != aModIt->second.end())
181       aFile << "*"; // import whole module
182     else {
183       // import specific features
184       std::set<std::string>::const_iterator anObjIt = aModIt->second.begin();
185       aFile << *anObjIt;
186       for (++anObjIt; anObjIt != aModIt->second.end(); ++anObjIt)
187         aFile << ", " << *anObjIt;
188     }
189     aFile << std::endl;
190   }
191   if (!myModules.empty())
192     aFile << std::endl;
193
194   aFile << "import model" << std::endl << std::endl;
195   aFile << "model.begin()" << std::endl;
196
197   // dump collected data
198   aFile << myDumpBuffer.str();
199
200   // standard footer
201   aFile << "model.end()" << std::endl;
202
203   aFile.close();
204   clear();
205
206   return true;
207 }
208
209 void ModelHighAPI_Dumper::importModule(const std::string& theModuleName,
210                                        const std::string& theObject)
211 {
212   myModules[theModuleName].insert(theObject);
213 }
214
215 void ModelHighAPI_Dumper::dumpEntitySetName()
216 {
217   if (!myLastEntityWithName)
218     return;
219
220 #ifdef DUMP_USER_DEFINED_NAMES
221   const std::string& aName = name(myLastEntityWithName);
222   myDumpBuffer << aName;
223   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(myLastEntityWithName);
224   if (aFeature)
225     myDumpBuffer << ".feature()";
226   myDumpBuffer << ".data().setName(\"" << aName << "\")" << std::endl;
227 #endif
228   myLastEntityWithName = EntityPtr();
229 }
230
231 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const char theChar)
232 {
233   myDumpBuffer << theChar;
234   return *this;
235 }
236
237 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const char* theString)
238 {
239   myDumpBuffer << theString;
240   return *this;
241 }
242
243 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const std::string& theString)
244 {
245   myDumpBuffer << theString;
246   return *this;
247 }
248
249 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const int theValue)
250 {
251   myDumpBuffer << theValue;
252   return *this;
253 }
254
255 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const double theValue)
256 {
257   myDumpBuffer << theValue;
258   return *this;
259 }
260
261 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const std::shared_ptr<GeomAPI_Pnt>& thePoint)
262 {
263   importModule("GeomAPI", "GeomAPI_Pnt");
264   myDumpBuffer << "GeomAPI_Pnt(" << thePoint->x() << ", "
265                << thePoint->y() << ", " << thePoint->z() << ")";
266   return *this;
267 }
268
269 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const std::shared_ptr<GeomAPI_Dir>& theDir)
270 {
271   importModule("GeomAPI", "GeomAPI_Dir");
272   myDumpBuffer << "GeomAPI_Dir(" << theDir->x() << ", "
273                << theDir->y() << ", " << theDir->z() << ")";
274   return *this;
275 }
276
277 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
278     const std::shared_ptr<GeomDataAPI_Dir>& theDir)
279 {
280   myDumpBuffer << theDir->x() << ", " << theDir->y() << ", " << theDir->z();
281   return *this;
282 }
283
284 static void dumpArray(std::ostringstream& theOutput, int theSize,
285                       double* theValues, std::string* theTexts)
286 {
287   for (int i = 0; i < theSize; ++i) {
288     if (i > 0)
289       theOutput << ", ";
290     if (theTexts[i].empty())
291       theOutput << theValues[i];
292     else
293       theOutput << "\"" << theTexts[i] << "\"";
294   }
295 }
296
297 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
298     const std::shared_ptr<GeomDataAPI_Point>& thePoint)
299 {
300   static const int aSize = 3;
301   double aValues[aSize] = {thePoint->x(), thePoint->y(), thePoint->z()};
302   std::string aTexts[aSize] = {thePoint->textX(), thePoint->textY(), thePoint->textZ()};
303   dumpArray(myDumpBuffer, aSize, aValues, aTexts);
304   return *this;
305 }
306
307 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
308     const std::shared_ptr<GeomDataAPI_Point2D>& thePoint)
309 {
310   static const int aSize = 2;
311   double aValues[aSize] = {thePoint->x(), thePoint->y()};
312   std::string aTexts[aSize] = {thePoint->textX(), thePoint->textY()};
313   dumpArray(myDumpBuffer, aSize, aValues, aTexts);
314   return *this;
315 }
316
317 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
318     const std::shared_ptr<ModelAPI_AttributeBoolean>& theAttrBool)
319 {
320   myDumpBuffer << (theAttrBool->value() ? "True" : "False");
321   return *this;
322 }
323
324 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
325     const std::shared_ptr<ModelAPI_AttributeInteger>& theAttrInt)
326 {
327   std::string aText = theAttrInt->text();
328   if (aText.empty())
329     myDumpBuffer << theAttrInt->value();
330   else
331     myDumpBuffer << "\"" << aText << "\"";
332   return *this;
333 }
334
335 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
336     const std::shared_ptr<ModelAPI_AttributeDouble>& theAttrReal)
337 {
338   std::string aText = theAttrReal->text();
339   if (aText.empty())
340     myDumpBuffer << theAttrReal->value();
341   else
342     myDumpBuffer << "\"" << aText << "\"";
343   return *this;
344 }
345
346 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
347     const std::shared_ptr<ModelAPI_AttributeString>& theAttrStr)
348 {
349   myDumpBuffer << "\"" << theAttrStr->value() << "\"";
350   return *this;
351 }
352
353 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const EntityPtr& theEntity)
354 {
355   myDumpBuffer << name(theEntity);
356   if (myNames[theEntity].second)
357     myLastEntityWithName = theEntity;
358   return *this;
359 }
360
361 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
362     const std::shared_ptr<ModelAPI_AttributeRefAttr>& theRefAttr)
363 {
364   if (theRefAttr->isObject()) {
365     FeaturePtr aFeature = ModelAPI_Feature::feature(theRefAttr->object());
366     myDumpBuffer << name(aFeature);
367   } else {
368     AttributePtr anAttr = theRefAttr->attr();
369     FeaturePtr anOwner = ModelAPI_Feature::feature(anAttr->owner());
370     myDumpBuffer << name(anOwner) << "." << attributeGetter(anOwner, anAttr->id()) << "()";
371   }
372   return *this;
373 }
374
375 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
376     const std::shared_ptr<ModelAPI_AttributeSelection>& theAttrSelect)
377 {
378   GeomShapePtr aShape = theAttrSelect->value();
379   if(!aShape.get()) {
380     aShape = theAttrSelect->context()->shape();
381   }
382
383   if(!aShape.get()) {
384     return *this;
385   }
386
387   std::string aShapeTypeStr = aShape->shapeTypeStr();
388
389   myDumpBuffer << "model.selection(\"" << aShapeTypeStr << "\", \"" << theAttrSelect->namingName() << "\")";
390   return *this;
391 }
392
393 /// Dump std::endl
394 MODELHIGHAPI_EXPORT
395 ModelHighAPI_Dumper& operator<<(ModelHighAPI_Dumper& theDumper,
396                                 std::basic_ostream<char>& (*theEndl)(std::basic_ostream<char>&))
397 {
398   theDumper.myDumpBuffer << theEndl;
399   theDumper.dumpEntitySetName();
400   return theDumper;
401 }