1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkUnstructuredGridBunykRayCastFunction.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 "vtkUnstructuredGridBunykRayCastFunction.h"
16 
17 #include "vtkArrayDispatch.h"
18 #include "vtkCamera.h"
19 #include "vtkCell.h"
20 #include "vtkCellArray.h"
21 #include "vtkCellIterator.h"
22 #include "vtkCellType.h"
23 #include "vtkColorTransferFunction.h"
24 #include "vtkDoubleArray.h"
25 #include "vtkFloatArray.h"
26 #include "vtkIdList.h"
27 #include "vtkMath.h"
28 #include "vtkMatrix4x4.h"
29 #include "vtkObjectFactory.h"
30 #include "vtkPiecewiseFunction.h"
31 #include "vtkPointData.h"
32 #include "vtkRenderer.h"
33 #include "vtkSmartPointer.h"
34 #include "vtkTransform.h"
35 #include "vtkUnstructuredGrid.h"
36 #include "vtkUnstructuredGridVolumeRayCastIterator.h"
37 #include "vtkUnstructuredGridVolumeRayCastMapper.h"
38 #include "vtkVolume.h"
39 #include "vtkVolumeProperty.h"
40 
41 #include <cassert>
42 #include <cstdlib>
43 
44 vtkStandardNewMacro(vtkUnstructuredGridBunykRayCastFunction);
45 
46 #define VTK_BUNYKRCF_NUMLISTS 100000
47 
48 namespace
49 {
50 
51 struct TemplateCastRayWorker
52 {
53   vtkUnstructuredGridBunykRayCastFunction* Self;
54   int NumComponents;
55   int X;
56   int Y;
57   double FarClipZ;
58   vtkUnstructuredGridBunykRayCastFunction::Intersection*& IntersectionPtr;
59   vtkUnstructuredGridBunykRayCastFunction::Triangle*& CurrentTriangle;
60   vtkIdType& CurrentTetra;
61   vtkIdType* IntersectedCells;
62   double* IntersectionLengths;
63   int MaxNumIntersections;
64 
65   // Result:
66   vtkIdType NumIntersections;
67 
TemplateCastRayWorker__anonddc0fbf50111::TemplateCastRayWorker68   TemplateCastRayWorker(vtkUnstructuredGridBunykRayCastFunction* self, int numComponents, int x,
69     int y, double farClipZ, vtkUnstructuredGridBunykRayCastFunction::Intersection*& intersectionPtr,
70     vtkUnstructuredGridBunykRayCastFunction::Triangle*& currentTriangle, vtkIdType& currentTetra,
71     vtkIdType* intersectedCells, double* intersectedLengths, int maxNumIntersections)
72     : Self(self)
73     , NumComponents(numComponents)
74     , X(x)
75     , Y(y)
76     , FarClipZ(farClipZ)
77     , IntersectionPtr(intersectionPtr)
78     , CurrentTriangle(currentTriangle)
79     , CurrentTetra(currentTetra)
80     , IntersectedCells(intersectedCells)
81     , IntersectionLengths(intersectedLengths)
82     , MaxNumIntersections(maxNumIntersections)
83     , NumIntersections(0)
84   {
85   }
86 
87   TemplateCastRayWorker& operator=(const TemplateCastRayWorker&) = delete;
88 
89   // Execute the algorithm with all arrays set to nullptr.
operator ()__anonddc0fbf50111::TemplateCastRayWorker90   void operator()()
91   {
92     (*this)(static_cast<vtkAOSDataArrayTemplate<float>*>(nullptr),
93       static_cast<vtkAOSDataArrayTemplate<float>*>(nullptr),
94       static_cast<vtkAOSDataArrayTemplate<float>*>(nullptr));
95   }
96 
97   template <typename ScalarArrayT, typename NearArrayT, typename FarArrayT>
operator ()__anonddc0fbf50111::TemplateCastRayWorker98   void operator()(
99     ScalarArrayT* scalarArray, NearArrayT* nearIntersectionArray, FarArrayT* farIntersectionArray)
100   {
101     typedef typename NearArrayT::ValueType ValueType;
102 
103     int imageViewportSize[2];
104     this->Self->GetImageViewportSize(imageViewportSize);
105 
106     int origin[2];
107     this->Self->GetImageOrigin(origin);
108     float fx = this->X - origin[0];
109     float fy = this->Y - origin[1];
110 
111     double* points = this->Self->GetPoints();
112     vtkUnstructuredGridBunykRayCastFunction::Triangle** triangles = this->Self->GetTetraTriangles();
113 
114     vtkMatrix4x4* viewToWorld = this->Self->GetViewToWorldMatrix();
115 
116     vtkUnstructuredGridBunykRayCastFunction::Triangle* nextTriangle;
117     vtkIdType nextTetra;
118 
119     this->NumIntersections = 0;
120 
121     double nearZ = VTK_DOUBLE_MIN;
122     double nearPoint[4];
123     double viewCoords[4];
124     viewCoords[0] = ((float)this->X / (float)(imageViewportSize[0] - 1)) * 2.0 - 1.0;
125     viewCoords[1] = ((float)this->Y / (float)(imageViewportSize[1] - 1)) * 2.0 - 1.0;
126     // viewCoords[2] set when an intersection is found.
127     viewCoords[3] = 1.0;
128     if (this->CurrentTriangle)
129     {
130       // Find intersection in currentTriangle (the entry point).
131       nearZ = -(fx * this->CurrentTriangle->A + fy * this->CurrentTriangle->B +
132                 this->CurrentTriangle->D) /
133         this->CurrentTriangle->C;
134 
135       viewCoords[2] = nearZ;
136 
137       viewToWorld->MultiplyPoint(viewCoords, nearPoint);
138       nearPoint[0] /= nearPoint[3];
139       nearPoint[1] /= nearPoint[3];
140       nearPoint[2] /= nearPoint[3];
141     }
142 
143     while (this->NumIntersections < this->MaxNumIntersections)
144     {
145       // If we have exited the mesh (or are entering it for the first time,
146       // find the next intersection with an external face (which has already
147       // been found with rasterization).
148       if (!this->CurrentTriangle)
149       {
150         if (!this->IntersectionPtr)
151         {
152           break; // No more intersections.
153         }
154         this->CurrentTriangle = this->IntersectionPtr->TriPtr;
155         this->CurrentTetra = this->IntersectionPtr->TriPtr->ReferredByTetra[0];
156         this->IntersectionPtr = this->IntersectionPtr->Next;
157 
158         // Find intersection in currentTriangle (the entry point).
159         nearZ = -(fx * this->CurrentTriangle->A + fy * this->CurrentTriangle->B +
160                   this->CurrentTriangle->D) /
161           this->CurrentTriangle->C;
162 
163         viewCoords[2] = nearZ;
164 
165         viewToWorld->MultiplyPoint(viewCoords, nearPoint);
166         nearPoint[0] /= nearPoint[3];
167         nearPoint[1] /= nearPoint[3];
168         nearPoint[2] /= nearPoint[3];
169       }
170 
171       // Find all triangles that the ray may exit.
172       vtkUnstructuredGridBunykRayCastFunction::Triangle* candidate[3];
173 
174       int index = 0;
175       int i;
176       for (i = 0; i < 4; i++)
177       {
178         if (triangles[this->CurrentTetra * 4 + i] != this->CurrentTriangle)
179         {
180           if (index == 3)
181           {
182             vtkGenericWarningMacro("Ugh - found too many triangles!");
183           }
184           else
185           {
186             candidate[index++] = triangles[this->CurrentTetra * 4 + i];
187           }
188         }
189       }
190 
191       double farZ = VTK_DOUBLE_MAX;
192       int minIdx = -1;
193 
194       // Determine which face the ray exits the cell from.
195       for (i = 0; i < 3; i++)
196       {
197         // Far intersection is the nearest intersectation that is farther
198         // than nearZ.
199         double tmpZ = 1.0;
200         if (candidate[i]->C != 0.0)
201         {
202           tmpZ = -(fx * candidate[i]->A + fy * candidate[i]->B + candidate[i]->D) / candidate[i]->C;
203         }
204         if (tmpZ > nearZ && tmpZ < farZ)
205         {
206           farZ = tmpZ;
207           minIdx = i;
208         }
209       }
210 
211       // Now, the code above should ensure that farZ > nearZ, but I have
212       // seen the case where we reach here with farZ == nearZ.  This is very
213       // bad as we need ensure we always move forward so that we do not get
214       // into loops.  I think there is something with GCC 3.2.3 that makes
215       // the optimizer be too ambitous and turn the > into >=.
216       if ((minIdx == -1) || (farZ <= nearZ))
217       {
218         // The ray never exited the cell?  Perhaps numerical inaccuracies
219         // got us here.  Just bail out as if we exited the mesh.
220         nextTriangle = nullptr;
221         nextTetra = -1;
222       }
223       else
224       {
225         if (farZ > this->FarClipZ)
226         {
227           // Exit happened after point of interest.  Bail out now (in case
228           // we wish to restart).
229           return;
230         }
231 
232         if (this->IntersectedCells)
233         {
234           this->IntersectedCells[this->NumIntersections] = this->CurrentTetra;
235         }
236 
237         nextTriangle = candidate[minIdx];
238 
239         // Compute intersection with exiting face.
240         double farPoint[4];
241         viewCoords[2] = farZ;
242         viewToWorld->MultiplyPoint(viewCoords, farPoint);
243         farPoint[0] /= farPoint[3];
244         farPoint[1] /= farPoint[3];
245         farPoint[2] /= farPoint[3];
246         double dist = sqrt((nearPoint[0] - farPoint[0]) * (nearPoint[0] - farPoint[0]) +
247           (nearPoint[1] - farPoint[1]) * (nearPoint[1] - farPoint[1]) +
248           (nearPoint[2] - farPoint[2]) * (nearPoint[2] - farPoint[2]));
249 
250         if (this->IntersectionLengths)
251         {
252           this->IntersectionLengths[this->NumIntersections] = dist;
253         }
254 
255         // compute the barycentric weights
256         float ax, ay;
257         double a1, b1, c1;
258         ax = points[3 * this->CurrentTriangle->PointIndex[0]];
259         ay = points[3 * this->CurrentTriangle->PointIndex[0] + 1];
260         b1 = ((fx - ax) * this->CurrentTriangle->P2Y - (fy - ay) * this->CurrentTriangle->P2X) /
261           this->CurrentTriangle->Denominator;
262         c1 = ((fy - ay) * this->CurrentTriangle->P1X - (fx - ax) * this->CurrentTriangle->P1Y) /
263           this->CurrentTriangle->Denominator;
264         a1 = 1.0 - b1 - c1;
265 
266         double a2, b2, c2;
267         ax = points[3 * nextTriangle->PointIndex[0]];
268         ay = points[3 * nextTriangle->PointIndex[0] + 1];
269         b2 = ((fx - ax) * nextTriangle->P2Y - (fy - ay) * nextTriangle->P2X) /
270           nextTriangle->Denominator;
271         c2 = ((fy - ay) * nextTriangle->P1X - (fx - ax) * nextTriangle->P1Y) /
272           nextTriangle->Denominator;
273         a2 = 1.0 - b2 - c2;
274 
275         if (nearIntersectionArray)
276         {
277           for (int c = 0; c < this->NumComponents; c++)
278           {
279             ValueType A, B, C;
280             A = scalarArray->GetTypedComponent(this->CurrentTriangle->PointIndex[0], c);
281             B = scalarArray->GetTypedComponent(this->CurrentTriangle->PointIndex[1], c);
282             C = scalarArray->GetTypedComponent(this->CurrentTriangle->PointIndex[2], c);
283             nearIntersectionArray->SetTypedComponent(
284               this->NumIntersections, c, static_cast<ValueType>(a1 * A + b1 * B + c1 * C));
285           }
286         }
287 
288         if (farIntersectionArray)
289         {
290           for (int c = 0; c < this->NumComponents; c++)
291           {
292             ValueType A, B, C;
293             A = scalarArray->GetTypedComponent(nextTriangle->PointIndex[0], c);
294             B = scalarArray->GetTypedComponent(nextTriangle->PointIndex[1], c);
295             C = scalarArray->GetTypedComponent(nextTriangle->PointIndex[2], c);
296             farIntersectionArray->SetTypedComponent(
297               this->NumIntersections, c, static_cast<ValueType>(a2 * A + b2 * B + c2 * C));
298           }
299         }
300 
301         this->NumIntersections++;
302 
303         // The far triangle has one or two tetras in its referred list.
304         // If one, return -1 for next tetra and nullptr for next triangle
305         // since we are exiting. If two, return the one that isn't the
306         // current one.
307         if ((nextTriangle)->ReferredByTetra[1] == -1)
308         {
309           nextTetra = -1;
310           nextTriangle = nullptr;
311         }
312         else
313         {
314           if (nextTriangle->ReferredByTetra[0] == this->CurrentTetra)
315           {
316             nextTetra = nextTriangle->ReferredByTetra[1];
317           }
318           else
319           {
320             nextTetra = nextTriangle->ReferredByTetra[0];
321           }
322         }
323 
324         nearZ = farZ;
325         nearPoint[0] = farPoint[0];
326         nearPoint[1] = farPoint[1];
327         nearPoint[2] = farPoint[2];
328         nearPoint[3] = farPoint[3];
329       }
330 
331       this->CurrentTriangle = nextTriangle;
332       this->CurrentTetra = nextTetra;
333     }
334   }
335 };
336 
337 } // end anon namespace
338 
339 //------------------------------------------------------------------------------
340 
341 // This is an internal hidden class.
342 
343 class vtkUnstructuredGridBunykRayCastIterator : public vtkUnstructuredGridVolumeRayCastIterator
344 {
345 public:
346   vtkTypeMacro(vtkUnstructuredGridBunykRayCastIterator, vtkUnstructuredGridVolumeRayCastIterator);
347   static vtkUnstructuredGridBunykRayCastIterator* New();
348 
349   void Initialize(int x, int y) override;
350 
351   vtkIdType GetNextIntersections(vtkIdList* intersectedCells, vtkDoubleArray* intersectionLengths,
352     vtkDataArray* scalars, vtkDataArray* nearIntersections,
353     vtkDataArray* farIntersections) override;
354 
355   vtkSetObjectMacro(RayCastFunction, vtkUnstructuredGridBunykRayCastFunction);
356   vtkGetObjectMacro(RayCastFunction, vtkUnstructuredGridBunykRayCastFunction);
357 
358 protected:
359   vtkUnstructuredGridBunykRayCastIterator();
360   ~vtkUnstructuredGridBunykRayCastIterator() override;
361 
362   int RayPosition[2];
363 
364   vtkUnstructuredGridBunykRayCastFunction* RayCastFunction;
365 
366   vtkUnstructuredGridBunykRayCastFunction::Intersection* IntersectionPtr;
367   vtkUnstructuredGridBunykRayCastFunction::Triangle* CurrentTriangle;
368   vtkIdType CurrentTetra;
369 
370 private:
371   vtkUnstructuredGridBunykRayCastIterator(const vtkUnstructuredGridBunykRayCastIterator&) = delete;
372   void operator=(const vtkUnstructuredGridBunykRayCastIterator&) = delete;
373 };
374 
375 vtkStandardNewMacro(vtkUnstructuredGridBunykRayCastIterator);
376 
vtkUnstructuredGridBunykRayCastIterator()377 vtkUnstructuredGridBunykRayCastIterator::vtkUnstructuredGridBunykRayCastIterator()
378 {
379   this->RayCastFunction = nullptr;
380 }
381 
~vtkUnstructuredGridBunykRayCastIterator()382 vtkUnstructuredGridBunykRayCastIterator::~vtkUnstructuredGridBunykRayCastIterator()
383 {
384   this->SetRayCastFunction(nullptr);
385 }
386 
Initialize(int x,int y)387 void vtkUnstructuredGridBunykRayCastIterator::Initialize(int x, int y)
388 {
389   this->RayPosition[0] = x;
390   this->RayPosition[1] = y;
391 
392   this->IntersectionPtr =
393     this->RayCastFunction->GetIntersectionList(this->RayPosition[0], this->RayPosition[1]);
394   this->CurrentTriangle = nullptr;
395   this->CurrentTetra = -1;
396 
397   // Intersect cells until we get to Bounds[0] (the near clip plane).
398   TemplateCastRayWorker worker(this->RayCastFunction, 0, this->RayPosition[0], this->RayPosition[1],
399     this->Bounds[0], this->IntersectionPtr, this->CurrentTriangle, this->CurrentTetra, nullptr,
400     nullptr, this->MaxNumberOfIntersections);
401   do
402   {
403     worker();
404   } while (worker.NumIntersections > 0);
405 }
406 
GetNextIntersections(vtkIdList * intersectedCells,vtkDoubleArray * intersectionLengths,vtkDataArray * scalars,vtkDataArray * nearIntersections,vtkDataArray * farIntersections)407 vtkIdType vtkUnstructuredGridBunykRayCastIterator::GetNextIntersections(vtkIdList* intersectedCells,
408   vtkDoubleArray* intersectionLengths, vtkDataArray* scalars, vtkDataArray* nearIntersections,
409   vtkDataArray* farIntersections)
410 {
411   if (intersectedCells)
412   {
413     intersectedCells->SetNumberOfIds(this->MaxNumberOfIntersections);
414   }
415   if (intersectionLengths)
416   {
417     intersectionLengths->SetNumberOfComponents(1);
418     intersectionLengths->SetNumberOfTuples(this->MaxNumberOfIntersections);
419   }
420 
421   vtkIdType numIntersections = 0;
422 
423   if (!scalars)
424   {
425     TemplateCastRayWorker worker(this->RayCastFunction, 0, this->RayPosition[0],
426       this->RayPosition[1], this->Bounds[1], this->IntersectionPtr, this->CurrentTriangle,
427       this->CurrentTetra, intersectedCells ? intersectedCells->GetPointer(0) : nullptr,
428       intersectionLengths ? intersectionLengths->GetPointer(0) : nullptr,
429       this->MaxNumberOfIntersections);
430     worker();
431     numIntersections = worker.NumIntersections;
432   }
433   else
434   {
435     if ((scalars->GetDataType() != nearIntersections->GetDataType()) ||
436       (scalars->GetDataType() != farIntersections->GetDataType()))
437     {
438       vtkErrorMacro(<< "Data types for scalars do not match up.");
439     }
440 
441     nearIntersections->SetNumberOfComponents(scalars->GetNumberOfComponents());
442     nearIntersections->SetNumberOfTuples(this->MaxNumberOfIntersections);
443     farIntersections->SetNumberOfComponents(scalars->GetNumberOfComponents());
444     farIntersections->SetNumberOfTuples(this->MaxNumberOfIntersections);
445 
446     TemplateCastRayWorker worker(this->RayCastFunction, scalars->GetNumberOfComponents(),
447       this->RayPosition[0], this->RayPosition[1], this->Bounds[1], this->IntersectionPtr,
448       this->CurrentTriangle, this->CurrentTetra,
449       intersectedCells ? intersectedCells->GetPointer(0) : nullptr,
450       intersectionLengths ? intersectionLengths->GetPointer(0) : nullptr,
451       this->MaxNumberOfIntersections);
452 
453     if (!vtkArrayDispatch::Dispatch3SameValueType::Execute(
454           scalars, nearIntersections, farIntersections, worker))
455     {
456       vtkWarningMacro("Dispatch failed for scalars and intersections.");
457     }
458     else
459     {
460       numIntersections = worker.NumIntersections;
461     }
462 
463     nearIntersections->SetNumberOfTuples(numIntersections);
464     farIntersections->SetNumberOfTuples(numIntersections);
465   }
466 
467   if (intersectedCells)
468   {
469     intersectedCells->SetNumberOfIds(numIntersections);
470   }
471   if (intersectionLengths)
472   {
473     intersectionLengths->SetNumberOfTuples(numIntersections);
474   }
475 
476   return numIntersections;
477 }
478 
479 //------------------------------------------------------------------------------
480 
481 // Constructor - initially everything to null, and create a matrix for use later
vtkUnstructuredGridBunykRayCastFunction()482 vtkUnstructuredGridBunykRayCastFunction::vtkUnstructuredGridBunykRayCastFunction()
483 {
484   this->Renderer = nullptr;
485   this->Volume = nullptr;
486   this->Mapper = nullptr;
487   this->Valid = 0;
488   this->Points = nullptr;
489   this->Image = nullptr;
490   this->TriangleList = nullptr;
491   this->TetraTriangles = nullptr;
492   this->TetraTrianglesSize = 0;
493   this->NumberOfPoints = 0;
494   this->ImageSize[0] = 0;
495   this->ImageSize[1] = 0;
496   this->ViewToWorldMatrix = vtkMatrix4x4::New();
497 
498   for (int i = 0; i < VTK_BUNYKRCF_MAX_ARRAYS; i++)
499   {
500     this->IntersectionBuffer[i] = nullptr;
501     this->IntersectionBufferCount[i] = 0;
502   }
503 
504   this->SavedTriangleListInput = nullptr;
505 }
506 
507 // Destructor - release all memory
~vtkUnstructuredGridBunykRayCastFunction()508 vtkUnstructuredGridBunykRayCastFunction::~vtkUnstructuredGridBunykRayCastFunction()
509 {
510   delete[] this->Points;
511 
512   this->ClearImage();
513   delete[] this->Image;
514   this->Image = nullptr;
515 
516   delete[] this->TetraTriangles;
517 
518   int i;
519   for (i = 0; i < 20; i++)
520   {
521     delete[] this->IntersectionBuffer[i];
522   }
523 
524   while (this->TriangleList)
525   {
526     Triangle* tmp;
527     tmp = this->TriangleList->Next;
528     delete this->TriangleList;
529     this->TriangleList = tmp;
530   }
531 
532   this->ViewToWorldMatrix->Delete();
533 }
534 
535 // Clear the intersection image. This does NOT release memory -
536 // it just sets the link pointers to nullptr. The memory is
537 // contained in the IntersectionBuffer arrays.
ClearImage()538 void vtkUnstructuredGridBunykRayCastFunction::ClearImage()
539 {
540   int i;
541   if (this->Image)
542   {
543     for (i = 0; i < this->ImageSize[0] * this->ImageSize[1]; i++)
544     {
545       this->Image[i] = nullptr;
546     }
547   }
548 
549   for (i = 0; i < VTK_BUNYKRCF_MAX_ARRAYS; i++)
550   {
551     this->IntersectionBufferCount[i] = 0;
552   }
553 }
554 
555 // Since we are managing the memory ourself for these intersections,
556 // we need a new method. In this method we return an unused
557 // intersection element from our storage arrays. If we don't
558 // have one, we create a new storage array (unless we have run
559 // out of memory). The memory can never shrink, and will only be
560 // deleted when the class is destructed.
NewIntersection()561 void* vtkUnstructuredGridBunykRayCastFunction::NewIntersection()
562 {
563   // Look for the first buffer that has enough space, or the
564   // first one that has not yet been allocated
565   int i;
566   for (i = 0; i < VTK_BUNYKRCF_MAX_ARRAYS; i++)
567   {
568     if (!this->IntersectionBuffer[i] || this->IntersectionBufferCount[i] < VTK_BUNYKRCF_ARRAY_SIZE)
569     {
570       break;
571     }
572   }
573 
574   // We have run out of space - return nullptr
575   if (i == VTK_BUNYKRCF_MAX_ARRAYS)
576   {
577     vtkErrorMacro("Out of space for intersections!");
578     return nullptr;
579   }
580 
581   // We need another array - allocate it and set its count to 0 indicating
582   // that we have not used any elements yet
583   if (!this->IntersectionBuffer[i])
584   {
585     this->IntersectionBuffer[i] = new Intersection[VTK_BUNYKRCF_ARRAY_SIZE];
586     this->IntersectionBufferCount[i] = 0;
587   }
588 
589   // Return the first unused element
590   return (this->IntersectionBuffer[i] + (this->IntersectionBufferCount[i]++));
591 }
592 
593 // The Initialize method is called from the ray caster at the start of
594 // rendering. In this method we check if the render is valid (there is
595 // a renderer, a volume, a mapper, input, etc). We build the basic
596 // structured if necessary. Then we compute the view dependent information
597 // such as plane equations and barycentric coordinates per triangle,
598 // tranfromed points in view space, and the intersection list per pixel.
Initialize(vtkRenderer * ren,vtkVolume * vol)599 void vtkUnstructuredGridBunykRayCastFunction::Initialize(vtkRenderer* ren, vtkVolume* vol)
600 {
601   // Check if this is a valid render - we have all the required info
602   // such as the volume, renderer, mapper, input, etc.
603   this->Valid = this->CheckValidity(ren, vol);
604   if (!this->Valid)
605   {
606     return;
607   }
608 
609   // Cache some objects for later use during rendering
610   this->Mapper = vtkUnstructuredGridVolumeRayCastMapper::SafeDownCast(vol->GetMapper());
611   this->Renderer = ren;
612   this->Volume = vol;
613 
614   vtkUnstructuredGridBase* input = this->Mapper->GetInput();
615   int numPoints = input->GetNumberOfPoints();
616 
617   // If the number of points have changed, recreate the structure
618   if (numPoints != this->NumberOfPoints)
619   {
620     delete[] this->Points;
621     this->Points = new double[3 * numPoints];
622     this->NumberOfPoints = numPoints;
623   }
624 
625   // Get the image size from the ray cast mapper. The ImageViewportSize is
626   // the size of the whole viewport (this does not necessary equal pixel
627   // size since we may be over / undersampling on the image plane). The size
628   // (which will be stored in ImageSize) and the ImageOrigin represent the
629   // subregion of the whole image that we will be considering.
630   int size[2];
631   this->Mapper->GetImageInUseSize(size);
632   this->Mapper->GetImageOrigin(this->ImageOrigin);
633   this->Mapper->GetImageViewportSize(this->ImageViewportSize);
634 
635   // If our intersection image is not the right size, recreate it.
636   // Clear out any old intersections
637   this->ClearImage();
638   if (this->ImageSize[0] * this->ImageSize[1] != size[0] * size[1])
639   {
640     delete[] this->Image;
641     this->Image = new Intersection*[size[0] * size[1]];
642     this->ImageSize[0] = size[0];
643     this->ImageSize[1] = size[1];
644     this->ClearImage();
645   }
646 
647   // Transform the points. As a by product, compute the ViewToWorldMatrix
648   // that will be used later
649   this->TransformPoints();
650 
651   // If it has not yet been built, or the data has changed in
652   // some way, we will need to recreate the triangle list. This is
653   // view independent - although we will leave space in the structure
654   // for the view dependent info
655   this->UpdateTriangleList();
656 
657   // For each triangle store the plane equation and barycentric
658   // coefficients to be used to speed up rendering
659   this->ComputeViewDependentInfo();
660 
661   // Project each boundary triangle onto the image and store intersections
662   // sorted by depth
663   this->ComputePixelIntersections();
664 }
665 
CheckValidity(vtkRenderer * ren,vtkVolume * vol)666 int vtkUnstructuredGridBunykRayCastFunction::CheckValidity(vtkRenderer* ren, vtkVolume* vol)
667 {
668   // We must have a renderer
669   if (!ren)
670   {
671     vtkErrorMacro("No Renderer");
672     return 0;
673   }
674 
675   // We must have a volume
676   if (!vol)
677   {
678     vtkErrorMacro("No Volume");
679     return 0;
680   }
681 
682   // We must have a mapper of the correct type
683   vtkUnstructuredGridVolumeRayCastMapper* mapper =
684     vtkUnstructuredGridVolumeRayCastMapper::SafeDownCast(vol->GetMapper());
685   if (!mapper)
686   {
687     vtkErrorMacro("No mapper or wrong type");
688     return 0;
689   }
690 
691   // The mapper must have input
692   vtkUnstructuredGridBase* input = mapper->GetInput();
693   if (!input)
694   {
695     vtkErrorMacro("No input to mapper");
696     return 0;
697   }
698 
699   // The input must have some points. This is a silent
700   // error - just render nothing if it occurs.
701   int numPoints = input->GetNumberOfPoints();
702   if (numPoints == 0)
703   {
704     this->Valid = 0;
705     return 0;
706   }
707 
708   return 1;
709 }
710 
711 // This is done once per render - transform the points into view coordinate.
712 // We also compute the ViewToWorldMatrix here (by inverting the matrix
713 // we use to project to view coordinates) so that later on in the
714 // rendering process we can convert points back to world coordinates.
TransformPoints()715 void vtkUnstructuredGridBunykRayCastFunction::TransformPoints()
716 {
717   vtkRenderer* ren = this->Renderer;
718   vtkVolume* vol = this->Volume;
719 
720   ren->ComputeAspect();
721   double* aspect = ren->GetAspect();
722 
723   vtkTransform* perspectiveTransform = vtkTransform::New();
724   vtkMatrix4x4* perspectiveMatrix = vtkMatrix4x4::New();
725 
726   // Get the view matrix in two steps - there is a one step method in camera
727   // but it turns off stereo so we do not want to use that one
728   vtkCamera* cam = ren->GetActiveCamera();
729   perspectiveTransform->Identity();
730   perspectiveTransform->Concatenate(
731     cam->GetProjectionTransformMatrix(aspect[0] / aspect[1], 0.0, 1.0));
732   perspectiveTransform->Concatenate(cam->GetViewTransformMatrix());
733   perspectiveTransform->Concatenate(vol->GetMatrix());
734   perspectiveMatrix->DeepCopy(perspectiveTransform->GetMatrix());
735 
736   // Invert this project matrix and store for later use
737   this->ViewToWorldMatrix->DeepCopy(perspectiveTransform->GetMatrix());
738   this->ViewToWorldMatrix->Invert();
739 
740   double* origPtr;
741   double* transformedPtr = this->Points;
742   double in[4], out[4];
743   in[3] = 1.0;
744   vtkUnstructuredGridBase* input = this->Mapper->GetInput();
745   int numPoints = input->GetNumberOfPoints();
746 
747   // Loop through all the points and transform them
748   for (int i = 0; i < numPoints; i++)
749   {
750     origPtr = input->GetPoint(i);
751     in[0] = origPtr[0];
752     in[1] = origPtr[1];
753     in[2] = origPtr[2];
754     perspectiveMatrix->MultiplyPoint(in, out);
755     transformedPtr[0] =
756       (out[0] / out[3] + 1.0) / 2.0 * (double)this->ImageViewportSize[0] - this->ImageOrigin[0];
757     transformedPtr[1] =
758       (out[1] / out[3] + 1.0) / 2.0 * (double)this->ImageViewportSize[1] - this->ImageOrigin[1];
759     transformedPtr[2] = out[2] / out[3];
760 
761     transformedPtr += 3;
762   }
763 
764   perspectiveTransform->Delete();
765   perspectiveMatrix->Delete();
766 }
767 
768 // This is done once per change in the data - build a list of
769 // enumerated triangles (up to four per tetra). Don't store
770 // duplicates, so we'll have to search for them.
UpdateTriangleList()771 void vtkUnstructuredGridBunykRayCastFunction::UpdateTriangleList()
772 {
773   int needsUpdate = 0;
774 
775   // If we have never created the list, we need updating
776   if (!this->TriangleList)
777   {
778     needsUpdate = 1;
779   }
780 
781   // If the data has changed in some way then we need to update
782   vtkUnstructuredGridBase* input = this->Mapper->GetInput();
783   if (this->SavedTriangleListInput != input ||
784     input->GetMTime() > this->SavedTriangleListMTime.GetMTime())
785   {
786     needsUpdate = 1;
787   }
788 
789   // If we don't need updating, return
790   if (!needsUpdate)
791   {
792     return;
793   }
794 
795   // Clear out the old triangle list
796   while (this->TriangleList)
797   {
798     Triangle* tmp;
799     tmp = this->TriangleList->Next;
800     delete this->TriangleList;
801     this->TriangleList = tmp;
802   }
803   this->TriangleList = nullptr;
804 
805   // A temporary structure to reduce search time - VTK_BUNYKRCF_NUMLISTS small
806   // lists instead of one big one
807   Triangle* tmpList[VTK_BUNYKRCF_NUMLISTS];
808 
809   vtkIdType i;
810   for (i = 0; i < VTK_BUNYKRCF_NUMLISTS; i++)
811   {
812     tmpList[i] = nullptr;
813   }
814 
815   vtkIdType numCells = input->GetNumberOfCells();
816 
817   // Provide a warnings for anomalous conditions.
818   int nonTetraWarningNeeded = 0;
819   int faceUsed3TimesWarning = 0;
820 
821   // Create a set of links from each tetra to the four triangles
822   // This is redundant information, but saves time during rendering
823 
824   if (this->TetraTriangles != nullptr && numCells != this->TetraTrianglesSize)
825   {
826     delete[] this->TetraTriangles;
827     this->TetraTriangles = nullptr;
828   }
829   if (this->TetraTriangles == nullptr)
830   {
831     this->TetraTriangles = new Triangle*[4 * numCells];
832     this->TetraTrianglesSize = numCells;
833   }
834 
835   // Loop through all the cells
836   vtkSmartPointer<vtkCellIterator> cellIter =
837     vtkSmartPointer<vtkCellIterator>::Take(input->NewCellIterator());
838   for (cellIter->InitTraversal(); !cellIter->IsDoneWithTraversal(); cellIter->GoToNextCell())
839   {
840     // We only handle tetra
841     if (cellIter->GetCellType() != VTK_TETRA)
842     {
843       nonTetraWarningNeeded = 1;
844       continue;
845     }
846 
847     // Get the four points
848     i = cellIter->GetCellId();
849     vtkIdList* ptIds = cellIter->GetPointIds();
850     vtkIdType pts[4];
851     pts[0] = ptIds->GetId(0);
852     pts[1] = ptIds->GetId(1);
853     pts[2] = ptIds->GetId(2);
854     pts[3] = ptIds->GetId(3);
855 
856     // Build each of the four triangles
857     int ii, jj;
858     for (jj = 0; jj < 4; jj++)
859     {
860       vtkIdType tri[3];
861       int idx = 0;
862       for (ii = 0; ii < 4; ii++)
863       {
864         if (ii != jj)
865         {
866           tri[idx++] = pts[ii];
867         }
868       }
869 
870       if (tri[0] > tri[1])
871       {
872         vtkIdType tmptri = tri[0];
873         tri[0] = tri[1];
874         tri[1] = tmptri;
875       }
876       if (tri[1] > tri[2])
877       {
878         vtkIdType tmptri = tri[1];
879         tri[1] = tri[2];
880         tri[2] = tmptri;
881       }
882       if (tri[0] > tri[1])
883       {
884         vtkIdType tmptri = tri[0];
885         tri[0] = tri[1];
886         tri[1] = tmptri;
887       }
888 
889       // Do we have this triangle already?
890       Triangle* triPtr = tmpList[tri[0] % VTK_BUNYKRCF_NUMLISTS];
891       while (triPtr)
892       {
893         if (triPtr->PointIndex[0] == tri[0] && triPtr->PointIndex[1] == tri[1] &&
894           triPtr->PointIndex[2] == tri[2])
895         {
896           break;
897         }
898         triPtr = triPtr->Next;
899       }
900 
901       if (triPtr)
902       {
903         if (triPtr->ReferredByTetra[1] != -1)
904         {
905           faceUsed3TimesWarning = 1;
906         }
907         triPtr->ReferredByTetra[1] = i;
908         this->TetraTriangles[i * 4 + jj] = triPtr;
909       }
910       else
911       {
912         Triangle* next = new Triangle;
913         next->PointIndex[0] = tri[0];
914         next->PointIndex[1] = tri[1];
915         next->PointIndex[2] = tri[2];
916         next->ReferredByTetra[0] = i;
917         next->ReferredByTetra[1] = -1;
918 
919         next->Next = tmpList[tri[0] % VTK_BUNYKRCF_NUMLISTS];
920         tmpList[tri[0] % VTK_BUNYKRCF_NUMLISTS] = next;
921         this->TetraTriangles[i * 4 + jj] = next;
922       }
923     }
924   }
925 
926   if (nonTetraWarningNeeded)
927   {
928     vtkWarningMacro("Input contains more than tetrahedra - only tetrahedra are supported");
929   }
930   if (faceUsed3TimesWarning)
931   {
932     vtkWarningMacro("Degenerate topology - cell face used more than twice");
933   }
934 
935   // Put the list together
936   for (i = 0; i < VTK_BUNYKRCF_NUMLISTS; i++)
937   {
938     if (tmpList[i])
939     {
940       Triangle* last = tmpList[i];
941       while (last->Next)
942       {
943         last = last->Next;
944       }
945       last->Next = this->TriangleList;
946       this->TriangleList = tmpList[i];
947     }
948   }
949 
950   this->SavedTriangleListInput = input;
951   this->SavedTriangleListMTime.Modified();
952 }
953 
ComputeViewDependentInfo()954 void vtkUnstructuredGridBunykRayCastFunction::ComputeViewDependentInfo()
955 {
956   Triangle* triPtr = this->TriangleList;
957   while (triPtr)
958   {
959     double P1[3], P2[3];
960     double A[3], B[3], C[3];
961 
962     A[0] = this->Points[3 * triPtr->PointIndex[0]];
963     A[1] = this->Points[3 * triPtr->PointIndex[0] + 1];
964     A[2] = this->Points[3 * triPtr->PointIndex[0] + 2];
965     B[0] = this->Points[3 * triPtr->PointIndex[1]];
966     B[1] = this->Points[3 * triPtr->PointIndex[1] + 1];
967     B[2] = this->Points[3 * triPtr->PointIndex[1] + 2];
968     C[0] = this->Points[3 * triPtr->PointIndex[2]];
969     C[1] = this->Points[3 * triPtr->PointIndex[2] + 1];
970     C[2] = this->Points[3 * triPtr->PointIndex[2] + 2];
971 
972     P1[0] = B[0] - A[0];
973     P1[1] = B[1] - A[1];
974     P1[2] = B[2] - A[2];
975 
976     P2[0] = C[0] - A[0];
977     P2[1] = C[1] - A[1];
978     P2[2] = C[2] - A[2];
979 
980     triPtr->Denominator = P1[0] * P2[1] - P2[0] * P1[1];
981 
982     if (triPtr->Denominator < 0)
983     {
984       double T[3];
985       triPtr->Denominator = -triPtr->Denominator;
986       T[0] = P1[0];
987       T[1] = P1[1];
988       T[2] = P1[2];
989       P1[0] = P2[0];
990       P1[1] = P2[1];
991       P1[2] = P2[2];
992       P2[0] = T[0];
993       P2[1] = T[1];
994       P2[2] = T[2];
995       vtkIdType tmpIndex = triPtr->PointIndex[1];
996       triPtr->PointIndex[1] = triPtr->PointIndex[2];
997       triPtr->PointIndex[2] = tmpIndex;
998     }
999 
1000     triPtr->P1X = P1[0];
1001     triPtr->P1Y = P1[1];
1002     triPtr->P2X = P2[0];
1003     triPtr->P2Y = P2[1];
1004 
1005     double result[3];
1006     vtkMath::Cross(P1, P2, result);
1007     triPtr->A = result[0];
1008     triPtr->B = result[1];
1009     triPtr->C = result[2];
1010     triPtr->D = -(A[0] * result[0] + A[1] * result[1] + A[2] * result[2]);
1011 
1012     triPtr = triPtr->Next;
1013   }
1014 }
1015 
ComputePixelIntersections()1016 void vtkUnstructuredGridBunykRayCastFunction::ComputePixelIntersections()
1017 {
1018   Triangle* triPtr = this->TriangleList;
1019   while (triPtr)
1020   {
1021     if (triPtr->ReferredByTetra[1] == -1)
1022     {
1023       if (this->IsTriangleFrontFacing(triPtr, triPtr->ReferredByTetra[0]))
1024       {
1025         int minX = static_cast<int>(this->Points[3 * triPtr->PointIndex[0]]);
1026         int maxX = minX + 1;
1027         int minY = static_cast<int>(this->Points[3 * triPtr->PointIndex[0] + 1]);
1028         int maxY = minY + 1;
1029 
1030         int tmp;
1031 
1032         tmp = static_cast<int>(this->Points[3 * triPtr->PointIndex[1]]);
1033         minX = (tmp < minX) ? (tmp) : (minX);
1034         maxX = ((tmp + 1) > maxX) ? (tmp + 1) : (maxX);
1035 
1036         tmp = static_cast<int>(this->Points[3 * triPtr->PointIndex[1] + 1]);
1037         minY = (tmp < minY) ? (tmp) : (minY);
1038         maxY = ((tmp + 1) > maxY) ? (tmp + 1) : (maxY);
1039 
1040         tmp = static_cast<int>(this->Points[3 * triPtr->PointIndex[2]]);
1041         minX = (tmp < minX) ? (tmp) : (minX);
1042         maxX = ((tmp + 1) > maxX) ? (tmp + 1) : (maxX);
1043 
1044         tmp = static_cast<int>(this->Points[3 * triPtr->PointIndex[2] + 1]);
1045         minY = (tmp < minY) ? (tmp) : (minY);
1046         maxY = ((tmp + 1) > maxY) ? (tmp + 1) : (maxY);
1047 
1048         double minZ = this->Points[3 * triPtr->PointIndex[0] + 2];
1049         double ftmp;
1050 
1051         ftmp = this->Points[3 * triPtr->PointIndex[1] + 2];
1052         minZ = (ftmp < minZ) ? (ftmp) : (minZ);
1053 
1054         ftmp = this->Points[3 * triPtr->PointIndex[2] + 2];
1055         minZ = (ftmp < minZ) ? (ftmp) : (minZ);
1056 
1057         if (minX < this->ImageSize[0] - 1 && minY < this->ImageSize[1] - 1 && maxX >= 0 &&
1058           maxY >= 0 && minZ > 0.0)
1059         {
1060           minX = (minX < 0) ? (0) : (minX);
1061           maxX = (maxX > (this->ImageSize[0] - 1)) ? (this->ImageSize[0] - 1) : (maxX);
1062 
1063           minY = (minY < 0) ? (0) : (minY);
1064           maxY = (maxY > (this->ImageSize[1] - 1)) ? (this->ImageSize[1] - 1) : (maxY);
1065 
1066           int x, y;
1067           double ax, ay, az;
1068           ax = this->Points[3 * triPtr->PointIndex[0]];
1069           ay = this->Points[3 * triPtr->PointIndex[0] + 1];
1070           az = this->Points[3 * triPtr->PointIndex[0] + 2];
1071 
1072           for (y = minY; y <= maxY; y++)
1073           {
1074             double qy = (double)y - ay;
1075             for (x = minX; x <= maxX; x++)
1076             {
1077               double qx = (double)x - ax;
1078               if (this->InTriangle(qx, qy, triPtr))
1079               {
1080                 Intersection* intersect = (Intersection*)this->NewIntersection();
1081                 if (intersect)
1082                 {
1083                   intersect->TriPtr = triPtr;
1084                   intersect->Z = az;
1085                   intersect->Next = nullptr;
1086 
1087                   if (!this->Image[y * this->ImageSize[0] + x] ||
1088                     intersect->Z < this->Image[y * this->ImageSize[0] + x]->Z)
1089                   {
1090                     intersect->Next = this->Image[y * this->ImageSize[0] + x];
1091                     this->Image[y * this->ImageSize[0] + x] = intersect;
1092                   }
1093                   else
1094                   {
1095                     Intersection* test = this->Image[y * this->ImageSize[0] + x];
1096                     while (test->Next && intersect->Z > test->Next->Z)
1097                     {
1098                       test = test->Next;
1099                     }
1100                     Intersection* tmpNext = test->Next;
1101                     test->Next = intersect;
1102                     intersect->Next = tmpNext;
1103                   }
1104                 }
1105               }
1106             }
1107           }
1108         }
1109       }
1110     }
1111     triPtr = triPtr->Next;
1112   }
1113 }
1114 
1115 // Taken from equation on bottom of left column of page 3 - but note that the
1116 // equation in the paper has a mistake: (q1+q2) must be less than 1 (not denom as
1117 // stated in the paper).
InTriangle(double x,double y,Triangle * triPtr)1118 int vtkUnstructuredGridBunykRayCastFunction::InTriangle(double x, double y, Triangle* triPtr)
1119 {
1120   double q1, q2;
1121 
1122   q1 = (x * triPtr->P2Y - y * triPtr->P2X) / triPtr->Denominator;
1123   q2 = (y * triPtr->P1X - x * triPtr->P1Y) / triPtr->Denominator;
1124 
1125   if (q1 >= 0 && q2 >= 0 && (q1 + q2) <= 1.0)
1126   {
1127     return 1;
1128   }
1129   else
1130   {
1131     return 0;
1132   }
1133 }
1134 
IsTriangleFrontFacing(Triangle * triPtr,vtkIdType tetraIndex)1135 int vtkUnstructuredGridBunykRayCastFunction::IsTriangleFrontFacing(
1136   Triangle* triPtr, vtkIdType tetraIndex)
1137 {
1138   vtkCell* cell = this->Mapper->GetInput()->GetCell(tetraIndex);
1139 
1140   vtkIdType pts[4];
1141   pts[0] = cell->GetPointId(0);
1142   pts[1] = cell->GetPointId(1);
1143   pts[2] = cell->GetPointId(2);
1144   pts[3] = cell->GetPointId(3);
1145 
1146   for (int i = 0; i < 4; i++)
1147   {
1148     if (pts[i] != triPtr->PointIndex[0] && pts[i] != triPtr->PointIndex[1] &&
1149       pts[i] != triPtr->PointIndex[2])
1150     {
1151       double d = triPtr->A * this->Points[3 * pts[i]] + triPtr->B * this->Points[3 * pts[i] + 1] +
1152         triPtr->C * this->Points[3 * pts[i] + 2] + triPtr->D;
1153 
1154       return (d > 0);
1155     }
1156   }
1157 
1158   assert(0);
1159   return false;
1160 }
1161 
NewIterator()1162 vtkUnstructuredGridVolumeRayCastIterator* vtkUnstructuredGridBunykRayCastFunction::NewIterator()
1163 {
1164   if (!this->Valid)
1165     return nullptr;
1166 
1167   vtkUnstructuredGridBunykRayCastIterator* iterator =
1168     vtkUnstructuredGridBunykRayCastIterator::New();
1169   iterator->SetRayCastFunction(this);
1170 
1171   return iterator;
1172 }
1173 
Finalize()1174 void vtkUnstructuredGridBunykRayCastFunction::Finalize()
1175 {
1176   this->Renderer = nullptr;
1177   this->Volume = nullptr;
1178   this->Mapper = nullptr;
1179 
1180   this->Valid = 0;
1181 }
1182 
1183 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)1184 void vtkUnstructuredGridBunykRayCastFunction::PrintSelf(ostream& os, vtkIndent indent)
1185 {
1186   this->Superclass::PrintSelf(os, indent);
1187 
1188   // Do not want to print this->ViewToWorldMatrix , this->ImageViewportSize
1189   // this->ScalarOpacityUnitDistance , or this->ImageOrigin - these are
1190   // internal ivar and not part of the public API for this class
1191 }
1192