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 "vtkAssemblyPaths.h"
18 #include "vtkCamera.h"
19 #include "vtkMath.h"
20 #include "vtkMatrix4x4.h"
21 #include "vtkObjectFactory.h"
22 #include "vtkProperty.h"
23 #include "vtkRenderer.h"
24 #include "vtkTexture.h"
25 #include "vtkTransform.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 //------------------------------------------------------------------------------
GetProp3D()78 vtkProp3D* vtkProp3DFollower::GetProp3D()
79 {
80   return this->Device;
81 }
82 
83 //------------------------------------------------------------------------------
ComputeMatrix()84 void vtkProp3DFollower::ComputeMatrix()
85 {
86   if (this->GetMTime() > this->MatrixMTime ||
87     (this->Camera && this->Camera->GetMTime() > this->MatrixMTime))
88   {
89     this->GetOrientation();
90     this->Transform->Push();
91     this->Transform->Identity();
92     this->Transform->PostMultiply();
93 
94     this->Transform->Translate(-this->Origin[0], -this->Origin[1], -this->Origin[2]);
95     // scale
96     this->Transform->Scale(this->Scale[0], this->Scale[1], this->Scale[2]);
97 
98     // rotate
99     this->Transform->RotateY(this->Orientation[1]);
100     this->Transform->RotateX(this->Orientation[0]);
101     this->Transform->RotateZ(this->Orientation[2]);
102 
103     if (this->Camera)
104     {
105       double *pos, *vup, distance;
106       double Rx[3], Ry[3], Rz[3];
107 
108       vtkMatrix4x4* matrix = this->InternalMatrix;
109       matrix->Identity();
110 
111       // do the rotation
112       // first rotate y
113       pos = this->Camera->GetPosition();
114       vup = this->Camera->GetViewUp();
115 
116       if (this->Camera->GetParallelProjection())
117       {
118         this->Camera->GetDirectionOfProjection(Rz);
119         Rz[0] = -Rz[0];
120         Rz[1] = -Rz[1];
121         Rz[2] = -Rz[2];
122       }
123       else
124       {
125         distance = sqrt((pos[0] - this->Position[0]) * (pos[0] - this->Position[0]) +
126           (pos[1] - this->Position[1]) * (pos[1] - this->Position[1]) +
127           (pos[2] - this->Position[2]) * (pos[2] - this->Position[2]));
128         for (int i = 0; i < 3; i++)
129         {
130           Rz[i] = (pos[i] - this->Position[i]) / distance;
131         }
132       }
133 
134       // instead use the view right angle:
135       double dop[3], vur[3];
136       this->Camera->GetDirectionOfProjection(dop);
137 
138       vtkMath::Cross(dop, vup, vur);
139       vtkMath::Normalize(vur);
140 
141       vtkMath::Cross(Rz, vur, Ry);
142       vtkMath::Normalize(Ry);
143       vtkMath::Cross(Ry, Rz, Rx);
144 
145       matrix->Element[0][0] = Rx[0];
146       matrix->Element[1][0] = Rx[1];
147       matrix->Element[2][0] = Rx[2];
148       matrix->Element[0][1] = Ry[0];
149       matrix->Element[1][1] = Ry[1];
150       matrix->Element[2][1] = Ry[2];
151       matrix->Element[0][2] = Rz[0];
152       matrix->Element[1][2] = Rz[1];
153       matrix->Element[2][2] = Rz[2];
154 
155       this->Transform->Concatenate(matrix);
156     }
157 
158     // translate to projection reference point PRP
159     // this is the camera's position blasted through
160     // the current matrix
161     this->Transform->Translate(this->Origin[0] + this->Position[0],
162       this->Origin[1] + this->Position[1], this->Origin[2] + this->Position[2]);
163 
164     // apply user defined matrix last if there is one
165     if (this->UserMatrix)
166     {
167       this->Transform->Concatenate(this->UserMatrix);
168     }
169 
170     this->Transform->PreMultiply();
171     this->Transform->GetMatrix(this->Matrix);
172     this->MatrixMTime.Modified();
173     this->Transform->Pop();
174   }
175 }
176 
177 //------------------------------------------------------------------------------
GetBounds()178 double* vtkProp3DFollower::GetBounds()
179 {
180   if (this->Device)
181   {
182     this->ComputeMatrix();
183     this->Device->SetUserMatrix(this->Matrix);
184     return this->Device->GetBounds();
185   }
186   else
187   {
188     return nullptr;
189   }
190 }
191 
192 //------------------------------------------------------------------------------
ReleaseGraphicsResources(vtkWindow * w)193 void vtkProp3DFollower::ReleaseGraphicsResources(vtkWindow* w)
194 {
195   if (this->Device)
196   {
197     this->Device->ReleaseGraphicsResources(w);
198   }
199 }
200 
201 //------------------------------------------------------------------------------
202 // Description:
203 // Does this prop have some translucent polygonal geometry?
HasTranslucentPolygonalGeometry()204 vtkTypeBool vtkProp3DFollower::HasTranslucentPolygonalGeometry()
205 {
206   if (this->Device)
207   {
208     return this->Device->HasTranslucentPolygonalGeometry();
209   }
210   else
211   {
212     return 0;
213   }
214 }
215 
216 //------------------------------------------------------------------------------
RenderOpaqueGeometry(vtkViewport * vp)217 int vtkProp3DFollower::RenderOpaqueGeometry(vtkViewport* vp)
218 {
219   if (this->Device)
220   {
221     this->ComputeMatrix();
222     this->Device->SetUserMatrix(this->Matrix);
223     if (this->GetPropertyKeys())
224     {
225       this->Device->SetPropertyKeys(this->GetPropertyKeys());
226     }
227     if (this->GetVisibility())
228     {
229       return this->Device->RenderOpaqueGeometry(vp);
230     }
231   }
232   return 0;
233 }
234 
235 //------------------------------------------------------------------------------
RenderTranslucentPolygonalGeometry(vtkViewport * vp)236 int vtkProp3DFollower::RenderTranslucentPolygonalGeometry(vtkViewport* vp)
237 {
238   if (this->Device)
239   {
240     this->ComputeMatrix();
241     this->Device->SetUserMatrix(this->Matrix);
242     if (this->GetPropertyKeys())
243     {
244       this->Device->SetPropertyKeys(this->GetPropertyKeys());
245     }
246     if (this->GetVisibility())
247     {
248       return this->Device->RenderTranslucentPolygonalGeometry(vp);
249     }
250   }
251   return 0;
252 }
253 
254 //------------------------------------------------------------------------------
RenderVolumetricGeometry(vtkViewport * vp)255 int vtkProp3DFollower::RenderVolumetricGeometry(vtkViewport* vp)
256 {
257   if (this->Device)
258   {
259     this->ComputeMatrix();
260     this->Device->SetUserMatrix(this->Matrix);
261     if (this->GetPropertyKeys())
262     {
263       this->Device->SetPropertyKeys(this->GetPropertyKeys());
264     }
265     if (this->GetVisibility())
266     {
267       return this->Device->RenderVolumetricGeometry(vp);
268     }
269   }
270   return 0;
271 }
272 
273 //------------------------------------------------------------------------------
ShallowCopy(vtkProp * prop)274 void vtkProp3DFollower::ShallowCopy(vtkProp* prop)
275 {
276   vtkProp3DFollower* f = vtkProp3DFollower::SafeDownCast(prop);
277   if (f != nullptr)
278   {
279     this->SetCamera(f->GetCamera());
280   }
281 
282   // Now do superclass
283   this->vtkProp3D::ShallowCopy(prop);
284 }
285 
286 //------------------------------------------------------------------------------
InitPathTraversal()287 void vtkProp3DFollower::InitPathTraversal()
288 {
289   if (this->Device)
290   {
291     this->Device->InitPathTraversal();
292   }
293 }
294 
295 //------------------------------------------------------------------------------
GetNextPath()296 vtkAssemblyPath* vtkProp3DFollower::GetNextPath()
297 {
298   if (this->Device)
299   {
300     return this->Device->GetNextPath();
301   }
302   else
303   {
304     return nullptr;
305   }
306 }
307 
308 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)309 void vtkProp3DFollower::PrintSelf(ostream& os, vtkIndent indent)
310 {
311   this->Superclass::PrintSelf(os, indent);
312 
313   if (this->Camera)
314   {
315     os << indent << "Camera:\n";
316     this->Camera->PrintSelf(os, indent.GetNextIndent());
317   }
318   else
319   {
320     os << indent << "Camera: (none)\n";
321   }
322 }
323