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