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_AttributeRefAttrList.h>
22 #include <ModelAPI_AttributeReference.h>
23 #include <ModelAPI_AttributeRefList.h>
24 #include <ModelAPI_AttributeSelection.h>
25 #include <ModelAPI_AttributeSelectionList.h>
26 #include <ModelAPI_AttributeString.h>
27 #include <ModelAPI_CompositeFeature.h>
28 #include <ModelAPI_Document.h>
29 #include <ModelAPI_Entity.h>
30 #include <ModelAPI_Feature.h>
31 #include <ModelAPI_Result.h>
32 #include <ModelAPI_ResultPart.h>
33
34 #include <PartSetPlugin_Part.h>
35
36 #include <OSD_OpenFile.hxx>
37
38 #include <fstream>
39
40 #define DUMP_USER_DEFINED_NAMES
41
42 ModelHighAPI_Dumper* ModelHighAPI_Dumper::mySelf = 0;
43
44 ModelHighAPI_Dumper::ModelHighAPI_Dumper()
45 {
46   clear();
47 }
48
49 void ModelHighAPI_Dumper::setInstance(ModelHighAPI_Dumper* theDumper)
50 {
51   if (mySelf == 0)
52     mySelf = theDumper;
53 }
54
55 ModelHighAPI_Dumper* ModelHighAPI_Dumper::getInstance()
56 {
57   return mySelf;
58 }
59
60 void ModelHighAPI_Dumper::clear(bool bufferOnly)
61 {
62   myDumpBuffer = std::ostringstream();
63   myDumpBuffer << std::setprecision(16);
64
65   clearNotDumped();
66
67   if (!bufferOnly) {
68     myFullDump = std::ostringstream();
69     myFullDump << std::setprecision(16);
70
71     myNames.clear();
72     myModules.clear();
73     myFeatureCount.clear();
74     myLastEntityWithName = EntityPtr();
75   }
76 }
77
78 void ModelHighAPI_Dumper::clearNotDumped()
79 {
80   myNotDumpedEntities.clear();
81 }
82
83 const std::string& ModelHighAPI_Dumper::name(const EntityPtr& theEntity)
84 {
85   EntityNameMap::const_iterator aFound = myNames.find(theEntity);
86   if (aFound != myNames.end())
87     return aFound->second.first;
88
89   // entity is not found, store it
90   std::string aName;
91   bool isUserDefined = false;
92   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theEntity);
93   if (aFeature) {
94     isUserDefined = true;
95     aName = aFeature->name();
96     const std::string& aKind = aFeature->getKind();
97     DocumentPtr aDoc = aFeature->document();
98     int& aNbFeatures = myFeatureCount[aDoc][aKind];
99
100     size_t anIndex = aName.find(aKind);
101     if (anIndex == 0 && aName[aKind.length()] == '_') { // name starts with "FeatureKind_"
102       std::string anIdStr = aName.substr(aKind.length() + 1, std::string::npos);
103       int anId = std::stoi(anIdStr);
104
105       // Check number of already registered objects of such kind. Index of current object
106       // should be greater than it to identify feature's name as automatically generated.
107       if (aNbFeatures < anId) {
108         isUserDefined = false;
109         aNbFeatures = anId - 1;
110       }
111     }
112
113     aNbFeatures += 1;
114   }
115
116   myNames[theEntity] = std::pair<std::string, bool>(aName, isUserDefined);
117   myNotDumpedEntities.insert(theEntity);
118   return myNames[theEntity].first;
119 }
120
121 const std::string& ModelHighAPI_Dumper::parentName(const FeaturePtr& theEntity)
122 {
123   const std::set<AttributePtr>& aRefs = theEntity->data()->refsToMe();
124   std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
125   for (; aRefIt != aRefs.end(); ++aRefIt) {
126     CompositeFeaturePtr anOwner = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(
127         ModelAPI_Feature::feature((*aRefIt)->owner()));
128     if (anOwner)
129       return name(anOwner);
130   }
131
132   static const std::string DUMMY;
133   return DUMMY;
134 }
135
136 bool ModelHighAPI_Dumper::process(const std::shared_ptr<ModelAPI_Document>& theDoc,
137                                   const std::string& theFileName)
138 {
139   // dump top level document feature
140   static const std::string aDocName("partSet");
141   myNames[theDoc] = std::pair<std::string, bool>(aDocName, false);
142   *this << aDocName << " = model.moduleDocument()" << std::endl;
143
144   // dump subfeatures and store result to file
145   return process(theDoc) && exportTo(theFileName);
146 }
147
148 bool ModelHighAPI_Dumper::process(const std::shared_ptr<ModelAPI_Document>& theDoc)
149 {
150   bool isOk = true;
151   // dump all features
152   std::list<FeaturePtr> aFeatures = theDoc->allFeatures();
153   std::list<FeaturePtr>::const_iterator aFeatIt = aFeatures.begin();
154   for (; aFeatIt != aFeatures.end(); ++aFeatIt) {
155     if (!isDumped(*aFeatIt))
156       dumpFeature(*aFeatIt);
157
158     // iteratively process composite features
159     CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aFeatIt);
160     if (!aCompFeat)
161       continue;
162
163     // sub-part is processed independently, because it provides separate document
164     if ((*aFeatIt)->getKind() == PartSetPlugin_Part::ID()) {
165       ResultPartPtr aPartResult =
166           std::dynamic_pointer_cast<ModelAPI_ResultPart>((*aFeatIt)->lastResult());
167       if (!aPartResult)
168         continue;
169       DocumentPtr aSubDoc = aPartResult->partDoc();
170       // set name of document
171       const std::string& aPartName = myNames[*aFeatIt].first;
172       std::string aDocName = aPartName + "_doc";
173       myNames[aSubDoc] = std::pair<std::string, bool>(aDocName, false);
174
175       // dump document in a single line
176       *this << aDocName << " = " << aPartName << ".document()" << std::endl;
177
178       isOk = process(aSubDoc) && isOk;
179     } else
180       isOk = process(aCompFeat) && isOk;
181   }
182   return isOk;
183 }
184
185 bool ModelHighAPI_Dumper::process(const std::shared_ptr<ModelAPI_CompositeFeature>& theComposite)
186 {
187   // dump all sub-features;
188   int aNbSubs = theComposite->numberOfSubs();
189   for (int anIndex = 0; anIndex < aNbSubs; ++anIndex) {
190     FeaturePtr aFeature = theComposite->subFeature(anIndex);
191     if (isDumped(aFeature))
192       continue;
193     dumpFeature(aFeature, true);
194   }
195   return true;
196 }
197
198 bool ModelHighAPI_Dumper::exportTo(const std::string& theFileName)
199 {
200   std::ofstream aFile;
201   OSD_OpenStream(aFile, theFileName.c_str(), std::ofstream::out);
202   if (!aFile.is_open())
203     return false;
204
205   // standard header
206   for (ModulesMap::const_iterator aModIt = myModules.begin();
207        aModIt != myModules.end(); ++aModIt) {
208     aFile << "from " << aModIt->first << " import ";
209     if (aModIt->second.empty() || 
210         aModIt->second.find(std::string()) != aModIt->second.end())
211       aFile << "*"; // import whole module
212     else {
213       // import specific features
214       std::set<std::string>::const_iterator anObjIt = aModIt->second.begin();
215       aFile << *anObjIt;
216       for (++anObjIt; anObjIt != aModIt->second.end(); ++anObjIt)
217         aFile << ", " << *anObjIt;
218     }
219     aFile << std::endl;
220   }
221   if (!myModules.empty())
222     aFile << std::endl;
223
224   aFile << "import model" << std::endl << std::endl;
225   aFile << "model.begin()" << std::endl;
226
227   // dump collected data
228   aFile << myFullDump.str();
229
230   // standard footer
231   aFile << "model.end()" << std::endl;
232
233   aFile.close();
234   clear();
235
236   return true;
237 }
238
239 void ModelHighAPI_Dumper::importModule(const std::string& theModuleName,
240                                        const std::string& theObject)
241 {
242   myModules[theModuleName].insert(theObject);
243 }
244
245 void ModelHighAPI_Dumper::dumpEntitySetName()
246 {
247   if (!myLastEntityWithName)
248     return;
249
250 #ifdef DUMP_USER_DEFINED_NAMES
251   const std::string& aName = name(myLastEntityWithName);
252   myDumpBuffer << aName;
253   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(myLastEntityWithName);
254   if (aFeature)
255     myDumpBuffer << ".feature()";
256   myDumpBuffer << ".data().setName(\"" << aName << "\")" << std::endl;
257 #endif
258   myNames[myLastEntityWithName].second = false; // don't dump "setName" for the entity twice
259   myLastEntityWithName = EntityPtr();
260 }
261
262 bool ModelHighAPI_Dumper::isDumped(const EntityPtr& theEntity) const
263 {
264   EntityNameMap::const_iterator aFound = myNames.find(theEntity);
265   return aFound != myNames.end();
266 }
267
268 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const char theChar)
269 {
270   myDumpBuffer << theChar;
271   return *this;
272 }
273
274 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const char* theString)
275 {
276   myDumpBuffer << theString;
277   return *this;
278 }
279
280 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const std::string& theString)
281 {
282   myDumpBuffer << theString;
283   return *this;
284 }
285
286 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const bool theValue)
287 {
288   myDumpBuffer << (theValue ? "True" : "False");
289   return *this;
290 }
291
292 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const int theValue)
293 {
294   myDumpBuffer << theValue;
295   return *this;
296 }
297
298 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const double theValue)
299 {
300   myDumpBuffer << theValue;
301   return *this;
302 }
303
304 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const std::shared_ptr<GeomAPI_Pnt>& thePoint)
305 {
306   importModule("GeomAPI", "GeomAPI_Pnt");
307   myDumpBuffer << "GeomAPI_Pnt(" << thePoint->x() << ", "
308                << thePoint->y() << ", " << thePoint->z() << ")";
309   return *this;
310 }
311
312 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const std::shared_ptr<GeomAPI_Dir>& theDir)
313 {
314   importModule("GeomAPI", "GeomAPI_Dir");
315   myDumpBuffer << "GeomAPI_Dir(" << theDir->x() << ", "
316                << theDir->y() << ", " << theDir->z() << ")";
317   return *this;
318 }
319
320 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
321     const std::shared_ptr<GeomDataAPI_Dir>& theDir)
322 {
323   myDumpBuffer << theDir->x() << ", " << theDir->y() << ", " << theDir->z();
324   return *this;
325 }
326
327 static void dumpArray(std::ostringstream& theOutput, int theSize,
328                       double* theValues, std::string* theTexts)
329 {
330   for (int i = 0; i < theSize; ++i) {
331     if (i > 0)
332       theOutput << ", ";
333     if (theTexts[i].empty())
334       theOutput << theValues[i];
335     else
336       theOutput << "\"" << theTexts[i] << "\"";
337   }
338 }
339
340 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
341     const std::shared_ptr<GeomDataAPI_Point>& thePoint)
342 {
343   static const int aSize = 3;
344   double aValues[aSize] = {thePoint->x(), thePoint->y(), thePoint->z()};
345   std::string aTexts[aSize] = {thePoint->textX(), thePoint->textY(), thePoint->textZ()};
346   dumpArray(myDumpBuffer, aSize, aValues, aTexts);
347   return *this;
348 }
349
350 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
351     const std::shared_ptr<GeomDataAPI_Point2D>& thePoint)
352 {
353   static const int aSize = 2;
354   double aValues[aSize] = {thePoint->x(), thePoint->y()};
355   std::string aTexts[aSize] = {thePoint->textX(), thePoint->textY()};
356   dumpArray(myDumpBuffer, aSize, aValues, aTexts);
357   return *this;
358 }
359
360 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
361     const std::shared_ptr<ModelAPI_AttributeBoolean>& theAttrBool)
362 {
363   myDumpBuffer << (theAttrBool->value() ? "True" : "False");
364   return *this;
365 }
366
367 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
368     const std::shared_ptr<ModelAPI_AttributeInteger>& theAttrInt)
369 {
370   std::string aText = theAttrInt->text();
371   if (aText.empty())
372     myDumpBuffer << theAttrInt->value();
373   else
374     myDumpBuffer << "\"" << aText << "\"";
375   return *this;
376 }
377
378 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
379     const std::shared_ptr<ModelAPI_AttributeDouble>& theAttrReal)
380 {
381   std::string aText = theAttrReal->text();
382   if (aText.empty())
383     myDumpBuffer << theAttrReal->value();
384   else
385     myDumpBuffer << "\"" << aText << "\"";
386   return *this;
387 }
388
389 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
390     const std::shared_ptr<ModelAPI_AttributeString>& theAttrStr)
391 {
392   myDumpBuffer << "\"" << theAttrStr->value() << "\"";
393   return *this;
394 }
395
396 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const FeaturePtr& theEntity)
397 {
398   myDumpBuffer << name(theEntity);
399   if (myNames[theEntity].second)
400     myLastEntityWithName = theEntity;
401   myNotDumpedEntities.erase(theEntity);
402   return *this;
403 }
404
405 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const ObjectPtr& theObject)
406 {
407   FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
408   myDumpBuffer << name(aFeature);
409   return *this;
410 }
411
412 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const AttributePtr& theAttr)
413 {
414   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttr->owner());
415   myDumpBuffer << name(anOwner) << "." << attributeGetter(anOwner, theAttr->id()) << "()";
416   return *this;
417 }
418
419 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
420     const std::shared_ptr<ModelAPI_AttributeRefAttr>& theRefAttr)
421 {
422   if (theRefAttr->isObject())
423     *this << theRefAttr->object();
424   else
425     *this << theRefAttr->attr();
426   return *this;
427 }
428
429 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
430     const std::shared_ptr<ModelAPI_AttributeRefAttrList>& theRefAttrList)
431 {
432   myDumpBuffer << "[";
433   std::list<std::pair<ObjectPtr, AttributePtr> > aList = theRefAttrList->list();
434   bool isAdded = false;
435   std::list<std::pair<ObjectPtr, AttributePtr> >::const_iterator anIt = aList.begin();
436   for (; anIt != aList.end(); ++anIt) {
437     if (isAdded)
438       myDumpBuffer << ", ";
439     else
440       isAdded = true;
441     if (anIt->first)
442       *this << anIt->first;
443     else if (anIt->second)
444       * this << anIt->second;
445   }
446   myDumpBuffer << "]";
447   return *this;
448 }
449
450 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
451     const std::shared_ptr<ModelAPI_AttributeReference>& theReference)
452 {
453   *this << theReference->value();
454   return *this;
455 }
456
457 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
458     const std::shared_ptr<ModelAPI_AttributeRefList>& theRefList)
459 {
460   static const int aThreshold = 2;
461   // if number of elements in the list if greater than a threshold,
462   // dump it in a separate line with specific name
463   std::string aDumped = myDumpBuffer.str();
464   if (aDumped.empty() || theRefList->size() <= aThreshold) {
465     myDumpBuffer << "[";
466     std::list<ObjectPtr> aList = theRefList->list();
467     bool isAdded = false;
468     std::list<ObjectPtr>::const_iterator anIt = aList.begin();
469     for (; anIt != aList.end(); ++anIt) {
470       if (isAdded)
471         myDumpBuffer << ", ";
472       else
473         isAdded = true;
474
475       *this << *anIt;
476     }
477     myDumpBuffer << "]";
478   } else {
479     // clear buffer and store list "as is"
480     myDumpBuffer = std::ostringstream();
481     *this << theRefList;
482     // save buffer and clear it again
483     std::string aDumpedList = myDumpBuffer.str();
484     myDumpBuffer = std::ostringstream();
485     // obtain name of list
486     FeaturePtr anOwner = ModelAPI_Feature::feature(theRefList->owner());
487     std::string aListName = name(anOwner) + "_objects";
488     // store all previous data
489     myDumpBuffer << aListName << " = " << aDumpedList << std::endl
490                  << aDumped << aListName;
491   }
492   return *this;
493 }
494
495 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
496     const std::shared_ptr<ModelAPI_AttributeSelection>& theAttrSelect)
497 {
498   myDumpBuffer << "model.selection(";
499
500   if(!theAttrSelect->isInitialized()) {
501     myDumpBuffer << ")";
502     return *this;
503   }
504
505   GeomShapePtr aShape = theAttrSelect->value();
506   if(!aShape.get()) {
507     aShape = theAttrSelect->context()->shape();
508   }
509
510   if(!aShape.get()) {
511     myDumpBuffer << ")";
512     return *this;
513   }
514
515   myDumpBuffer << "\"" << aShape->shapeTypeStr() << "\", \"" << theAttrSelect->namingName() << "\")";
516   return *this;
517 }
518
519 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
520     const std::shared_ptr<ModelAPI_AttributeSelectionList>& theAttrSelList)
521 {
522   myDumpBuffer << "[";
523
524   GeomShapePtr aShape;
525   std::string aShapeTypeStr;
526
527   bool isAdded = false;
528
529   for(int anIndex = 0; anIndex < theAttrSelList->size(); ++anIndex) {
530     AttributeSelectionPtr anAttribute = theAttrSelList->value(anIndex);
531     aShape = anAttribute->value();
532     if(!aShape.get()) {
533       aShape = anAttribute->context()->shape();
534     }
535
536     if(!aShape.get()) {
537       continue;
538     }
539
540     if(isAdded) {
541       myDumpBuffer << ", ";
542     } else {
543       isAdded = true;
544     }
545     myDumpBuffer << "model.selection(\"" << aShape->shapeTypeStr() << "\", \"" << anAttribute->namingName() << "\")";
546   }
547
548   myDumpBuffer << "]";
549   return *this;
550 }
551
552 /// Dump std::endl
553 MODELHIGHAPI_EXPORT
554 ModelHighAPI_Dumper& operator<<(ModelHighAPI_Dumper& theDumper,
555                                 std::basic_ostream<char>& (*theEndl)(std::basic_ostream<char>&))
556 {
557   theDumper.myDumpBuffer << theEndl;
558   theDumper.dumpEntitySetName();
559
560   // store all not-dumped entities first
561   std::set<EntityPtr> aNotDumped = theDumper.myNotDumpedEntities;
562   std::string aBufCopy = theDumper.myDumpBuffer.str();
563   theDumper.clear(true);
564   std::set<EntityPtr>::const_iterator anIt = aNotDumped.begin();
565   for (; anIt != aNotDumped.end(); ++anIt) {
566     FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
567     theDumper.dumpFeature(aFeature, true);
568
569     // if the feature is composite, dump all its subs
570     CompositeFeaturePtr aCompFeat =
571         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature);
572     if (aCompFeat)
573       theDumper.process(aCompFeat);
574   }
575
576   // avoid multiple empty lines
577   size_t anInd = std::string::npos;
578   while ((anInd = aBufCopy.find("\n\n\n")) != std::string::npos)
579     aBufCopy.erase(anInd, 1);
580   // then store currently dumped string
581   theDumper.myFullDump << aBufCopy;
582
583   return theDumper;
584 }