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