Salome HOME
Dump Python extension
[modules/geom.git] / src / GEOM / GEOM_Engine.cxx
1 // Copyright (C) 2005  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
3 // 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either 
7 // version 2.1 of the License.
8 // 
9 // This library is distributed in the hope that it will be useful 
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
12 // Lesser General Public License for more details.
13 //
14 // You should have received a copy of the GNU Lesser General Public  
15 // License along with this library; if not, write to the Free Software 
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 //
18 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 //
20 #ifdef WNT
21 #pragma warning( disable:4786 )
22 #endif
23
24 #include "GEOM_Engine.hxx"
25
26 #include "GEOM_Solver.hxx"
27 #include "GEOM_Function.hxx"
28 #include "GEOM_ISubShape.hxx"
29 #include "GEOM_SubShapeDriver.hxx"
30 #include "GEOM_DataMapIteratorOfDataMapOfAsciiStringTransient.hxx"
31 #include "GEOM_PythonDump.hxx"
32
33 #include "utilities.h"
34
35 #include <TDF_Tool.hxx>
36 #include <TDF_Data.hxx>
37 #include <TDF_LabelSequence.hxx>
38 #include <TDataStd_Integer.hxx>
39 #include <TDataStd_ChildNodeIterator.hxx>
40 #include <TFunction_Driver.hxx>
41 #include <TFunction_DriverTable.hxx>
42
43 #include <TopExp.hxx>
44 #include <TopTools_IndexedMapOfShape.hxx>
45
46 #include <TCollection_AsciiString.hxx>
47 #include <TCollection_ExtendedString.hxx>
48 #include <TColStd_SequenceOfAsciiString.hxx>
49 #include <TColStd_MapOfTransient.hxx>
50 #include <TColStd_HSequenceOfInteger.hxx>
51
52
53 #include <Interface_DataMapIteratorOfDataMapOfIntegerTransient.hxx>
54 #include <Resource_DataMapIteratorOfDataMapOfAsciiStringAsciiString.hxx>
55
56 #include <map>
57 #include <string>
58 #include <vector>
59
60 #include <Standard_Failure.hxx>
61 #include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
62
63 #define COMMA ','
64 #define O_BRACKET '('
65 #define C_BRACKET ')'
66 #define O_SQR_BRACKET '['
67 #define C_SQR_BRACKET ']'
68 #define PY_NULL "None"
69
70 #ifdef _DEBUG_
71 static int MYDEBUG = 0;
72 #else
73 static int MYDEBUG = 0;
74 #endif
75
76 static GEOM_Engine* TheEngine = NULL;
77
78 using namespace std;
79
80 static TCollection_AsciiString BuildIDFromObject(Handle(GEOM_Object)& theObject)
81 {
82   TCollection_AsciiString anID(theObject->GetDocID()), anEntry;
83   TDF_Tool::Entry(theObject->GetEntry(), anEntry);
84   anID+=(TCollection_AsciiString("_")+anEntry);
85   return anID;
86 }
87
88 static TCollection_AsciiString BuildID(Standard_Integer theDocID, char* theEntry)
89 {
90   TCollection_AsciiString anID(theDocID);
91   anID+=(TCollection_AsciiString("_")+theEntry);
92   return anID;
93 }
94
95 static Standard_Integer ExtractDocID(TCollection_AsciiString& theID)
96 {
97   TCollection_AsciiString aDocID = theID.Token("_");
98   if(aDocID.Length() < 1) return -1;
99   return aDocID.IntegerValue();
100 }
101
102 void ProcessFunction(Handle(GEOM_Function)& theFunction, 
103                      TCollection_AsciiString& theScript,
104                      TVariablesList theVariables,
105                      TColStd_MapOfTransient& theProcessed);
106
107 void ReplaceVariables(TCollection_AsciiString& theCommand, 
108                       TVariablesList theVariables);
109
110
111
112 Handle(TColStd_HSequenceOfInteger) FindEntries(TCollection_AsciiString& theString);
113
114
115 //=============================================================================
116 /*!
117  *  GetEngine
118  */
119 //=============================================================================
120 GEOM_Engine* GEOM_Engine::GetEngine() { return TheEngine; }
121
122
123 //=============================================================================
124 /*!
125  *  SetEngine
126  */
127 //=============================================================================
128 void GEOM_Engine::SetEngine(GEOM_Engine* theEngine) { TheEngine = theEngine; }
129
130 //=============================================================================
131 /*!
132  *  Constructor
133  */
134 //=============================================================================
135 GEOM_Engine::GEOM_Engine()
136 {
137   TFunction_DriverTable::Get()->AddDriver(GEOM_Object::GetSubShapeID(), new GEOM_SubShapeDriver());
138
139   _OCAFApp = new GEOM_Application();
140   _UndoLimit = 10;
141 }
142
143 /*!
144  *  Destructor
145  */
146 GEOM_Engine::~GEOM_Engine()
147
148   GEOM_DataMapIteratorOfDataMapOfAsciiStringTransient It(_objects);
149   for(; It.More(); It.Next()) 
150     {
151       RemoveObject(Handle(GEOM_Object)::DownCast(It.Value()));
152     }
153
154   //Close all documents not closed
155   for(Interface_DataMapIteratorOfDataMapOfIntegerTransient anItr(_mapIDDocument); anItr.More(); anItr.Next())
156     Close(anItr.Key());
157
158   _mapIDDocument.Clear();
159   _objects.Clear();
160 }
161
162 //=============================================================================
163 /*!
164  *  GetDocument
165  */
166 //=============================================================================
167 Handle(TDocStd_Document) GEOM_Engine::GetDocument(int theDocID)
168 {
169   Handle(TDocStd_Document) aDoc;
170   if(!_mapIDDocument.IsBound(theDocID)) {
171     _OCAFApp->NewDocument("SALOME_GEOM", aDoc);
172     aDoc->SetUndoLimit(_UndoLimit);
173     _mapIDDocument.Bind(theDocID, aDoc);
174     TDataStd_Integer::Set(aDoc->Main(), theDocID);
175   }
176
177   return Handle(TDocStd_Document)::DownCast(_mapIDDocument(theDocID));
178 }
179
180 //=============================================================================
181 /*!
182  *  GetDocID
183  */
184 //=============================================================================
185 int GEOM_Engine::GetDocID(Handle(TDocStd_Document) theDocument)
186 {
187   if(theDocument.IsNull()) return -1;
188   for(Interface_DataMapIteratorOfDataMapOfIntegerTransient anItr(_mapIDDocument); anItr.More(); anItr.Next())
189     if(anItr.Value() == theDocument) return anItr.Key();
190
191   return -1;
192
193 }
194
195 //=============================================================================
196 /*!
197  *  GetObject
198  */
199 //=============================================================================
200 Handle(GEOM_Object) GEOM_Engine::GetObject(int theDocID, char* theEntry)
201 {
202   TCollection_AsciiString anID = BuildID(theDocID, theEntry);
203   if(_objects.IsBound(anID)) return Handle(GEOM_Object)::DownCast(_objects(anID));
204
205   TDF_Label aLabel;
206   Handle(TDocStd_Document) aDoc = GetDocument(theDocID);
207   TDF_Tool::Label(aDoc->Main().Data(), theEntry, aLabel, Standard_True);
208   Handle(GEOM_Object) anObject = new GEOM_Object(aLabel);
209
210   _objects.Bind(anID, anObject);
211
212   return anObject;
213 }
214
215 //=============================================================================
216 /*!
217  *  AddObject
218  */
219 //=============================================================================
220 Handle(GEOM_Object) GEOM_Engine::AddObject(int theDocID, int theType)
221 {
222   Handle(TDocStd_Document) aDoc = GetDocument(theDocID);
223   Handle(TDataStd_TreeNode) aRoot = TDataStd_TreeNode::Set(aDoc->Main());
224
225   // NPAL18604: use existing label to decrease memory usage,
226   //            if this label has been freed (object deleted)
227   bool useExisting = false;
228   TDF_Label aChild;
229   if (!_lastCleared.IsNull()) {
230     if (_lastCleared.Root() == aDoc->Main().Root()) {
231       useExisting = true;
232       aChild = _lastCleared;
233       _lastCleared.Nullify();
234     }
235   }
236   if (!useExisting) {
237     // create new label
238     aChild = TDF_TagSource::NewChild(aDoc->Main());
239   }
240
241   Handle(GEOM_Object) anObject = new GEOM_Object(aChild, theType);
242
243   //Put an object in the map of created objects
244   TCollection_AsciiString anID = BuildIDFromObject(anObject);
245   if(_objects.IsBound(anID)) _objects.UnBind(anID);
246   _objects.Bind(anID, anObject);
247
248   return anObject;
249 }
250
251 //=============================================================================
252 /*!
253  *  AddSubShape
254  */
255 //=============================================================================
256 Handle(GEOM_Object) GEOM_Engine::AddSubShape(Handle(GEOM_Object) theMainShape, 
257                                              Handle(TColStd_HArray1OfInteger) theIndices,
258                                              bool isStandaloneOperation)
259 {
260   if(theMainShape.IsNull() || theIndices.IsNull()) return NULL;
261
262   Handle(TDocStd_Document) aDoc = GetDocument(theMainShape->GetDocID());
263   Handle(TDataStd_TreeNode) aRoot = TDataStd_TreeNode::Set(aDoc->Main());
264
265   // NPAL18604: use existing label to decrease memory usage,
266   //            if this label has been freed (object deleted)
267   bool useExisting = false;
268   TDF_Label aChild;
269   if (!_lastCleared.IsNull()) {
270     if (_lastCleared.Root() == aDoc->Main().Root()) {
271       useExisting = true;
272       aChild = _lastCleared;
273       _lastCleared.Nullify();
274     }
275   }
276   if (!useExisting) {
277     // create new label
278     aChild = TDF_TagSource::NewChild(aDoc->Main());
279   }
280
281   Handle(GEOM_Function) aMainShape = theMainShape->GetLastFunction();
282   Handle(GEOM_Object) anObject = new GEOM_Object(aChild, 28); //28 is SUBSHAPE type
283   Handle(GEOM_Function) aFunction = anObject->AddFunction(GEOM_Object::GetSubShapeID(), 1);
284
285   GEOM_ISubShape aSSI(aFunction);
286   aSSI.SetMainShape(aMainShape);
287   aSSI.SetIndices(theIndices);
288
289   try {
290 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
291     OCC_CATCH_SIGNALS;
292 #endif
293     GEOM_Solver aSolver (GEOM_Engine::GetEngine());
294     if (!aSolver.ComputeFunction(aFunction)) {
295       MESSAGE("GEOM_Engine::AddSubShape Error: Can't build a sub shape");
296       return NULL;
297     }
298   }
299   catch (Standard_Failure) {
300     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
301     MESSAGE("GEOM_Engine::AddSubShape Error: " << aFail->GetMessageString());
302     return NULL;
303   }
304
305   //Put an object in the map of created objects
306   TCollection_AsciiString anID = BuildIDFromObject(anObject);
307   if(_objects.IsBound(anID)) _objects.UnBind(anID);
308   _objects.Bind(anID, anObject);
309
310   GEOM::TPythonDump pd (aFunction);
311  
312   if (isStandaloneOperation) {
313     pd << anObject << " = geompy.GetSubShape(" << theMainShape << ", [";
314     Standard_Integer i = theIndices->Lower(), up = theIndices->Upper();
315     for (; i <= up - 1; i++) {
316       pd << theIndices->Value(i) << ", ";
317     }
318     pd << theIndices->Value(up) << "])";
319   }
320   else
321     pd << "None";
322
323   return anObject;
324 }
325
326 //=============================================================================
327 /*!
328  *  RemoveObject
329  */
330 //=============================================================================
331 bool GEOM_Engine::RemoveObject(Handle(GEOM_Object) theObject)
332 {
333   if (!theObject) return false;
334
335   //Remove an object from the map of available objects
336   TCollection_AsciiString anID = BuildIDFromObject(theObject);
337   if (_objects.IsBound(anID)) _objects.UnBind(anID);
338
339   int nb = theObject->GetNbFunctions();
340   Handle(TDataStd_TreeNode) aNode;
341   for (int i = 1; i<=nb; i++) {
342     Handle(GEOM_Function) aFunction = theObject->GetFunction(i);
343     if (aFunction->GetEntry().FindAttribute(GEOM_Function::GetFunctionTreeID(), aNode)) 
344       aNode->Remove();
345   }
346
347   TDF_Label aLabel = theObject->GetEntry();
348   aLabel.ForgetAllAttributes(Standard_True);
349   _lastCleared = aLabel;
350
351   theObject.Nullify();
352
353   return true;
354 }
355
356 //=============================================================================
357 /*!
358  *  Undo
359  */
360 //=============================================================================
361 void GEOM_Engine::Undo(int theDocID)
362 {
363   GetDocument(theDocID)->Undo();
364 }
365
366 //=============================================================================
367 /*!
368  *  Redo
369  */
370 //=============================================================================
371 void GEOM_Engine::Redo(int theDocID)
372 {
373   GetDocument(theDocID)->Redo();
374 }
375
376 //=============================================================================
377 /*!
378  *  Save
379  */
380 //=============================================================================
381 bool GEOM_Engine::Save(int theDocID, char* theFileName)
382 {
383   if(!_mapIDDocument.IsBound(theDocID)) return false;
384   Handle(TDocStd_Document) aDoc = Handle(TDocStd_Document)::DownCast(_mapIDDocument(theDocID));
385
386   _OCAFApp->SaveAs(aDoc, theFileName);
387
388   return true;
389 }
390
391 //=============================================================================
392 /*!
393  *  Load
394  */
395 //=============================================================================
396 bool GEOM_Engine::Load(int theDocID, char* theFileName)
397 {
398   Handle(TDocStd_Document) aDoc;
399   if(_OCAFApp->Open(theFileName, aDoc) != CDF_RS_OK) {
400     return false;
401   }
402
403   aDoc->SetUndoLimit(_UndoLimit);
404
405   if(_mapIDDocument.IsBound(theDocID)) _mapIDDocument.UnBind(theDocID);
406   _mapIDDocument.Bind(theDocID, aDoc);
407
408   TDataStd_Integer::Set(aDoc->Main(), theDocID);
409
410   return true;
411 }
412
413 //=============================================================================
414 /*!
415  *  Close
416  */
417 //=============================================================================
418 void GEOM_Engine::Close(int theDocID)
419 {
420   if (_mapIDDocument.IsBound(theDocID)) {
421     Handle(TDocStd_Document) aDoc = Handle(TDocStd_Document)::DownCast(_mapIDDocument(theDocID));
422
423     //Remove all GEOM Objects associated to the given document
424     TColStd_SequenceOfAsciiString aSeq;
425     GEOM_DataMapIteratorOfDataMapOfAsciiStringTransient It (_objects);
426     for (; It.More(); It.Next()) {
427       TCollection_AsciiString anObjID (It.Key());
428       Standard_Integer anID = ExtractDocID(anObjID);
429       if (theDocID == anID) aSeq.Append(It.Key());
430     }
431     for (Standard_Integer i=1; i<=aSeq.Length(); i++) _objects.UnBind(aSeq.Value(i));
432
433     _lastCleared.Nullify();
434
435     _mapIDDocument.UnBind(theDocID);
436     _OCAFApp->Close(aDoc);
437     aDoc.Nullify();
438   }
439 }
440
441 //=============================================================================
442 /*!
443  *  DumpPython
444  */
445 //=============================================================================
446 TCollection_AsciiString GEOM_Engine::DumpPython(int theDocID,
447                                                 Resource_DataMapOfAsciiStringAsciiString& theObjectNames,
448                                                 TVariablesList theVariables,
449                                                 bool isPublished,
450                                                 bool& aValidScript)
451 {
452   TCollection_AsciiString aScript;
453   Handle(TDocStd_Document) aDoc = GetDocument(theDocID);
454
455   if (aDoc.IsNull()) return TCollection_AsciiString("def RebuildData(theStudy): pass\n");
456
457   aScript = "import geompy\n";
458   aScript += "import math\n";
459   aScript += "import SALOMEDS\n\n";
460   aScript += "def RebuildData(theStudy):";
461   aScript += "\n\tgeompy.init_geom(theStudy)";
462
463   Standard_Integer posToInertGlobalVars = aScript.Length() + 1;
464
465   Handle(TDataStd_TreeNode) aNode, aRoot;
466   Handle(GEOM_Function) aFunction;
467   TColStd_MapOfTransient aMap;
468
469   if (aDoc->Main().FindAttribute(GEOM_Function::GetFunctionTreeID(), aRoot)) {
470     TDataStd_ChildNodeIterator Itr(aRoot);
471     for (; Itr.More(); Itr.Next()) {
472       aNode = Itr.Value();
473       aFunction = GEOM_Function::GetFunction(aNode->Label());
474       if (aFunction.IsNull()) {
475         MESSAGE ( "Null function !!!!" );
476         continue;
477       }
478       ProcessFunction(aFunction, aScript, theVariables,aMap);
479     }
480   }
481
482   Resource_DataMapOfAsciiStringAsciiString aEntry2StEntry, aStEntry2Entry;
483   Resource_DataMapIteratorOfDataMapOfAsciiStringAsciiString anEntryToNameIt;
484   // build maps entry <-> studyEntry
485   for (anEntryToNameIt.Initialize( theObjectNames );
486        anEntryToNameIt.More();
487        anEntryToNameIt.Next())
488   {
489     const TCollection_AsciiString& aEntry = anEntryToNameIt.Key();
490     // look for an object by entry
491     TDF_Label L;
492     TDF_Tool::Label( aDoc->GetData(), aEntry, L );
493     if ( L.IsNull() ) continue;
494     Handle(GEOM_Object) obj = GEOM_Object::GetObject( L );
495     // fill maps
496     if ( !obj.IsNull() ) {
497       TCollection_AsciiString aStudyEntry (obj->GetAuxData());
498       aEntry2StEntry.Bind( aEntry,  aStudyEntry);
499       aStEntry2Entry.Bind( aStudyEntry, aEntry );
500     }
501   }
502
503   Handle(TColStd_HSequenceOfInteger) aSeq = FindEntries(aScript);
504   Standard_Integer aLen = aSeq->Length(), objectCounter = 0, aStart = 1, aScriptLength = aScript.Length();
505   Resource_DataMapOfAsciiStringAsciiString aNameToEntry, anEntryToBadName;
506
507   //Replace entries by the names
508   TCollection_AsciiString anUpdatedScript, anEntry, aName, aBaseName("geomObj_"),
509     allowedChars ("qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPLKJHGFDSAZXCVBNM0987654321_");
510   if (aLen == 0) anUpdatedScript = aScript;
511
512   for (Standard_Integer i = 1; i <= aLen; i+=2) {
513     anUpdatedScript += aScript.SubString(aStart, aSeq->Value(i)-1);
514     anEntry = aScript.SubString(aSeq->Value(i), aSeq->Value(i+1));
515     if (theObjectNames.IsBound(anEntry)) {
516       aName = theObjectNames.Find(anEntry);
517       // check validity of aName
518       bool isValidName = true;
519       if ( aName.IsIntegerValue() ) { // aName must not start with a digit
520         aName.Insert( 1, 'a' );
521         isValidName = false;
522       }
523       int p, p2=1; // replace not allowed chars
524       while ((p = aName.FirstLocationNotInSet(allowedChars, p2, aName.Length()))) {
525         aName.SetValue(p, '_');
526         p2=p;
527         isValidName = false;
528       }
529       if ( aNameToEntry.IsBound( aName ) && anEntry != aNameToEntry( aName ))
530       {  // diff objects have same name - make a new name by appending a digit
531         TCollection_AsciiString aName2;
532         Standard_Integer i = 0;
533         do {
534           aName2 = aName + "_" + ++i;
535         } while ( aNameToEntry.IsBound( aName2 ) && anEntry != aNameToEntry( aName2 ));
536         aName = aName2;
537         isValidName = false;
538       }
539       if ( !isValidName ) {
540         if ( isPublished )
541           anEntryToBadName.Bind( anEntry, theObjectNames.Find(anEntry) );
542         theObjectNames( anEntry ) = aName;
543       }
544     }
545     else {
546       do {
547         aName = aBaseName + TCollection_AsciiString(++objectCounter);
548       } while(aNameToEntry.IsBound(aName));
549       theObjectNames.Bind(anEntry, aName);
550     }
551     aNameToEntry.Bind(aName, anEntry); // to detect same name of diff objects
552
553     anUpdatedScript += aName;
554     aStart = aSeq->Value(i+1) + 1;
555   }
556
557   //Add final part of the script
558   if (aLen && aSeq->Value(aLen) < aScriptLength)
559     anUpdatedScript += aScript.SubString(aSeq->Value(aLen)+1, aScriptLength); // mkr : IPAL11865
560
561   // ouv : NPAL12872
562   for (anEntryToNameIt.Initialize( theObjectNames );
563        anEntryToNameIt.More();
564        anEntryToNameIt.Next())
565   {
566     const TCollection_AsciiString& aEntry = anEntryToNameIt.Key();
567     const TCollection_AsciiString& aName = anEntryToNameIt.Value();
568
569     TDF_Label L;
570     TDF_Tool::Label( aDoc->GetData(), aEntry, L );
571     if ( L.IsNull() )
572       continue;
573
574     Handle(GEOM_Object) obj = GEOM_Object::GetObject( L );
575     if ( obj.IsNull() )
576       continue;
577
578     bool anAutoColor = obj->GetAutoColor();
579     if ( anAutoColor )
580     {
581       TCollection_AsciiString aCommand( "\n\t" );
582       aCommand += aName + ".SetAutoColor(1)";
583       anUpdatedScript += aCommand.ToCString();
584     }
585
586     SALOMEDS::Color aColor = obj->GetColor();
587     if ( aColor.R > 0 || aColor.G > 0 || aColor.B > 0 )
588     {
589       TCollection_AsciiString aCommand( "\n\t" );
590       aCommand += aName + ".SetColor(SALOMEDS.Color(" + aColor.R + "," + aColor.G + "," + aColor.B + "))";
591       anUpdatedScript += aCommand.ToCString();
592     }
593   }
594
595   // Make script to publish in study
596   if ( isPublished )
597   {
598     std::map< int, std::string > anEntryToCommandMap; // sort publishing commands by object entry
599     for (anEntryToNameIt.Initialize( theObjectNames );
600          anEntryToNameIt.More();
601          anEntryToNameIt.Next())
602     {
603       const TCollection_AsciiString& aEntry = anEntryToNameIt.Key();
604       const TCollection_AsciiString& aName = anEntryToNameIt.Value();
605       if ( !aEntry2StEntry.IsBound( aEntry ))
606         continue; // was not published
607       TCollection_AsciiString aCommand("\n\tgeompy."), aFatherEntry;
608
609       // find a father entry
610       const TCollection_AsciiString& aStudyEntry = aEntry2StEntry( aEntry );
611       TCollection_AsciiString aFatherStudyEntry =
612         aStudyEntry.SubString( 1, aStudyEntry.SearchFromEnd(":") - 1 );
613       if ( aStEntry2Entry.IsBound( aFatherStudyEntry ))
614         aFatherEntry = aStEntry2Entry( aFatherStudyEntry );
615
616       // make a command
617       if ( !aFatherEntry.IsEmpty() && theObjectNames.IsBound( aFatherEntry )) {
618         aCommand += "addToStudyInFather( ";
619         aCommand += theObjectNames( aFatherEntry ) + ", ";
620       }
621       else
622         aCommand += "addToStudy( ";
623       if ( anEntryToBadName.IsBound( aEntry ))
624         aCommand += aName + ", \"" + anEntryToBadName( aEntry ) + "\" )";
625       else 
626         aCommand += aName + ", \"" + aName + "\" )";
627
628       // bind a command to the last digit of the entry
629       int tag =
630         aEntry.SubString( aEntry.SearchFromEnd(":")+1, aEntry.Length() ).IntegerValue();
631       anEntryToCommandMap.insert( std::make_pair( tag, aCommand.ToCString() ));
632     }
633
634     // add publishing commands to the script
635     std::map< int, std::string >::iterator anEntryToCommand = anEntryToCommandMap.begin();
636     for ( ; anEntryToCommand != anEntryToCommandMap.end(); ++anEntryToCommand ) {
637       anUpdatedScript += (char*)anEntryToCommand->second.c_str();
638     }
639   }
640
641   //anUpdatedScript += "\n\tpass\n";
642   anUpdatedScript += "\n";
643   aValidScript = true;
644
645   // fill _studyEntry2NameMap and build globalVars
646   TCollection_AsciiString globalVars;
647   _studyEntry2NameMap.Clear();
648   Resource_DataMapIteratorOfDataMapOfAsciiStringAsciiString aStEntryToEntryIt;
649   for (aStEntryToEntryIt.Initialize( aStEntry2Entry );
650        aStEntryToEntryIt.More();
651        aStEntryToEntryIt.Next() )
652   {
653     const TCollection_AsciiString & name = theObjectNames( aStEntryToEntryIt.Value() );
654     _studyEntry2NameMap.Bind (aStEntryToEntryIt.Key(), name );
655     if ( !globalVars.IsEmpty() )
656       globalVars += ", ";
657     globalVars += name;
658   }
659   if ( !globalVars.IsEmpty() ) {
660     globalVars.Insert( 1, "\n\tglobal " );
661     anUpdatedScript.Insert( posToInertGlobalVars, globalVars );
662   }
663
664   return anUpdatedScript;
665 }
666
667 //=======================================================================
668 //function : GetDumpName
669 //purpose  : 
670 //=======================================================================
671
672 const char* GEOM_Engine::GetDumpName (const char* theStudyEntry) const
673 {
674   if ( _studyEntry2NameMap.IsBound( (char*)theStudyEntry ))
675     return _studyEntry2NameMap( (char*)theStudyEntry ).ToCString();
676
677   return NULL;
678 }
679
680 //=======================================================================
681 //function : GetAllDumpNames
682 //purpose  : 
683 //=======================================================================
684
685 Handle(TColStd_HSequenceOfAsciiString) GEOM_Engine::GetAllDumpNames() const
686 {
687   Handle(TColStd_HSequenceOfAsciiString) aRetSeq = new TColStd_HSequenceOfAsciiString;
688
689   Resource_DataMapIteratorOfDataMapOfAsciiStringAsciiString it (_studyEntry2NameMap);
690   for (; it.More(); it.Next()) {
691     aRetSeq->Append(it.Value());
692   }
693
694   return aRetSeq;
695 }
696
697
698 //===========================================================================
699 //                     Internal functions
700 //===========================================================================
701 void ProcessFunction(Handle(GEOM_Function)& theFunction, 
702                      TCollection_AsciiString& theScript,
703                      TVariablesList theVariables,
704                      TColStd_MapOfTransient& theProcessed)
705 {
706   if(theFunction.IsNull() || theProcessed.Contains(theFunction)) return;
707
708 /*
709   TDF_LabelSequence aSeq;
710   theFunction->GetDependency(aSeq);
711   Standard_Integer aLen = aSeq.Length();
712   for(Standard_Integer i = 1; i<= aLen; i++) {
713     Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(aSeq.Value(i));
714     if(aFunction.IsNull()) continue;
715     ProcessFunction(aFunction, theScript, theProcessed);
716   }
717 */
718
719   TCollection_AsciiString aDescr = theFunction->GetDescription();
720   if(aDescr.Length() == 0) {
721     //cout << "Warning: the function has no description" << endl;
722     return;
723   }
724   //Check if its internal function which doesn't requires dumping
725   if(aDescr == "None") return;
726
727   //Replace parameter by notebook variables
728   ReplaceVariables(aDescr,theVariables);
729   theScript += "\n\t";
730   theScript += aDescr;
731
732  
733   theProcessed.Add(theFunction);
734   return;
735 }
736
737 //=============================================================================
738 /*!
739  *  FindEntries: Returns a sequence of start/end positions of entries in the string
740  */
741 //=============================================================================
742 Handle(TColStd_HSequenceOfInteger) FindEntries(TCollection_AsciiString& theString)
743 {
744   Handle(TColStd_HSequenceOfInteger) aSeq = new TColStd_HSequenceOfInteger;
745   Standard_Integer aLen = theString.Length();
746   Standard_Boolean isFound = Standard_False;
747
748   const char* arr = theString.ToCString();
749   Standard_Integer i = 0, j;
750
751   while(i < aLen) {
752     int c = (int)arr[i];
753     j = i+1;
754     if(c >= 48 && c <= 57) { //Is digit?
755  
756       isFound = Standard_False;
757       while((j < aLen) && ((c >= 48 && c <= 57) || c == 58) ) { //Check if it is an entry
758         c = (int)arr[j++];  
759         if(c == 58) isFound = Standard_True;
760       }
761       
762       if(isFound && arr[j-2] != 58) { // last char should be a diggit
763         aSeq->Append(i+1); // +1 because AsciiString starts from 1
764         aSeq->Append(j-1);
765       }
766     }
767      
768     i = j;
769   }
770
771   return aSeq;
772 }
773
774 //=============================================================================
775 /*!
776  *  ReplaceVariables: Replace parameters of the function by variales from 
777  *                    Notebook if need
778  */
779 //=============================================================================
780 void ReplaceVariables(TCollection_AsciiString& theCommand, 
781                       TVariablesList theVariables)
782 {
783   if (MYDEBUG)
784     cout<<"Command : "<<theCommand<<endl;
785
786   if (MYDEBUG) {
787     cout<<"All Entries:"<<endl;
788     TVariablesList::const_iterator it = theVariables.begin();
789     for(;it != theVariables.end();it++)
790       cout<<"\t'"<<(*it).first<<"'"<<endl;
791   }
792
793   //Additional case - multi-row commands
794   int aCommandIndex = 1;
795   while( aCommandIndex < 10 ) { // tmp check
796     TCollection_AsciiString aCommand = theCommand.Token("\n",aCommandIndex);
797     if( aCommand.Length() == 0 )
798       break;
799
800     if (MYDEBUG)
801       cout<<"Sub-command : "<<aCommand<<endl;
802
803     Standard_Integer aStartCommandPos = theCommand.Location(aCommand,1,theCommand.Length());
804     Standard_Integer aEndCommandPos = aStartCommandPos + aCommand.Length();
805
806     //Get Entry of the result object
807     TCollection_AsciiString anEntry = aCommand.Token("=",1);
808
809     //Remove white spaces
810     anEntry.RightAdjust();
811     anEntry.LeftAdjust();
812     if(MYDEBUG)
813       cout<<"Result entry : '" <<anEntry<<"'"<<endl;
814
815     //Check if result is list of entries - enough to get the first entry in this case
816     int aNbEntries = 1;
817     if( anEntry.Value( 1 ) == O_SQR_BRACKET && anEntry.Value( anEntry.Length() ) == C_SQR_BRACKET ) {
818       while(anEntry.Location(aNbEntries,COMMA,1,anEntry.Length()))
819         aNbEntries++;
820       TCollection_AsciiString aSeparator(COMMA);
821       anEntry = anEntry.Token(aSeparator.ToCString(),1);
822       anEntry.Remove( 1, 1 );
823       anEntry.RightAdjust();
824       anEntry.LeftAdjust();
825       if(MYDEBUG)
826         cout<<"Sub-entry : '" <<anEntry<<"'"<<endl;
827     }
828     
829     //Find variables used for object construction
830     vector<TVariable> aVariables;
831     TVariablesList::const_iterator it = theVariables.find(anEntry);
832     if( it != theVariables.end() ) 
833       aVariables = (*it).second;
834
835     if(aVariables.empty()) {
836       if(MYDEBUG)
837         cout<<"Valiables list empty!!!"<<endl;
838       aCommandIndex++;
839       continue;
840     }
841   
842     if(MYDEBUG) {
843       cout<<"Variables from SObject:"<<endl;
844       for (int i = 0; i < aVariables.size();i++)
845         cout<<"\t Variable["<<i<<"] = "<<aVariables[i].myVariable<<endl;
846     }
847
848     //Calculate total number of parameters
849     Standard_Integer aTotalNbParams = 1;
850     while(aCommand.Location(aTotalNbParams,COMMA,1,aCommand.Length()))
851       aTotalNbParams++;
852
853     if(MYDEBUG)
854       cout<<"aTotalNbParams = "<<aTotalNbParams<<endl;
855
856     Standard_Integer aFirstParam = aNbEntries;
857
858     //Replace parameters by variables
859     Standard_Integer aStartPos = 0;
860     Standard_Integer aEndPos = 0;
861     int iVar = 0;
862     TCollection_AsciiString aVar, aReplacedVar;
863     for(Standard_Integer i=aFirstParam;i <= aTotalNbParams;i++) {
864       //Replace first parameter (bettwen '(' character and first ',' character)
865       if(i == aFirstParam)
866       {
867         aStartPos = aCommand.Location(O_BRACKET, 1, aCommand.Length()) + 1;
868         if(aTotalNbParams - aNbEntries > 0 )
869           aEndPos = aCommand.Location(aFirstParam, COMMA, 1, aCommand.Length());
870         else
871           aEndPos = aCommand.Location(C_BRACKET, 1, aCommand.Length()); 
872       }
873       //Replace last parameter (bettwen ',' character and ')' character)
874       else if(i == aTotalNbParams)
875       {
876         aStartPos = aCommand.Location(i-1, COMMA, 1, aCommand.Length()) + 2;
877         aEndPos = aCommand.Location(C_BRACKET, 1, aCommand.Length());
878       }
879       //Replace other parameters (bettwen two ',' characters)
880       else if(i != aFirstParam && i != aTotalNbParams )
881       {
882         aStartPos = aCommand.Location(i-1, COMMA, 1, aCommand.Length()) + 2;
883         aEndPos = aCommand.Location(i, COMMA, 1, aCommand.Length());
884       }
885
886       if( aCommand.Value( aStartPos ) == O_SQR_BRACKET )
887         aStartPos++;
888       if( aCommand.Value( aEndPos-1 ) == C_SQR_BRACKET )
889         aEndPos--;
890
891       if(MYDEBUG) 
892         cout<<"aStartPos = "<<aStartPos<<", aEndPos = "<<aEndPos<<endl;
893
894       aVar = aCommand.SubString(aStartPos, aEndPos-1);
895       aVar.RightAdjust();
896       aVar.LeftAdjust();
897     
898       if(MYDEBUG) 
899         cout<<"Variable: '"<< aVar <<"'"<<endl;
900
901       // specific case for sketcher
902       if(aVar.Location( TCollection_AsciiString("Sketcher:"), 1, aVar.Length() ) != 0) {
903         Standard_Integer aNbSections = 1;
904         while( aVar.Location( aNbSections, ':', 1, aVar.Length() ) )
905           aNbSections++;
906         aNbSections--;
907
908         int aStartSectionPos = 0, aEndSectionPos = 0;
909         TCollection_AsciiString aSection, aReplacedSection;
910         for(Standard_Integer aSectionIndex = 1; aSectionIndex <= aNbSections; aSectionIndex++) {
911           aStartSectionPos = aVar.Location( aSectionIndex, ':', 1, aVar.Length() ) + 1;
912           if( aSectionIndex != aNbSections )
913             aEndSectionPos = aVar.Location( aSectionIndex + 1, ':', 1, aVar.Length() );
914           else
915             aEndSectionPos = aVar.Length();
916
917           aSection = aVar.SubString(aStartSectionPos, aEndSectionPos-1);
918           if(MYDEBUG) 
919             cout<<"aSection: "<<aSection<<endl;
920
921           Standard_Integer aNbParams = 1;
922           while( aSection.Location( aNbParams, ' ', 1, aSection.Length() ) )
923             aNbParams++;
924           aNbParams--;
925
926           int aStartParamPos = 0, aEndParamPos = 0;
927           TCollection_AsciiString aParameter, aReplacedParameter;
928           for(Standard_Integer aParamIndex = 1; aParamIndex <= aNbParams; aParamIndex++) {
929             aStartParamPos = aSection.Location( aParamIndex, ' ', 1, aSection.Length() ) + 1;
930             if( aParamIndex != aNbParams )
931               aEndParamPos = aSection.Location( aParamIndex + 1, ' ', 1, aSection.Length() );
932             else
933               aEndParamPos = aSection.Length() + 1;
934
935             aParameter = aSection.SubString(aStartParamPos, aEndParamPos-1);
936             if(MYDEBUG) 
937               cout<<"aParameter: "<<aParameter<<endl;
938
939             if(iVar >= aVariables.size())
940               continue;
941
942             aReplacedParameter = aVariables[iVar].myVariable;
943             if(aReplacedParameter.IsEmpty()) {
944               iVar++;
945               continue;
946             }
947
948             if(aVariables[iVar].isVariable) {
949               aReplacedParameter.InsertBefore(1,"'");
950               aReplacedParameter.InsertAfter(aReplacedParameter.Length(),"'");
951             }
952
953             if(MYDEBUG) 
954               cout<<"aSection before : "<<aSection<<endl;
955             aSection.Remove(aStartParamPos, aEndParamPos - aStartParamPos);
956             aSection.Insert(aStartParamPos, aReplacedParameter);
957             if(MYDEBUG) 
958               cout<<"aSection after  : "<<aSection<<endl<<endl;
959             iVar++;
960           }
961           if(MYDEBUG) 
962             cout<<"aVar before : "<<aVar<<endl;
963           aVar.Remove(aStartSectionPos, aEndSectionPos - aStartSectionPos);
964           aVar.Insert(aStartSectionPos, aSection);
965           if(MYDEBUG) 
966             cout<<"aVar after  : "<<aVar<<endl<<endl;
967         }
968
969         if(MYDEBUG) 
970           cout<<"aCommand before : "<<aCommand<<endl;
971         aCommand.Remove(aStartPos, aEndPos - aStartPos);
972         aCommand.Insert(aStartPos, aVar);
973         if(MYDEBUG) 
974           cout<<"aCommand after  : "<<aCommand<<endl;
975
976         break;
977       } // end of specific case for sketcher
978
979       //If parameter is entry or 'None', skip it
980       if(theVariables.find(aVar) != theVariables.end() || aVar == PY_NULL)
981         continue;
982
983       if(iVar >= aVariables.size())
984         continue;
985
986       aReplacedVar = aVariables[iVar].myVariable;
987       if(aReplacedVar.IsEmpty()) {
988         iVar++;
989         continue;
990       }
991
992       if(aVariables[iVar].isVariable) {
993         aReplacedVar.InsertBefore(1,"\"");
994         aReplacedVar.InsertAfter(aReplacedVar.Length(),"\"");
995       }
996
997       aCommand.Remove(aStartPos, aEndPos - aStartPos);
998       aCommand.Insert(aStartPos, aReplacedVar);
999       iVar++;
1000     }
1001
1002     theCommand.Remove(aStartCommandPos, aEndCommandPos - aStartCommandPos);
1003     theCommand.Insert(aStartCommandPos, aCommand);
1004
1005     aCommandIndex++;
1006   }
1007
1008   if (MYDEBUG)
1009     cout<<"Command : "<<theCommand<<endl;
1010 }