Salome HOME
eed344ecc15452519a83d1a93b15be599f87ea32
[modules/gui.git] / src / VTKViewer / VTKViewer_Utilities.cxx
1 // Copyright (C) 2007-2023  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, or (at your option) any later version.
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_FLOAT_MAX;
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   VTK::ActorCollectionCopy aCopy(theRenderer->GetActors());
113   vtkActorCollection* aCollection = aCopy.GetActors();
114   return ComputeBounds( aCollection, theBounds );
115 }
116
117 /*! Compute the bounds of actors*/
118 int
119 ComputeBounds(vtkActorCollection* theCollection, double theBounds[6])
120 {
121   int aCount = 0;
122
123   theBounds[0] = theBounds[2] = theBounds[4] = VTK_FLOAT_MAX;
124   theBounds[1] = theBounds[3] = theBounds[5] = -VTK_FLOAT_MAX;
125
126   // loop through all props
127   theCollection->InitTraversal();
128   while (vtkActor* aProp = theCollection->GetNextActor()) {
129     // if it's invisible, or has no geometry, we can skip the rest
130     if(aProp->GetVisibility() && aProp->GetMapper() && vtkMath::AreBoundsInitialized(aProp->GetBounds())){
131       if(VTKViewer_Actor* anActor = VTKViewer_Actor::SafeDownCast(aProp))
132         if(anActor->IsInfinitive())
133           continue;
134       double *aBounds = aProp->GetBounds();
135       static double MIN_DISTANCE = 1./VTK_FLOAT_MAX;
136       static double MAX_DISTANCE = 0.9*VTK_FLOAT_MAX;
137
138       if(fabs(aBounds[1] - aBounds[0]) < MIN_DISTANCE) {
139         aBounds[0]-=0.001;
140         aBounds[1]+=0.001;
141       }
142
143       if(fabs(aBounds[3] - aBounds[2]) < MIN_DISTANCE) {
144         aBounds[2]-=0.001;
145         aBounds[3]+=0.001;
146       }
147
148       if(fabs(aBounds[5] - aBounds[4]) < MIN_DISTANCE) {
149         aBounds[4]-=0.001;
150         aBounds[5]+=0.001;
151       }
152       
153       // make sure we haven't got bogus bounds
154       if ( aBounds != NULL &&
155            aBounds[0] > -MAX_DISTANCE && aBounds[1] < MAX_DISTANCE &&
156            aBounds[2] > -MAX_DISTANCE && aBounds[3] < MAX_DISTANCE &&
157            aBounds[4] > -MAX_DISTANCE && aBounds[5] < MAX_DISTANCE)           
158       {
159         aCount++;
160
161         theBounds[0] = std::min(aBounds[0],theBounds[0]);
162         theBounds[2] = std::min(aBounds[2],theBounds[2]);
163         theBounds[4] = std::min(aBounds[4],theBounds[4]);
164
165         theBounds[1] = std::max(aBounds[1],theBounds[1]);
166         theBounds[3] = std::max(aBounds[3],theBounds[3]);
167         theBounds[5] = std::max(aBounds[5],theBounds[5]);
168
169       }//not bogus
170     }
171   }
172   return aCount;
173 }
174
175 /*!@see vtkRenderer::ResetCameraClippingRange(double bounds[6]) method*/
176 void
177 ResetCameraClippingRange(vtkRenderer* theRenderer)
178 {
179   if(!theRenderer || !theRenderer->VisibleActorCount()) return;
180   
181   vtkCamera* anActiveCamera = theRenderer->GetActiveCamera();
182   if( anActiveCamera == NULL ){
183     return;
184   }
185   
186   // Find the plane equation for the camera view plane
187   double vn[3];
188   anActiveCamera->GetViewPlaneNormal(vn);
189   double  position[3];
190   anActiveCamera->GetPosition(position);
191   
192   double bounds[6];
193   //theRenderer->ComputeVisiblePropBounds(bounds);
194   ComputeVisiblePropBounds(theRenderer, bounds);
195   
196   double center[3];
197   center[0] = (bounds[0] + bounds[1])/2.0;
198   center[1] = (bounds[2] + bounds[3])/2.0;
199   center[2] = (bounds[4] + bounds[5])/2.0;
200   
201   double width = sqrt((bounds[1]-bounds[0])*(bounds[1]-bounds[0]) +
202     (bounds[3]-bounds[2])*(bounds[3]-bounds[2]) +
203     (bounds[5]-bounds[4])*(bounds[5]-bounds[4]));
204   
205   double distance = sqrt((position[0]-center[0])*(position[0]-center[0]) +
206        (position[1]-center[1])*(position[1]-center[1]) +
207        (position[2]-center[2])*(position[2]-center[2]));
208   
209   double range[2] = {distance - width/2.0, distance + width/2.0};
210   
211   // Do not let the range behind the camera throw off the calculation.
212   if (range[0] < 0.0) range[0] = 0.0;
213   
214   anActiveCamera->SetClippingRange( range );
215 }
216
217 /*!Compute trihedron size.*/
218 bool
219 ComputeTrihedronSize( vtkRenderer* theRenderer,
220                       double& theNewSize,
221                       const double theSize, 
222                       const double theSizeInPercents )
223 {
224   // calculating diagonal of visible props of the renderer
225   double bnd[ 6 ];
226   if ( ComputeVisiblePropBounds( theRenderer, bnd ) == 0 )
227   {
228     bnd[ 1 ] = bnd[ 3 ] = bnd[ 5 ] = 100;
229     bnd[ 0 ] = bnd[ 2 ] = bnd[ 4 ] = 0;
230   }
231   double aLength = 0;
232
233   aLength = bnd[ 1 ]-bnd[ 0 ];
234   aLength = std::max( ( bnd[ 3 ] - bnd[ 2 ] ),aLength );
235   aLength = std::max( ( bnd[ 5 ] - bnd[ 4 ] ),aLength );
236
237   static double EPS_SIZE = 5.0E-3;
238   theNewSize = aLength * theSizeInPercents / 100.0;
239
240   // if the new trihedron size have sufficient difference, then apply the value
241   return fabs( theNewSize - theSize) > theSize * EPS_SIZE ||
242          fabs( theNewSize-theSize ) > theNewSize * EPS_SIZE;
243 }
244
245 bool IsBBEmpty(vtkRenderer* theRenderer)
246 {
247   if(!theRenderer)
248     return false;
249
250   double aNewBndBox[6];
251   aNewBndBox[ 0 ] = aNewBndBox[ 2 ] = aNewBndBox[ 4 ] = VTK_FLOAT_MAX;
252   aNewBndBox[ 1 ] = aNewBndBox[ 3 ] = aNewBndBox[ 5 ] = -VTK_FLOAT_MAX;
253   
254   // iterate through displayed objects and set size if necessary
255   VTK::ActorCollectionCopy aCopy(theRenderer->GetActors());
256   vtkActorCollection* anActors = aCopy.GetActors();
257   anActors->InitTraversal();
258   bool isAny = false;
259   while(vtkActor* anAct = anActors->GetNextActor())
260     //if(SALOME_Actor* anActor = dynamic_cast<SALOME_Actor*>(anAct))
261     if(VTKViewer_Actor* anActor = VTKViewer_Actor::SafeDownCast(anAct))
262       if(anActor->GetVisibility() && !anActor->IsInfinitive())
263       {
264         double *aBounds = anActor->GetBounds();
265         if(aBounds[0] > -VTK_FLOAT_MAX && aBounds[1] < VTK_FLOAT_MAX &&
266            aBounds[2] > -VTK_FLOAT_MAX && aBounds[3] < VTK_FLOAT_MAX &&
267            aBounds[4] > -VTK_FLOAT_MAX && aBounds[5] < VTK_FLOAT_MAX)
268           isAny = true;
269       }
270   
271   return !isAny;
272 }
273
274 /*!
275   Check that the given bounding box is valid, i.e each min bound < each max bound
276 */
277
278 bool isBoundValid(double* theBounds) {
279   if(theBounds[0] > theBounds[1] ||
280      theBounds[2] > theBounds[3] ||
281      theBounds[4] > theBounds[5])
282     return false;
283   else 
284     return true;
285 }
286
287 bool ComputeBBCenter(vtkRenderer* theRenderer, double theCenter[3])
288 {  
289   theCenter[0] = theCenter[1] = theCenter[2] = 0.0;
290   
291   if(!theRenderer)
292     return false;
293
294   double aNewBndBox[6];
295   aNewBndBox[ 0 ] = aNewBndBox[ 2 ] = aNewBndBox[ 4 ] = VTK_FLOAT_MAX;
296   aNewBndBox[ 1 ] = aNewBndBox[ 3 ] = aNewBndBox[ 5 ] = -VTK_FLOAT_MAX;
297
298   // iterate through displayed objects and set size if necessary
299   VTK::ActorCollectionCopy aCopy(theRenderer->GetActors());
300   vtkActorCollection* anActors = aCopy.GetActors();
301   anActors->InitTraversal();
302   bool isAny = false;
303   while(vtkActor* anAct = anActors->GetNextActor())
304   {
305     //if(SALOME_Actor* anActor = dynamic_cast<SALOME_Actor*>(anAct))
306     if(VTKViewer_Actor* anActor = VTKViewer_Actor::SafeDownCast(anAct))
307     {
308       if(anActor->GetVisibility() && !anActor->IsInfinitive())
309       {
310         double *aBounds = anActor->GetBounds();
311         
312         //Ignore invalid bounds
313         if(!isBoundValid(aBounds)) continue;
314
315         if(aBounds[0] > -VTK_FLOAT_MAX && aBounds[1] < VTK_FLOAT_MAX &&
316            aBounds[2] > -VTK_FLOAT_MAX && aBounds[3] < VTK_FLOAT_MAX &&
317            aBounds[4] > -VTK_FLOAT_MAX && aBounds[5] < VTK_FLOAT_MAX)
318         {
319           for(int i = 0; i < 5; i = i + 2){
320             if(aBounds[i] < aNewBndBox[i]) 
321               aNewBndBox[i] = aBounds[i];
322             if(aBounds[i+1] > aNewBndBox[i+1]) 
323               aNewBndBox[i+1] = aBounds[i+1];
324           }
325           isAny = true;
326         }
327       }
328     }
329   }
330   
331   if ( !isAny )
332   {
333     // null bounding box => the center is (0,0,0)
334     return true;
335   }
336
337   if(aNewBndBox[0] > -VTK_FLOAT_MAX && aNewBndBox[1] < VTK_FLOAT_MAX &&
338      aNewBndBox[2] > -VTK_FLOAT_MAX && aNewBndBox[3] < VTK_FLOAT_MAX &&
339      aNewBndBox[4] > -VTK_FLOAT_MAX && aNewBndBox[5] < VTK_FLOAT_MAX)
340   {
341     static double MIN_DISTANCE = 1.0 / VTK_FLOAT_MAX;
342     
343     double aLength = aNewBndBox[1]-aNewBndBox[0];
344     aLength = std::max((aNewBndBox[3]-aNewBndBox[2]),aLength);
345     aLength = std::max((aNewBndBox[5]-aNewBndBox[4]),aLength);
346     
347     if(aLength < MIN_DISTANCE)
348       return false;
349
350     double aWidth = 
351       sqrt((aNewBndBox[1]-aNewBndBox[0])*(aNewBndBox[1]-aNewBndBox[0]) +
352            (aNewBndBox[3]-aNewBndBox[2])*(aNewBndBox[3]-aNewBndBox[2]) +
353            (aNewBndBox[5]-aNewBndBox[4])*(aNewBndBox[5]-aNewBndBox[4]));
354     
355     if(aWidth < MIN_DISTANCE)
356       return false;
357
358     theCenter[0] = (aNewBndBox[0] + aNewBndBox[1])/2.0;
359     theCenter[1] = (aNewBndBox[2] + aNewBndBox[3])/2.0;
360     theCenter[2] = (aNewBndBox[4] + aNewBndBox[5])/2.0;
361     return true;
362   }
363
364   return false;
365
366   /*
367   double aBounds[6];
368   int aCount = ComputeVisiblePropBounds(theRenderer,aBounds);
369   printf("aNewBndBox[0] = %f, aNewBndBox[1] = %f,\naNewBndBox[2] = %f, aNewBndBox[3] = %f,\naNewBndBox[4] = %f, aNewBndBox[5] = %f\n",
370            aBounds[0],aBounds[1],aBounds[2],aBounds[3],aBounds[4],aBounds[5]);
371   printf("aCount = %d\n",aCount);
372
373   if(aCount){
374     static double MIN_DISTANCE = 1.0 / VTK_FLOAT_MAX;
375
376     double aLength = aBounds[1]-aBounds[0];
377     aLength = max((aBounds[3]-aBounds[2]),aLength);
378     aLength = max((aBounds[5]-aBounds[4]),aLength);
379     
380     if(aLength < MIN_DISTANCE)
381       return false;
382
383     double aWidth = 
384       sqrt((aBounds[1]-aBounds[0])*(aBounds[1]-aBounds[0]) +
385            (aBounds[3]-aBounds[2])*(aBounds[3]-aBounds[2]) +
386            (aBounds[5]-aBounds[4])*(aBounds[5]-aBounds[4]));
387     
388     if(aWidth < MIN_DISTANCE)
389       return false;
390
391     theCenter[0] = (aBounds[0] + aBounds[1])/2.0;
392     theCenter[1] = (aBounds[2] + aBounds[3])/2.0;
393     theCenter[2] = (aBounds[4] + aBounds[5])/2.0;
394     return true;
395   }
396   return false;*/
397 }