Salome HOME
Minor change.
[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       setFillingColor( HYDROGUI_Tool::GenerateFillingColor( aDocument, aGeomObjectsNames ) );
166     }
167     else if ( myObject->IsKind( STANDARD_TYPE(HYDROData_Image) ) )
168     {
169       Handle(HYDROData_Image) anImageObj =
170         Handle(HYDROData_Image)::DownCast( myObject );
171
172       removeTextureFile();
173
174       QString aTextureFileName = generateTextureFileName( anImageObj );
175
176       QImage anImage = anImageObj->Image();
177       QString aFilePath = anImageObj->GetFilePath();
178       QTransform aTrsf = anImageObj->Trsf();
179
180       int aWidth = anImage.width();
181       int aHeight = anImage.height();
182
183       QTransform anInversion = QTransform::fromScale( -1, -1 );
184       anImage = anImage.transformed( anInversion * aTrsf, Qt::SmoothTransformation );
185
186       // temporary optimization, to reduce the saved image size (and the texture quality)
187       QImage anImageToSave = reduceTexture( anImage, 500 );
188       anImageToSave.save( aTextureFileName );
189
190       QPointF aPoint1( 0, 0 );
191       QPointF aPoint2( aWidth, 0 );
192       QPointF aPoint3( aWidth, aHeight );
193       QPointF aPoint4( 0, aHeight );
194
195       aPoint1 = aTrsf.map( aPoint1 );
196       aPoint2 = aTrsf.map( aPoint2 );
197       aPoint3 = aTrsf.map( aPoint3 );
198       aPoint4 = aTrsf.map( aPoint4 );
199
200       QPolygonF aPolygon = QPolygonF() << aPoint1 << aPoint2 << aPoint3 << aPoint4;
201       QRectF aRect = aPolygon.boundingRect();
202
203       gp_Pnt aPnt1( aRect.topLeft().x(), aRect.topLeft().y(), 0 );
204       gp_Pnt aPnt2( aRect.topRight().x(), aRect.topRight().y(), 0 );
205       gp_Pnt aPnt3( aRect.bottomRight().x(), aRect.bottomRight().y(), 0 );
206       gp_Pnt aPnt4( aRect.bottomLeft().x(), aRect.bottomLeft().y(), 0 );
207
208       TopoDS_Edge anEdge1 = BRepBuilderAPI_MakeEdge( aPnt1, aPnt2 ).Edge();
209       TopoDS_Edge anEdge2 = BRepBuilderAPI_MakeEdge( aPnt2, aPnt3 ).Edge();
210       TopoDS_Edge anEdge3 = BRepBuilderAPI_MakeEdge( aPnt3, aPnt4 ).Edge();
211       TopoDS_Edge anEdge4 = BRepBuilderAPI_MakeEdge( aPnt4, aPnt1 ).Edge();
212
213       TopoDS_Wire aWire = BRepBuilderAPI_MakeWire( anEdge1, anEdge2, anEdge3, anEdge4 ).Wire();
214
215       setTextureFileName( aTextureFileName, false, false );
216       setFace( aWire, false, false );
217     }
218   }
219
220   if ( myShape.IsNull() || !isVisible() )
221     return;
222
223   myContext->Display( myShape, theIsUpdateViewer );
224 }
225
226 void HYDROGUI_Shape::setVisible( const bool theState,
227                                  const bool theIsUpdateViewer )
228 {
229   if ( myIsVisible == theState )
230     return;
231
232   myIsVisible = theState;
233
234   if ( myShape.IsNull() )
235     return;
236
237   if ( myIsVisible )
238     myContext->Display( myShape, theIsUpdateViewer );
239   else
240     myContext->Erase( myShape, theIsUpdateViewer );
241 }
242
243 void HYDROGUI_Shape::highlight( bool theIsHighlight )
244 {
245   if ( myIsHighlight == theIsHighlight )
246     return;
247
248   myIsHighlight = theIsHighlight;
249
250   if ( myContext.IsNull() || myShape.IsNull() )
251     return;
252
253   colorShapeBorder( getActiveColor() );
254   myContext->Display( myShape );
255 }
256
257 bool HYDROGUI_Shape::isHighlighted() const
258 {
259   return myIsHighlight;
260 }
261
262 void HYDROGUI_Shape::setWire( const TopoDS_Wire& theWire,
263                               const bool         theToDisplay,
264                               const bool         theIsUpdateViewer )
265 {
266   myTopoShape = theWire;
267   myDisplayMode = AIS_WireFrame;
268
269   buildShape();
270   updateShape( theToDisplay, theIsUpdateViewer );
271 }
272
273 void HYDROGUI_Shape::setFace( const TopoDS_Wire& theWire,
274                               const bool         theToDisplay,
275                               const bool         theIsUpdateViewer )
276 {
277   BRepBuilderAPI_MakeFace aFaceBuilder( theWire, Standard_True );
278   aFaceBuilder.Build();
279   if( aFaceBuilder.IsDone() )
280   {
281     TopoDS_Face aFace = aFaceBuilder.Face();
282     setFace( aFace, theToDisplay, theIsUpdateViewer );
283   }
284 }
285
286 void HYDROGUI_Shape::setFace( const TopoDS_Face& theFace,
287                               const bool         theToDisplay,
288                               const bool         theIsUpdateViewer )
289 {
290   myTopoShape = theFace;
291   myDisplayMode = myTextureFileName.isEmpty() ? AIS_Shaded : AIS_ExactHLR;
292
293   buildShape();
294   updateShape( theToDisplay, theIsUpdateViewer );
295 }
296
297 void HYDROGUI_Shape::setFillingColor( const QColor& theColor,
298                                       const bool    theToDisplay,
299                                       const bool    theIsUpdateViewer )
300 {
301   myFillingColor = theColor;
302   updateShape( theToDisplay, theIsUpdateViewer );
303 }
304
305 QColor HYDROGUI_Shape::getFillingColor() const
306 {
307   return myFillingColor;
308 }
309
310 void HYDROGUI_Shape::setBorderColor( const QColor& theColor,
311                                      const bool    theToDisplay,
312                                      const bool    theIsUpdateViewer )
313 {
314   myBorderColor = theColor;
315   updateShape( theToDisplay, theIsUpdateViewer );
316 }
317
318 QColor HYDROGUI_Shape::getBorderColor() const
319 {
320   return myBorderColor;
321 }
322
323 void HYDROGUI_Shape::setHighlightColor( const QColor& theColor )
324 {
325   myHighlightColor = theColor;
326 }
327
328 QColor HYDROGUI_Shape::getHighlightColor() const
329 {
330   return myHighlightColor;
331 }
332
333 void HYDROGUI_Shape::setTextureFileName( const QString& theFileName,
334                                          const bool     theToDisplay,
335                                          const bool     theIsUpdateViewer )
336 {
337   myTextureFileName = theFileName;
338   updateShape( theToDisplay, theIsUpdateViewer );
339 }
340
341 QString HYDROGUI_Shape::getTextureFileName() const
342 {
343   return myTextureFileName;
344 }
345
346 void HYDROGUI_Shape::buildShape()
347 {
348   // Erase previously created shape
349   erase();
350
351   if ( myTopoShape.IsNull() )
352     return;
353
354   myShape = new AIS_TexturedShape( myTopoShape );
355
356   if ( !myObject.IsNull() )
357     myShape->SetOwner( myObject );
358
359   myShape->SetTransparency( 0 );
360   myShape->SetDisplayMode( (AIS_DisplayMode)myDisplayMode );
361
362   QString aTextureFileName = getTextureFileName();
363   if( !aTextureFileName.isEmpty() )
364   {
365     myShape->SetTextureFileName( HYDROGUI_Tool::ToAsciiString( aTextureFileName ) );
366     myShape->SetTextureMapOn();
367     myShape->DisableTextureModulate();
368   }
369
370     // Init default params for shape
371   const Handle(AIS_Drawer)& anAttributes = myShape->Attributes();
372   if ( !anAttributes.IsNull() )
373   {
374     if ( myDisplayMode == AIS_Shaded )
375     {
376       Handle(Prs3d_IsoAspect) anIsoAspect = anAttributes->UIsoAspect();
377       if ( !anIsoAspect.IsNull() )
378         anIsoAspect->SetNumber( 0 );
379       
380       anIsoAspect = anAttributes->VIsoAspect();
381       if ( !anIsoAspect.IsNull() )
382         anIsoAspect->SetNumber( 0 );
383
384       Handle(Prs3d_ShadingAspect) aShadingAspect = anAttributes->ShadingAspect();
385       if ( !aShadingAspect.IsNull() )
386       {
387         Graphic3d_MaterialAspect aMatAspect;
388         aMatAspect.SetAmbient( 1 );
389         aMatAspect.SetDiffuse( 0 );
390
391         aShadingAspect->Aspect()->SetFrontMaterial( aMatAspect );
392         aShadingAspect->Aspect()->SetBackMaterial( aMatAspect );
393       }
394     }
395     else if ( myDisplayMode == AIS_WireFrame )
396     {
397       anAttributes->SetWireDraw( true );
398     }
399   }
400 }
401
402 void HYDROGUI_Shape::updateShape( const bool theToDisplay,
403                                   const bool theIsUpdateViewer )
404 {
405   if ( myShape.IsNull() )
406     return;
407
408   const Handle(AIS_Drawer)& anAttributes = myShape->Attributes();
409   if ( !anAttributes.IsNull() )
410   {
411     if ( myDisplayMode == AIS_Shaded )
412     {
413       // Coloring face filling
414       Handle(Prs3d_ShadingAspect) aShadingAspect = anAttributes->ShadingAspect();
415       if ( !aShadingAspect.IsNull() )
416       {
417         Quantity_Color aFillingColor( getQuantityColorVal( myFillingColor.red() ), 
418                                       getQuantityColorVal( myFillingColor.green() ),
419                                       getQuantityColorVal( myFillingColor.blue() ),
420                                       Quantity_TOC_RGB );
421
422         aShadingAspect->SetColor( aFillingColor );
423         aShadingAspect->SetTransparency( 1 - getQuantityColorVal( myFillingColor.alpha() ) );
424       }
425     }
426     else if ( myDisplayMode == AIS_WireFrame )
427     {
428     }
429
430     // Coloring borders
431     colorShapeBorder( getActiveColor() );
432   }
433
434   if ( !theToDisplay || !isVisible() || myContext.IsNull() )
435     return;
436   
437   myContext->Display( myShape, theIsUpdateViewer );
438 }
439
440 QColor HYDROGUI_Shape::getActiveColor() const
441 {
442   return isHighlighted() ? myHighlightColor : myBorderColor;
443 }
444
445 double HYDROGUI_Shape::getQuantityColorVal( const int theColorVal )
446 {
447   return theColorVal == 0 ? 0 : ( (double)theColorVal / 255 );
448 }
449
450 void HYDROGUI_Shape::colorShapeBorder( const QColor& theColor )
451 {
452   if ( myShape.IsNull() )
453     return;
454
455   const Handle(AIS_Drawer)& anAttributes = myShape->Attributes();
456   if ( anAttributes.IsNull() )
457     return;
458
459   Quantity_Color aBorderColor( getQuantityColorVal( theColor.red() ), 
460                                getQuantityColorVal( theColor.green() ),
461                                getQuantityColorVal( theColor.blue() ),
462                                Quantity_TOC_RGB );
463   if ( myDisplayMode == AIS_Shaded )
464   {
465     if ( theColor.alpha() == 0 )
466     {
467       anAttributes->SetFaceBoundaryDraw( false );
468     }
469     else
470     {
471       anAttributes->SetFaceBoundaryDraw( true );
472
473       Handle(Prs3d_LineAspect) aBoundaryAspect = anAttributes->FaceBoundaryAspect();
474       if ( !aBoundaryAspect.IsNull() )
475         aBoundaryAspect->SetColor( aBorderColor );
476     }
477   }
478   else if ( myDisplayMode == AIS_WireFrame )
479   {
480     myShape->SetColor( aBorderColor );
481   }
482 }
483
484 QString HYDROGUI_Shape::generateTextureFileName( const Handle(HYDROData_Entity)& theImageObj )
485 {
486   QString aResult;
487   if( !theImageObj.IsNull() )
488   {
489     QString aTempDir = HYDROGUI_Tool::GetTempDir( true );
490
491     int aStudyId = HYDROGUI_Tool::GetActiveStudyId();
492     QString aPrefix = QString( "image_%1" ).arg( aStudyId );
493
494     QString anEntry = HYDROGUI_DataObject::dataObjectEntry( theImageObj, false );
495     anEntry.replace( ':', '_' );
496
497     QString anExtension = "bmp";
498
499     aResult = QString( "%1/%2_%3.%4" ).arg( aTempDir, aPrefix, anEntry, anExtension );
500   }
501   return aResult;
502 }
503
504 void HYDROGUI_Shape::removeTextureFile() const
505 {
506   QFile aFile( getTextureFileName() );
507   if( aFile.exists() )
508     aFile.remove();
509 }
510
511 QImage HYDROGUI_Shape::reduceTexture( const QImage& theImage, const int theSizeLimit )
512 {
513   double aSizeLimit = (double)theSizeLimit;
514   double aWidth = (double)theImage.width();
515   double aHeight = (double)theImage.height();
516   if( aWidth > aSizeLimit || aHeight > aSizeLimit )
517   {
518     if( aWidth > aHeight )
519     {
520       aHeight /= ( aWidth / aSizeLimit );
521       aWidth = aSizeLimit;
522     }
523     else
524     {
525       aWidth /= ( aHeight / aSizeLimit );
526       aHeight = aSizeLimit;
527     }
528   }
529   return theImage.scaled( aWidth, aHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation );
530 }