Salome HOME
Merge from V6_main 01/04/2013
[modules/gui.git] / src / VTKViewer / VTKViewer_Utilities.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 "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(double 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   double aBounds[6];
48   int aCount = ComputeVisiblePropBounds(theRenderer,aBounds);
49
50   if(theUsingZeroFocalPoint || aCount){
51     static double MIN_DISTANCE = 1.0 / VTK_LARGE_FLOAT;
52
53     double 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     double 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     double aViewPlaneNormal[3];
69     aCamera->GetViewPlaneNormal(aViewPlaneNormal);
70     
71     double 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     double aViewAngle = aCamera->GetViewAngle();
80     double aDistance = 2.0*aWidth/tan(aViewAngle*vtkMath::Pi()/360.0);
81     
82     // check view-up vector against view plane normal
83     double 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 *= double(aWinSize[1])/double(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                          double 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       double *aBounds = aProp->GetBounds();
128       static double MIN_DISTANCE = 1./VTK_LARGE_FLOAT;
129       static double MAX_DISTANCE = 0.9*VTK_LARGE_FLOAT;
130
131       if(abs(aBounds[1] - aBounds[0]) < MIN_DISTANCE) {
132         aBounds[0]-=0.001;
133         aBounds[1]+=0.001;
134       }
135
136       if(abs(aBounds[3] - aBounds[2]) < MIN_DISTANCE) {
137         aBounds[2]-=0.001;
138         aBounds[3]+=0.001;
139       }
140
141       if(abs(aBounds[5] - aBounds[4]) < MIN_DISTANCE) {
142         aBounds[4]-=0.001;
143         aBounds[5]+=0.001;
144       }
145       
146       // make sure we haven't got bogus bounds
147       if ( aBounds != NULL &&
148            aBounds[0] > -MAX_DISTANCE && aBounds[1] < MAX_DISTANCE &&
149            aBounds[2] > -MAX_DISTANCE && aBounds[3] < MAX_DISTANCE &&
150            aBounds[4] > -MAX_DISTANCE && aBounds[5] < MAX_DISTANCE)           
151       {
152         aCount++;
153
154         theBounds[0] = std::min(aBounds[0],theBounds[0]);
155         theBounds[2] = std::min(aBounds[2],theBounds[2]);
156         theBounds[4] = std::min(aBounds[4],theBounds[4]);
157
158         theBounds[1] = std::max(aBounds[1],theBounds[1]);
159         theBounds[3] = std::max(aBounds[3],theBounds[3]);
160         theBounds[5] = std::max(aBounds[5],theBounds[5]);
161
162       }//not bogus
163     }
164   }
165   return aCount;
166 }
167
168 /*!@see vtkRenderer::ResetCameraClippingRange(double bounds[6]) method*/
169 void
170 ResetCameraClippingRange(vtkRenderer* theRenderer)
171 {
172   if(!theRenderer || !theRenderer->VisibleActorCount()) return;
173   
174   vtkCamera* anActiveCamera = theRenderer->GetActiveCamera();
175   if( anActiveCamera == NULL ){
176     return;
177   }
178   
179   // Find the plane equation for the camera view plane
180   double vn[3];
181   anActiveCamera->GetViewPlaneNormal(vn);
182   double  position[3];
183   anActiveCamera->GetPosition(position);
184   
185   double bounds[6];
186   //theRenderer->ComputeVisiblePropBounds(bounds);
187   ComputeVisiblePropBounds(theRenderer, bounds);
188   
189   double center[3];
190   center[0] = (bounds[0] + bounds[1])/2.0;
191   center[1] = (bounds[2] + bounds[3])/2.0;
192   center[2] = (bounds[4] + bounds[5])/2.0;
193   
194   double width = sqrt((bounds[1]-bounds[0])*(bounds[1]-bounds[0]) +
195     (bounds[3]-bounds[2])*(bounds[3]-bounds[2]) +
196     (bounds[5]-bounds[4])*(bounds[5]-bounds[4]));
197   
198   double distance = sqrt((position[0]-center[0])*(position[0]-center[0]) +
199        (position[1]-center[1])*(position[1]-center[1]) +
200        (position[2]-center[2])*(position[2]-center[2]));
201   
202   double range[2] = {distance - width/2.0, distance + width/2.0};
203   
204   // Do not let the range behind the camera throw off the calculation.
205   if (range[0] < 0.0) range[0] = 0.0;
206   
207   anActiveCamera->SetClippingRange( range );
208 }
209
210 /*!Compute trihedron size.*/
211 bool
212 ComputeTrihedronSize( vtkRenderer* theRenderer,
213                       double& theNewSize,
214                       const double theSize, 
215                       const double theSizeInPercents )
216 {
217   // calculating diagonal of visible props of the renderer
218   double bnd[ 6 ];
219   if ( ComputeVisiblePropBounds( theRenderer, bnd ) == 0 )
220   {
221     bnd[ 1 ] = bnd[ 3 ] = bnd[ 5 ] = 100;
222     bnd[ 0 ] = bnd[ 2 ] = bnd[ 4 ] = 0;
223   }
224   double aLength = 0;
225
226   aLength = bnd[ 1 ]-bnd[ 0 ];
227   aLength = std::max( ( bnd[ 3 ] - bnd[ 2 ] ),aLength );
228   aLength = std::max( ( bnd[ 5 ] - bnd[ 4 ] ),aLength );
229
230   static double EPS_SIZE = 5.0E-3;
231   theNewSize = aLength * theSizeInPercents / 100.0;
232
233   // if the new trihedron size have sufficient difference, then apply the value
234   return fabs( theNewSize - theSize) > theSize * EPS_SIZE ||
235          fabs( theNewSize-theSize ) > theNewSize * EPS_SIZE;
236 }
237
238 bool IsBBEmpty(vtkRenderer* theRenderer)
239 {
240   if(!theRenderer)
241     return false;
242
243   double aNewBndBox[6];
244   aNewBndBox[ 0 ] = aNewBndBox[ 2 ] = aNewBndBox[ 4 ] = VTK_LARGE_FLOAT;
245   aNewBndBox[ 1 ] = aNewBndBox[ 3 ] = aNewBndBox[ 5 ] = -VTK_LARGE_FLOAT;
246   
247   // iterate through displayed objects and set size if necessary
248   VTK::ActorCollectionCopy aCopy(theRenderer->GetActors());
249   vtkActorCollection* anActors = aCopy.GetActors();
250   anActors->InitTraversal();
251   bool isAny = false;
252   while(vtkActor* anAct = anActors->GetNextActor())
253     //if(SALOME_Actor* anActor = dynamic_cast<SALOME_Actor*>(anAct))
254     if(VTKViewer_Actor* anActor = VTKViewer_Actor::SafeDownCast(anAct))
255       if(anActor->GetVisibility() && !anActor->IsInfinitive())
256       {
257         double *aBounds = anActor->GetBounds();
258         if(aBounds[0] > -VTK_LARGE_FLOAT && aBounds[1] < VTK_LARGE_FLOAT &&
259            aBounds[2] > -VTK_LARGE_FLOAT && aBounds[3] < VTK_LARGE_FLOAT &&
260            aBounds[4] > -VTK_LARGE_FLOAT && aBounds[5] < VTK_LARGE_FLOAT)
261           isAny = true;
262       }
263   
264   return !isAny;
265 }
266
267 bool ComputeBBCenter(vtkRenderer* theRenderer, double theCenter[3])
268 {  
269   theCenter[0] = theCenter[1] = theCenter[2] = 0.0;
270   
271   if(!theRenderer)
272     return false;
273
274   double aNewBndBox[6];
275   aNewBndBox[ 0 ] = aNewBndBox[ 2 ] = aNewBndBox[ 4 ] = VTK_LARGE_FLOAT;
276   aNewBndBox[ 1 ] = aNewBndBox[ 3 ] = aNewBndBox[ 5 ] = -VTK_LARGE_FLOAT;
277
278   // iterate through displayed objects and set size if necessary
279   VTK::ActorCollectionCopy aCopy(theRenderer->GetActors());
280   vtkActorCollection* anActors = aCopy.GetActors();
281   anActors->InitTraversal();
282   bool isAny = false;
283   while(vtkActor* anAct = anActors->GetNextActor())
284   {
285     //if(SALOME_Actor* anActor = dynamic_cast<SALOME_Actor*>(anAct))
286     if(VTKViewer_Actor* anActor = VTKViewer_Actor::SafeDownCast(anAct))
287     {
288       if(anActor->GetVisibility() && !anActor->IsInfinitive())
289       {
290         double *aBounds = anActor->GetBounds();
291         if(aBounds[0] > -VTK_LARGE_FLOAT && aBounds[1] < VTK_LARGE_FLOAT &&
292            aBounds[2] > -VTK_LARGE_FLOAT && aBounds[3] < VTK_LARGE_FLOAT &&
293            aBounds[4] > -VTK_LARGE_FLOAT && aBounds[5] < VTK_LARGE_FLOAT)
294         {
295           for(int i = 0; i < 5; i = i + 2){
296             if(aBounds[i] < aNewBndBox[i]) 
297               aNewBndBox[i] = aBounds[i];
298             if(aBounds[i+1] > aNewBndBox[i+1]) 
299               aNewBndBox[i+1] = aBounds[i+1];
300           }
301           isAny = true;
302         }
303       }
304     }
305   }
306   
307   if ( !isAny )
308   {
309     // null bounding box => the center is (0,0,0)
310     return true;
311   }
312
313   if(aNewBndBox[0] > -VTK_LARGE_FLOAT && aNewBndBox[1] < VTK_LARGE_FLOAT &&
314      aNewBndBox[2] > -VTK_LARGE_FLOAT && aNewBndBox[3] < VTK_LARGE_FLOAT &&
315      aNewBndBox[4] > -VTK_LARGE_FLOAT && aNewBndBox[5] < VTK_LARGE_FLOAT)
316   {
317     static double MIN_DISTANCE = 1.0 / VTK_LARGE_FLOAT;
318     
319     double aLength = aNewBndBox[1]-aNewBndBox[0];
320     aLength = std::max((aNewBndBox[3]-aNewBndBox[2]),aLength);
321     aLength = std::max((aNewBndBox[5]-aNewBndBox[4]),aLength);
322     
323     if(aLength < MIN_DISTANCE)
324       return false;
325
326     double aWidth = 
327       sqrt((aNewBndBox[1]-aNewBndBox[0])*(aNewBndBox[1]-aNewBndBox[0]) +
328            (aNewBndBox[3]-aNewBndBox[2])*(aNewBndBox[3]-aNewBndBox[2]) +
329            (aNewBndBox[5]-aNewBndBox[4])*(aNewBndBox[5]-aNewBndBox[4]));
330     
331     if(aWidth < MIN_DISTANCE)
332       return false;
333
334     theCenter[0] = (aNewBndBox[0] + aNewBndBox[1])/2.0;
335     theCenter[1] = (aNewBndBox[2] + aNewBndBox[3])/2.0;
336     theCenter[2] = (aNewBndBox[4] + aNewBndBox[5])/2.0;
337     return true;
338   }
339
340   return false;
341
342   /*
343   double aBounds[6];
344   int aCount = ComputeVisiblePropBounds(theRenderer,aBounds);
345   printf("aNewBndBox[0] = %f, aNewBndBox[1] = %f,\naNewBndBox[2] = %f, aNewBndBox[3] = %f,\naNewBndBox[4] = %f, aNewBndBox[5] = %f\n",
346            aBounds[0],aBounds[1],aBounds[2],aBounds[3],aBounds[4],aBounds[5]);
347   printf("aCount = %d\n",aCount);
348
349   if(aCount){
350     static double MIN_DISTANCE = 1.0 / VTK_LARGE_FLOAT;
351
352     double aLength = aBounds[1]-aBounds[0];
353     aLength = max((aBounds[3]-aBounds[2]),aLength);
354     aLength = max((aBounds[5]-aBounds[4]),aLength);
355     
356     if(aLength < MIN_DISTANCE)
357       return false;
358
359     double aWidth = 
360       sqrt((aBounds[1]-aBounds[0])*(aBounds[1]-aBounds[0]) +
361            (aBounds[3]-aBounds[2])*(aBounds[3]-aBounds[2]) +
362            (aBounds[5]-aBounds[4])*(aBounds[5]-aBounds[4]));
363     
364     if(aWidth < MIN_DISTANCE)
365       return false;
366
367     theCenter[0] = (aBounds[0] + aBounds[1])/2.0;
368     theCenter[1] = (aBounds[2] + aBounds[3])/2.0;
369     theCenter[2] = (aBounds[4] + aBounds[5])/2.0;
370     return true;
371   }
372   return false;*/
373 }