1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkPropAssembly.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 "vtkPropAssembly.h"
16 
17 #include "vtkAssemblyNode.h"
18 #include "vtkAssemblyPath.h"
19 #include "vtkAssemblyPaths.h"
20 #include "vtkMath.h"
21 #include "vtkObjectFactory.h"
22 #include "vtkProp.h"
23 #include "vtkPropCollection.h"
24 #include "vtkViewport.h"
25 
26 vtkStandardNewMacro(vtkPropAssembly);
27 
28 // Construct object with no children.
vtkPropAssembly()29 vtkPropAssembly::vtkPropAssembly()
30 {
31   this->Parts = vtkPropCollection::New();
32   vtkMath::UninitializeBounds(this->Bounds);
33 }
34 
~vtkPropAssembly()35 vtkPropAssembly::~vtkPropAssembly()
36 {
37   vtkCollectionSimpleIterator pit;
38   vtkProp *part;
39   for ( this->Parts->InitTraversal(pit);
40        (part=this->Parts->GetNextProp(pit)); )
41   {
42     part->RemoveConsumer(this);
43   }
44 
45   this->Parts->Delete();
46   this->Parts = nullptr;
47 }
48 
49 // Add a part to the list of Parts.
AddPart(vtkProp * prop)50 void vtkPropAssembly::AddPart(vtkProp *prop)
51 {
52   if ( ! this->Parts->IsItemPresent(prop) )
53   {
54     this->Parts->AddItem(prop);
55     prop->AddConsumer(this);
56     this->Modified();
57   }
58 }
59 
60 // Remove a part from the list of parts,
RemovePart(vtkProp * prop)61 void vtkPropAssembly::RemovePart(vtkProp *prop)
62 {
63   if ( this->Parts->IsItemPresent(prop) )
64   {
65     prop->RemoveConsumer(this);
66     this->Parts->RemoveItem(prop);
67     this->Modified();
68   }
69 }
70 
71 // Get the list of parts for this prop assembly.
GetParts()72 vtkPropCollection *vtkPropAssembly::GetParts()
73 {
74   return this->Parts;
75 }
76 
77 // Render this assembly and all of its Parts. The rendering process is recursive.
RenderTranslucentPolygonalGeometry(vtkViewport * ren)78 int vtkPropAssembly::RenderTranslucentPolygonalGeometry(vtkViewport *ren)
79 {
80   vtkProp *prop;
81   vtkAssemblyPath *path;
82   double fraction;
83   int renderedSomething=0;
84 
85   // Make sure the paths are up-to-date
86   this->UpdatePaths();
87 
88   double numberOfItems =  static_cast<double>(this->Parts->GetNumberOfItems());
89   fraction = numberOfItems >= 1.0 ?
90     this->AllocatedRenderTime / numberOfItems : this->AllocatedRenderTime;
91 
92 
93   // render the Paths
94   vtkCollectionSimpleIterator sit;
95   for ( this->Paths->InitTraversal(sit); (path = this->Paths->GetNextPath(sit)); )
96   {
97     prop = path->GetLastNode()->GetViewProp();
98     if ( prop->GetVisibility() )
99     {
100       prop->SetAllocatedRenderTime(fraction, ren);
101       prop->PokeMatrix(path->GetLastNode()->GetMatrix());
102       renderedSomething += prop->RenderTranslucentPolygonalGeometry(ren);
103       prop->PokeMatrix(nullptr);
104     }
105   }
106 
107   return renderedSomething;
108 }
109 
110 // Description:
111 // Does this prop have some translucent polygonal geometry?
HasTranslucentPolygonalGeometry()112 vtkTypeBool vtkPropAssembly::HasTranslucentPolygonalGeometry()
113 {
114   vtkProp *prop;
115   vtkAssemblyPath *path;
116   int result=0;
117 
118   // Make sure the paths are up-to-date
119   this->UpdatePaths();
120 
121   // render the Paths
122   vtkCollectionSimpleIterator sit;
123   for ( this->Paths->InitTraversal(sit); !result && (path = this->Paths->GetNextPath(sit)); )
124   {
125     prop = path->GetLastNode()->GetViewProp();
126     if ( prop->GetVisibility() )
127     {
128       result=prop->HasTranslucentPolygonalGeometry();
129     }
130   }
131   return result;
132 }
133 
134 
135 // Render this assembly and all of its Parts. The rendering process is recursive.
RenderVolumetricGeometry(vtkViewport * ren)136 int vtkPropAssembly::RenderVolumetricGeometry(vtkViewport *ren)
137 {
138   vtkProp *prop;
139   vtkAssemblyPath *path;
140   double fraction;
141   int renderedSomething=0;
142 
143    // Make sure the paths are up-to-date
144   this->UpdatePaths();
145 
146   double numberOfItems =  static_cast<double>(this->Parts->GetNumberOfItems());
147   fraction = numberOfItems >= 1.0 ?
148     this->AllocatedRenderTime / numberOfItems : this->AllocatedRenderTime;
149 
150   // render the Paths
151   vtkCollectionSimpleIterator sit;
152   for ( this->Paths->InitTraversal(sit); (path = this->Paths->GetNextPath(sit)); )
153   {
154     prop = path->GetLastNode()->GetViewProp();
155     if ( prop->GetVisibility() )
156     {
157       prop->SetAllocatedRenderTime(fraction, ren);
158       prop->PokeMatrix(path->GetLastNode()->GetMatrix());
159       renderedSomething += prop->RenderVolumetricGeometry(ren);
160       prop->PokeMatrix(nullptr);
161     }
162   }
163 
164   return renderedSomething;
165 }
166 
167 // Render this assembly and all its parts. The rendering process is recursive.
RenderOpaqueGeometry(vtkViewport * ren)168 int vtkPropAssembly::RenderOpaqueGeometry(vtkViewport *ren)
169 {
170   vtkProp *prop;
171   vtkAssemblyPath *path;
172   double fraction;
173   int   renderedSomething=0;
174 
175   // Make sure the paths are up-to-date
176   this->UpdatePaths();
177 
178   double numberOfItems =  static_cast<double>(this->Parts->GetNumberOfItems());
179   fraction = numberOfItems >= 1.0 ?
180     this->AllocatedRenderTime / numberOfItems : this->AllocatedRenderTime;
181 
182   // render the Paths
183   vtkCollectionSimpleIterator sit;
184   for ( this->Paths->InitTraversal(sit); (path = this->Paths->GetNextPath(sit)); )
185   {
186     prop = path->GetLastNode()->GetViewProp();
187     if ( prop->GetVisibility() )
188     {
189       prop->SetAllocatedRenderTime(fraction, ren);
190       prop->PokeMatrix(path->GetLastNode()->GetMatrix());
191       renderedSomething += prop->RenderOpaqueGeometry(ren);
192       prop->PokeMatrix(nullptr);
193     }
194   }
195 
196   return renderedSomething;
197 }
198 
199 // Render this assembly and all its parts. The rendering process is recursive.
RenderOverlay(vtkViewport * ren)200 int vtkPropAssembly::RenderOverlay(vtkViewport *ren)
201 {
202   vtkProp *prop;
203   vtkAssemblyPath *path;
204   double fraction;
205   int   renderedSomething=0;
206 
207   // Make sure the paths are up-to-date
208   this->UpdatePaths();
209 
210   double numberOfItems =  static_cast<double>(this->Parts->GetNumberOfItems());
211   fraction = numberOfItems >= 1.0 ?
212     this->AllocatedRenderTime / numberOfItems : this->AllocatedRenderTime;
213 
214   vtkCollectionSimpleIterator sit;
215   for ( this->Paths->InitTraversal(sit); (path = this->Paths->GetNextPath(sit)); )
216   {
217     prop = path->GetLastNode()->GetViewProp();
218     if ( prop->GetVisibility() )
219     {
220       prop->SetAllocatedRenderTime(fraction, ren);
221       prop->PokeMatrix(path->GetLastNode()->GetMatrix());
222       renderedSomething += prop->RenderOverlay(ren);
223       prop->PokeMatrix(nullptr);
224     }
225   }
226 
227   return renderedSomething;
228 }
229 
230 
ReleaseGraphicsResources(vtkWindow * renWin)231 void vtkPropAssembly::ReleaseGraphicsResources(vtkWindow *renWin)
232 {
233   vtkProp *part;
234 
235   vtkProp::ReleaseGraphicsResources(renWin);
236 
237   // broadcast the message down the Parts
238   vtkCollectionSimpleIterator pit;
239   for ( this->Parts->InitTraversal(pit);
240         (part=this->Parts->GetNextProp(pit)); )
241   {
242     part->ReleaseGraphicsResources(renWin);
243   }
244 }
245 
246 // Get the bounds for the assembly as (Xmin,Xmax,Ymin,Ymax,Zmin,Zmax).
GetBounds()247 double *vtkPropAssembly::GetBounds()
248 {
249   vtkProp *part;
250   int i, n;
251   double bbox[24];
252   int partVisible=0;
253 
254   // carefully compute the bounds
255   vtkCollectionSimpleIterator pit;
256   for ( this->Parts->InitTraversal(pit);
257         (part=this->Parts->GetNextProp(pit)); )
258   {
259     if ( part->GetVisibility() && part->GetUseBounds() )
260     {
261       const double *bounds = part->GetBounds();
262 
263       if ( bounds != nullptr )
264       {
265         //  For the purposes of GetBounds, an object is visible only if
266         //  its visibility is on and it has visible parts.
267         if (!partVisible)
268         {
269           // initialize the bounds
270           this->Bounds[0] =this->Bounds[2] =this->Bounds[4] = VTK_DOUBLE_MAX;
271           this->Bounds[1] =this->Bounds[3] =this->Bounds[5] = -VTK_DOUBLE_MAX;
272           partVisible = 1;
273         }
274 
275         // fill out vertices of a bounding box
276         bbox[ 0] = bounds[1]; bbox[ 1] = bounds[3]; bbox[ 2] = bounds[5];
277         bbox[ 3] = bounds[1]; bbox[ 4] = bounds[2]; bbox[ 5] = bounds[5];
278         bbox[ 6] = bounds[0]; bbox[ 7] = bounds[2]; bbox[ 8] = bounds[5];
279         bbox[ 9] = bounds[0]; bbox[10] = bounds[3]; bbox[11] = bounds[5];
280         bbox[12] = bounds[1]; bbox[13] = bounds[3]; bbox[14] = bounds[4];
281         bbox[15] = bounds[1]; bbox[16] = bounds[2]; bbox[17] = bounds[4];
282         bbox[18] = bounds[0]; bbox[19] = bounds[2]; bbox[20] = bounds[4];
283         bbox[21] = bounds[0]; bbox[22] = bounds[3]; bbox[23] = bounds[4];
284 
285         for (i = 0; i < 8; i++)
286         {
287           for (n = 0; n < 3; n++)
288           {
289             if (bbox[i*3+n] < this->Bounds[n*2])
290             {
291               this->Bounds[n*2] = bbox[i*3+n];
292             }
293             if (bbox[i*3+n] > this->Bounds[n*2+1])
294             {
295               this->Bounds[n*2+1] = bbox[i*3+n];
296             }
297           }
298         }//for each point of box
299       }//if bounds
300     }//for each part
301   }//for each part
302 
303   if ( ! partVisible )
304   {
305     return nullptr;
306   }
307   else
308   {
309     return this->Bounds;
310   }
311 }
312 
GetMTime()313 vtkMTimeType vtkPropAssembly::GetMTime()
314 {
315   vtkMTimeType mTime=this->vtkProp::GetMTime();
316   vtkMTimeType time;
317   vtkProp *part;
318 
319   vtkCollectionSimpleIterator pit;
320   for (this->Parts->InitTraversal(pit);
321        (part=this->Parts->GetNextProp(pit)); )
322   {
323     time = part->GetMTime();
324     mTime = ( time > mTime ? time : mTime );
325   }
326 
327   return mTime;
328 }
329 
330 // Shallow copy another vtkPropAssembly.
ShallowCopy(vtkProp * prop)331 void vtkPropAssembly::ShallowCopy(vtkProp *prop)
332 {
333   vtkPropAssembly *propAssembly = vtkPropAssembly::SafeDownCast(prop);
334   if ( propAssembly != nullptr && propAssembly != this )
335   {
336     vtkCollectionSimpleIterator pit;
337     vtkProp *part;
338     for ( this->Parts->InitTraversal(pit);
339         (part=this->Parts->GetNextProp(pit)); )
340     {
341       part->RemoveConsumer(this);
342     }
343     this->Parts->RemoveAllItems();
344     for ( propAssembly->Parts->InitTraversal(pit);
345         (part=propAssembly->Parts->GetNextProp(pit)); )
346     {
347       this->AddPart(part);
348     }
349   }
350 
351   this->vtkProp::ShallowCopy(prop);
352 }
353 
InitPathTraversal()354 void vtkPropAssembly::InitPathTraversal()
355 {
356   this->UpdatePaths();
357   this->Paths->InitTraversal();
358 }
359 
GetNextPath()360 vtkAssemblyPath *vtkPropAssembly::GetNextPath()
361 {
362   if ( this->Paths )
363   {
364     return this->Paths->GetNextItem();
365   }
366   return nullptr;
367 }
368 
GetNumberOfPaths()369 int vtkPropAssembly::GetNumberOfPaths()
370 {
371   this->UpdatePaths();
372   return this->Paths->GetNumberOfItems();
373 }
374 
375 
376 // Build the assembly paths if necessary.
UpdatePaths()377 void vtkPropAssembly::UpdatePaths()
378 {
379   if ( this->GetMTime() > this->PathTime )
380   {
381     if ( this->Paths != nullptr )
382     {
383       this->Paths->Delete();
384       this->Paths = nullptr;
385     }
386 
387     // Create the list to hold all the paths
388     this->Paths = vtkAssemblyPaths::New();
389     vtkAssemblyPath *path = vtkAssemblyPath::New();
390 
391     //add ourselves to the path to start things off
392     path->AddNode(this,nullptr);
393 
394     vtkProp *prop;
395     // Add nodes as we proceed down the hierarchy
396     vtkCollectionSimpleIterator pit;
397     for ( this->Parts->InitTraversal(pit);
398           (prop = this->Parts->GetNextProp(pit)); )
399     {
400       // add a matrix, if any
401       path->AddNode(prop,prop->GetMatrix());
402 
403       // dive into the hierarchy
404       prop->BuildPaths(this->Paths,path);
405 
406       // when returned, pop the last node off of the
407       // current path
408       path->DeleteLastNode();
409     }
410 
411     path->Delete();
412     this->PathTime.Modified();
413   }
414 }
415 
BuildPaths(vtkAssemblyPaths * paths,vtkAssemblyPath * path)416 void vtkPropAssembly::BuildPaths(vtkAssemblyPaths *paths,
417                                  vtkAssemblyPath *path)
418 {
419   vtkProp *prop;
420 
421   vtkCollectionSimpleIterator pit;
422   for ( this->Parts->InitTraversal(pit);
423         (prop = this->Parts->GetNextProp(pit)); )
424   {
425     path->AddNode(prop,nullptr);
426 
427     // dive into the hierarchy
428     prop->BuildPaths(paths,path);
429 
430     // when returned, pop the last node off of the
431     // current path
432     path->DeleteLastNode();
433   }
434 }
435 
436 
PrintSelf(ostream & os,vtkIndent indent)437 void vtkPropAssembly::PrintSelf(ostream& os, vtkIndent indent)
438 {
439   this->Superclass::PrintSelf(os,indent);
440 
441   os << indent << "There are: " << this->Parts->GetNumberOfItems()
442      << " parts in this assembly\n";
443 }
444