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