Salome HOME
5fe12bb06bb5eed219a510286f0fbee89d20b804
[modules/hydro.git] / src / HYDROData / HYDROData_Image.cxx
1
2 #include "HYDROData_Image.h"
3
4 #include "HYDROData_Iterator.h"
5 #include "HYDROOperations_Factory.h"
6 #include "HYDROData_Tool.h"
7
8 #include <TDataStd_RealArray.hxx>
9 #include <TDataStd_ByteArray.hxx>
10 #include <TDataStd_IntegerArray.hxx>
11 #include <TDataStd_ReferenceList.hxx>
12 #include <TDataStd_Name.hxx>
13 #include <TDataStd_UAttribute.hxx>
14 #include <TDataStd_AsciiString.hxx>
15 #include <TDF_ListIteratorOfLabelList.hxx>
16
17 #include <ImageComposer_Operator.h>
18 #include <ImageComposer_MetaTypes.h>
19
20 #include <QStringList>
21
22 static const Standard_GUID GUID_MUST_BE_UPDATED("80f2bb81-3873-4631-8ddd-940d2119f000");
23 static const Standard_GUID GUID_SELF_SPLITTED("997995aa-5c19-40bf-9a60-ab4b70ad04d8");
24
25 #define PYTHON_IMAGE_ID "KIND_IMAGE"
26
27 IMPLEMENT_STANDARD_HANDLE(HYDROData_Image, HYDROData_Object)
28 IMPLEMENT_STANDARD_RTTIEXT(HYDROData_Image, HYDROData_Object)
29
30 HYDROData_Image::HYDROData_Image()
31 {
32 }
33
34 HYDROData_Image::~HYDROData_Image()
35 {
36 }
37
38 QStringList HYDROData_Image::DumpToPython( MapOfTreatedObjects& theTreatedObjects ) const
39 {
40   QStringList aResList;
41
42   Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( this );
43   if ( aDocument.IsNull() )
44     return aResList;
45                              
46   QString aDocName = aDocument->GetDocPyName();
47   QString anImageName = GetName();
48
49   aResList << QString( "%1 = %2.CreateObject( %3 );" )
50               .arg( anImageName ).arg( aDocName ).arg( PYTHON_IMAGE_ID );
51   aResList << QString( "%1.SetName( \"%2\" );" )
52               .arg( anImageName ).arg( anImageName );
53
54   QString aFilePath = GetFilePath();
55   if ( !aFilePath.isEmpty() )
56   {
57     aResList << QString( "" );
58     aResList << QString( "%1.LoadImage( \"%2\" );" )
59                 .arg( anImageName ).arg( aFilePath );
60
61     // Dump transformation matrix for image
62     aResList << QString( "" );
63
64     QTransform aTrsf = Trsf();
65
66     aResList << QString( "trsf = QTransform( %1, %2, %3," )
67                 .arg( aTrsf.m11() ).arg( aTrsf.m12() ).arg( aTrsf.m13() );
68     aResList << QString( "                   %1, %2, %3," )
69                 .arg( aTrsf.m21() ).arg( aTrsf.m22() ).arg( aTrsf.m23() );
70     aResList << QString( "                   %1, %2, %3 );" )
71                 .arg( aTrsf.m31() ).arg( aTrsf.m32() ).arg( aTrsf.m33() );
72
73     aResList << QString( "%1.SetTrsf( trsf );" ).arg( anImageName );
74
75     // Dump transformation points for image
76     aResList << QString( "" );
77
78     QPoint aPointAIn,  aPointBIn,  aPointCIn;
79     QPointF aPointAOut, aPointBOut, aPointCOut;
80     TrsfPoints( aPointAIn,  aPointBIn,  aPointCIn,
81                 aPointAOut, aPointBOut, aPointCOut );
82
83     aResList << QString( "a_in = QPoint( %1, %2 );" )
84                 .arg( aPointAIn.x() ).arg( aPointAIn.y() );
85
86     aResList << QString( "b_in = QPoint( %1, %2 );" )
87                 .arg( aPointBIn.x() ).arg( aPointBIn.y() );
88
89     aResList << QString( "c_in = QPoint( %1, %2 );" )
90                 .arg( aPointCIn.x() ).arg( aPointCIn.y() );
91
92     aResList << QString( "a_out = QPointF( %1, %2 );" )
93                 .arg( aPointAOut.x() ).arg( aPointAOut.y() );
94
95     aResList << QString( "b_out = QPointF( %1, %2 );" )
96                 .arg( aPointBOut.x() ).arg( aPointBOut.y() );
97
98     aResList << QString( "c_out = QPointF( %1, %2 );" )
99                 .arg( aPointCOut.x() ).arg( aPointCOut.y() );
100
101     QString aGap = QString().fill( ' ', anImageName.size() + 16 );
102     aResList << QString( "%1.SetTrsfPoints( a_in,  b_in,  c_in," ).arg( anImageName );
103     aResList << QString( aGap            + "a_out, b_out, c_out );" );
104   }
105   else
106   {
107     // Image is composed from other image(s)
108
109     QString anOperatorName = OperatorName();
110     if ( !anOperatorName.isEmpty() )
111     {
112       aResList << QString( "" );
113
114       aResList << QString( "%1.SetOperatorName( \"%2\" );" )
115                   .arg( anImageName ).arg( anOperatorName );
116
117       ImageComposer_Operator* anImageOp = HYDROOperations_Factory::Factory()->Operator( this );
118       if ( anImageOp )
119       {
120         // Dump operation arguments
121         QString anOpArgsArrayName;
122         QStringList anOpArgs = anImageOp->dumpArgsToPython( anOpArgsArrayName );
123         if ( !anOpArgs.isEmpty() )
124         {
125           aResList << QString( "" );
126           aResList << anOpArgs;
127
128           aResList << QString( "" );
129           aResList << QString( "%1.SetArgs( %2 );" )
130                       .arg( anImageName ).arg( anOpArgsArrayName );
131         }
132       }
133     }
134     
135     int aNbReferences = NbReferences();
136     if ( aNbReferences > 0 )
137     {
138       aResList << QString( "" );
139
140       for ( int i = 0; i < aNbReferences; ++i )
141       {
142         Handle(HYDROData_Image) aRefImg = Handle(HYDROData_Image)::DownCast( Reference( i ) );
143         if ( aRefImg.IsNull() )
144           continue;
145
146         QString aRefImgName = aRefImg->GetName();
147
148         // The definition of reference image must be dumped before this
149         if ( !theTreatedObjects.contains( aRefImgName ) )
150         {
151           // Write definition of reference image
152           QStringList aRefImgDump = aRefImg->DumpToPython( theTreatedObjects );
153           if ( aRefImgDump.isEmpty() )
154             continue;
155
156           QStringList aTmpList = aResList;
157           aResList = aRefImgDump;
158
159           aResList.append( "" );
160           aResList.append( aTmpList );
161
162           theTreatedObjects.insert( aRefImgName, aRefImg );
163         }
164
165         aResList << QString( "%1.AppendReference( %2 );" )
166                     .arg( anImageName ).arg( aRefImgName );
167       }
168     }
169
170     // Necessary to update image in case of composed operator
171     aResList << QString( "" );
172     aResList << QString( "%1.Update( False );" ).arg( anImageName );
173   }
174
175   return aResList;
176 }
177
178 void HYDROData_Image::Update( const bool theIsForce )
179 {
180   HYDROOperations_Factory* aFactory = HYDROOperations_Factory::Factory();
181
182   // Update image only if there is an operation
183   ImageComposer_Operator* anOp = aFactory->Operator( OperatorName() );
184   if ( anOp ) 
185   {
186     // Fill by arguments and process the operation
187     QVariant anObj1, anObj2;
188     int aNbReferences = NbReferences();
189
190     if ( aNbReferences > 0 )
191     {
192       // First referenced object
193       Handle(HYDROData_Object) aRefObj = Reference( 0 );
194       if ( !aRefObj.IsNull() )
195       {
196         anObj1 = aRefObj->GetDataVariant();
197         if ( !anObj1.isNull() && anObj1.canConvert<ImageComposer_Image>() )
198         {
199           ImageComposer_Image anImage = anObj1.value<ImageComposer_Image>();
200           QTransform aTransform = anImage.transform();
201           SetTrsf( aTransform );
202         }
203       }
204     }
205
206     if ( aNbReferences > 1 )
207     {
208       // Second referenced object
209       Handle(HYDROData_Object) aRefObj = Reference( 1 );
210       if ( !aRefObj.IsNull() )
211         anObj2 = aRefObj->GetDataVariant();
212     }
213
214     ImageComposer_Image aResImg = anOp->process( anObj1, anObj2 );
215     SetImage( aResImg );
216   }
217
218   if ( theIsForce )
219   {
220     Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( this );
221     if ( !aDocument.IsNull() )
222     {
223       // Change the states of this and all depended images
224       MustBeUpdated( true );
225       HYDROData_Tool::SetMustBeUpdatedImages( aDocument );
226       MustBeUpdated( false );
227     }
228   }
229 }
230
231 QVariant HYDROData_Image::GetDataVariant()
232 {
233   QTransform aTransform = Trsf();
234
235   ImageComposer_Image anImage = Image();
236   anImage.setTransform( aTransform );
237
238   QVariant aVarData;
239   aVarData.setValue<ImageComposer_Image>( anImage );
240   
241   return aVarData;
242 }
243
244 void HYDROData_Image::SetImage(const QImage& theImage)
245 {
246   if (theImage.isNull()) {
247     // for empty image remove all previously stored attributes
248     myLab.ForgetAttribute(TDataStd_IntegerArray::GetID());
249     myLab.ForgetAttribute(TDataStd_ByteArray::GetID());
250     return;
251   }
252   // store width, height, bytes per line and format in integer array 
253   Handle(TDataStd_IntegerArray) aParams;
254   if (!myLab.FindAttribute(TDataStd_IntegerArray::GetID(), aParams)) {
255     aParams = TDataStd_IntegerArray::Set(myLab, 1, 4);
256   }
257   aParams->SetValue(1, theImage.width());
258   aParams->SetValue(2, theImage.height());
259   aParams->SetValue(3, theImage.bytesPerLine());
260   aParams->SetValue(4, (int)(theImage.format()));
261   // store data of image in byte array
262   const char* aData = (const char*)(theImage.bits());
263   SaveByteArray(0, aData, theImage.byteCount());
264 }
265
266 bool HYDROData_Image::LoadImage(const QString& theFilePath)
267 {
268   QImage anImage( theFilePath );
269   SetImage( anImage );
270   return !anImage.isNull();
271 }
272
273 QImage HYDROData_Image::Image()
274 {
275   Handle(TDataStd_IntegerArray) aParams;
276   if (!myLab.FindAttribute(TDataStd_IntegerArray::GetID(), aParams))
277     return QImage(); // return empty image if there is no array
278   int aLen = 0;
279   uchar* anArray = (uchar*)ByteArray(0, aLen);
280   if (!aLen)
281     return QImage(); // return empty image if there is no array
282   QImage aResult(anArray, aParams->Value(1), aParams->Value(2),
283                  aParams->Value(3), QImage::Format(aParams->Value(4)));
284   return aResult;
285 }
286
287 void HYDROData_Image::SetFilePath(const QString& theFilePath)
288 {
289   TCollection_AsciiString anAsciiStr( theFilePath.toStdString().c_str() );
290   TDataStd_AsciiString::Set( myLab.FindChild( DataTag_FilePath ), anAsciiStr );
291 }
292
293 QString HYDROData_Image::GetFilePath() const
294 {
295   QString aRes;
296
297   Handle(TDataStd_AsciiString) anAsciiStr;
298   if ( myLab.FindChild( DataTag_FilePath ).FindAttribute( TDataStd_AsciiString::GetID(), anAsciiStr ) )
299     aRes = QString( anAsciiStr->Get().ToCString() );
300
301   return aRes;
302 }
303
304 void HYDROData_Image::SetTrsf(const QTransform& theTrsf)
305 {
306   // locate 9 coeffs of matrix into the real array
307   Handle(TDataStd_RealArray) anArray;
308   if (!myLab.FindAttribute(TDataStd_RealArray::GetID(), anArray)) {
309     if (theTrsf.isIdentity()) return; // no need to store identity transformation
310     anArray = TDataStd_RealArray::Set(myLab, 1, 9);
311   }
312   anArray->SetValue(1, theTrsf.m11());
313   anArray->SetValue(2, theTrsf.m12());
314   anArray->SetValue(3, theTrsf.m13());
315   anArray->SetValue(4, theTrsf.m21());
316   anArray->SetValue(5, theTrsf.m22());
317   anArray->SetValue(6, theTrsf.m23());
318   anArray->SetValue(7, theTrsf.m31());
319   anArray->SetValue(8, theTrsf.m32());
320   anArray->SetValue(9, theTrsf.m33());
321 }
322
323 QTransform HYDROData_Image::Trsf() const
324 {
325   // get 9 coeffs of matrix from the real array
326   Handle(TDataStd_RealArray) anArray;
327   if (!myLab.FindAttribute(TDataStd_RealArray::GetID(), anArray))
328     return QTransform(); // return identity if there is no array
329   QTransform aTrsf(
330     anArray->Value(1), anArray->Value(2), anArray->Value(3), 
331     anArray->Value(4), anArray->Value(5), anArray->Value(6), 
332     anArray->Value(7), anArray->Value(8), anArray->Value(9));
333   return aTrsf;
334 }
335
336 void HYDROData_Image::SetTrsfPoints(const QPoint& thePointAIn,
337                                     const QPoint& thePointBIn,
338                                     const QPoint& thePointCIn,
339                                     const QPointF& thePointAOut,
340                                     const QPointF& thePointBOut,
341                                     const QPointF& thePointCOut)
342 {
343   Handle(TDataStd_RealArray) anArray;
344   if (!myLab.FindChild(DataTag_TrsfPoints).FindAttribute(TDataStd_RealArray::GetID(), anArray)) {
345     anArray = TDataStd_RealArray::Set(myLab.FindChild(DataTag_TrsfPoints), 1, 12);
346   }
347   anArray->SetValue(1, thePointAIn.x());
348   anArray->SetValue(2, thePointAIn.y());
349   anArray->SetValue(3, thePointBIn.x());
350   anArray->SetValue(4, thePointBIn.y());
351   anArray->SetValue(5, thePointCIn.x());
352   anArray->SetValue(6, thePointCIn.y());
353   anArray->SetValue(7, thePointAOut.x());
354   anArray->SetValue(8, thePointAOut.y());
355   anArray->SetValue(9, thePointBOut.x());
356   anArray->SetValue(10, thePointBOut.y());
357   anArray->SetValue(11, thePointCOut.x());
358   anArray->SetValue(12, thePointCOut.y());
359 }
360
361 void HYDROData_Image::TrsfPoints(QPoint& thePointAIn,
362                                  QPoint& thePointBIn,
363                                  QPoint& thePointCIn,
364                                  QPointF& thePointAOut,
365                                  QPointF& thePointBOut,
366                                  QPointF& thePointCOut) const
367 {
368   Handle(TDataStd_RealArray) anArray;
369   if (myLab.FindChild(DataTag_TrsfPoints).FindAttribute(TDataStd_RealArray::GetID(), anArray)) {
370     thePointAIn = QPointF( anArray->Value(1), anArray->Value(2) ).toPoint();
371     thePointBIn = QPointF( anArray->Value(3), anArray->Value(4) ).toPoint();
372     thePointCIn = QPointF( anArray->Value(5), anArray->Value(6) ).toPoint();
373     thePointAOut = QPointF( anArray->Value(7), anArray->Value(8) );
374     thePointBOut = QPointF( anArray->Value(9), anArray->Value(10) );
375     thePointCOut = QPointF( anArray->Value(11), anArray->Value(12) );
376   }
377 }
378
379 bool HYDROData_Image::HasTrsfPoints() const
380 {
381   Handle(TDataStd_RealArray) anArray;
382   return myLab.FindChild(DataTag_TrsfPoints).FindAttribute(TDataStd_RealArray::GetID(), anArray);
383 }
384
385 void HYDROData_Image::AppendReference(Handle(HYDROData_Object) theReferenced)
386 {
387   Handle(TDataStd_ReferenceList) aRefs;
388   if (!myLab.FindAttribute(TDataStd_ReferenceList::GetID(), aRefs))
389     aRefs = TDataStd_ReferenceList::Set(myLab);
390   aRefs->Append(theReferenced->Label());
391 }
392
393 int HYDROData_Image::NbReferences() const
394 {
395   Handle(TDataStd_ReferenceList) aRefs;
396   if (!myLab.FindAttribute(TDataStd_ReferenceList::GetID(), aRefs))
397     return 0;
398   return aRefs->Extent();
399 }
400
401 Handle(HYDROData_Object) HYDROData_Image::Reference(const int theIndex) const
402 {
403   Handle(TDataStd_ReferenceList) aRefs;
404   if (!myLab.FindAttribute(TDataStd_ReferenceList::GetID(), aRefs))
405     return Handle(HYDROData_Object)();
406   if (theIndex < 0 || theIndex >= aRefs->Extent())
407     return Handle(HYDROData_Object)();
408
409   TDF_ListIteratorOfLabelList anIter(aRefs->List());
410   for(int anIndex = 0; anIndex != theIndex; anIter.Next(), anIndex++);
411   const TDF_Label& aRefLab = anIter.Value();
412   return Handle(HYDROData_Object)::DownCast(HYDROData_Iterator::Object(aRefLab));
413 }
414
415 void HYDROData_Image::ChangeReference(
416     const int theIndex, Handle(HYDROData_Object) theReferenced)
417 {
418   Handle(TDataStd_ReferenceList) aRefs;
419   if (!myLab.FindAttribute(TDataStd_ReferenceList::GetID(), aRefs))
420     aRefs = TDataStd_ReferenceList::Set(myLab);
421   if (theIndex >= aRefs->Extent()) { // for too big index append it just to the end
422     AppendReference(theReferenced);
423   } else { // remove and insert new
424     TDF_ListIteratorOfLabelList anIter(aRefs->List());
425     int anIndex = 0;
426     for(; anIndex != theIndex; anIter.Next(), anIndex++);
427     const TDF_Label& aRemovedLab = anIter.Value();
428     anIter.Next();
429     aRefs->Remove(aRemovedLab);
430     if (anIter.More()) 
431       aRefs->InsertBefore(theReferenced->Label(), anIter.Value());
432     else 
433       aRefs->Append(theReferenced->Label());
434   }
435 }
436
437 void HYDROData_Image::RemoveReference(const int theIndex)
438 {
439   Handle(TDataStd_ReferenceList) aRefs;
440   if (!myLab.FindAttribute(TDataStd_ReferenceList::GetID(), aRefs))
441     return; // no references, nothing to remove
442   if (aRefs->Extent() == 1 && theIndex == 0) { // remove all if only one
443     ClearReferences();
444     return;
445   }
446   TDF_ListIteratorOfLabelList anIter(aRefs->List());
447   int anIndex = 0;
448   for(; anIndex != theIndex && anIter.More(); anIter.Next(), anIndex++);
449   if (anIter.More())
450     aRefs->Remove(anIter.Value());
451 }
452
453 void HYDROData_Image::ClearReferences()
454 {
455   myLab.ForgetAttribute(TDataStd_ReferenceList::GetID());
456 }
457
458 void HYDROData_Image::SetOperatorName(const QString theOpName)
459 {
460   TDataStd_Name::Set(myLab.FindChild(DataTag_Operator),
461     TCollection_ExtendedString(theOpName.toLatin1().constData()));
462 }
463
464 QString HYDROData_Image::OperatorName() const
465 {
466   Handle(TDataStd_Name) aName;
467   if (myLab.FindChild(DataTag_Operator).
468         FindAttribute(TDataStd_Name::GetID(), aName)) {
469     TCollection_AsciiString aStr(aName->Get());
470     return QString(aStr.ToCString());
471   }
472   return QString();
473 }
474
475 void HYDROData_Image::SetArgs(const QByteArray& theArgs)
476 {
477   SaveByteArray(DataTag_Operator, theArgs.constData(), theArgs.length());
478 }
479
480 QByteArray HYDROData_Image::Args() const
481 {
482   int aLen = 0;
483   const char* aData = ByteArray(DataTag_Operator, aLen);
484   if (!aLen)
485     return QByteArray();
486   return QByteArray(aData, aLen);
487 }
488
489 void HYDROData_Image::MustBeUpdated(bool theFlag)
490 {
491   if (theFlag) {
492     TDataStd_UAttribute::Set(myLab, GUID_MUST_BE_UPDATED);
493   } else {
494     myLab.ForgetAttribute(GUID_MUST_BE_UPDATED);
495   }
496 }
497
498 bool HYDROData_Image::MustBeUpdated() const
499 {
500   return myLab.IsAttribute(GUID_MUST_BE_UPDATED);
501 }
502
503 void HYDROData_Image::SetIsSelfSplitted(bool theFlag)
504 {
505   if (theFlag) {
506     TDataStd_UAttribute::Set(myLab, GUID_SELF_SPLITTED);
507   } else {
508     myLab.ForgetAttribute(GUID_SELF_SPLITTED);
509   }
510 }
511
512 bool HYDROData_Image::IsSelfSplitted() const
513 {
514   return myLab.IsAttribute(GUID_SELF_SPLITTED);
515 }