1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkProp3DFollower.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtkProp3DFollower.h"
16 
17 #include "vtkCamera.h"
18 #include "vtkMath.h"
19 #include "vtkMatrix4x4.h"
20 #include "vtkObjectFactory.h"
21 #include "vtkProperty.h"
22 #include "vtkRenderer.h"
23 #include "vtkTexture.h"
24 #include "vtkTransform.h"
25 #include "vtkAssemblyPaths.h"
26 
27 #include <cmath>
28 
29 vtkStandardNewMacro(vtkProp3DFollower);
30 
31 vtkCxxSetObjectMacro(vtkProp3DFollower,Camera,vtkCamera);
32 
33 //----------------------------------------------------------------------
34 // Creates a follower with no camera set
vtkProp3DFollower()35 vtkProp3DFollower::vtkProp3DFollower()
36 {
37   this->Camera = nullptr;
38   this->Device = nullptr;
39 
40   this->InternalMatrix = vtkMatrix4x4::New();
41 }
42 
43 //----------------------------------------------------------------------
~vtkProp3DFollower()44 vtkProp3DFollower::~vtkProp3DFollower()
45 {
46   if (this->Camera)
47   {
48     this->Camera->UnRegister(this);
49   }
50 
51   if (this->Device)
52   {
53     this->Device->Delete();
54   }
55 
56   this->InternalMatrix->Delete();
57 }
58 
59 //----------------------------------------------------------------------------
SetProp3D(vtkProp3D * prop)60 void vtkProp3DFollower::SetProp3D(vtkProp3D *prop)
61 {
62   if (this->Device != prop)
63   {
64     if ( this->Device != nullptr )
65     {
66       this->Device->Delete();
67     }
68     this->Device = prop;
69     if ( this->Device != nullptr )
70     {
71       this->Device->Register(this);
72     }
73     this->Modified();
74   }
75 }
76 
77 
78 //----------------------------------------------------------------------------
GetProp3D()79 vtkProp3D *vtkProp3DFollower::GetProp3D()
80 {
81   return this->Device;
82 }
83 
84 
85 //----------------------------------------------------------------------------
ComputeMatrix()86 void vtkProp3DFollower::ComputeMatrix()
87 {
88   if ( this->GetMTime() > this->MatrixMTime ||
89        (this->Camera && this->Camera->GetMTime() > this->MatrixMTime) )
90   {
91     this->GetOrientation();
92     this->Transform->Push();
93     this->Transform->Identity();
94     this->Transform->PostMultiply();
95 
96     this->Transform->Translate(-this->Origin[0],
97                                -this->Origin[1],
98                                -this->Origin[2]);
99     // scale
100     this->Transform->Scale(this->Scale[0],
101                            this->Scale[1],
102                            this->Scale[2]);
103 
104     // rotate
105     this->Transform->RotateY(this->Orientation[1]);
106     this->Transform->RotateX(this->Orientation[0]);
107     this->Transform->RotateZ(this->Orientation[2]);
108 
109     if (this->Camera)
110     {
111       double *pos, *vup, distance;
112       double Rx[3], Ry[3], Rz[3];
113 
114       vtkMatrix4x4 *matrix = this->InternalMatrix;
115       matrix->Identity();
116 
117       // do the rotation
118       // first rotate y
119       pos = this->Camera->GetPosition();
120       vup = this->Camera->GetViewUp();
121 
122       if (this->Camera->GetParallelProjection())
123       {
124         this->Camera->GetDirectionOfProjection(Rz);
125         Rz[0] = -Rz[0];
126         Rz[1] = -Rz[1];
127         Rz[2] = -Rz[2];
128       }
129       else
130       {
131         distance = sqrt(
132           (pos[0] - this->Position[0])*(pos[0] - this->Position[0]) +
133           (pos[1] - this->Position[1])*(pos[1] - this->Position[1]) +
134           (pos[2] - this->Position[2])*(pos[2] - this->Position[2]));
135         for (int i = 0; i < 3; i++)
136         {
137           Rz[i] = (pos[i] - this->Position[i])/distance;
138         }
139       }
140 
141       //instead use the view right angle:
142       double dop[3], vur[3];
143       this->Camera->GetDirectionOfProjection(dop);
144 
145       vtkMath::Cross(dop,vup,vur);
146       vtkMath::Normalize(vur);
147 
148       vtkMath::Cross(Rz, vur, Ry);
149       vtkMath::Normalize(Ry);
150       vtkMath::Cross(Ry,Rz,Rx);
151 
152       matrix->Element[0][0] = Rx[0];
153       matrix->Element[1][0] = Rx[1];
154       matrix->Element[2][0] = Rx[2];
155       matrix->Element[0][1] = Ry[0];
156       matrix->Element[1][1] = Ry[1];
157       matrix->Element[2][1] = Ry[2];
158       matrix->Element[0][2] = Rz[0];
159       matrix->Element[1][2] = Rz[1];
160       matrix->Element[2][2] = Rz[2];
161 
162       this->Transform->Concatenate(matrix);
163     }
164 
165     // translate to projection reference point PRP
166     // this is the camera's position blasted through
167     // the current matrix
168     this->Transform->Translate(this->Origin[0] + this->Position[0],
169                                this->Origin[1] + this->Position[1],
170                                this->Origin[2] + this->Position[2]);
171 
172     // apply user defined matrix last if there is one
173     if (this->UserMatrix)
174     {
175       this->Transform->Concatenate(this->UserMatrix);
176     }
177 
178     this->Transform->PreMultiply();
179     this->Transform->GetMatrix(this->Matrix);
180     this->MatrixMTime.Modified();
181     this->Transform->Pop();
182   }
183 }
184 
185 //-----------------------------------------------------------------------------
GetBounds()186 double *vtkProp3DFollower::GetBounds()
187 {
188   if ( this->Device )
189   {
190     this->ComputeMatrix();
191     this->Device->SetUserMatrix(this->Matrix);
192     return this->Device->GetBounds();
193   }
194   else
195   {
196     return nullptr;
197   }
198 }
199 
200 
201 //-----------------------------------------------------------------------------
ReleaseGraphicsResources(vtkWindow * w)202 void vtkProp3DFollower::ReleaseGraphicsResources(vtkWindow *w)
203 {
204   if ( this->Device )
205   {
206     this->Device->ReleaseGraphicsResources(w);
207   }
208 }
209 
210 //-----------------------------------------------------------------------------
211 // Description:
212 // Does this prop have some translucent polygonal geometry?
HasTranslucentPolygonalGeometry()213 vtkTypeBool vtkProp3DFollower::HasTranslucentPolygonalGeometry()
214 {
215   if ( this->Device )
216   {
217     return this->Device->HasTranslucentPolygonalGeometry();
218   }
219   else
220   {
221     return 0;
222   }
223 }
224 
225 //----------------------------------------------------------------------
RenderOpaqueGeometry(vtkViewport * vp)226 int vtkProp3DFollower::RenderOpaqueGeometry(vtkViewport *vp)
227 {
228   if ( this->Device )
229   {
230     this->ComputeMatrix();
231     this->Device->SetUserMatrix(this->Matrix);
232     if (this->GetPropertyKeys())
233     {
234       this->Device->SetPropertyKeys(this->GetPropertyKeys());
235     }
236     if (this->GetVisibility())
237     {
238       return this->Device->RenderOpaqueGeometry(vp);
239     }
240   }
241   return 0;
242 }
243 
244 //-----------------------------------------------------------------------------
RenderTranslucentPolygonalGeometry(vtkViewport * vp)245 int vtkProp3DFollower::RenderTranslucentPolygonalGeometry(vtkViewport *vp)
246 {
247   if ( this->Device )
248   {
249     this->ComputeMatrix();
250     this->Device->SetUserMatrix(this->Matrix);
251     if (this->GetPropertyKeys())
252     {
253       this->Device->SetPropertyKeys(this->GetPropertyKeys());
254     }
255     if (this->GetVisibility())
256     {
257       return this->Device->RenderTranslucentPolygonalGeometry(vp);
258     }
259   }
260   return 0;
261 }
262 
263 //----------------------------------------------------------------------
RenderVolumetricGeometry(vtkViewport * vp)264 int vtkProp3DFollower::RenderVolumetricGeometry(vtkViewport *vp)
265 {
266   if ( this->Device )
267   {
268     this->ComputeMatrix();
269     this->Device->SetUserMatrix(this->Matrix);
270     if (this->GetPropertyKeys())
271     {
272       this->Device->SetPropertyKeys(this->GetPropertyKeys());
273     }
274     if (this->GetVisibility())
275     {
276       return this->Device->RenderVolumetricGeometry(vp);
277     }
278   }
279   return 0;
280 }
281 
282 //----------------------------------------------------------------------
ShallowCopy(vtkProp * prop)283 void vtkProp3DFollower::ShallowCopy(vtkProp *prop)
284 {
285   vtkProp3DFollower *f = vtkProp3DFollower::SafeDownCast(prop);
286   if ( f != nullptr )
287   {
288     this->SetCamera(f->GetCamera());
289   }
290 
291   // Now do superclass
292   this->vtkProp3D::ShallowCopy(prop);
293 }
294 
295 //----------------------------------------------------------------------------
InitPathTraversal()296 void vtkProp3DFollower::InitPathTraversal()
297 {
298   if ( this->Device )
299   {
300     this->Device->InitPathTraversal();
301   }
302 }
303 
304 //----------------------------------------------------------------------------
GetNextPath()305 vtkAssemblyPath *vtkProp3DFollower::GetNextPath()
306 {
307   if ( this->Device )
308   {
309     return this->Device->GetNextPath();
310   }
311   else
312   {
313     return nullptr;
314   }
315 }
316 
317 //----------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)318 void vtkProp3DFollower::PrintSelf(ostream& os, vtkIndent indent)
319 {
320   this->Superclass::PrintSelf(os,indent);
321 
322   if ( this->Camera )
323   {
324     os << indent << "Camera:\n";
325     this->Camera->PrintSelf(os,indent.GetNextIndent());
326   }
327   else
328   {
329     os << indent << "Camera: (none)\n";
330   }
331 }
332