Salome HOME
Dump to python corrected.
[modules/hydro.git] / src / HYDROData / HYDROData_Image.cxx
1
2 #include "HYDROData_Image.h"
3
4 #include "HYDROData_Document.h"
5 #include "HYDROData_Lambert93.h"
6 #include "HYDROData_OperationsFactory.h"
7
8 #include <TDataStd_RealArray.hxx>
9 #include <TDataStd_ByteArray.hxx>
10 #include <TDataStd_Integer.hxx>
11 #include <TDataStd_IntegerArray.hxx>
12 #include <TDataStd_ReferenceList.hxx>
13 #include <TDataStd_UAttribute.hxx>
14 #include <TDataStd_AsciiString.hxx>
15
16 #include <ImageComposer_Operator.h>
17 #include <ImageComposer_MetaTypes.h>
18
19 #include <QStringList>
20 #include <QFile>
21
22 #include <boost/math/special_functions/fpclassify.hpp>
23
24 static const Standard_GUID GUID_SELF_SPLITTED("997995aa-5c19-40bf-9a60-ab4b70ad04d8");
25 static const Standard_GUID GUID_HAS_LOCAL_POINTS("FD8841AA-FC44-42fa-B6A7-0F682CCC6F27");
26 static const Standard_GUID GUID_HAS_GLOBAL_POINTS("330D0E81-742D-4ea3-92D4-484877CFA7C1");
27
28 IMPLEMENT_STANDARD_HANDLE(HYDROData_Image, HYDROData_Entity)
29 IMPLEMENT_STANDARD_RTTIEXT(HYDROData_Image, HYDROData_Entity)
30
31 HYDROData_Image::HYDROData_Image()
32 : HYDROData_Entity()
33 {
34 }
35
36 HYDROData_Image::~HYDROData_Image()
37 {
38 }
39
40 QStringList HYDROData_Image::DumpToPython( MapOfTreatedObjects& theTreatedObjects ) const
41 {
42   QStringList aResList = dumpObjectCreation( theTreatedObjects );
43   QString anImageName = GetObjPyName();
44
45   QString aFilePath = GetFilePath();
46   if ( !aFilePath.isEmpty() )
47   {
48     aResList << QString( "" );
49     aResList << QString( "%1.LoadImage( \"%2\" );" )
50                 .arg( anImageName ).arg( aFilePath );
51     aResList << QString( "" );
52
53     // Dump transformation points for image
54
55     QString aGap = QString().fill( ' ', anImageName.size() + 16 );
56
57     bool anIsByTwoPoints = IsByTwoPoints();
58
59     QPoint aLocalPointA, aLocalPointB, aLocalPointC;
60     if ( GetLocalPoints( aLocalPointA, aLocalPointB, aLocalPointC ) )
61     {
62       aResList << QString( "%1.SetLocalPoints( QPoint( %2, %3 )," )
63                   .arg( anImageName ).arg( aLocalPointA.x() ).arg( aLocalPointA.y() );
64       aResList << QString( aGap             + "QPoint( %1, %2 )," )
65                   .arg( aLocalPointB.x() ).arg( aLocalPointB.y() );
66       aResList << QString( aGap             + "QPoint( %1, %2 ) );" )
67                   .arg( aLocalPointC.x() ).arg( aLocalPointC.y() );
68       aResList << QString( "" );
69     }
70
71     HYDROData_Image::TransformationMode aTransformationMode;
72     QPointF aTrsfPointA, aTrsfPointB, aTrsfPointC;
73     if ( GetGlobalPoints( aTransformationMode, aTrsfPointA, aTrsfPointB, aTrsfPointC ) )
74     {
75       aResList << QString( "%1.SetGlobalPoints( %2," )
76                   .arg( anImageName ).arg( aTransformationMode );
77       aResList << QString( aGap             +  "QPointF( %1, %2 )," )
78                   .arg( aTrsfPointA.x() ).arg( aTrsfPointA.y() );
79       aResList << QString( aGap             +  "QPointF( %1, %2 )," )
80                   .arg( aTrsfPointB.x() ).arg( aTrsfPointB.y() );
81       aResList << QString( aGap             +  "QPointF( %1, %2 ) );" )
82                   .arg( aTrsfPointC.x() ).arg( aTrsfPointC.y() );
83
84       if ( aTransformationMode == ReferenceImage )
85       {
86         Handle(HYDROData_Image) aRefImg = GetTrsfReferenceImage();
87         setPythonReferenceObject( theTreatedObjects, aResList, aRefImg, "SetTrsfReferenceImage" );
88       }
89     }
90   }
91   else
92   {
93     // Image is composed from other image(s)
94
95     QString anOperatorName = OperatorName();
96     if ( !anOperatorName.isEmpty() )
97     {
98       aResList << QString( "" );
99
100       aResList << QString( "%1.SetOperatorName( \"%2\" );" )
101                   .arg( anImageName ).arg( anOperatorName );
102
103       ImageComposer_Operator* anImageOp = 
104         HYDROData_OperationsFactory::Factory()->Operator( OperatorName() );
105       if ( anImageOp )
106       {
107         // Dump operation arguments
108         QString anOpArgsArrayName;
109         QStringList anOpArgs = anImageOp->dumpArgsToPython( anOpArgsArrayName );
110         if ( !anOpArgs.isEmpty() )
111         {
112           aResList << QString( "" );
113           aResList << anOpArgs;
114
115           aResList << QString( "" );
116           aResList << QString( "%1.SetArgs( %2 );" )
117                       .arg( anImageName ).arg( anOpArgsArrayName );
118         }
119       }
120     }
121     
122     int aNbReferences = NbReferences();
123     if ( aNbReferences > 0 )
124     {
125       aResList << QString( "" );
126
127       for ( int i = 0; i < aNbReferences; ++i )
128       {
129         Handle(HYDROData_Image) aRefImg = Handle(HYDROData_Image)::DownCast( Reference( i ) );
130         setPythonReferenceObject( theTreatedObjects, aResList, aRefImg, "AppendReference" );
131       }
132     }
133
134     // Necessary to update image in case of composed operator
135     aResList << QString( "" );
136     aResList << QString( "%1.Update();" ).arg( anImageName );
137   }
138
139   aResList << QString( "" );
140
141   return aResList;
142 }
143
144 void HYDROData_Image::Update()
145 {
146   bool anIsToUpdate = IsMustBeUpdated();
147
148   HYDROData_Entity::Update();
149
150   if ( !anIsToUpdate )
151     return;
152
153   HYDROData_OperationsFactory* aFactory = HYDROData_OperationsFactory::Factory();
154
155   ImageComposer_Operator* anOp = aFactory->Operator( OperatorName() );
156   if ( anOp ) // Update image if there is an operation
157   {
158     // Fill by arguments and process the operation
159     anOp->setBinArgs( Args() );
160
161     QVariant anObj1, anObj2;
162     int aNbReferences = NbReferences();
163
164     if ( aNbReferences > 0 )
165     {
166       // First referenced object
167       Handle(HYDROData_Entity) aRefObj = Reference( 0 );
168       if ( !aRefObj.IsNull() )
169       {
170         anObj1 = aRefObj->GetDataVariant();
171         if ( !anObj1.isNull() && anObj1.canConvert<ImageComposer_Image>() )
172         {
173           ImageComposer_Image anImage = anObj1.value<ImageComposer_Image>();
174           QTransform aTransform = anImage.transform();
175           SetTrsf( aTransform );
176         }
177       }
178     }
179
180     if ( aNbReferences > 1 )
181     {
182       // Second referenced object
183       Handle(HYDROData_Entity) aRefObj = Reference( 1 );
184       if ( !aRefObj.IsNull() )
185         anObj2 = aRefObj->GetDataVariant();
186     }
187
188     ImageComposer_Image aResImg = anOp->process( anObj1, anObj2 );
189     SetImage( aResImg );
190     SetTrsf( aResImg.transform() );
191   }
192   else // Update image if it positioned relatively to other image
193   {
194     UpdateTrsf();
195   }
196
197   SetToUpdate( false );
198 }
199
200 QVariant HYDROData_Image::GetDataVariant()
201 {
202   QTransform aTransform = Trsf();
203
204   ImageComposer_Image anImage = Image();
205   anImage.setTransform( aTransform );
206
207   QVariant aVarData;
208   aVarData.setValue<ImageComposer_Image>( anImage );
209   
210   return aVarData;
211 }
212
213 HYDROData_SequenceOfObjects HYDROData_Image::GetAllReferenceObjects() const
214 {
215   HYDROData_SequenceOfObjects aResSeq = HYDROData_Entity::GetAllReferenceObjects();
216
217   Handle(HYDROData_Image) aRefImage = GetTrsfReferenceImage();
218   if ( !aRefImage.IsNull() )
219     aResSeq.Append( aRefImage );
220
221   HYDROData_SequenceOfObjects aSeqRefObjects = GetReferenceObjects( 0 );
222   aResSeq.Append( aSeqRefObjects );
223
224   return aResSeq;
225 }
226
227 void HYDROData_Image::SetImage(const QImage& theImage)
228 {
229   if ( theImage.isNull() )
230   {
231     // for empty image remove all previously stored attributes
232     myLab.ForgetAttribute(TDataStd_IntegerArray::GetID());
233     myLab.ForgetAttribute(TDataStd_ByteArray::GetID());
234   }
235   else
236   {
237     QImage anImage;
238
239     // convert 8-bits images
240     if ( theImage.format() == QImage::Format_Indexed8 ) {
241       anImage = theImage.convertToFormat( QImage::Format_RGB32 );
242     } else {
243       anImage = theImage;
244     }
245
246     // store width, height, bytes per line and format in integer array 
247     Handle(TDataStd_IntegerArray) aParams;
248     if (!myLab.FindAttribute(TDataStd_IntegerArray::GetID(), aParams)) {
249       aParams = TDataStd_IntegerArray::Set(myLab, 1, 4);
250     }
251     aParams->SetValue(1, anImage.width());
252     aParams->SetValue(2, anImage.height());
253     aParams->SetValue(3, anImage.bytesPerLine());
254     aParams->SetValue(4, (int)(anImage.format()));
255     // store data of image in byte array
256     const char* aData = (const char*)(anImage.bits());
257     SaveByteArray(0, aData, anImage.byteCount());
258   }
259
260   SetToUpdate( true );
261 }
262
263 bool HYDROData_Image::LoadImage( const QString& theFilePath )
264 {
265   QImage anImage( theFilePath );
266   SetImage( anImage );
267   return !anImage.isNull();
268 }
269
270 QImage HYDROData_Image::Image()
271 {
272   Handle(TDataStd_IntegerArray) aParams;
273   if (!myLab.FindAttribute(TDataStd_IntegerArray::GetID(), aParams))
274     return QImage(); // return empty image if there is no array
275   int aLen = 0;
276   uchar* anArray = (uchar*)ByteArray(0, aLen);
277   if (!aLen)
278     return QImage(); // return empty image if there is no array
279   QImage aResult(anArray, aParams->Value(1), aParams->Value(2),
280                  aParams->Value(3), QImage::Format(aParams->Value(4)));
281   return aResult;
282 }
283
284 void HYDROData_Image::SetFilePath( const QString& theFilePath )
285 {
286   TCollection_AsciiString anAsciiStr( theFilePath.toStdString().c_str() );
287   TDataStd_AsciiString::Set( myLab.FindChild( DataTag_FilePath ), anAsciiStr );
288
289   SetToUpdate( true );
290 }
291
292 QString HYDROData_Image::GetFilePath() const
293 {
294   QString aRes;
295
296   TDF_Label aLabel = myLab.FindChild( DataTag_FilePath, false );
297   if ( !aLabel.IsNull() )
298   {
299     Handle(TDataStd_AsciiString) anAsciiStr;
300     if ( aLabel.FindAttribute( TDataStd_AsciiString::GetID(), anAsciiStr ) )
301       aRes = QString( anAsciiStr->Get().ToCString() );
302   }
303
304   return aRes;
305 }
306
307 void HYDROData_Image::SetTrsf(const QTransform& theTrsf)
308 {
309   // locate 9 coeffs of matrix into the real array
310   Handle(TDataStd_RealArray) anArray;
311   if (!myLab.FindAttribute(TDataStd_RealArray::GetID(), anArray)) {
312     if (theTrsf.isIdentity()) return; // no need to store identity transformation
313     anArray = TDataStd_RealArray::Set(myLab, 1, 9);
314   }
315   anArray->SetValue(1, theTrsf.m11());
316   anArray->SetValue(2, theTrsf.m12());
317   anArray->SetValue(3, theTrsf.m13());
318   anArray->SetValue(4, theTrsf.m21());
319   anArray->SetValue(5, theTrsf.m22());
320   anArray->SetValue(6, theTrsf.m23());
321   anArray->SetValue(7, theTrsf.m31());
322   anArray->SetValue(8, theTrsf.m32());
323   anArray->SetValue(9, theTrsf.m33());
324
325   SetToUpdate( true );
326 }
327
328 QTransform HYDROData_Image::Trsf() const
329 {
330   // get 9 coeffs of matrix from the real array
331   Handle(TDataStd_RealArray) anArray;
332   if (!myLab.FindAttribute(TDataStd_RealArray::GetID(), anArray))
333     return QTransform(); // return identity if there is no array
334   QTransform aTrsf(
335     anArray->Value(1), anArray->Value(2), anArray->Value(3), 
336     anArray->Value(4), anArray->Value(5), anArray->Value(6), 
337     anArray->Value(7), anArray->Value(8), anArray->Value(9));
338   return aTrsf;
339 }
340
341 void HYDROData_Image::UpdateTrsf()
342 {
343   QPoint aPointA, aPointB, aPointC;
344   if ( !GetLocalPoints( aPointA, aPointB, aPointC ) )
345     return;
346
347   TransformationMode aTrsfMode;
348   QPointF aTrsfPointA, aTrsfPointB, aTrsfPointC;
349   if ( !GetGlobalPoints( aTrsfMode, aTrsfPointA, aTrsfPointB, aTrsfPointC ) )
350     return;
351
352   QTransform aRefTransform;
353   Handle(HYDROData_Image) aRefImage = GetTrsfReferenceImage();
354
355   bool anIsRefImage = aTrsfMode == ReferenceImage;
356   if ( anIsRefImage )
357   {
358     if ( aRefImage.IsNull() )
359       return;
360
361     aRefTransform = aRefImage->Trsf();
362   }
363
364   bool anIsByTwoPoints = IsByTwoPoints();
365
366   // Convert lambert coordinates to cartesian
367   if ( aTrsfMode == ManualGeodesic )
368   {
369     double aXCart = 0, aYCart = 0;
370
371     HYDROData_Lambert93::toXY( aTrsfPointA.y(), aTrsfPointA.x(), aXCart, aYCart );
372     aTrsfPointA = QPointF( aXCart, aYCart );
373
374     HYDROData_Lambert93::toXY( aTrsfPointB.y(), aTrsfPointB.x(), aXCart, aYCart );
375     aTrsfPointB = QPointF( aXCart, aYCart );
376
377     if ( !anIsByTwoPoints )
378     {
379       HYDROData_Lambert93::toXY( aTrsfPointC.y(), aTrsfPointC.x(), aXCart, aYCart );
380       aTrsfPointC = QPointF( aXCart, aYCart );
381     }
382   }
383
384   // generate third points if needed
385   if ( anIsByTwoPoints )
386   {
387     aPointC = generateThirdPoint( aPointA, aPointB, true ).toPoint();
388     aTrsfPointC = generateThirdPoint( aTrsfPointA, aTrsfPointB, anIsRefImage );
389   }
390
391   int xa = aPointA.x();
392   int ya = aPointA.y();
393   int xb = aPointB.x();
394   int yb = aPointB.y();
395   int xc = aPointC.x();
396   int yc = aPointC.y();
397
398   double xta = aTrsfPointA.x();
399   double yta = aTrsfPointA.y();
400   double xtb = aTrsfPointB.x();
401   double ytb = aTrsfPointB.y();
402   double xtc = aTrsfPointC.x();
403   double ytc = aTrsfPointC.y();
404
405   // first, check that three input points don't belong to a single line
406   if( ( yb - ya ) * ( xc - xa ) == ( yc - ya ) * ( xb - xa ) )
407     return;
408
409   // the same check for the reference points
410   if( anIsRefImage && ( ( ytb - yta ) * ( xtc - xta ) == ( ytc - yta ) * ( xtb - xta ) ) )
411     return;
412
413   QTransform aTransform1( xa, ya, 1, xb, yb, 1, xc, yc, 1 );
414   QTransform aTransform2( xta, yta, 1, xtb, ytb, 1, xtc, ytc, 1 );
415
416   bool anIsInvertible = false;
417   QTransform aTransform1Inverted = aTransform1.inverted( &anIsInvertible );
418   if( !anIsInvertible )
419     return;
420
421   QTransform aResTransform = aTransform1Inverted * aTransform2;
422   if( anIsRefImage )
423     aResTransform *= aRefTransform;
424
425   SetTrsf( aResTransform );
426 }
427
428 bool HYDROData_Image::IsByTwoPoints() const
429 {
430   if ( !HasLocalPoints() || !HasGlobalPoints() )
431     return false;
432
433   QPoint aPointA, aPointB, aPointC;
434   GetLocalPoints( aPointA, aPointB, aPointC );
435
436   return aPointC.x() < 0 && aPointC.y() < 0; 
437 }
438
439 bool HYDROData_Image::HasReferences() const
440 {
441   Handle(HYDROData_Image) aRefImage = GetTrsfReferenceImage();
442   int aNbReferences = NbReferences();
443
444   return !aRefImage.IsNull() || aNbReferences > 0;
445 }
446
447 void HYDROData_Image::RemoveAllReferences()
448 {
449   if ( !HasReferences() )
450     return;
451
452   Handle(HYDROData_Image) aRefImage = GetTrsfReferenceImage();
453   if ( !aRefImage.IsNull() )
454   {
455     RemoveTrsfReferenceImage();
456   }
457   else
458   {
459     ClearReferences();
460     SetOperatorName( "" );
461     SetArgs( "" );
462     SetIsSelfSplitted( false );
463   }
464
465   bool anIsByTwoPoints = IsByTwoPoints();
466
467   QImage anImage = Image();
468   if ( anImage.isNull() )
469   {
470     SetToUpdate( false );
471     return;
472   }
473
474   // Set local points to default position
475   QPoint aLocalPointA = QPoint( 0, 0 );
476   QPoint aLocalPointB = QPoint( anImage.width(), 0 );
477   QPoint aLocalPointC = anIsByTwoPoints ? QPoint( INT_MIN, INT_MIN ) : QPoint( 0, anImage.height() );
478
479   SetLocalPoints( aLocalPointA, aLocalPointB, aLocalPointC, false );
480
481   // Calculate global points
482   QTransform aTransform = Trsf();
483
484   QPointF aTrsfPointA = QPointF( aTransform.map( aLocalPointA ) );
485   QPointF aTrsfPointB = QPointF( aTransform.map( aLocalPointB ) );
486   QPointF aTrsfPointC = anIsByTwoPoints ? QPointF( INT_MIN, INT_MIN ) : 
487                                           QPointF( aTransform.map( aLocalPointC ) );
488
489   SetGlobalPoints( ManualCartesian, aTrsfPointA, aTrsfPointB, aTrsfPointC );
490
491   SetToUpdate( false );
492 }
493
494 void HYDROData_Image::SetLocalPoints( const QPoint& thePointA,
495                                       const QPoint& thePointB,
496                                       const QPoint& thePointC,
497                                       const bool    theIsUpdate )
498 {
499   Handle(TDataStd_RealArray) anArray;
500   if ( !myLab.FindChild( DataTag_TrsfPoints ).FindAttribute( TDataStd_RealArray::GetID(), anArray ) )
501     anArray = TDataStd_RealArray::Set( myLab.FindChild( DataTag_TrsfPoints ), 1, 12 );
502
503   anArray->SetValue( 1, thePointA.x() );
504   anArray->SetValue( 2, thePointA.y() );
505   anArray->SetValue( 3, thePointB.x() );
506   anArray->SetValue( 4, thePointB.y() );
507   anArray->SetValue( 5, thePointC.x() );
508   anArray->SetValue( 6, thePointC.y() );
509
510   TDataStd_UAttribute::Set( myLab.FindChild( DataTag_TrsfPoints ), GUID_HAS_LOCAL_POINTS );
511
512   if ( theIsUpdate )
513     UpdateTrsf();
514
515   SetToUpdate( true );
516 }
517
518 bool HYDROData_Image::GetLocalPoints( QPoint& thePointA,
519                                       QPoint& thePointB,
520                                       QPoint& thePointC ) const
521 {
522   if ( !HasLocalPoints() )
523     return false;
524
525   Handle(TDataStd_RealArray) anArray;
526   myLab.FindChild( DataTag_TrsfPoints ).FindAttribute( TDataStd_RealArray::GetID(), anArray );
527
528   thePointA = QPointF( anArray->Value( 1 ), anArray->Value( 2 ) ).toPoint();
529   thePointB = QPointF( anArray->Value( 3 ), anArray->Value( 4 ) ).toPoint();
530   thePointC = QPointF( anArray->Value( 5 ), anArray->Value( 6 ) ).toPoint();
531
532   return true;
533 }
534
535 bool HYDROData_Image::HasLocalPoints() const
536 {
537   TDF_Label aLabel = myLab.FindChild( DataTag_TrsfPoints, false );
538   if ( aLabel.IsNull() || !aLabel.IsAttribute( GUID_HAS_LOCAL_POINTS ) )
539     return false;
540
541   Handle(TDataStd_RealArray) anArray;
542   return aLabel.FindAttribute( TDataStd_RealArray::GetID(), anArray );
543 }
544
545
546 void HYDROData_Image::SetGlobalPoints( const TransformationMode& theMode,
547                                        const QPointF&            thePointA,
548                                        const QPointF&            thePointB,
549                                        const QPointF&            thePointC,
550                                        const bool                theIsUpdate )
551 {
552   Handle(TDataStd_RealArray) anArray;
553   if ( !myLab.FindChild( DataTag_TrsfPoints ).FindAttribute( TDataStd_RealArray::GetID(), anArray ) )
554     anArray = TDataStd_RealArray::Set( myLab.FindChild( DataTag_TrsfPoints ), 1, 12 );
555
556   anArray->SetValue( 7,  thePointA.x() );
557   anArray->SetValue( 8,  thePointA.y() );
558   anArray->SetValue( 9,  thePointB.x() );
559   anArray->SetValue( 10, thePointB.y() );
560   anArray->SetValue( 11, thePointC.x() );
561   anArray->SetValue( 12, thePointC.y() );
562   
563   SetTrsfMode( theMode );
564
565   TDataStd_UAttribute::Set( myLab.FindChild( DataTag_TrsfPoints ), GUID_HAS_GLOBAL_POINTS );
566
567   if ( theIsUpdate )
568     UpdateTrsf();
569
570   SetToUpdate( true );
571 }
572
573 bool HYDROData_Image::GetGlobalPoints( TransformationMode& theMode,
574                                        QPointF&            thePointA,
575                                        QPointF&            thePointB,
576                                        QPointF&            thePointC ) const
577 {
578   if ( !HasGlobalPoints() )
579     return false;
580
581   theMode = GetTrsfMode();
582
583   Handle(TDataStd_RealArray) anArray;
584   myLab.FindChild( DataTag_TrsfPoints ).FindAttribute( TDataStd_RealArray::GetID(), anArray );
585
586   thePointA = QPointF( anArray->Value( 7  ), anArray->Value( 8  ) );
587   thePointB = QPointF( anArray->Value( 9  ), anArray->Value( 10 ) );
588   thePointC = QPointF( anArray->Value( 11 ), anArray->Value( 12 ) );
589
590   return true;
591 }
592
593 bool HYDROData_Image::SetGlobalPointsFromFile( const QString& theFileName )
594 {
595   bool aRes = false;
596
597   // Try to open the file
598   QFile aFile( theFileName );
599   if ( !aFile.exists() || !aFile.open( QIODevice::ReadOnly ) ) {
600     return aRes;
601   }
602
603   QPointF aPointA, aPointB;
604   double aXmin, anYmin, aXmax, anYmax;
605   aXmin = anYmin = aXmax = anYmax = -1;
606
607   while ( !aFile.atEnd() && 
608           ( aXmin < 0 || anYmin < 0 || aXmax < 0 || anYmax < 0 ) ) {
609     // Read line
610     QString aLine = aFile.readLine().simplified();
611     aLine.replace( " ", "" );
612     if ( aLine.isEmpty() ) {
613       continue;
614     }
615
616     // Try to read double value after ":"
617     bool isDoubleOk = false;
618     double aDoubleValue = -1;
619     QStringList aValues = aLine.split( ":", QString::SkipEmptyParts );
620     if ( aValues.count() == 2 ) {
621       aDoubleValue = aValues.last().toDouble( &isDoubleOk );
622     }
623
624     // Check the result
625     if ( !isDoubleOk ||
626          boost::math::isnan( aDoubleValue ) ||
627          boost::math::isinf( aDoubleValue ) ) {
628       continue;
629     }
630
631     // Set the value
632     if ( aLine.startsWith( "Xminimum" ) ) {
633       aXmin = aDoubleValue;    
634     } 
635     else if ( aLine.startsWith( "Yminimum" ) ) {
636       anYmin = aDoubleValue; 
637     }
638     else if ( aLine.startsWith( "Xmaximum" ) ) {
639       aXmax = aDoubleValue;
640     }
641     else if ( aLine.startsWith( "Ymaximum" ) ) {
642       anYmax = aDoubleValue;  
643     }
644   }
645
646   // Close the file
647   aFile.close();
648
649   if ( aXmin >= 0 && anYmin >= 0 ) {
650     aPointA.setX( aXmin );
651     aPointA.setY( anYmin );
652   }
653     
654   if ( aXmax >= 0 && anYmax >= 0 ) {
655     aPointB.setX( aXmax );
656     aPointB.setY( anYmax );
657   }
658
659   if ( !aPointA.isNull() && !aPointB.isNull() ) {
660     SetGlobalPoints( ManualCartesian, aPointA, aPointB );
661     aRes = true;
662   }
663
664   return aRes;
665 }
666
667 bool HYDROData_Image::HasGlobalPoints() const
668 {
669   TDF_Label aLabel = myLab.FindChild( DataTag_TrsfPoints, false );
670   if ( aLabel.IsNull() || !aLabel.IsAttribute( GUID_HAS_GLOBAL_POINTS ) )
671     return false;
672
673   Handle(TDataStd_RealArray) anArray;
674   return aLabel.FindAttribute( TDataStd_RealArray::GetID(), anArray );
675 }
676
677 void HYDROData_Image::SetReferencePoints( const Handle(HYDROData_Image)& theRefImage,
678                                           const QPointF&                 thePointA,
679                                           const QPointF&                 thePointB,
680                                           const QPointF&                 thePointC,
681                                           const bool                     theIsUpdate )
682 {
683   SetTrsfReferenceImage( theRefImage );
684   SetGlobalPoints( ReferenceImage, thePointA, thePointB, thePointC, theIsUpdate );
685 }
686
687 bool HYDROData_Image::GetReferencePoints( Handle(HYDROData_Image)& theRefImage,
688                                           QPointF&                 thePointA,
689                                           QPointF&                 thePointB,
690                                           QPointF&                 thePointC ) const
691 {
692   if ( !HasReferencePoints() )
693     return false;
694
695   theRefImage = GetTrsfReferenceImage();
696
697   TransformationMode aMode;
698   GetGlobalPoints( aMode, thePointA, thePointB, thePointC );
699
700   return true;
701 }
702
703 bool HYDROData_Image::HasReferencePoints() const
704 {
705   if ( !HasGlobalPoints() )
706     return false;
707
708   Handle(HYDROData_Image) aRefImage = GetTrsfReferenceImage();
709   if ( aRefImage.IsNull() )
710     return false;
711
712   TransformationMode aTrsfMode = GetTrsfMode();
713   if ( aTrsfMode != ReferenceImage )
714     return false;
715
716   return true;
717 }
718
719 void HYDROData_Image::SetTrsfMode( const TransformationMode& theMode )
720 {
721   TDataStd_Integer::Set( myLab.FindChild( DataTag_TrsfMode ), (int)theMode );
722   SetToUpdate( true );
723 }
724
725 HYDROData_Image::TransformationMode HYDROData_Image::GetTrsfMode() const
726 {
727   TransformationMode aResMode = ManualGeodesic;
728
729   TDF_Label aLabel = myLab.FindChild( DataTag_TrsfPoints, false );
730   if ( !aLabel.IsNull() )
731   {
732     Handle(TDataStd_Integer) aMode;
733     if ( myLab.FindChild( DataTag_TrsfMode ).FindAttribute( TDataStd_Integer::GetID(), aMode ) )
734       aResMode = (TransformationMode)aMode->Get();
735   }
736
737   return aResMode;
738 }
739
740 void HYDROData_Image::SetTrsfReferenceImage( const Handle(HYDROData_Image)& theRefImage )
741 {
742   SetReferenceObject( theRefImage, DataTag_TrsfImage );
743   SetToUpdate( true );
744 }
745
746 Handle(HYDROData_Image) HYDROData_Image::GetTrsfReferenceImage() const
747 {
748   return Handle(HYDROData_Image)::DownCast( GetReferenceObject( DataTag_TrsfImage ) );
749 }
750
751 void HYDROData_Image::RemoveTrsfReferenceImage()
752 {
753   RemoveReferenceObject( DataTag_TrsfImage );
754   SetToUpdate( true );
755 }
756
757 void HYDROData_Image::AppendReference( const Handle(HYDROData_Entity)& theReferenced )
758 {
759   AddReferenceObject( theReferenced, 0 );
760   SetToUpdate( true );
761 }
762
763 int HYDROData_Image::NbReferences() const
764 {
765   return NbReferenceObjects( 0 );
766 }
767
768 Handle(HYDROData_Entity) HYDROData_Image::Reference( const int theIndex ) const
769 {
770   return GetReferenceObject( 0, theIndex );
771 }
772
773 void HYDROData_Image::ChangeReference(
774     const int theIndex, Handle(HYDROData_Entity) theReferenced)
775 {
776   SetReferenceObject( theReferenced, 0, theIndex );
777   SetToUpdate( true );
778 }
779
780 void HYDROData_Image::RemoveReference(const int theIndex)
781 {
782   RemoveReferenceObject( 0, theIndex );
783   SetToUpdate( true );
784 }
785
786 void HYDROData_Image::ClearReferences()
787 {
788   ClearReferenceObjects( 0 );
789   SetToUpdate( true );
790 }
791
792 void HYDROData_Image::SetOperatorName( const QString theOpName )
793 {
794   TCollection_AsciiString anAsciiStr( theOpName.toStdString().c_str() );
795   TDataStd_AsciiString::Set( myLab.FindChild( DataTag_Operator ), anAsciiStr );
796   SetToUpdate( true );
797 }
798
799 QString HYDROData_Image::OperatorName() const
800 {
801   QString aRes;
802
803   TDF_Label aLabel = myLab.FindChild( DataTag_Operator, false );
804   if ( !aLabel.IsNull() )
805   {
806     Handle(TDataStd_AsciiString) anAsciiStr;
807     if ( aLabel.FindAttribute( TDataStd_AsciiString::GetID(), anAsciiStr ) )
808       aRes = QString( anAsciiStr->Get().ToCString() );
809   }
810
811   return aRes;
812 }
813
814 void HYDROData_Image::SetArgs(const QByteArray& theArgs)
815 {
816   SaveByteArray(DataTag_Operator, theArgs.constData(), theArgs.length());
817   SetToUpdate( true );
818 }
819
820 QByteArray HYDROData_Image::Args() const
821 {
822   int aLen = 0;
823   const char* aData = ByteArray(DataTag_Operator, aLen);
824   if (!aLen)
825     return QByteArray();
826   return QByteArray(aData, aLen);
827 }
828
829 void HYDROData_Image::SetIsSelfSplitted(bool theFlag)
830 {
831   if (theFlag) {
832     TDataStd_UAttribute::Set(myLab, GUID_SELF_SPLITTED);
833   } else {
834     myLab.ForgetAttribute(GUID_SELF_SPLITTED);
835   }
836   SetToUpdate( true );
837 }
838
839 bool HYDROData_Image::IsSelfSplitted() const
840 {
841   return myLab.IsAttribute(GUID_SELF_SPLITTED);
842 }
843
844 QPointF HYDROData_Image::generateThirdPoint( const QPointF& thePointA,
845                                              const QPointF& thePointB,
846                                              const bool&    theIsLocal ) const
847 {
848   // Rotate vector to 90 degrees : clockwise - for local
849   //                               counterclockwise - for global
850   const double aTheta = theIsLocal ? -M_PI_2 : M_PI_2;
851
852   QPointF aResPoint;
853
854   // Move to (0,0) for correct rotation
855   double x = thePointB.x() - thePointA.x();
856   double y = thePointB.y() - thePointA.y();
857
858   aResPoint.setX( x * cos( aTheta ) - y * sin( aTheta ) );
859   aResPoint.setY( x * sin( aTheta ) + y * cos( aTheta ) );
860
861   // Move back to origin position
862   aResPoint.setX( aResPoint.x() + thePointA.x() );
863   aResPoint.setY( aResPoint.y() + thePointA.y() );
864
865   return aResPoint;
866 }
867