Salome HOME
Dump Python. Insert
[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   aScript += "\n\tgeompy.init_geom(theStudy)";
370   
371   Handle(TDataStd_TreeNode) aNode, aRoot;
372   Handle(GEOM_Function) aFunction;
373   TColStd_MapOfTransient aMap;
374
375   if(aDoc->Main().FindAttribute(GEOM_Function::GetFunctionTreeID(), aRoot)) {
376     TDataStd_ChildNodeIterator Itr(aRoot);
377     for(; Itr.More(); Itr.Next()) {
378       aNode = Itr.Value();
379       aFunction = GEOM_Function::GetFunction(aNode->Label());
380       if(aFunction.IsNull()) {
381         cout << "Null function !!!!" << endl;
382         continue;
383       }
384       ProcessFunction(aFunction, aScript, aMap);
385     }
386   }
387
388   Resource_DataMapOfAsciiStringAsciiString aEntry2StEntry, aStEntry2Entry;
389   Resource_DataMapIteratorOfDataMapOfAsciiStringAsciiString anEntryToNameIt;
390   if ( isPublished )
391   {
392     // build maps entry <-> studyEntry
393     for (anEntryToNameIt.Initialize( theObjectNames );
394          anEntryToNameIt.More();
395          anEntryToNameIt.Next())
396     {
397       const TCollection_AsciiString& aEntry = anEntryToNameIt.Key();
398       // look for an object by entry
399       TDF_Label L;
400       TDF_Tool::Label( aDoc->GetData(), aEntry, L );
401       if ( L.IsNull() ) continue;
402       Handle(GEOM_Object) obj = GEOM_Object::GetObject( L );
403       // fill maps
404       if ( !obj.IsNull() ) {
405         TCollection_AsciiString aStudyEntry (obj->GetAuxData());
406         aEntry2StEntry.Bind( aEntry,  aStudyEntry);
407         aStEntry2Entry.Bind( aStudyEntry, aEntry );
408       }
409     }
410   }
411
412   Handle(TColStd_HSequenceOfInteger) aSeq = FindEntries(aScript);
413   Standard_Integer aLen = aSeq->Length(), objectCounter = 0, aStart = 1, aScriptLength = aScript.Length();
414   Resource_DataMapOfAsciiStringAsciiString aNameToEntry;
415
416   //Replace entries by the names
417   TCollection_AsciiString anUpdatedScript, anEntry, aName, aBaseName("geomObj_");
418   if(aLen == 0) anUpdatedScript = aScript;
419
420   for(Standard_Integer i = 1; i <= aLen; i+=2) {
421     anUpdatedScript += aScript.SubString(aStart, aSeq->Value(i)-1);
422     anEntry = aScript.SubString(aSeq->Value(i), aSeq->Value(i+1));
423     if(theObjectNames.IsBound(anEntry)) {
424       aName = theObjectNames.Find(anEntry);
425       if ( aNameToEntry.IsBound( aName ) && anEntry != aNameToEntry( aName ))
426       {  // diff objects have same name - make a new name
427         TCollection_AsciiString aName2;
428         Standard_Integer i = 0;
429         do {
430           aName2 = aName + "_" + ++i;
431         } while ( aNameToEntry.IsBound( aName2 ) && anEntry != aNameToEntry( aName2 ));
432         aName = aName2;
433         theObjectNames( anEntry ) = aName;
434       }
435     }
436     else {
437       do {
438         aName = aBaseName + TCollection_AsciiString(++objectCounter);
439       } while(aNameToEntry.IsBound(aName));
440       theObjectNames.Bind(anEntry, aName);
441     }
442     aNameToEntry.Bind(aName, anEntry); // to detect same name of diff objects
443
444     anUpdatedScript += aName;
445     aStart = aSeq->Value(i+1) + 1;
446   }
447
448   //Add final part of the script
449   if(aSeq->Value(aLen) < aScriptLength)  anUpdatedScript += aScript.SubString(aSeq->Value(aLen)+1, aScriptLength);
450  
451   // Make script to publish in study
452   if ( isPublished )
453   {
454     map< int, string > anEntryToCommandMap; // sort publishing commands by object entry
455     for (anEntryToNameIt.Initialize( theObjectNames );
456          anEntryToNameIt.More();
457          anEntryToNameIt.Next())
458     {
459       const TCollection_AsciiString& aEntry = anEntryToNameIt.Key();
460       const TCollection_AsciiString& aName = anEntryToNameIt.Value();
461       if ( !aEntry2StEntry.IsBound( aEntry ))
462         continue; // was not published
463       TCollection_AsciiString aCommand("\n\tgeompy."), aFatherEntry;
464       // find a father entry
465       const TCollection_AsciiString& aStudyEntry = aEntry2StEntry( aEntry );
466       TCollection_AsciiString aFatherStudyEntry =
467         aStudyEntry.SubString( 1, aStudyEntry.SearchFromEnd(":") - 1 );
468       if ( aStEntry2Entry.IsBound( aFatherStudyEntry ))
469         aFatherEntry = aStEntry2Entry( aFatherStudyEntry );
470       // make a command
471       if ( !aFatherEntry.IsEmpty() && theObjectNames.IsBound( aFatherEntry )) {
472         aCommand += "addToStudyInFather( ";
473         aCommand += theObjectNames( aFatherEntry ) + ", ";
474       }
475       else
476         aCommand += "addToStudy( ";
477       aCommand += aName + ", \"" + aName + "\" )";
478       // bind a command to the last digit of the entry
479       int tag =
480         aEntry.SubString( aEntry.SearchFromEnd(":")+1, aEntry.Length() ).IntegerValue();
481       anEntryToCommandMap.insert( make_pair( tag, aCommand.ToCString() ));
482     }
483
484     // add publishing commands to the script
485     map< int, string >::iterator anEntryToCommand = anEntryToCommandMap.begin();
486     for ( ; anEntryToCommand != anEntryToCommandMap.end(); ++anEntryToCommand ) {
487       //cout << anEntryToCommand->first << endl;
488       anUpdatedScript += (char*)anEntryToCommand->second.c_str();
489     }
490   }
491
492   anUpdatedScript += "\n\tpass\n";
493   aValidScript = true;
494   
495   return anUpdatedScript;
496 }
497
498
499 //===========================================================================
500 //                     Internal functions
501 //===========================================================================
502 void ProcessFunction(Handle(GEOM_Function)& theFunction, 
503                      TCollection_AsciiString& theScript,
504                      TColStd_MapOfTransient& theProcessed)
505 {
506   if(theFunction.IsNull() || theProcessed.Contains(theFunction)) return;
507
508 /*
509   TDF_LabelSequence aSeq;
510   theFunction->GetDependency(aSeq);
511   Standard_Integer aLen = aSeq.Length();
512   for(Standard_Integer i = 1; i<= aLen; i++) {
513     Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(aSeq.Value(i));
514     if(aFunction.IsNull()) continue;
515     ProcessFunction(aFunction, theScript, theProcessed);
516   }
517 */
518
519   TCollection_AsciiString aDescr = theFunction->GetDescription();
520   if(aDescr.Length() == 0) {
521     //cout << "Warning: the function has no description" << endl;
522     return;
523   }
524   //Check if its internal function which doesn't requires dumping
525   if(aDescr == "None") return;
526
527   theScript += "\n\t";
528   theScript += aDescr;
529  
530   theProcessed.Add(theFunction);
531   return;
532 }
533
534 //=============================================================================
535 /*!
536  *  FindEntries: Returns a sequence of start/end positions of entries in the string
537  */
538 //=============================================================================
539 Handle(TColStd_HSequenceOfInteger) FindEntries(TCollection_AsciiString& theString)
540 {
541   Handle(TColStd_HSequenceOfInteger) aSeq = new TColStd_HSequenceOfInteger;
542   Standard_Integer aLen = theString.Length();
543   Standard_Boolean isFound = Standard_False;
544
545   char* arr = theString.ToCString();
546   Standard_Integer i = 0, j;
547
548   while(i < aLen) {
549     int c = (int)arr[i];
550     j = i+1;
551     if(c >= 48 && c <= 57) { //Is digit?
552  
553       isFound = Standard_False;
554       while((j < aLen) && ((c >= 48 && c <= 57) || c == 58) ) { //Check if it is an entry
555         c = (int)arr[j++];  
556         if(c == 58) isFound = Standard_True;
557       }
558       
559       if(isFound && arr[j-2] != 58) { // last char should be a diggit
560         aSeq->Append(i+1); // +1 because AsciiString starts from 1
561         aSeq->Append(j-1);
562       }
563     }
564      
565     i = j;
566   }
567
568   return aSeq;
569 }