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