]> SALOME platform Git repositories - modules/geom.git/blob - src/GEOM/GEOM_Engine.cxx
Salome HOME
Dump Python. Add publishing in study
[modules/geom.git] / src / GEOM / GEOM_Engine.cxx
1 #include "GEOM_Engine.hxx"
2
3 #include "GEOM_Solver.hxx"
4 #include "GEOM_Function.hxx"
5 #include "GEOM_ISubShape.hxx"
6 #include "GEOM_SubShapeDriver.hxx"
7 #include "GEOM_DataMapIteratorOfDataMapOfAsciiStringTransient.hxx"
8
9 #include "utilities.h"
10
11 #include <Interface_DataMapIteratorOfDataMapOfIntegerTransient.hxx>
12
13 #include <TDF_Tool.hxx>
14 #include <TDF_Data.hxx>
15 #include <TDF_LabelSequence.hxx>
16 #include <TDataStd_Integer.hxx>
17 #include <TDataStd_ChildNodeIterator.hxx>
18 #include <TFunction_Driver.hxx>
19 #include <TFunction_DriverTable.hxx>
20
21 #include <TopExp.hxx>
22 #include <TopTools_IndexedMapOfShape.hxx>
23
24 #include <TCollection_AsciiString.hxx>
25 #include <TCollection_ExtendedString.hxx>
26 #include <TColStd_SequenceOfAsciiString.hxx>
27 #include <TColStd_SequenceOfTransient.hxx>
28 #include <TColStd_HSequenceOfTransient.hxx>
29 #include <TColStd_ListOfTransient.hxx>
30 #include <TColStd_MapOfTransient.hxx>
31 #include <TColStd_HSequenceOfInteger.hxx>
32
33 #include <Resource_DataMapIteratorOfDataMapOfAsciiStringAsciiString.hxx>
34
35 #include <map>
36 #include <string>
37
38 #include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
39
40 static GEOM_Engine* TheEngine = NULL;
41
42 static TCollection_AsciiString BuildIDFromObject(Handle(GEOM_Object)& theObject)
43 {
44   TCollection_AsciiString anID(theObject->GetDocID()), anEntry;
45   TDF_Tool::Entry(theObject->GetEntry(), anEntry);
46   anID+=(TCollection_AsciiString("_")+anEntry);
47   return anID;
48 }
49
50 static TCollection_AsciiString BuildID(Standard_Integer theDocID, char* theEntry)
51 {
52   TCollection_AsciiString anID(theDocID);
53   anID+=(TCollection_AsciiString("_")+theEntry);
54   return anID;
55 }
56
57 static Standard_Integer ExtractDocID(TCollection_AsciiString& theID)
58 {
59   TCollection_AsciiString aDocID = theID.Token("_");
60   if(aDocID.Length() < 1) return -1;
61   return aDocID.IntegerValue();
62 }
63
64 void ProcessFunction(Handle(GEOM_Function)& theFunction, 
65                      TCollection_AsciiString& theScript,
66                      TColStd_MapOfTransient& theProcessed);
67
68 Handle(TColStd_HSequenceOfInteger) FindEntries(TCollection_AsciiString& theString);
69
70 //=============================================================================
71 /*!
72  *  GetEngine
73  */
74 //=============================================================================
75 GEOM_Engine* GEOM_Engine::GetEngine() { return TheEngine; }
76
77
78 //=============================================================================
79 /*!
80  *  SetEngine
81  */
82 //=============================================================================
83 void GEOM_Engine::SetEngine(GEOM_Engine* theEngine) { TheEngine = theEngine; }
84
85 //=============================================================================
86 /*!
87  *  Constructor
88  */
89 //=============================================================================
90 GEOM_Engine::GEOM_Engine()
91 {
92   TFunction_DriverTable::Get()->AddDriver(GEOM_Object::GetSubShapeID(), new GEOM_SubShapeDriver());
93
94   _OCAFApp = new GEOM_Application();
95   _UndoLimit = 10;
96 }
97
98 //=============================================================================
99 /*!
100  *  GetDocument
101  */
102 //=============================================================================
103 Handle(TDocStd_Document) GEOM_Engine::GetDocument(int theDocID)
104 {
105   Handle(TDocStd_Document) aDoc;
106   if(!_mapIDDocument.IsBound(theDocID)) {
107     _OCAFApp->NewDocument("SALOME_GEOM", aDoc);
108     aDoc->SetUndoLimit(_UndoLimit);
109     _mapIDDocument.Bind(theDocID, aDoc);
110     TDataStd_Integer::Set(aDoc->Main(), theDocID);
111   }
112
113   return Handle(TDocStd_Document)::DownCast(_mapIDDocument(theDocID));
114 }
115
116 //=============================================================================
117 /*!
118  *  GetDocID
119  */
120 //=============================================================================
121 int GEOM_Engine::GetDocID(Handle(TDocStd_Document) theDocument)
122 {
123   if(theDocument.IsNull()) return -1;
124   for(Interface_DataMapIteratorOfDataMapOfIntegerTransient anItr(_mapIDDocument); anItr.More(); anItr.Next())
125     if(anItr.Value() == theDocument) return anItr.Key();
126
127   return -1;
128
129 }
130
131 //=============================================================================
132 /*!
133  *  GetObject
134  */
135 //=============================================================================
136 Handle(GEOM_Object) GEOM_Engine::GetObject(int theDocID, char* theEntry)
137 {
138   TCollection_AsciiString anID = BuildID(theDocID, theEntry);
139   if(_objects.IsBound(anID)) return Handle(GEOM_Object)::DownCast(_objects(anID));
140
141   TDF_Label aLabel;
142   Handle(TDocStd_Document) aDoc = GetDocument(theDocID);
143   TDF_Tool::Label(aDoc->Main().Data(), theEntry, aLabel, Standard_True);
144   Handle(GEOM_Object) anObject = new GEOM_Object(aLabel);
145
146   _objects.Bind(anID, anObject);
147
148   return anObject;
149 }
150
151 //=============================================================================
152 /*!
153  *  AddObject
154  */
155 //=============================================================================
156 Handle(GEOM_Object) GEOM_Engine::AddObject(int theDocID, int theType)
157 {
158     Handle(TDocStd_Document) aDoc = GetDocument(theDocID);
159     Handle(TDataStd_TreeNode) aRoot = TDataStd_TreeNode::Set(aDoc->Main());
160
161     TDF_Label aChild = TDF_TagSource::NewChild(aDoc->Main());
162     Handle(GEOM_Object) anObject = new GEOM_Object(aChild, theType);
163
164     //Put an object in the map of created objects
165     TCollection_AsciiString anID = BuildIDFromObject(anObject);
166     if(_objects.IsBound(anID)) _objects.UnBind(anID);
167     _objects.Bind(anID, anObject);
168
169     return anObject;
170 }
171
172 //=============================================================================
173 /*!
174  *  AddSubShape
175  */
176 //=============================================================================
177 Handle(GEOM_Object) GEOM_Engine::AddSubShape(Handle(GEOM_Object) theMainShape, 
178                                              Handle(TColStd_HArray1OfInteger) theIndices,
179                                              bool isStandaloneOperation)
180 {
181   if(theMainShape.IsNull() || theIndices.IsNull()) return NULL;
182
183   Handle(TDocStd_Document) aDoc = GetDocument(theMainShape->GetDocID());
184   Handle(TDataStd_TreeNode) aRoot = TDataStd_TreeNode::Set(aDoc->Main());
185
186   TDF_Label aChild = TDF_TagSource::NewChild(aDoc->Main());
187
188   Handle(GEOM_Function) aMainShape = theMainShape->GetLastFunction();
189   Handle(GEOM_Object) anObject = new GEOM_Object(aChild, 28); //28 is SUBSHAPE type
190   Handle(GEOM_Function) aFunction = anObject->AddFunction(GEOM_Object::GetSubShapeID(), 1);
191
192   GEOM_ISubShape aSSI(aFunction);
193   aSSI.SetMainShape(aMainShape);
194   aSSI.SetIndices(theIndices);
195
196   try {
197     GEOM_Solver aSolver (GEOM_Engine::GetEngine());
198     if (!aSolver.ComputeFunction(aFunction)) {
199       MESSAGE("GEOM_Engine::AddSubShape Error: Can't build a sub shape");
200       return NULL;
201     }
202   }
203   catch (Standard_Failure) {
204     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
205     MESSAGE("GEOM_Engine::AddSubShape Error: " << aFail->GetMessageString());
206     return NULL;
207   }
208
209   //Put an object in the map of created objects
210   TCollection_AsciiString anID = BuildIDFromObject(anObject);
211   if(_objects.IsBound(anID)) _objects.UnBind(anID);
212   _objects.Bind(anID, anObject);
213
214   TCollection_AsciiString aDescr("");
215  
216   if(isStandaloneOperation) {
217     TCollection_AsciiString anEntry;
218     TDF_Tool::Entry(anObject->GetEntry(), anEntry);
219     aDescr += anEntry;
220     aDescr += " = geom.AddSubShape(";
221     TDF_Tool::Entry(theMainShape->GetEntry(), anEntry);
222     aDescr += (anEntry+", ");
223     aDescr += (", [");
224     for(Standard_Integer i=theIndices->Lower(); i<=theIndices->Upper(); i++) {
225       aDescr += (TCollection_AsciiString(theIndices->Value(i))+", ");
226     }
227     aDescr.Trunc(aDescr.Length()-1);
228     aDescr += "])";  
229   }
230   else 
231     TCollection_AsciiString aDescr("None");
232  
233   aFunction->SetDescription(aDescr);
234
235   return anObject;
236 }
237
238 //=============================================================================
239 /*!
240  *  RemoveObject
241  */
242 //=============================================================================
243 bool GEOM_Engine::RemoveObject(Handle(GEOM_Object) theObject)
244 {
245   if(!theObject) return false;
246
247   //Remove an object from the map of available objects
248   TCollection_AsciiString anID = BuildIDFromObject(theObject);
249   if(_objects.IsBound(anID)) _objects.UnBind(anID);
250
251   int nb = theObject->GetNbFunctions();
252   Handle(TDataStd_TreeNode) aNode;
253   for(int i = 1; i<=nb; i++) {
254     Handle(GEOM_Function) aFunction = theObject->GetFunction(i);
255     if(aFunction->GetEntry().FindAttribute(GEOM_Function::GetFunctionTreeID(), aNode)) 
256       aNode->Remove();
257   }
258
259   TDF_Label aLabel = theObject->GetEntry();
260   aLabel.ForgetAllAttributes(Standard_True);
261
262   theObject.Nullify();
263
264   return true;
265 }
266
267 //=============================================================================
268 /*!
269  *  Undo
270  */
271 //=============================================================================
272 void GEOM_Engine::Undo(int theDocID)
273 {
274   GetDocument(theDocID)->Undo();
275 }
276
277 //=============================================================================
278 /*!
279  *  Redo
280  */
281 //=============================================================================
282 void GEOM_Engine::Redo(int theDocID)
283 {
284   GetDocument(theDocID)->Redo();
285 }
286
287 //=============================================================================
288 /*!
289  *  Save
290  */
291 //=============================================================================
292 bool GEOM_Engine::Save(int theDocID, char* theFileName)
293 {
294   if(!_mapIDDocument.IsBound(theDocID)) return false;
295   Handle(TDocStd_Document) aDoc = Handle(TDocStd_Document)::DownCast(_mapIDDocument(theDocID));
296
297   _OCAFApp->SaveAs(aDoc, theFileName);
298
299   return true;
300 }
301
302 //=============================================================================
303 /*!
304  *  Load
305  */
306 //=============================================================================
307 bool GEOM_Engine::Load(int theDocID, char* theFileName)
308 {
309   Handle(TDocStd_Document) aDoc;
310   if(_OCAFApp->Open(theFileName, aDoc) != CDF_RS_OK) {
311     return false;
312   }
313
314   aDoc->SetUndoLimit(_UndoLimit);
315
316   if(_mapIDDocument.IsBound(theDocID)) _mapIDDocument.UnBind(theDocID);
317   _mapIDDocument.Bind(theDocID, aDoc);
318
319   TDataStd_Integer::Set(aDoc->Main(), theDocID);
320
321   _OCAFApp->SaveAs(aDoc, "/dn05/salome/srn/Test.sdg");
322
323   return true;
324 }
325
326 //=============================================================================
327 /*!
328  *  Close
329  */
330 //=============================================================================
331 void GEOM_Engine::Close(int theDocID)
332 {
333   if(_mapIDDocument.IsBound(theDocID)) {
334     Handle(TDocStd_Document) aDoc = Handle(TDocStd_Document)::DownCast(_mapIDDocument(theDocID));
335
336     //Remove all GEOM Objects associated to the given document
337     TColStd_SequenceOfAsciiString aSeq;
338     GEOM_DataMapIteratorOfDataMapOfAsciiStringTransient It(_objects);
339     for(; It.More(); It.Next()) {
340       TCollection_AsciiString anObjID(It.Key());
341       Standard_Integer anID = ExtractDocID(anObjID);
342       if(theDocID == anID) aSeq.Append(It.Key());
343     }
344     for(Standard_Integer i=1; i<=aSeq.Length(); i++) _objects.UnBind(aSeq.Value(i));
345
346    _mapIDDocument.UnBind(theDocID);
347     _OCAFApp->Close(aDoc);
348     aDoc.Nullify();
349   }
350 }
351
352 //=============================================================================
353 /*!
354  *  DumpPython
355  */
356 //=============================================================================
357 TCollection_AsciiString GEOM_Engine::DumpPython(int theDocID, 
358                                                 Resource_DataMapOfAsciiStringAsciiString& theObjectNames,
359                                                 bool isPublished, 
360                                                 bool& aValidScript)
361 {
362   TCollection_AsciiString aScript;
363   Handle(TDocStd_Document) aDoc = GetDocument(theDocID);
364   
365   if(aDoc.IsNull()) return TCollection_AsciiString("def RebuildData(theStudy): pass\n");
366  
367   aScript = "import geompy\n\n";
368   aScript += "def RebuildData(theStudy):";
369   
370   Handle(TDataStd_TreeNode) aNode, aRoot;
371   Handle(GEOM_Function) aFunction;
372   TColStd_MapOfTransient aMap;
373
374   if(aDoc->Main().FindAttribute(GEOM_Function::GetFunctionTreeID(), aRoot)) {
375     TDataStd_ChildNodeIterator Itr(aRoot);
376     for(; Itr.More(); Itr.Next()) {
377       aNode = Itr.Value();
378       aFunction = GEOM_Function::GetFunction(aNode->Label());
379       if(aFunction.IsNull()) {
380         cout << "Null function !!!!" << endl;
381         continue;
382       }
383       ProcessFunction(aFunction, aScript, aMap);
384     }
385   }
386
387   Resource_DataMapOfAsciiStringAsciiString aEntry2StEntry, aStEntry2Entry;
388   Resource_DataMapIteratorOfDataMapOfAsciiStringAsciiString anEntryToNameIt;
389   if ( isPublished )
390   {
391     // build maps entry <-> studyEntry
392     for (anEntryToNameIt.Initialize( theObjectNames );
393          anEntryToNameIt.More();
394          anEntryToNameIt.Next())
395     {
396       const TCollection_AsciiString& aEntry = anEntryToNameIt.Key();
397       // look for an object by entry
398       TDF_Label L;
399       TDF_Tool::Label( aDoc->GetData(), aEntry, L );
400       if ( L.IsNull() ) continue;
401       Handle(GEOM_Object) obj = GEOM_Object::GetObject( L );
402       // fill maps
403       if ( !obj.IsNull() ) {
404         TCollection_AsciiString aStudyEntry (obj->GetAuxData());
405         aEntry2StEntry.Bind( aEntry,  aStudyEntry);
406         aStEntry2Entry.Bind( aStudyEntry, aEntry );
407       }
408     }
409   }
410
411   Handle(TColStd_HSequenceOfInteger) aSeq = FindEntries(aScript);
412   Standard_Integer aLen = aSeq->Length(), objectCounter = 0, aStart = 1, aScriptLength = aScript.Length();
413   Resource_DataMapOfAsciiStringAsciiString aNameToEntry;
414
415   //Replace entries by the names
416   TCollection_AsciiString anUpdatedScript, anEntry, aName, aBaseName("geomObj_");
417   if(aLen == 0) anUpdatedScript = aScript;
418
419   for(Standard_Integer i = 1; i <= aLen; i+=2) {
420     anUpdatedScript += aScript.SubString(aStart, aSeq->Value(i)-1);
421     anEntry = aScript.SubString(aSeq->Value(i), aSeq->Value(i+1));
422     if(theObjectNames.IsBound(anEntry)) {
423       aName = theObjectNames.Find(anEntry);
424       if ( aNameToEntry.IsBound( aName ) && anEntry != aNameToEntry( aName ))
425       {  // diff objects have same name - make a new name
426         TCollection_AsciiString aName2;
427         Standard_Integer i = 0;
428         do {
429           aName2 = aName + "_" + ++i;
430         } while ( aNameToEntry.IsBound( aName2 ) && anEntry != aNameToEntry( aName2 ));
431         aName = aName2;
432         theObjectNames( anEntry ) = aName;
433       }
434     }
435     else {
436       do {
437         aName = aBaseName + TCollection_AsciiString(++objectCounter);
438       } while(aNameToEntry.IsBound(aName));
439       theObjectNames.Bind(anEntry, aName);
440     }
441     aNameToEntry.Bind(aName, anEntry); // to detect same name of diff objects
442
443     anUpdatedScript += aName;
444     aStart = aSeq->Value(i+1) + 1;
445   }
446
447   //Add final part of the script
448   if(aSeq->Value(aLen) < aScriptLength)  anUpdatedScript += aScript.SubString(aSeq->Value(aLen)+1, aScriptLength);
449  
450   // Make script to publish in study
451   if ( isPublished )
452   {
453     map< int, string > anEntryToCommandMap; // sort publishing commands by object entry
454     for (anEntryToNameIt.Initialize( theObjectNames );
455          anEntryToNameIt.More();
456          anEntryToNameIt.Next())
457     {
458       const TCollection_AsciiString& aEntry = anEntryToNameIt.Key();
459       const TCollection_AsciiString& aName = anEntryToNameIt.Value();
460       if ( !aEntry2StEntry.IsBound( aEntry ))
461         continue; // was not published
462       TCollection_AsciiString aCommand("\n\tgeompy."), aFatherEntry;
463       // find a father entry
464       const TCollection_AsciiString& aStudyEntry = aEntry2StEntry( aEntry );
465       TCollection_AsciiString aFatherStudyEntry =
466         aStudyEntry.SubString( 1, aStudyEntry.SearchFromEnd(":") - 1 );
467       if ( aStEntry2Entry.IsBound( aFatherStudyEntry ))
468         aFatherEntry = aStEntry2Entry( aFatherStudyEntry );
469       // make a command
470       if ( !aFatherEntry.IsEmpty() && theObjectNames.IsBound( aFatherEntry )) {
471         aCommand += "addToStudyInFather( ";
472         aCommand += theObjectNames( aFatherEntry ) + ", ";
473       }
474       else
475         aCommand += "addToStudy( ";
476       aCommand += aName + ", \"" + aName + "\" )";
477       // bind a command to the last digit of the entry
478       int tag =
479         aEntry.SubString( aEntry.SearchFromEnd(":")+1, aEntry.Length() ).IntegerValue();
480       anEntryToCommandMap.insert( make_pair( tag, aCommand.ToCString() ));
481     }
482
483     // add publishing commands to the script
484     map< int, string >::iterator anEntryToCommand = anEntryToCommandMap.begin();
485     for ( ; anEntryToCommand != anEntryToCommandMap.end(); ++anEntryToCommand ) {
486       //cout << anEntryToCommand->first << endl;
487       anUpdatedScript += (char*)anEntryToCommand->second.c_str();
488     }
489   }
490
491   anUpdatedScript += "\n\tpass\n";
492   aValidScript = true;
493   
494   return anUpdatedScript;
495 }
496
497
498 //===========================================================================
499 //                     Internal functions
500 //===========================================================================
501 void ProcessFunction(Handle(GEOM_Function)& theFunction, 
502                      TCollection_AsciiString& theScript,
503                      TColStd_MapOfTransient& theProcessed)
504 {
505   if(theFunction.IsNull() || theProcessed.Contains(theFunction)) return;
506
507 /*
508   TDF_LabelSequence aSeq;
509   theFunction->GetDependency(aSeq);
510   Standard_Integer aLen = aSeq.Length();
511   for(Standard_Integer i = 1; i<= aLen; i++) {
512     Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(aSeq.Value(i));
513     if(aFunction.IsNull()) continue;
514     ProcessFunction(aFunction, theScript, theProcessed);
515   }
516 */
517
518   TCollection_AsciiString aDescr = theFunction->GetDescription();
519   if(aDescr.Length() == 0) {
520     //cout << "Warning: the function has no description" << endl;
521     return;
522   }
523   //Check if its internal function which doesn't requires dumping
524   if(aDescr == "None") return;
525
526   theScript += "\n\t";
527   theScript += aDescr;
528  
529   theProcessed.Add(theFunction);
530   return;
531 }
532
533 //=============================================================================
534 /*!
535  *  FindEntries: Returns a sequence of start/end positions of entries in the string
536  */
537 //=============================================================================
538 Handle(TColStd_HSequenceOfInteger) FindEntries(TCollection_AsciiString& theString)
539 {
540   Handle(TColStd_HSequenceOfInteger) aSeq = new TColStd_HSequenceOfInteger;
541   Standard_Integer aLen = theString.Length();
542   Standard_Boolean isFound = Standard_False;
543
544   char* arr = theString.ToCString();
545   Standard_Integer i = 0, j;
546
547   while(i < aLen) {
548     int c = (int)arr[i];
549     j = i+1;
550     if(c >= 48 && c <= 57) { //Is digit?
551  
552       isFound = Standard_False;
553       while((j < aLen) && ((c >= 48 && c <= 57) || c == 58) ) { //Check if it is an entry
554         c = (int)arr[j++];  
555         if(c == 58) isFound = Standard_True;
556       }
557       
558       if(isFound && arr[j-2] != 58) { // last char should be a diggit
559         aSeq->Append(i+1); // +1 because AsciiString starts from 1
560         aSeq->Append(j-1);
561       }
562     }
563      
564     i = j;
565   }
566
567   return aSeq;
568 }