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