Salome HOME
Bug #490: batch mode error.
[modules/hydro.git] / src / HYDROData / HYDROData_Document.cxx
1
2 #include <HYDROData_Document.h>
3 #include <HYDROData_Application.h>
4 #include <HYDROData_Iterator.h>
5 #include <HYDROData_Tool.h>
6
7 #include <TDataStd_Integer.hxx>
8 #include <TDataXtd_Position.hxx>
9
10 #include <TDF_Delta.hxx>
11
12 #include <gp_Pnt.hxx>
13
14 #include <QFile>
15 #include <QStringList>
16 #include <QTextStream>
17
18 IMPLEMENT_STANDARD_HANDLE(HYDROData_Document,MMgt_TShared)
19 IMPLEMENT_STANDARD_RTTIEXT(HYDROData_Document,MMgt_TShared)
20
21 #define PYTHON_DOC_NAME "hydro_doc"
22
23 static const int UNDO_LIMIT = 10; // number of possible undo operations in the module
24
25 static const int TAG_PROPS = 1; // general properties tag
26 static const int TAG_PROPS_NEW_ID = 1; // general properties: tag for storage of the new object ID
27 static const int TAG_OBJECTS = 2; // tag of the objects sub-tree
28 static const int TAG_HISTORY = 3; // tag of the history sub-tree (Root for History)
29 static const int TAG_LOCAL_CS = 4; // tag of local coordinate system information
30 static const gp_Pnt2d DEFAULT_LOCAL_CS( 0, 0 );
31
32 using namespace std;
33
34 typedef QMap<Standard_Integer,Handle_HYDROData_Entity> MapOfOrdered;
35 typedef QMap<QString,Handle_HYDROData_Entity> MapOfUnordered;
36
37 Handle(HYDROData_Document) HYDROData_Document::Document(const int theStudyID)
38 {
39   Handle(HYDROData_Document) aResult = 
40     HYDROData_Application::GetApplication()->GetDocument(theStudyID);
41   if (aResult.IsNull()) {
42     aResult = new HYDROData_Document();
43     HYDROData_Application::GetApplication()->AddDocument(theStudyID, aResult);
44   }
45   return aResult;
46 }
47
48 Handle(HYDROData_Document) HYDROData_Document::Document(
49   const TDF_Label& theObjectLabel )
50 {
51   Handle(HYDROData_Document) aResDoc;
52   if ( theObjectLabel.IsNull() )
53     return aResDoc;
54
55   Handle(TDocStd_Document) anObjDoc;
56   try
57   {
58     anObjDoc = TDocStd_Document::Get( theObjectLabel );
59   }
60   catch( ... )
61   {
62   }
63
64   if ( anObjDoc.IsNull() )
65     return aResDoc;
66
67   HYDROData_Application* anApp = HYDROData_Application::GetApplication();
68
69   DataMapOfStudyIDDocument::Iterator aMapIt( anApp->myDocuments );
70   for ( ; aMapIt.More(); aMapIt.Next() )
71   {
72     Handle(HYDROData_Document) anAppDoc = aMapIt.Value();
73     if ( anAppDoc.IsNull() || anAppDoc->myDoc != anObjDoc )
74       continue;
75
76     aResDoc = anAppDoc;
77     break;
78   }
79
80   return aResDoc;
81 }
82
83 bool HYDROData_Document::HasDocument(const int theStudyID)
84 {
85   Handle(HYDROData_Document) aResult = 
86     HYDROData_Application::GetApplication()->GetDocument(theStudyID);
87   return !aResult.IsNull();
88 }
89
90 bool HYDROData_Document::DocumentId(const Handle(HYDROData_Document)& theDocument,
91                                     int&                              theDocId )
92 {
93   return HYDROData_Application::GetApplication()->GetDocumentId(theDocument, theDocId);
94 }
95
96 Data_DocError HYDROData_Document::Load(const char* theFileName, const int theStudyID)
97 {
98   Handle(TDocStd_Document) aResult;
99   TCollection_ExtendedString aPath ((const Standard_CString)theFileName);
100   PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus) -1;
101   try
102   {
103     aStatus = HYDROData_Application::GetApplication()->Open (aPath, aResult);
104   }
105   catch (Standard_Failure)
106   {}
107   if (!aResult.IsNull()) {
108     aResult->SetUndoLimit(UNDO_LIMIT);
109     HYDROData_Application::GetApplication()->AddDocument(theStudyID, new HYDROData_Document(aResult));
110   }
111   // recognize error
112   Data_DocError anError;
113   switch(aStatus) {
114   case PCDM_RS_OK:
115     anError = DocError_OK;
116     break;
117   case PCDM_RS_NoDriver:
118   case PCDM_RS_UnknownFileDriver:
119   case PCDM_RS_NoSchema:
120   case PCDM_RS_DriverFailure:
121   case PCDM_RS_WrongResource:
122     anError = DocError_ResourcesProblem;
123     break;
124   case PCDM_RS_OpenError:
125   case PCDM_RS_NoDocument:
126   case PCDM_RS_WrongStreamMode:
127   case PCDM_RS_PermissionDenied:
128     anError = DocError_CanNotOpen;
129     break;
130   case PCDM_RS_NoVersion:
131     anError = DocError_InvalidVersion;
132     break;
133   case PCDM_RS_ExtensionFailure:
134   case PCDM_RS_FormatFailure:
135   case PCDM_RS_TypeFailure:
136   case PCDM_RS_TypeNotFoundInSchema:
137   case PCDM_RS_UnrecognizedFileFormat:
138     anError = DocError_InvalidFormat;
139     break;
140   case PCDM_RS_MakeFailure:
141   default:
142     anError = DocError_UnknownProblem;
143     break;
144   }
145   return anError;
146 }
147
148 Data_DocError HYDROData_Document::Save(const char* theFileName)
149 {
150   TCollection_ExtendedString aPath ((const Standard_CString)theFileName);
151   PCDM_StoreStatus aStatus;
152   try {
153     aStatus = HYDROData_Application::GetApplication()->SaveAs (myDoc, aPath);
154   }
155   catch (Standard_Failure) {}
156   myTransactionsAfterSave = 0;
157   Standard::Purge(); // Release free memory
158
159   // recognize error
160   Data_DocError anError;
161   switch(aStatus) {
162   case PCDM_SS_OK:
163     anError = DocError_OK;
164     break;
165   case PCDM_SS_DriverFailure:
166     anError = DocError_ResourcesProblem;
167     break;
168   case PCDM_SS_WriteFailure:
169   //case PCDM_SS_DiskWritingFailure:
170   //case PCDM_SS_UserRightsFailure:
171     anError = DocError_CanNotOpen;
172     break;
173   default:
174     anError = DocError_UnknownProblem;
175     break;
176   }
177   return anError;
178 }
179
180 void HYDROData_Document::Close()
181 {
182   myDoc->Close();
183   HYDROData_Application::GetApplication()->RemoveDocument(this);
184 }
185
186 bool HYDROData_Document::DumpToPython( const QString& theFileName,
187                                        const bool     theIsMultiFile ) const
188 {
189   // Try to open the file
190   QFile aFile( theFileName );
191   if ( !aFile.open( QIODevice::WriteOnly ) )
192     return false;
193
194   MapOfTreatedObjects aTreatedObjects;
195
196   // Dump header for python script
197   QStringList aHeaderDump = DumpToPython( aTreatedObjects, theIsMultiFile );
198   if ( aHeaderDump.isEmpty() )
199     return false;
200
201   HYDROData_Tool::WriteStringsToFile( aFile, aHeaderDump );
202
203   bool aRes = true;
204
205   // Dump the local CS data to Python 
206   UpdateLCSFields();
207   QString aLCS = QString( "%1.SetLocalCS( %2, %3 )" ).arg( GetDocPyName() ).arg( myLX ).arg( myLY );
208   if( theIsMultiFile )
209     aLCS.prepend( "  " );
210   HYDROData_Tool::WriteStringsToFile( aFile, QStringList() << aLCS );
211
212   // Dump all model objects to Python script
213   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_IMAGE );
214   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_POLYLINEXY );
215   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_BATHYMETRY );
216   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_PROFILE );
217   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_POLYLINE );
218   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_IMMERSIBLE_ZONE );
219   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_STREAM );
220   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_CHANNEL );
221   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_DIGUE );
222   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_OBSTACLE );
223   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_CALCULATION );
224
225   // Dump code to close python fuction
226   if ( aRes && theIsMultiFile )
227   {
228     QStringList aFooterScript;
229     aFooterScript << QString( "" );
230     aFooterScript << QString( "  pass" );
231     HYDROData_Tool::WriteStringsToFile( aFile, aFooterScript );
232   }
233
234   return aRes;
235 }
236
237 QString HYDROData_Document::GetDocPyName() const
238 {
239   QString aDocName = PYTHON_DOC_NAME;
240   
241   /*
242   int aDocId = 1;
243   if ( DocumentId( this, aDocId ) )
244     aDocName += "_" + QString::number( aDocId );
245   */
246   
247   return aDocName;
248 }
249
250 QStringList HYDROData_Document::DumpToPython( MapOfTreatedObjects& theTreatedObjects,
251                                               const bool           theIsMultiFile ) const
252 {
253   QString aDocName = GetDocPyName();
254
255   // Append document in to the map of treated objects to prevent names overlaping
256   theTreatedObjects.insert( aDocName, this );
257
258   int aDocId = 1;
259   if ( !DocumentId( this, aDocId ) )
260     aDocId = 1;
261
262   QStringList aResScript;
263
264   aResScript << QString( "from HYDROPy import *" );
265   aResScript << QString( "from PyQt4.QtCore import *" );
266   aResScript << QString( "from PyQt4.QtGui import *" );
267
268   if ( theIsMultiFile )
269   {
270     aResScript << QString( "import salome" );
271     aResScript << QString( "" );
272     aResScript << QString( "def RebuildData( theStudy ):" );
273     aResScript << QString( "  %1 = HYDROData_Document.Document( theStudy._get_StudyId() );" ).arg( aDocName );
274   }
275   else
276   {
277     aResScript << QString( "" );
278     aResScript << QString( "%1 = HYDROData_Document.Document( theStudy._get_StudyId() );" ).arg( aDocName );
279   }
280
281   return aResScript;
282 }
283
284 bool HYDROData_Document::dumpPartitionToPython( QFile&               theFile,
285                                                 const bool           theIsMultiFile,
286                                                 MapOfTreatedObjects& theTreatedObjects,
287                                                 const ObjectKind&    theObjectKind ) const
288 {
289   if ( !theFile.isOpen() )
290     return false;
291
292   QTextStream anOutStream( &theFile );
293
294   bool aRes = true;
295
296   HYDROData_Iterator anIterator( this, theObjectKind );
297   for( ; anIterator.More(); anIterator.Next() )
298   {
299     Handle(HYDROData_Entity) anObject = anIterator.Current();
300     if ( anObject.IsNull() )
301       continue;
302
303     QString anObjName = anObject->GetName();
304     if ( theTreatedObjects.contains( anObjName ) )
305       continue;
306
307     theTreatedObjects.insert( anObjName, anObject );
308
309     QStringList anObjDump = anObject->DumpToPython( theTreatedObjects );
310
311     if ( theIsMultiFile )
312     {
313       // For multifile dump we use the function, see the document dump header
314       QStringList::iterator anIt = anObjDump.begin();
315       for ( ; anIt != anObjDump.end(); ++anIt )
316         anIt->prepend( "  " );
317     }
318     
319     HYDROData_Tool::WriteStringsToFile( theFile, anObjDump );
320   }
321   
322   return aRes;
323 }
324
325 bool takeLastDigits( QString& theStr, int& aRes )
326 {
327   aRes = -1;
328
329   QString anStrNum;
330   for ( int i = theStr.length() - 1; i >= 0; --i )
331   {
332     const QChar& aChar = theStr.at( i );
333     if ( !aChar.isDigit() )
334       break;
335
336     anStrNum.prepend( aChar );
337   }
338
339   if ( anStrNum.isEmpty() )
340     return false;
341
342   theStr.remove( theStr.length() - anStrNum.length(), anStrNum.length() );
343   aRes = anStrNum.toInt();
344
345   return true;
346 }
347
348 bool isObjectNameLessThan( const QString& theStr1, const QString& theStr2 )
349 {
350   QString aStr1 = theStr1, aStr2 = theStr2;
351
352   int aNum1 = -1, aNum2 = -1;
353   if ( takeLastDigits( aStr1, aNum1 ) && takeLastDigits( aStr2, aNum2 ) )
354   {
355     if ( aStr1 == aStr2 )
356       return aNum1 < aNum2;
357   }
358
359   return theStr1 < theStr2;
360 }
361
362 HYDROData_SequenceOfObjects HYDROData_Document::GetObjectsLayerOrder(
363   const Standard_Boolean theIsAll ) const
364 {
365   HYDROData_SequenceOfObjects anOrder;
366
367   MapOfOrdered   aMapOfOrdered;
368   MapOfUnordered aMapOfUnordered;
369
370   HYDROData_Iterator anIter( this );
371   for ( ; anIter.More(); anIter.Next() )
372   {
373     Handle(HYDROData_Entity) anObject = anIter.Current();
374     if ( anObject.IsNull() || !anObject->IsHas2dPrs() )
375       continue;
376
377     Standard_Integer anObjZLevel = -1;
378     if ( anObject->GetZLevel( anObjZLevel ) )
379     {
380       aMapOfOrdered.insert( anObjZLevel, anObject );
381     }
382     else
383     {
384       QString anObjName = anObject->GetName();
385       if ( anObjName.isEmpty() )
386         continue;
387
388       aMapOfUnordered.insert( anObjName, anObject );
389     }
390   }
391
392   MapOfOrdered::const_iterator anOrderedMapIt = aMapOfOrdered.constBegin();
393   for ( ; anOrderedMapIt != aMapOfOrdered.constEnd(); anOrderedMapIt++ )
394   {
395     const Handle(HYDROData_Entity)& anObject = anOrderedMapIt.value();
396     anOrder.Prepend( anObject );
397   }
398
399   if ( theIsAll )
400   {
401     QStringList aSortedNames = aMapOfUnordered.keys();
402     qSort( aSortedNames.begin(), aSortedNames.end(), isObjectNameLessThan );
403
404     for ( int i = 0; i < aSortedNames.length(); ++i )
405     {
406       QString anObjName = aSortedNames.value( i );
407
408       const Handle(HYDROData_Entity)& anObject = aMapOfUnordered.value( anObjName );
409       anOrder.Append( anObject );
410     }
411   }
412
413   return anOrder;
414 }
415
416 void HYDROData_Document::SetObjectsLayerOrder( const HYDROData_SequenceOfObjects& theOrder )
417 {
418   // At first we remove previous model order
419   RemoveObjectsLayerOrder();
420
421   // Make new objects order
422   Standard_Integer aLevel = 0;
423   for ( int i = theOrder.Length(), n = 1; i >= n; --i )
424   {
425     const Handle(HYDROData_Entity)& anObject = theOrder.Value( i );
426     if ( anObject.IsNull() || !anObject->IsHas2dPrs() )
427       continue;
428
429     anObject->SetZLevel( aLevel++ );
430   }
431 }
432
433 void HYDROData_Document::Show( const Handle_HYDROData_Entity& theObject )
434 {
435   HYDROData_SequenceOfObjects anOrder;
436   anOrder.Append( theObject );
437   Show( anOrder );
438 }
439
440 void HYDROData_Document::Show( const HYDROData_SequenceOfObjects& theObjects )
441 {
442   MapOfUnordered aMapOfUnordered;
443
444   for ( int i = 1, n = theObjects.Length(); i <= n; ++i )
445   {
446     const Handle(HYDROData_Entity)& anObject = theObjects.Value( i );
447     if ( anObject.IsNull() || !anObject->IsHas2dPrs() )
448       continue;
449
450     Standard_Integer anObjZLevel = -1;
451     if ( anObject->GetZLevel( anObjZLevel ) )
452     {
453       continue; // Skip objects that already have the z-level
454     }
455     else
456     {
457       QString anObjName = anObject->GetName();
458       if ( anObjName.isEmpty() )
459         continue;
460
461       aMapOfUnordered.insert( anObjName, anObject );
462     }
463   }
464
465   if ( aMapOfUnordered.isEmpty() )
466     return; // Nothing to show
467
468   Standard_Integer aTopId = 0;
469
470   HYDROData_SequenceOfObjects aModelOrder = GetObjectsLayerOrder( Standard_False );
471   if ( !aModelOrder.IsEmpty() )
472   {
473     const Handle(HYDROData_Entity)& anObject = aModelOrder.First();
474     anObject->GetZLevel( aTopId );
475     aTopId++;
476   }
477
478   aTopId += aMapOfUnordered.size() - 1;
479
480   QStringList aSortedNames = aMapOfUnordered.keys();
481   qSort( aSortedNames.begin(), aSortedNames.end(), isObjectNameLessThan );
482
483   for ( int i = 0; i < aSortedNames.length(); ++i )
484   {
485     QString anObjName = aSortedNames.value( i );
486
487     const Handle(HYDROData_Entity)& anObject = aMapOfUnordered.value( anObjName );
488     anObject->SetZLevel( aTopId-- );
489   }
490 }
491
492 void HYDROData_Document::RemoveObjectsLayerOrder()
493 {
494   HYDROData_Iterator anIter( this );
495   for ( ; anIter.More(); anIter.Next() )
496   {
497     Handle(HYDROData_Entity) anObject = anIter.Current();
498     if ( anObject.IsNull() || !anObject->IsHas2dPrs() )
499       continue;
500
501     anObject->RemoveZLevel();
502   }
503 }
504
505 void HYDROData_Document::StartOperation()
506 {
507   myDoc->NewCommand();
508 }
509
510 void HYDROData_Document::CommitOperation(const TCollection_ExtendedString& theName)
511 {
512   if( !myDoc->CommitCommand() ) // it means that there were no modifications done
513   {
514     myDoc->NewCommand();
515     NewID(); // workaround: do something just to modify the document
516     myDoc->CommitCommand();
517   }
518   myTransactionsAfterSave++;
519
520   if( theName.Length() != 0 )
521   {
522     const TDF_DeltaList& aList = GetUndos();
523     if( !aList.IsEmpty() )
524     {
525       Handle(TDF_Delta) aDelta = aList.Last();
526       if( !aDelta.IsNull() )
527         aDelta->SetName( theName );
528     }
529   }
530 }
531
532 void HYDROData_Document::AbortOperation()
533 {
534   myDoc->AbortCommand();
535 }
536
537 bool HYDROData_Document::IsOperation()
538 {
539   return myDoc->HasOpenCommand() != 0;
540 }
541
542 bool HYDROData_Document::IsModified()
543 {
544   return myTransactionsAfterSave != 0;
545 }
546
547 bool HYDROData_Document::CanUndo()
548 {
549   return myDoc->GetAvailableUndos() > 0;
550 }
551
552 const TDF_DeltaList& HYDROData_Document::GetUndos()
553 {
554   return myDoc->GetUndos();
555 }
556
557 void HYDROData_Document::ClearUndos()
558 {
559   return myDoc->ClearUndos();
560 }
561
562 void HYDROData_Document::Undo()
563 {
564   myDoc->Undo();
565   myTransactionsAfterSave--;
566 }
567
568 bool HYDROData_Document::CanRedo()
569 {
570   return myDoc->GetAvailableRedos() > 0;
571 }
572
573 const TDF_DeltaList& HYDROData_Document::GetRedos()
574 {
575   return myDoc->GetRedos();
576 }
577
578 void HYDROData_Document::ClearRedos()
579 {
580   return myDoc->ClearRedos();
581 }
582
583 void HYDROData_Document::Redo()
584 {
585   myDoc->Redo();
586   myTransactionsAfterSave++;
587 }
588
589 Handle(HYDROData_Entity) HYDROData_Document::CreateObject( const ObjectKind theKind )
590 {
591   return HYDROData_Iterator::CreateObject( this, theKind );
592 }
593
594 Handle(HYDROData_Entity) HYDROData_Document::FindObjectByName( 
595   const QString&   theName,
596   const ObjectKind theObjectKind ) const
597 {
598   Handle(HYDROData_Entity) anObject;
599   if ( theName.isEmpty() )
600     return anObject;
601
602   QStringList aNamesList;
603   aNamesList << theName;
604
605   HYDROData_SequenceOfObjects aSeqOfObjs = FindObjectsByNames( aNamesList, theObjectKind );
606   if( aSeqOfObjs.IsEmpty() )
607     return anObject;
608   
609   anObject = aSeqOfObjs.First();
610   return anObject;
611 }
612
613 HYDROData_SequenceOfObjects HYDROData_Document::FindObjectsByNames(
614   const QStringList& theNames, 
615   const ObjectKind   theObjectKind ) const
616 {
617   HYDROData_SequenceOfObjects aResSeq;
618
619   QStringList aNamesList = theNames;
620
621   HYDROData_Iterator anIter( this, theObjectKind );
622   for( ; anIter.More(); anIter.Next() )
623   {
624     Handle(HYDROData_Entity) anObject = anIter.Current();
625     if( anObject.IsNull() )
626       continue;
627
628     QString anObjName = anObject->GetName();
629     if ( anObjName.isEmpty() || !aNamesList.contains( anObjName ) )
630       continue;
631
632     aResSeq.Append( anObject );
633
634     aNamesList.removeAll( anObjName );
635     if ( aNamesList.isEmpty() )
636       break;
637   }
638
639   return aResSeq;
640 }
641
642 HYDROData_Document::HYDROData_Document()
643 {
644   HYDROData_Application::GetApplication()->NewDocument("BinOcaf", myDoc);
645   myDoc->SetUndoLimit(UNDO_LIMIT);
646   NewID(); // needed to have at least one attribute in initial document to avoid errors
647   myTransactionsAfterSave = 0;
648   myLX = -1;
649   myLY = -1;
650 }
651
652 HYDROData_Document::HYDROData_Document(const Handle(TDocStd_Document)& theDoc)
653 {
654   myDoc = theDoc;
655   myTransactionsAfterSave = 0;
656   myLX = -1;
657   myLY = -1;
658 }
659
660 HYDROData_Document::~HYDROData_Document()
661 {
662 }
663
664 int HYDROData_Document::NewID()
665 {
666   TDF_Label anIDLab = myDoc->Main().FindChild(TAG_PROPS).
667     FindChild(TAG_PROPS_NEW_ID);
668   Handle(TDataStd_Integer) anInt;
669   if (!anIDLab.FindAttribute(TDataStd_Integer::GetID(), anInt)) {
670     anInt = TDataStd_Integer::Set(anIDLab, 0);
671   }
672   // just increment value and return
673   anInt->Set(anInt->Get() + 1);
674   return anInt->Get();
675 }
676
677 TDF_Label HYDROData_Document::LabelOfObjects()
678 {
679   return myDoc->Main().FindChild(TAG_OBJECTS);
680 }
681
682 TDF_Label HYDROData_Document::LabelOfLocalCS() const
683 {
684   return myDoc->Main().FindChild(TAG_LOCAL_CS);
685 }
686
687 void HYDROData_Document::GetLocalCS( double& theLX, double& theLY ) const
688 {
689   TDF_Label aLocalCSLab = LabelOfLocalCS();
690
691   Handle( TDataXtd_Position ) aLocalCS;
692   if( aLocalCSLab.FindAttribute( TDataXtd_Position::GetID(), aLocalCS ) )
693   {
694     gp_Pnt aLocalCS3d = aLocalCS->GetPosition();
695     theLX = aLocalCS3d.X();
696     theLY = aLocalCS3d.Y();
697   }
698   else
699   {
700     theLX = DEFAULT_LOCAL_CS.X();
701     theLY = DEFAULT_LOCAL_CS.Y();
702   }
703 }
704
705 void HYDROData_Document::SetLocalCS( double theLX, double theLY )
706 {
707   UpdateLCSFields();
708
709   // update the local CS data in attribute
710   TDF_Label aLocalCSLab = LabelOfLocalCS();
711   Handle( TDataXtd_Position ) aLocalCS;
712   if( !aLocalCSLab.FindAttribute( TDataXtd_Position::GetID(), aLocalCS ) )
713     aLocalCS = TDataXtd_Position::Set( aLocalCSLab );
714
715   gp_Pnt aLocalCS3d( theLX, theLY, 0 );
716   aLocalCS->SetPosition( aLocalCS3d );
717
718   // calculate delta for coordinates
719   double aDX = myLX - theLX;
720   double aDY = myLY - theLY;
721
722   // update the local CS data in internal fields
723   myLX = theLX;
724   myLY = theLY;
725
726   //update all objects in the document
727   HYDROData_Iterator anIterator( this, KIND_UNKNOWN );
728   for( ; anIterator.More(); anIterator.Next() )
729     anIterator.Current()->UpdateLocalCS( aDX, aDY );
730 }
731
732 void HYDROData_Document::UpdateLCSFields() const
733 {
734   if( myLX >= 0 && myLY >= 0 )
735     return;
736
737   double aLX, aLY;
738   GetLocalCS( aLX, aLY );
739   HYDROData_Document* aThat = const_cast<HYDROData_Document*>( this );
740   aThat->myLX = aLX;
741   aThat->myLY = aLY;
742 }
743
744 void HYDROData_Document::Transform( double& X, double& Y, bool IsToLocalCS ) const
745 {
746   UpdateLCSFields();
747   if( IsToLocalCS )
748   {
749     X -= myLX;
750     Y -= myLY;
751   }
752   else
753   {
754     X += myLX;
755     Y += myLY;
756   }
757 }
758
759 void HYDROData_Document::Transform( gp_Pnt& thePnt, bool IsToLocalCS ) const
760 {
761   double X = thePnt.X();
762   double Y = thePnt.Y();
763   double Z = thePnt.Z();
764   Transform( X, Y, IsToLocalCS );
765   thePnt = gp_Pnt( X, Y, Z ); 
766 }
767
768 void HYDROData_Document::Transform( gp_XYZ& thePnt, bool IsToLocalCS ) const
769 {
770   double X = thePnt.X();
771   double Y = thePnt.Y();
772   double Z = thePnt.Z();
773   Transform( X, Y, IsToLocalCS );
774   thePnt = gp_XYZ( X, Y, Z ); 
775 }
776
777 void HYDROData_Document::Transform( gp_XY& thePnt, bool IsToLocalCS ) const
778 {
779   double X = thePnt.X();
780   double Y = thePnt.Y();
781   Transform( X, Y, IsToLocalCS );
782   thePnt = gp_XY( X, Y ); 
783 }