Salome HOME
refs #430: incorrect coordinates in dump polyline
[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   HYDROData_Tool::WriteStringsToFile( aFile, QStringList() << aLCS );
209
210   // Dump all model objects to Python script
211   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_IMAGE );
212   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_POLYLINEXY );
213   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_BATHYMETRY );
214   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_PROFILE );
215   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_POLYLINE );
216   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_IMMERSIBLE_ZONE );
217   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_STREAM );
218   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_CHANNEL );
219   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_DIGUE );
220   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_OBSTACLE );
221   aRes = aRes && dumpPartitionToPython( aFile, theIsMultiFile, aTreatedObjects, KIND_CALCULATION );
222
223   // Dump code to close python fuction
224   if ( aRes && theIsMultiFile )
225   {
226     QStringList aFooterScript;
227     aFooterScript << QString( "" );
228     aFooterScript << QString( "  pass" );
229     HYDROData_Tool::WriteStringsToFile( aFile, aFooterScript );
230   }
231
232   return aRes;
233 }
234
235 QString HYDROData_Document::GetDocPyName() const
236 {
237   QString aDocName = PYTHON_DOC_NAME;
238   
239   /*
240   int aDocId = 1;
241   if ( DocumentId( this, aDocId ) )
242     aDocName += "_" + QString::number( aDocId );
243   */
244   
245   return aDocName;
246 }
247
248 QStringList HYDROData_Document::DumpToPython( MapOfTreatedObjects& theTreatedObjects,
249                                               const bool           theIsMultiFile ) const
250 {
251   QString aDocName = GetDocPyName();
252
253   // Append document in to the map of treated objects to prevent names overlaping
254   theTreatedObjects.insert( aDocName, this );
255
256   int aDocId = 1;
257   if ( !DocumentId( this, aDocId ) )
258     aDocId = 1;
259
260   QStringList aResScript;
261
262   aResScript << QString( "from HYDROPy import *" );
263   aResScript << QString( "from PyQt4.QtCore import *" );
264   aResScript << QString( "from PyQt4.QtGui import *" );
265
266   if ( theIsMultiFile )
267   {
268     aResScript << QString( "" );
269     aResScript << QString( "def RebuildData( theStudy ):" );
270     aResScript << QString( "  %1 = HYDROData_Document.Document( theStudy._get_StudyId() );" ).arg( aDocName );
271   }
272   else
273   {
274     aResScript << QString( "" );
275     aResScript << QString( "%1 = HYDROData_Document.Document( theStudy._get_StudyId() );" ).arg( aDocName );
276   }
277
278   return aResScript;
279 }
280
281 bool HYDROData_Document::dumpPartitionToPython( QFile&               theFile,
282                                                 const bool           theIsMultiFile,
283                                                 MapOfTreatedObjects& theTreatedObjects,
284                                                 const ObjectKind&    theObjectKind ) const
285 {
286   if ( !theFile.isOpen() )
287     return false;
288
289   QTextStream anOutStream( &theFile );
290
291   bool aRes = true;
292
293   HYDROData_Iterator anIterator( this, theObjectKind );
294   for( ; anIterator.More(); anIterator.Next() )
295   {
296     Handle(HYDROData_Entity) anObject = anIterator.Current();
297     if ( anObject.IsNull() )
298       continue;
299
300     QString anObjName = anObject->GetName();
301     if ( theTreatedObjects.contains( anObjName ) )
302       continue;
303
304     theTreatedObjects.insert( anObjName, anObject );
305
306     QStringList anObjDump = anObject->DumpToPython( theTreatedObjects );
307
308     if ( theIsMultiFile )
309     {
310       // For multifile dump we use the function, see the document dump header
311       QStringList::iterator anIt = anObjDump.begin();
312       for ( ; anIt != anObjDump.end(); ++anIt )
313         anIt->prepend( "  " );
314     }
315     
316     HYDROData_Tool::WriteStringsToFile( theFile, anObjDump );
317   }
318   
319   return aRes;
320 }
321
322 bool takeLastDigits( QString& theStr, int& aRes )
323 {
324   aRes = -1;
325
326   QString anStrNum;
327   for ( int i = theStr.length() - 1; i >= 0; --i )
328   {
329     const QChar& aChar = theStr.at( i );
330     if ( !aChar.isDigit() )
331       break;
332
333     anStrNum.prepend( aChar );
334   }
335
336   if ( anStrNum.isEmpty() )
337     return false;
338
339   theStr.remove( theStr.length() - anStrNum.length(), anStrNum.length() );
340   aRes = anStrNum.toInt();
341
342   return true;
343 }
344
345 bool isObjectNameLessThan( const QString& theStr1, const QString& theStr2 )
346 {
347   QString aStr1 = theStr1, aStr2 = theStr2;
348
349   int aNum1 = -1, aNum2 = -1;
350   if ( takeLastDigits( aStr1, aNum1 ) && takeLastDigits( aStr2, aNum2 ) )
351   {
352     if ( aStr1 == aStr2 )
353       return aNum1 < aNum2;
354   }
355
356   return theStr1 < theStr2;
357 }
358
359 HYDROData_SequenceOfObjects HYDROData_Document::GetObjectsLayerOrder(
360   const Standard_Boolean theIsAll ) const
361 {
362   HYDROData_SequenceOfObjects anOrder;
363
364   MapOfOrdered   aMapOfOrdered;
365   MapOfUnordered aMapOfUnordered;
366
367   HYDROData_Iterator anIter( this );
368   for ( ; anIter.More(); anIter.Next() )
369   {
370     Handle(HYDROData_Entity) anObject = anIter.Current();
371     if ( anObject.IsNull() || !anObject->IsHas2dPrs() )
372       continue;
373
374     Standard_Integer anObjZLevel = -1;
375     if ( anObject->GetZLevel( anObjZLevel ) )
376     {
377       aMapOfOrdered.insert( anObjZLevel, anObject );
378     }
379     else
380     {
381       QString anObjName = anObject->GetName();
382       if ( anObjName.isEmpty() )
383         continue;
384
385       aMapOfUnordered.insert( anObjName, anObject );
386     }
387   }
388
389   MapOfOrdered::const_iterator anOrderedMapIt = aMapOfOrdered.constBegin();
390   for ( ; anOrderedMapIt != aMapOfOrdered.constEnd(); anOrderedMapIt++ )
391   {
392     const Handle(HYDROData_Entity)& anObject = anOrderedMapIt.value();
393     anOrder.Prepend( anObject );
394   }
395
396   if ( theIsAll )
397   {
398     QStringList aSortedNames = aMapOfUnordered.keys();
399     qSort( aSortedNames.begin(), aSortedNames.end(), isObjectNameLessThan );
400
401     for ( int i = 0; i < aSortedNames.length(); ++i )
402     {
403       QString anObjName = aSortedNames.value( i );
404
405       const Handle(HYDROData_Entity)& anObject = aMapOfUnordered.value( anObjName );
406       anOrder.Append( anObject );
407     }
408   }
409
410   return anOrder;
411 }
412
413 void HYDROData_Document::SetObjectsLayerOrder( const HYDROData_SequenceOfObjects& theOrder )
414 {
415   // At first we remove previous model order
416   RemoveObjectsLayerOrder();
417
418   // Make new objects order
419   Standard_Integer aLevel = 0;
420   for ( int i = theOrder.Length(), n = 1; i >= n; --i )
421   {
422     const Handle(HYDROData_Entity)& anObject = theOrder.Value( i );
423     if ( anObject.IsNull() || !anObject->IsHas2dPrs() )
424       continue;
425
426     anObject->SetZLevel( aLevel++ );
427   }
428 }
429
430 void HYDROData_Document::Show( const Handle_HYDROData_Entity& theObject )
431 {
432   HYDROData_SequenceOfObjects anOrder;
433   anOrder.Append( theObject );
434   Show( anOrder );
435 }
436
437 void HYDROData_Document::Show( const HYDROData_SequenceOfObjects& theObjects )
438 {
439   MapOfUnordered aMapOfUnordered;
440
441   for ( int i = 1, n = theObjects.Length(); i <= n; ++i )
442   {
443     const Handle(HYDROData_Entity)& anObject = theObjects.Value( i );
444     if ( anObject.IsNull() || !anObject->IsHas2dPrs() )
445       continue;
446
447     Standard_Integer anObjZLevel = -1;
448     if ( anObject->GetZLevel( anObjZLevel ) )
449     {
450       continue; // Skip objects that already have the z-level
451     }
452     else
453     {
454       QString anObjName = anObject->GetName();
455       if ( anObjName.isEmpty() )
456         continue;
457
458       aMapOfUnordered.insert( anObjName, anObject );
459     }
460   }
461
462   if ( aMapOfUnordered.isEmpty() )
463     return; // Nothing to show
464
465   Standard_Integer aTopId = 0;
466
467   HYDROData_SequenceOfObjects aModelOrder = GetObjectsLayerOrder( Standard_False );
468   if ( !aModelOrder.IsEmpty() )
469   {
470     const Handle(HYDROData_Entity)& anObject = aModelOrder.First();
471     anObject->GetZLevel( aTopId );
472     aTopId++;
473   }
474
475   aTopId += aMapOfUnordered.size() - 1;
476
477   QStringList aSortedNames = aMapOfUnordered.keys();
478   qSort( aSortedNames.begin(), aSortedNames.end(), isObjectNameLessThan );
479
480   for ( int i = 0; i < aSortedNames.length(); ++i )
481   {
482     QString anObjName = aSortedNames.value( i );
483
484     const Handle(HYDROData_Entity)& anObject = aMapOfUnordered.value( anObjName );
485     anObject->SetZLevel( aTopId-- );
486   }
487 }
488
489 void HYDROData_Document::RemoveObjectsLayerOrder()
490 {
491   HYDROData_Iterator anIter( this );
492   for ( ; anIter.More(); anIter.Next() )
493   {
494     Handle(HYDROData_Entity) anObject = anIter.Current();
495     if ( anObject.IsNull() || !anObject->IsHas2dPrs() )
496       continue;
497
498     anObject->RemoveZLevel();
499   }
500 }
501
502 void HYDROData_Document::StartOperation()
503 {
504   myDoc->NewCommand();
505 }
506
507 void HYDROData_Document::CommitOperation(const TCollection_ExtendedString& theName)
508 {
509   if( !myDoc->CommitCommand() ) // it means that there were no modifications done
510   {
511     myDoc->NewCommand();
512     NewID(); // workaround: do something just to modify the document
513     myDoc->CommitCommand();
514   }
515   myTransactionsAfterSave++;
516
517   if( theName.Length() != 0 )
518   {
519     const TDF_DeltaList& aList = GetUndos();
520     if( !aList.IsEmpty() )
521     {
522       Handle(TDF_Delta) aDelta = aList.Last();
523       if( !aDelta.IsNull() )
524         aDelta->SetName( theName );
525     }
526   }
527 }
528
529 void HYDROData_Document::AbortOperation()
530 {
531   myDoc->AbortCommand();
532 }
533
534 bool HYDROData_Document::IsOperation()
535 {
536   return myDoc->HasOpenCommand() != 0;
537 }
538
539 bool HYDROData_Document::IsModified()
540 {
541   return myTransactionsAfterSave != 0;
542 }
543
544 bool HYDROData_Document::CanUndo()
545 {
546   return myDoc->GetAvailableUndos() > 0;
547 }
548
549 const TDF_DeltaList& HYDROData_Document::GetUndos()
550 {
551   return myDoc->GetUndos();
552 }
553
554 void HYDROData_Document::ClearUndos()
555 {
556   return myDoc->ClearUndos();
557 }
558
559 void HYDROData_Document::Undo()
560 {
561   myDoc->Undo();
562   myTransactionsAfterSave--;
563 }
564
565 bool HYDROData_Document::CanRedo()
566 {
567   return myDoc->GetAvailableRedos() > 0;
568 }
569
570 const TDF_DeltaList& HYDROData_Document::GetRedos()
571 {
572   return myDoc->GetRedos();
573 }
574
575 void HYDROData_Document::ClearRedos()
576 {
577   return myDoc->ClearRedos();
578 }
579
580 void HYDROData_Document::Redo()
581 {
582   myDoc->Redo();
583   myTransactionsAfterSave++;
584 }
585
586 Handle(HYDROData_Entity) HYDROData_Document::CreateObject( const ObjectKind theKind )
587 {
588   return HYDROData_Iterator::CreateObject( this, theKind );
589 }
590
591 Handle(HYDROData_Entity) HYDROData_Document::FindObjectByName( 
592   const QString&   theName,
593   const ObjectKind theObjectKind ) const
594 {
595   Handle(HYDROData_Entity) anObject;
596   if ( theName.isEmpty() )
597     return anObject;
598
599   QStringList aNamesList;
600   aNamesList << theName;
601
602   HYDROData_SequenceOfObjects aSeqOfObjs = FindObjectsByNames( aNamesList, theObjectKind );
603   if( aSeqOfObjs.IsEmpty() )
604     return anObject;
605   
606   anObject = aSeqOfObjs.First();
607   return anObject;
608 }
609
610 HYDROData_SequenceOfObjects HYDROData_Document::FindObjectsByNames(
611   const QStringList& theNames, 
612   const ObjectKind   theObjectKind ) const
613 {
614   HYDROData_SequenceOfObjects aResSeq;
615
616   QStringList aNamesList = theNames;
617
618   HYDROData_Iterator anIter( this, theObjectKind );
619   for( ; anIter.More(); anIter.Next() )
620   {
621     Handle(HYDROData_Entity) anObject = anIter.Current();
622     if( anObject.IsNull() )
623       continue;
624
625     QString anObjName = anObject->GetName();
626     if ( anObjName.isEmpty() || !aNamesList.contains( anObjName ) )
627       continue;
628
629     aResSeq.Append( anObject );
630
631     aNamesList.removeAll( anObjName );
632     if ( aNamesList.isEmpty() )
633       break;
634   }
635
636   return aResSeq;
637 }
638
639 HYDROData_Document::HYDROData_Document()
640 {
641   HYDROData_Application::GetApplication()->NewDocument("BinOcaf", myDoc);
642   myDoc->SetUndoLimit(UNDO_LIMIT);
643   NewID(); // needed to have at least one attribute in initial document to avoid errors
644   myTransactionsAfterSave = 0;
645   myLX = -1;
646   myLY = -1;
647 }
648
649 HYDROData_Document::HYDROData_Document(const Handle(TDocStd_Document)& theDoc)
650 {
651   myDoc = theDoc;
652   myTransactionsAfterSave = 0;
653   myLX = -1;
654   myLY = -1;
655 }
656
657 HYDROData_Document::~HYDROData_Document()
658 {
659 }
660
661 int HYDROData_Document::NewID()
662 {
663   TDF_Label anIDLab = myDoc->Main().FindChild(TAG_PROPS).
664     FindChild(TAG_PROPS_NEW_ID);
665   Handle(TDataStd_Integer) anInt;
666   if (!anIDLab.FindAttribute(TDataStd_Integer::GetID(), anInt)) {
667     anInt = TDataStd_Integer::Set(anIDLab, 0);
668   }
669   // just increment value and return
670   anInt->Set(anInt->Get() + 1);
671   return anInt->Get();
672 }
673
674 TDF_Label HYDROData_Document::LabelOfObjects()
675 {
676   return myDoc->Main().FindChild(TAG_OBJECTS);
677 }
678
679 TDF_Label HYDROData_Document::LabelOfLocalCS() const
680 {
681   return myDoc->Main().FindChild(TAG_LOCAL_CS);
682 }
683
684 void HYDROData_Document::GetLocalCS( double& theLX, double& theLY ) const
685 {
686   TDF_Label aLocalCSLab = LabelOfLocalCS();
687
688   Handle( TDataXtd_Position ) aLocalCS;
689   if( aLocalCSLab.FindAttribute( TDataXtd_Position::GetID(), aLocalCS ) )
690   {
691     gp_Pnt aLocalCS3d = aLocalCS->GetPosition();
692     theLX = aLocalCS3d.X();
693     theLY = aLocalCS3d.Y();
694   }
695   else
696   {
697     theLX = DEFAULT_LOCAL_CS.X();
698     theLY = DEFAULT_LOCAL_CS.Y();
699   }
700 }
701
702 void HYDROData_Document::SetLocalCS( double theLX, double theLY )
703 {
704   UpdateLCSFields();
705
706   // update the local CS data in attribute
707   TDF_Label aLocalCSLab = LabelOfLocalCS();
708   Handle( TDataXtd_Position ) aLocalCS;
709   if( !aLocalCSLab.FindAttribute( TDataXtd_Position::GetID(), aLocalCS ) )
710     aLocalCS = TDataXtd_Position::Set( aLocalCSLab );
711
712   gp_Pnt aLocalCS3d( theLX, theLY, 0 );
713   aLocalCS->SetPosition( aLocalCS3d );
714
715   // calculate delta for coordinates
716   double aDX = myLX - theLX;
717   double aDY = myLY - theLY;
718
719   // update the local CS data in internal fields
720   myLX = theLX;
721   myLY = theLY;
722
723   //update all objects in the document
724   HYDROData_Iterator anIterator( this, KIND_UNKNOWN );
725   for( ; anIterator.More(); anIterator.Next() )
726     anIterator.Current()->UpdateLocalCS( aDX, aDY );
727 }
728
729 void HYDROData_Document::UpdateLCSFields() const
730 {
731   if( myLX >= 0 && myLY >= 0 )
732     return;
733
734   double aLX, aLY;
735   GetLocalCS( aLX, aLY );
736   HYDROData_Document* aThat = const_cast<HYDROData_Document*>( this );
737   aThat->myLX = aLX;
738   aThat->myLY = aLY;
739 }
740
741 void HYDROData_Document::Transform( double& X, double& Y, bool IsToLocalCS ) const
742 {
743   UpdateLCSFields();
744   if( IsToLocalCS )
745   {
746     X -= myLX;
747     Y -= myLY;
748   }
749   else
750   {
751     X += myLX;
752     Y += myLY;
753   }
754 }
755
756 void HYDROData_Document::Transform( gp_Pnt& thePnt, bool IsToLocalCS ) const
757 {
758   double X = thePnt.X();
759   double Y = thePnt.Y();
760   double Z = thePnt.Z();
761   Transform( X, Y, IsToLocalCS );
762   thePnt = gp_Pnt( X, Y, Z ); 
763 }
764
765 void HYDROData_Document::Transform( gp_XYZ& thePnt, bool IsToLocalCS ) const
766 {
767   double X = thePnt.X();
768   double Y = thePnt.Y();
769   double Z = thePnt.Z();
770   Transform( X, Y, IsToLocalCS );
771   thePnt = gp_XYZ( X, Y, Z ); 
772 }
773
774 void HYDROData_Document::Transform( gp_XY& thePnt, bool IsToLocalCS ) const
775 {
776   double X = thePnt.X();
777   double Y = thePnt.Y();
778   Transform( X, Y, IsToLocalCS );
779   thePnt = gp_XY( X, Y ); 
780 }