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