Salome HOME
Fix for the bug #37: Error when import image with format not supported.
[modules/hydro.git] / src / HYDROGUI / HYDROGUI_Shape.cxx
1 // Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 #include "HYDROGUI_Shape.h"
24
25 #include "HYDROGUI_DataObject.h"
26 #include "HYDROGUI_Tool.h"
27
28 #include <AIS_Drawer.hxx>
29
30 #include <BRepBuilderAPI_MakeEdge.hxx>
31 #include <BRepBuilderAPI_MakeWire.hxx>
32 #include <BRepBuilderAPI_MakeFace.hxx>
33
34 #include <gp_Pnt.hxx>
35
36 #include <Graphic3d_AspectFillArea3d.hxx>
37 #include <Graphic3d_MaterialAspect.hxx>
38
39 #include <HYDROData_Document.h>
40 #include <HYDROData_Image.h>
41 #include <HYDROData_ImmersibleZone.h>
42 #include <HYDROData_Polyline.h>
43 #include <HYDROData_Region.h>
44 #include <HYDROData_Zone.h>
45
46 #include <TopoDS.hxx>
47 #include <TopoDS_Wire.hxx>
48 #include <TopoDS_Face.hxx>
49
50 #include <Precision.hxx>
51
52 #include <Prs3d_ShadingAspect.hxx>
53 #include <Prs3d_LineAspect.hxx>
54 #include <Prs3d_IsoAspect.hxx>
55
56 #include <QColor>
57 #include <QFile>
58
59 HYDROGUI_Shape::HYDROGUI_Shape( const Handle(AIS_InteractiveContext)& theContext,
60                                 const Handle(HYDROData_Entity)&       theObject )
61 : myContext( theContext ),
62   myObject( theObject ),
63   myIsHighlight( false ),
64   myFillingColor( Qt::transparent ),
65   myBorderColor( Qt::black ),
66   myHighlightColor( Qt::white ),
67   myIsToUpdate( false ),
68   myIsVisible( true ),
69   myDisplayMode( AIS_WireFrame )
70 {
71 }
72
73 HYDROGUI_Shape::~HYDROGUI_Shape()
74 {
75   erase();
76
77   if ( !myShape.IsNull() )
78     myShape.Nullify();
79
80   removeTextureFile();
81 }
82
83 void HYDROGUI_Shape::display( const bool theIsUpdateViewer )
84 {
85   if ( myContext.IsNull() || myShape.IsNull() || !isVisible() )
86     return;
87
88   myContext->Display( myShape, theIsUpdateViewer );
89 }
90
91 void HYDROGUI_Shape::erase( const bool theIsUpdateViewer )
92 {
93   if ( myContext.IsNull() || myShape.IsNull() )
94     return;
95
96   myContext->Erase( myShape, theIsUpdateViewer );
97 }
98
99 void HYDROGUI_Shape::update( const bool theIsUpdateViewer )
100 {
101   setIsToUpdate( false );
102
103   if ( myContext.IsNull() )
104     return;
105
106   // Try to retrieve information from object
107   if ( !myObject.IsNull() )
108   {
109     Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( myObject->Label() );
110   
111     if ( myObject->IsKind( STANDARD_TYPE(HYDROData_ImmersibleZone) ) )
112     {
113       Handle(HYDROData_ImmersibleZone) aZoneObj =
114         Handle(HYDROData_ImmersibleZone)::DownCast( myObject );
115
116       QColor aFillingColor = aZoneObj->GetFillingColor();
117       QColor aBorderColor = aZoneObj->GetBorderColor();
118       TopoDS_Face aZoneFace = TopoDS::Face( aZoneObj->GetTopShape() );
119
120       setFillingColor( aFillingColor, false, false );
121       setBorderColor( aBorderColor, false, false );
122       setFace( aZoneFace, false, false );
123     }
124     else if ( myObject->IsKind( STANDARD_TYPE(HYDROData_Polyline) ) )
125     {
126       Handle(HYDROData_Polyline) aPolyline =
127         Handle(HYDROData_Polyline)::DownCast( myObject );
128
129       TopoDS_Wire aPolylineWire = TopoDS::Wire( aPolyline->GetTopShape() );
130
131       setWire( aPolylineWire, false, false );
132     }
133     else if ( myObject->IsKind( STANDARD_TYPE(HYDROData_Region) ) )
134     {
135       Handle(HYDROData_Region) aRegion =
136         Handle(HYDROData_Region)::DownCast( myObject );
137     }
138     else if ( myObject->IsKind( STANDARD_TYPE(HYDROData_Zone) ) )
139     {
140       Handle(HYDROData_Zone) aZone =
141         Handle(HYDROData_Zone)::DownCast( myObject );
142
143       TopoDS_Face aZoneFace = TopoDS::Face( aZone->GetShape() );
144
145       // Generate the filling color for zone
146       QStringList aGeomObjectsNames;
147
148       HYDROData_SequenceOfObjects aRefObjects = aZone->GetGeometryObjects();
149       HYDROData_SequenceOfObjects::Iterator anIter( aRefObjects );
150       for ( ; anIter.More(); anIter.Next() )
151       {
152         Handle(HYDROData_Object) aRefbject = 
153           Handle(HYDROData_Object)::DownCast( anIter.Value() );
154         if ( aRefbject.IsNull() )
155           continue;
156
157         QString aRefObjectName = aRefbject->GetName();
158         if ( aRefObjectName.isEmpty() )
159           continue;
160
161         aGeomObjectsNames.append( aRefObjectName );
162       }
163        
164       setFace( aZoneFace, false, false );
165       if (aZone->IsMergingNeed() && aZone->GetMergeType() == HYDROData_Zone::Merge_UNKNOWN )
166       {
167         // Red color for a zone with bathymetry conflict
168         setFillingColor( Qt::red );
169       }
170       else
171       {
172         setFillingColor( HYDROGUI_Tool::GenerateFillingColor( aDocument, aGeomObjectsNames ) );
173       }
174     }
175     else if ( myObject->IsKind( STANDARD_TYPE(HYDROData_Image) ) )
176     {
177       Handle(HYDROData_Image) anImageObj =
178         Handle(HYDROData_Image)::DownCast( myObject );
179
180       removeTextureFile();
181
182       QString aTextureFileName = generateTextureFileName( anImageObj );
183
184       QImage anImage = anImageObj->Image();
185       QString aFilePath = anImageObj->GetFilePath();
186       QTransform aTrsf = anImageObj->Trsf();
187
188       int aWidth = anImage.width();
189       int aHeight = anImage.height();
190
191       QTransform anInversion = QTransform::fromScale( -1, -1 );
192       anImage = anImage.transformed( anInversion * aTrsf, Qt::SmoothTransformation );
193
194       // temporary optimization, to reduce the saved image size (and the texture quality)
195       QImage anImageToSave = reduceTexture( anImage, 500 );
196       anImageToSave.save( aTextureFileName );
197
198       QPointF aPoint1( 0, 0 );
199       QPointF aPoint2( aWidth, 0 );
200       QPointF aPoint3( aWidth, aHeight );
201       QPointF aPoint4( 0, aHeight );
202
203       aPoint1 = aTrsf.map( aPoint1 );
204       aPoint2 = aTrsf.map( aPoint2 );
205       aPoint3 = aTrsf.map( aPoint3 );
206       aPoint4 = aTrsf.map( aPoint4 );
207
208       QPolygonF aPolygon = QPolygonF() << aPoint1 << aPoint2 << aPoint3 << aPoint4;
209       QRectF aRect = aPolygon.boundingRect();
210
211       gp_Pnt aPnt1( aRect.topLeft().x(), aRect.topLeft().y(), 0 );
212       gp_Pnt aPnt2( aRect.topRight().x(), aRect.topRight().y(), 0 );
213       gp_Pnt aPnt3( aRect.bottomRight().x(), aRect.bottomRight().y(), 0 );
214       gp_Pnt aPnt4( aRect.bottomLeft().x(), aRect.bottomLeft().y(), 0 );
215
216       TopoDS_Edge anEdge1 = BRepBuilderAPI_MakeEdge( aPnt1, aPnt2 ).Edge();
217       TopoDS_Edge anEdge2 = BRepBuilderAPI_MakeEdge( aPnt2, aPnt3 ).Edge();
218       TopoDS_Edge anEdge3 = BRepBuilderAPI_MakeEdge( aPnt3, aPnt4 ).Edge();
219       TopoDS_Edge anEdge4 = BRepBuilderAPI_MakeEdge( aPnt4, aPnt1 ).Edge();
220
221       TopoDS_Wire aWire = BRepBuilderAPI_MakeWire( anEdge1, anEdge2, anEdge3, anEdge4 ).Wire();
222
223       setTextureFileName( aTextureFileName, false, false );
224       setFace( aWire, false, false );
225     }
226   }
227
228   if ( myShape.IsNull() || !isVisible() )
229     return;
230
231   myContext->Display( myShape, theIsUpdateViewer );
232 }
233
234 void HYDROGUI_Shape::setVisible( const bool theState,
235                                  const bool theIsUpdateViewer )
236 {
237   if ( myIsVisible == theState )
238     return;
239
240   myIsVisible = theState;
241
242   if ( myShape.IsNull() )
243     return;
244
245   if ( myIsVisible )
246     myContext->Display( myShape, theIsUpdateViewer );
247   else
248     myContext->Erase( myShape, theIsUpdateViewer );
249 }
250
251 void HYDROGUI_Shape::highlight( bool theIsHighlight )
252 {
253   if ( myIsHighlight == theIsHighlight )
254     return;
255
256   myIsHighlight = theIsHighlight;
257
258   if ( myContext.IsNull() || myShape.IsNull() )
259     return;
260
261   colorShapeBorder( getActiveColor() );
262   myContext->Display( myShape );
263 }
264
265 bool HYDROGUI_Shape::isHighlighted() const
266 {
267   return myIsHighlight;
268 }
269
270 void HYDROGUI_Shape::setWire( const TopoDS_Wire& theWire,
271                               const bool         theToDisplay,
272                               const bool         theIsUpdateViewer )
273 {
274   myTopoShape = theWire;
275   myDisplayMode = AIS_WireFrame;
276
277   buildShape();
278   updateShape( theToDisplay, theIsUpdateViewer );
279 }
280
281 void HYDROGUI_Shape::setFace( const TopoDS_Wire& theWire,
282                               const bool         theToDisplay,
283                               const bool         theIsUpdateViewer )
284 {
285   BRepBuilderAPI_MakeFace aFaceBuilder( theWire, Standard_True );
286   aFaceBuilder.Build();
287   if( aFaceBuilder.IsDone() )
288   {
289     TopoDS_Face aFace = aFaceBuilder.Face();
290     setFace( aFace, theToDisplay, theIsUpdateViewer );
291   }
292 }
293
294 void HYDROGUI_Shape::setFace( const TopoDS_Face& theFace,
295                               const bool         theToDisplay,
296                               const bool         theIsUpdateViewer )
297 {
298   myTopoShape = theFace;
299   myDisplayMode = myTextureFileName.isEmpty() ? AIS_Shaded : AIS_ExactHLR;
300
301   buildShape();
302   updateShape( theToDisplay, theIsUpdateViewer );
303 }
304
305 void HYDROGUI_Shape::setFillingColor( const QColor& theColor,
306                                       const bool    theToDisplay,
307                                       const bool    theIsUpdateViewer )
308 {
309   myFillingColor = theColor;
310   updateShape( theToDisplay, theIsUpdateViewer );
311 }
312
313 QColor HYDROGUI_Shape::getFillingColor() const
314 {
315   return myFillingColor;
316 }
317
318 void HYDROGUI_Shape::setBorderColor( const QColor& theColor,
319                                      const bool    theToDisplay,
320                                      const bool    theIsUpdateViewer )
321 {
322   myBorderColor = theColor;
323   updateShape( theToDisplay, theIsUpdateViewer );
324 }
325
326 QColor HYDROGUI_Shape::getBorderColor() const
327 {
328   return myBorderColor;
329 }
330
331 void HYDROGUI_Shape::setHighlightColor( const QColor& theColor )
332 {
333   myHighlightColor = theColor;
334 }
335
336 QColor HYDROGUI_Shape::getHighlightColor() const
337 {
338   return myHighlightColor;
339 }
340
341 void HYDROGUI_Shape::setTextureFileName( const QString& theFileName,
342                                          const bool     theToDisplay,
343                                          const bool     theIsUpdateViewer )
344 {
345   myTextureFileName = theFileName;
346   updateShape( theToDisplay, theIsUpdateViewer );
347 }
348
349 QString HYDROGUI_Shape::getTextureFileName() const
350 {
351   return myTextureFileName;
352 }
353
354 void HYDROGUI_Shape::buildShape()
355 {
356   // Erase previously created shape
357   erase();
358
359   if ( myTopoShape.IsNull() )
360     return;
361
362   myShape = new AIS_TexturedShape( myTopoShape );
363
364   if ( !myObject.IsNull() )
365     myShape->SetOwner( myObject );
366
367   myShape->SetTransparency( 0 );
368   myShape->SetDisplayMode( (AIS_DisplayMode)myDisplayMode );
369
370   QString aTextureFileName = getTextureFileName();
371   if( !aTextureFileName.isEmpty() )
372   {
373     myShape->SetTextureFileName( HYDROGUI_Tool::ToAsciiString( aTextureFileName ) );
374     myShape->SetTextureMapOn();
375     myShape->DisableTextureModulate();
376   }
377
378     // Init default params for shape
379   const Handle(AIS_Drawer)& anAttributes = myShape->Attributes();
380   if ( !anAttributes.IsNull() )
381   {
382     if ( myDisplayMode == AIS_Shaded )
383     {
384       Handle(Prs3d_IsoAspect) anIsoAspect = anAttributes->UIsoAspect();
385       if ( !anIsoAspect.IsNull() )
386         anIsoAspect->SetNumber( 0 );
387       
388       anIsoAspect = anAttributes->VIsoAspect();
389       if ( !anIsoAspect.IsNull() )
390         anIsoAspect->SetNumber( 0 );
391
392       Handle(Prs3d_ShadingAspect) aShadingAspect = anAttributes->ShadingAspect();
393       if ( !aShadingAspect.IsNull() )
394       {
395         Graphic3d_MaterialAspect aMatAspect;
396         aMatAspect.SetAmbient( 1 );
397         aMatAspect.SetDiffuse( 0 );
398
399         aShadingAspect->Aspect()->SetFrontMaterial( aMatAspect );
400         aShadingAspect->Aspect()->SetBackMaterial( aMatAspect );
401       }
402     }
403     else if ( myDisplayMode == AIS_WireFrame )
404     {
405       anAttributes->SetWireDraw( true );
406     }
407   }
408 }
409
410 void HYDROGUI_Shape::updateShape( const bool theToDisplay,
411                                   const bool theIsUpdateViewer )
412 {
413   if ( myShape.IsNull() )
414     return;
415
416   const Handle(AIS_Drawer)& anAttributes = myShape->Attributes();
417   if ( !anAttributes.IsNull() )
418   {
419     if ( myDisplayMode == AIS_Shaded )
420     {
421       // Coloring face filling
422       Handle(Prs3d_ShadingAspect) aShadingAspect = anAttributes->ShadingAspect();
423       if ( !aShadingAspect.IsNull() )
424       {
425         Quantity_Color aFillingColor( getQuantityColorVal( myFillingColor.red() ), 
426                                       getQuantityColorVal( myFillingColor.green() ),
427                                       getQuantityColorVal( myFillingColor.blue() ),
428                                       Quantity_TOC_RGB );
429
430         aShadingAspect->SetColor( aFillingColor );
431         aShadingAspect->SetTransparency( 1 - getQuantityColorVal( myFillingColor.alpha() ) );
432       }
433     }
434     else if ( myDisplayMode == AIS_WireFrame )
435     {
436     }
437
438     // Coloring borders
439     colorShapeBorder( getActiveColor() );
440   }
441
442   if ( !theToDisplay || !isVisible() || myContext.IsNull() )
443     return;
444   
445   myContext->Display( myShape, theIsUpdateViewer );
446 }
447
448 QColor HYDROGUI_Shape::getActiveColor() const
449 {
450   return isHighlighted() ? myHighlightColor : myBorderColor;
451 }
452
453 double HYDROGUI_Shape::getQuantityColorVal( const int theColorVal )
454 {
455   return theColorVal == 0 ? 0 : ( (double)theColorVal / 255 );
456 }
457
458 void HYDROGUI_Shape::colorShapeBorder( const QColor& theColor )
459 {
460   if ( myShape.IsNull() )
461     return;
462
463   const Handle(AIS_Drawer)& anAttributes = myShape->Attributes();
464   if ( anAttributes.IsNull() )
465     return;
466
467   Quantity_Color aBorderColor( getQuantityColorVal( theColor.red() ), 
468                                getQuantityColorVal( theColor.green() ),
469                                getQuantityColorVal( theColor.blue() ),
470                                Quantity_TOC_RGB );
471   if ( myDisplayMode == AIS_Shaded )
472   {
473     if ( theColor.alpha() == 0 )
474     {
475       anAttributes->SetFaceBoundaryDraw( false );
476     }
477     else
478     {
479       anAttributes->SetFaceBoundaryDraw( true );
480
481       Handle(Prs3d_LineAspect) aBoundaryAspect = anAttributes->FaceBoundaryAspect();
482       if ( !aBoundaryAspect.IsNull() )
483         aBoundaryAspect->SetColor( aBorderColor );
484     }
485   }
486   else if ( myDisplayMode == AIS_WireFrame )
487   {
488     myShape->SetColor( aBorderColor );
489   }
490 }
491
492 QString HYDROGUI_Shape::generateTextureFileName( const Handle(HYDROData_Entity)& theImageObj )
493 {
494   QString aResult;
495   if( !theImageObj.IsNull() )
496   {
497     QString aTempDir = HYDROGUI_Tool::GetTempDir( true );
498
499     int aStudyId = HYDROGUI_Tool::GetActiveStudyId();
500     QString aPrefix = QString( "image_%1" ).arg( aStudyId );
501
502     QString anEntry = HYDROGUI_DataObject::dataObjectEntry( theImageObj, false );
503     anEntry.replace( ':', '_' );
504
505     QString anExtension = "bmp";
506
507     aResult = QString( "%1/%2_%3.%4" ).arg( aTempDir, aPrefix, anEntry, anExtension );
508   }
509   return aResult;
510 }
511
512 void HYDROGUI_Shape::removeTextureFile() const
513 {
514   QFile aFile( getTextureFileName() );
515   if( aFile.exists() )
516     aFile.remove();
517 }
518
519 QImage HYDROGUI_Shape::reduceTexture( const QImage& theImage, const int theSizeLimit )
520 {
521   double aSizeLimit = (double)theSizeLimit;
522   double aWidth = (double)theImage.width();
523   double aHeight = (double)theImage.height();
524   if( aWidth > aSizeLimit || aHeight > aSizeLimit )
525   {
526     if( aWidth > aHeight )
527     {
528       aHeight /= ( aWidth / aSizeLimit );
529       aWidth = aSizeLimit;
530     }
531     else
532     {
533       aWidth /= ( aHeight / aSizeLimit );
534       aHeight = aSizeLimit;
535     }
536   }
537   return theImage.scaled( aWidth, aHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation );
538 }