Salome HOME
15cfe20606228b0d40be3280f8accff9a1eed370
[modules/gui.git] / src / VTKViewer / VTKViewer_Utilities.cxx
1 // Copyright (C) 2007-2012  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 "VTKViewer_Utilities.h"
24 #include "VTKViewer_Actor.h"
25 #include "VTKViewer_Algorithm.h"
26
27 #include <algorithm>
28
29 // VTK Includes
30 #include <vtkMath.h>
31 #include <vtkCamera.h>
32 #include <vtkRenderer.h>
33 #include <vtkRenderWindow.h>
34
35 /*!@see vtkRenderer::ResetCamera(vtkFloatingPointType bounds[6]) method*/
36 void 
37 ResetCamera(vtkRenderer* theRenderer, 
38             int theUsingZeroFocalPoint)
39 {  
40   if(!theRenderer)
41     return;
42
43   vtkCamera* aCamera = theRenderer->GetActiveCamera();
44   if(!aCamera) 
45     return;
46
47   vtkFloatingPointType aBounds[6];
48   int aCount = ComputeVisiblePropBounds(theRenderer,aBounds);
49
50   if(theUsingZeroFocalPoint || aCount){
51     static vtkFloatingPointType MIN_DISTANCE = 1.0 / VTK_LARGE_FLOAT;
52
53     vtkFloatingPointType aLength = aBounds[1]-aBounds[0];
54     aLength = std::max((aBounds[3]-aBounds[2]),aLength);
55     aLength = std::max((aBounds[5]-aBounds[4]),aLength);
56     
57     if(aLength < MIN_DISTANCE)
58       return;
59
60     vtkFloatingPointType aWidth = 
61       sqrt((aBounds[1]-aBounds[0])*(aBounds[1]-aBounds[0]) +
62            (aBounds[3]-aBounds[2])*(aBounds[3]-aBounds[2]) +
63            (aBounds[5]-aBounds[4])*(aBounds[5]-aBounds[4]));
64     
65     if(aWidth < MIN_DISTANCE)
66       return;
67
68     vtkFloatingPointType aViewPlaneNormal[3];
69     aCamera->GetViewPlaneNormal(aViewPlaneNormal);
70     
71     vtkFloatingPointType aCenter[3] = {0.0, 0.0, 0.0};
72     if(!theUsingZeroFocalPoint){
73       aCenter[0] = (aBounds[0] + aBounds[1])/2.0;
74       aCenter[1] = (aBounds[2] + aBounds[3])/2.0;
75       aCenter[2] = (aBounds[4] + aBounds[5])/2.0;
76     }
77     aCamera->SetFocalPoint(aCenter[0],aCenter[1],aCenter[2]);
78     
79     vtkFloatingPointType aViewAngle = aCamera->GetViewAngle();
80     vtkFloatingPointType aDistance = 2.0*aWidth/tan(aViewAngle*vtkMath::Pi()/360.0);
81     
82     // check view-up vector against view plane normal
83     vtkFloatingPointType aViewUp[3];
84     aCamera->GetViewUp(aViewUp);
85     if(fabs(vtkMath::Dot(aViewUp,aViewPlaneNormal)) > 0.999)
86       aCamera->SetViewUp(-aViewUp[2], aViewUp[0], aViewUp[1]);
87     
88     // update the camera
89     aCamera->SetPosition(aCenter[0]+aDistance*aViewPlaneNormal[0],
90                          aCenter[1]+aDistance*aViewPlaneNormal[1],
91                          aCenter[2]+aDistance*aViewPlaneNormal[2]);
92
93     // find size of the window
94     int* aWinSize = theRenderer->GetSize();
95     if(aWinSize[0] < aWinSize[1]) 
96       aWidth *= vtkFloatingPointType(aWinSize[1])/vtkFloatingPointType(aWinSize[0]);
97     
98     if(theUsingZeroFocalPoint) 
99       aWidth *= sqrt(2.0);
100     
101     aCamera->SetParallelScale(aWidth/2.0);
102   }
103
104   ResetCameraClippingRange(theRenderer);
105 }
106
107 /*! Compute the bounds of the visible props*/
108 int
109 ComputeVisiblePropBounds(vtkRenderer* theRenderer, 
110                          vtkFloatingPointType theBounds[6])
111 {
112   int aCount = 0;
113   
114   theBounds[0] = theBounds[2] = theBounds[4] = VTK_LARGE_FLOAT;
115   theBounds[1] = theBounds[3] = theBounds[5] = -VTK_LARGE_FLOAT;
116   
117   // loop through all props
118   VTK::ActorCollectionCopy aCopy(theRenderer->GetActors());
119   vtkActorCollection* aCollection = aCopy.GetActors();
120   aCollection->InitTraversal();
121   while (vtkActor* aProp = aCollection->GetNextActor()) {
122     // if it's invisible, or has no geometry, we can skip the rest 
123     if(aProp->GetVisibility() && aProp->GetMapper() && vtkMath::AreBoundsInitialized(aProp->GetBounds())){
124       if(VTKViewer_Actor* anActor = VTKViewer_Actor::SafeDownCast(aProp))
125         if(anActor->IsInfinitive())
126           continue;
127         
128       vtkFloatingPointType *aBounds = aProp->GetBounds();
129       static vtkFloatingPointType MAX_DISTANCE = 0.9*VTK_LARGE_FLOAT;
130       // make sure we haven't got bogus bounds
131       if ( aBounds != NULL &&
132            aBounds[0] > -MAX_DISTANCE && aBounds[1] < MAX_DISTANCE &&
133            aBounds[2] > -MAX_DISTANCE && aBounds[3] < MAX_DISTANCE &&
134            aBounds[4] > -MAX_DISTANCE && aBounds[5] < MAX_DISTANCE )
135       {
136         aCount++;
137
138         theBounds[0] = std::min(aBounds[0],theBounds[0]);
139         theBounds[2] = std::min(aBounds[2],theBounds[2]);
140         theBounds[4] = std::min(aBounds[4],theBounds[4]);
141
142         theBounds[1] = std::max(aBounds[1],theBounds[1]);
143         theBounds[3] = std::max(aBounds[3],theBounds[3]);
144         theBounds[5] = std::max(aBounds[5],theBounds[5]);
145
146       }//not bogus
147     }
148   }
149   return aCount;
150 }
151
152 /*!@see vtkRenderer::ResetCameraClippingRange(vtkFloatingPointType bounds[6]) method*/
153 void
154 ResetCameraClippingRange(vtkRenderer* theRenderer)
155 {
156   if(!theRenderer || !theRenderer->VisibleActorCount()) return;
157   
158   vtkCamera* anActiveCamera = theRenderer->GetActiveCamera();
159   if( anActiveCamera == NULL ){
160     return;
161   }
162   
163   // Find the plane equation for the camera view plane
164   vtkFloatingPointType vn[3];
165   anActiveCamera->GetViewPlaneNormal(vn);
166   vtkFloatingPointType  position[3];
167   anActiveCamera->GetPosition(position);
168   
169   vtkFloatingPointType bounds[6];
170   theRenderer->ComputeVisiblePropBounds(bounds);
171   
172   vtkFloatingPointType center[3];
173   center[0] = (bounds[0] + bounds[1])/2.0;
174   center[1] = (bounds[2] + bounds[3])/2.0;
175   center[2] = (bounds[4] + bounds[5])/2.0;
176   
177   vtkFloatingPointType width = sqrt((bounds[1]-bounds[0])*(bounds[1]-bounds[0]) +
178     (bounds[3]-bounds[2])*(bounds[3]-bounds[2]) +
179     (bounds[5]-bounds[4])*(bounds[5]-bounds[4]));
180   
181   vtkFloatingPointType distance = sqrt((position[0]-center[0])*(position[0]-center[0]) +
182        (position[1]-center[1])*(position[1]-center[1]) +
183        (position[2]-center[2])*(position[2]-center[2]));
184   
185   vtkFloatingPointType range[2] = {distance - width/2.0, distance + width/2.0};
186   
187   // Do not let the range behind the camera throw off the calculation.
188   if (range[0] < 0.0) range[0] = 0.0;
189   
190   anActiveCamera->SetClippingRange( range );
191 }
192
193 /*!Compute trihedron size.*/
194 bool
195 ComputeTrihedronSize( vtkRenderer* theRenderer,
196                       vtkFloatingPointType& theNewSize,
197                       const vtkFloatingPointType theSize, 
198                       const vtkFloatingPointType theSizeInPercents )
199 {
200   // calculating diagonal of visible props of the renderer
201   vtkFloatingPointType bnd[ 6 ];
202   if ( ComputeVisiblePropBounds( theRenderer, bnd ) == 0 )
203   {
204     bnd[ 1 ] = bnd[ 3 ] = bnd[ 5 ] = 100;
205     bnd[ 0 ] = bnd[ 2 ] = bnd[ 4 ] = 0;
206   }
207   vtkFloatingPointType aLength = 0;
208
209   aLength = bnd[ 1 ]-bnd[ 0 ];
210   aLength = std::max( ( bnd[ 3 ] - bnd[ 2 ] ),aLength );
211   aLength = std::max( ( bnd[ 5 ] - bnd[ 4 ] ),aLength );
212
213   static vtkFloatingPointType EPS_SIZE = 5.0E-3;
214   theNewSize = aLength * theSizeInPercents / 100.0;
215
216   // if the new trihedron size have sufficient difference, then apply the value
217   return fabs( theNewSize - theSize) > theSize * EPS_SIZE ||
218          fabs( theNewSize-theSize ) > theNewSize * EPS_SIZE;
219 }
220
221 bool IsBBEmpty(vtkRenderer* theRenderer)
222 {
223   if(!theRenderer)
224     return false;
225
226   vtkFloatingPointType aNewBndBox[6];
227   aNewBndBox[ 0 ] = aNewBndBox[ 2 ] = aNewBndBox[ 4 ] = VTK_LARGE_FLOAT;
228   aNewBndBox[ 1 ] = aNewBndBox[ 3 ] = aNewBndBox[ 5 ] = -VTK_LARGE_FLOAT;
229   
230   // iterate through displayed objects and set size if necessary
231   VTK::ActorCollectionCopy aCopy(theRenderer->GetActors());
232   vtkActorCollection* anActors = aCopy.GetActors();
233   anActors->InitTraversal();
234   bool isAny = false;
235   while(vtkActor* anAct = anActors->GetNextActor())
236     //if(SALOME_Actor* anActor = dynamic_cast<SALOME_Actor*>(anAct))
237     if(VTKViewer_Actor* anActor = VTKViewer_Actor::SafeDownCast(anAct))
238       if(anActor->GetVisibility() && !anActor->IsInfinitive())
239       {
240         vtkFloatingPointType *aBounds = anActor->GetBounds();
241         if(aBounds[0] > -VTK_LARGE_FLOAT && aBounds[1] < VTK_LARGE_FLOAT &&
242            aBounds[2] > -VTK_LARGE_FLOAT && aBounds[3] < VTK_LARGE_FLOAT &&
243            aBounds[4] > -VTK_LARGE_FLOAT && aBounds[5] < VTK_LARGE_FLOAT)
244           isAny = true;
245       }
246   
247   return !isAny;
248 }
249
250 bool ComputeBBCenter(vtkRenderer* theRenderer, vtkFloatingPointType theCenter[3])
251 {  
252   theCenter[0] = theCenter[1] = theCenter[2] = 0.0;
253   
254   if(!theRenderer)
255     return false;
256
257   vtkFloatingPointType aNewBndBox[6];
258   aNewBndBox[ 0 ] = aNewBndBox[ 2 ] = aNewBndBox[ 4 ] = VTK_LARGE_FLOAT;
259   aNewBndBox[ 1 ] = aNewBndBox[ 3 ] = aNewBndBox[ 5 ] = -VTK_LARGE_FLOAT;
260
261   // iterate through displayed objects and set size if necessary
262   VTK::ActorCollectionCopy aCopy(theRenderer->GetActors());
263   vtkActorCollection* anActors = aCopy.GetActors();
264   anActors->InitTraversal();
265   bool isAny = false;
266   while(vtkActor* anAct = anActors->GetNextActor())
267   {
268     //if(SALOME_Actor* anActor = dynamic_cast<SALOME_Actor*>(anAct))
269     if(VTKViewer_Actor* anActor = VTKViewer_Actor::SafeDownCast(anAct))
270     {
271       if(anActor->GetVisibility() && !anActor->IsInfinitive())
272       {
273         vtkFloatingPointType *aBounds = anActor->GetBounds();
274         if(aBounds[0] > -VTK_LARGE_FLOAT && aBounds[1] < VTK_LARGE_FLOAT &&
275            aBounds[2] > -VTK_LARGE_FLOAT && aBounds[3] < VTK_LARGE_FLOAT &&
276            aBounds[4] > -VTK_LARGE_FLOAT && aBounds[5] < VTK_LARGE_FLOAT)
277         {
278           for(int i = 0; i < 5; i = i + 2){
279             if(aBounds[i] < aNewBndBox[i]) 
280               aNewBndBox[i] = aBounds[i];
281             if(aBounds[i+1] > aNewBndBox[i+1]) 
282               aNewBndBox[i+1] = aBounds[i+1];
283           }
284           isAny = true;
285         }
286       }
287     }
288   }
289   
290   if ( !isAny )
291   {
292     // null bounding box => the center is (0,0,0)
293     return true;
294   }
295
296   if(aNewBndBox[0] > -VTK_LARGE_FLOAT && aNewBndBox[1] < VTK_LARGE_FLOAT &&
297      aNewBndBox[2] > -VTK_LARGE_FLOAT && aNewBndBox[3] < VTK_LARGE_FLOAT &&
298      aNewBndBox[4] > -VTK_LARGE_FLOAT && aNewBndBox[5] < VTK_LARGE_FLOAT)
299   {
300     static vtkFloatingPointType MIN_DISTANCE = 1.0 / VTK_LARGE_FLOAT;
301     
302     vtkFloatingPointType aLength = aNewBndBox[1]-aNewBndBox[0];
303     aLength = std::max((aNewBndBox[3]-aNewBndBox[2]),aLength);
304     aLength = std::max((aNewBndBox[5]-aNewBndBox[4]),aLength);
305     
306     if(aLength < MIN_DISTANCE)
307       return false;
308
309     vtkFloatingPointType aWidth = 
310       sqrt((aNewBndBox[1]-aNewBndBox[0])*(aNewBndBox[1]-aNewBndBox[0]) +
311            (aNewBndBox[3]-aNewBndBox[2])*(aNewBndBox[3]-aNewBndBox[2]) +
312            (aNewBndBox[5]-aNewBndBox[4])*(aNewBndBox[5]-aNewBndBox[4]));
313     
314     if(aWidth < MIN_DISTANCE)
315       return false;
316
317     theCenter[0] = (aNewBndBox[0] + aNewBndBox[1])/2.0;
318     theCenter[1] = (aNewBndBox[2] + aNewBndBox[3])/2.0;
319     theCenter[2] = (aNewBndBox[4] + aNewBndBox[5])/2.0;
320     return true;
321   }
322
323   return false;
324
325   /*
326   vtkFloatingPointType aBounds[6];
327   int aCount = ComputeVisiblePropBounds(theRenderer,aBounds);
328   printf("aNewBndBox[0] = %f, aNewBndBox[1] = %f,\naNewBndBox[2] = %f, aNewBndBox[3] = %f,\naNewBndBox[4] = %f, aNewBndBox[5] = %f\n",
329            aBounds[0],aBounds[1],aBounds[2],aBounds[3],aBounds[4],aBounds[5]);
330   printf("aCount = %d\n",aCount);
331
332   if(aCount){
333     static vtkFloatingPointType MIN_DISTANCE = 1.0 / VTK_LARGE_FLOAT;
334
335     vtkFloatingPointType aLength = aBounds[1]-aBounds[0];
336     aLength = max((aBounds[3]-aBounds[2]),aLength);
337     aLength = max((aBounds[5]-aBounds[4]),aLength);
338     
339     if(aLength < MIN_DISTANCE)
340       return false;
341
342     vtkFloatingPointType aWidth = 
343       sqrt((aBounds[1]-aBounds[0])*(aBounds[1]-aBounds[0]) +
344            (aBounds[3]-aBounds[2])*(aBounds[3]-aBounds[2]) +
345            (aBounds[5]-aBounds[4])*(aBounds[5]-aBounds[4]));
346     
347     if(aWidth < MIN_DISTANCE)
348       return false;
349
350     theCenter[0] = (aBounds[0] + aBounds[1])/2.0;
351     theCenter[1] = (aBounds[2] + aBounds[3])/2.0;
352     theCenter[2] = (aBounds[4] + aBounds[5])/2.0;
353     return true;
354   }
355   return false;*/
356 }