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