1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkVolumeOutlineSource.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 "vtkVolumeOutlineSource.h"
16
17 #include "vtkCellArray.h"
18 #include "vtkCellArrayIterator.h"
19 #include "vtkCellData.h"
20 #include "vtkDataSet.h"
21 #include "vtkDemandDrivenPipeline.h"
22 #include "vtkIdList.h"
23 #include "vtkImageData.h"
24 #include "vtkInformation.h"
25 #include "vtkInformationVector.h"
26 #include "vtkMath.h"
27 #include "vtkNew.h"
28 #include "vtkObjectFactory.h"
29 #include "vtkPoints.h"
30 #include "vtkPolyData.h"
31 #include "vtkStreamingDemandDrivenPipeline.h"
32 #include "vtkUnsignedCharArray.h"
33 #include "vtkVolumeMapper.h"
34
35 vtkStandardNewMacro(vtkVolumeOutlineSource);
36
37 vtkCxxSetObjectMacro(vtkVolumeOutlineSource, VolumeMapper, vtkVolumeMapper);
38
39 //------------------------------------------------------------------------------
vtkVolumeOutlineSource()40 vtkVolumeOutlineSource::vtkVolumeOutlineSource()
41 {
42 this->VolumeMapper = nullptr;
43 this->GenerateScalars = 0;
44 this->GenerateOutline = 1;
45 this->GenerateFaces = 0;
46 this->ActivePlaneId = -1;
47
48 this->Color[0] = 1.0;
49 this->Color[1] = 0.0;
50 this->Color[2] = 0.0;
51
52 this->ActivePlaneColor[0] = 1.0;
53 this->ActivePlaneColor[1] = 1.0;
54 this->ActivePlaneColor[2] = 0.0;
55
56 this->SetNumberOfInputPorts(0);
57 }
58
59 //------------------------------------------------------------------------------
~vtkVolumeOutlineSource()60 vtkVolumeOutlineSource::~vtkVolumeOutlineSource()
61 {
62 if (this->VolumeMapper)
63 {
64 this->VolumeMapper->Delete();
65 this->VolumeMapper = nullptr;
66 }
67 }
68
69 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)70 void vtkVolumeOutlineSource::PrintSelf(ostream& os, vtkIndent indent)
71 {
72 this->Superclass::PrintSelf(os, indent);
73
74 os << indent << "VolumeMapper: ";
75 if (this->VolumeMapper)
76 {
77 os << this->VolumeMapper << "\n";
78 }
79 else
80 {
81 os << "(none)\n";
82 }
83
84 os << indent << "GenerateFaces: " << (this->GenerateFaces ? "On\n" : "Off\n");
85
86 os << indent << "GenerateOutline: " << (this->GenerateOutline ? "On\n" : "Off\n");
87
88 os << indent << "GenerateScalars: " << (this->GenerateScalars ? "On\n" : "Off\n");
89
90 os << indent << "Color: " << this->Color[0] << ", " << this->Color[1] << ", " << this->Color[2]
91 << "\n";
92
93 os << indent << "ActivePlaneId: " << this->ActivePlaneId << "\n";
94
95 os << indent << "ActivePlaneColor: " << this->ActivePlaneColor[0] << ", "
96 << this->ActivePlaneColor[1] << ", " << this->ActivePlaneColor[2] << "\n";
97 }
98
99 //------------------------------------------------------------------------------
ComputeCubePlanes(double planes[3][4],double croppingPlanes[6],double bounds[6])100 int vtkVolumeOutlineSource::ComputeCubePlanes(
101 double planes[3][4], double croppingPlanes[6], double bounds[6])
102 {
103 // Combine the CroppingRegionPlanes and the Bounds to create
104 // a single array. For each dimension, store the planes in
105 // the following order: lo_bound, lo_crop_plane, hi_crop_plane, hi_bound.
106 // Also do range checking to ensure that the cropping planes
107 // are clamped to the bound limits.
108
109 for (int i = 0; i < 3; i++)
110 {
111 int j0 = 2 * i;
112 int j1 = 2 * i + 1;
113
114 double a = bounds[j0];
115 double b = croppingPlanes[j0];
116 double c = croppingPlanes[j1];
117 double d = bounds[j1];
118
119 // Sanity check
120 if (a > d || b > c)
121 {
122 return 0;
123 }
124
125 // Clamp cropping planes to bounds
126 if (b < a)
127 {
128 b = a;
129 }
130 if (b > d)
131 {
132 b = d;
133 }
134 if (c < a)
135 {
136 c = a;
137 }
138 if (c > d)
139 {
140 c = d;
141 }
142
143 planes[i][0] = a;
144 planes[i][1] = b;
145 planes[i][2] = c;
146 planes[i][3] = d;
147 }
148
149 return 1;
150 }
151
152 //------------------------------------------------------------------------------
ComputePipelineMTime(vtkInformation * vtkNotUsed (request),vtkInformationVector ** vtkNotUsed (inputVector),vtkInformationVector * vtkNotUsed (outputVector),int vtkNotUsed (requestFromOutputPort),vtkMTimeType * mtime)153 int vtkVolumeOutlineSource::ComputePipelineMTime(vtkInformation* vtkNotUsed(request),
154 vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* vtkNotUsed(outputVector),
155 int vtkNotUsed(requestFromOutputPort), vtkMTimeType* mtime)
156 {
157 vtkMTimeType mTime = this->GetMTime();
158 if (this->VolumeMapper)
159 {
160 vtkMTimeType mapperMTime = this->VolumeMapper->GetMTime();
161 if (mapperMTime > mTime)
162 {
163 mTime = mapperMTime;
164 }
165 vtkDemandDrivenPipeline* input =
166 vtkDemandDrivenPipeline::SafeDownCast(this->VolumeMapper->GetInputExecutive());
167 if (input)
168 {
169 // Need to do this because we are not formally connected
170 // to the Mapper's pipeline
171 input->UpdateInformation();
172 vtkMTimeType pipelineMTime = input->GetPipelineMTime();
173 if (pipelineMTime > mTime)
174 {
175 mTime = pipelineMTime;
176 }
177 }
178 }
179
180 *mtime = mTime;
181
182 return 1;
183 }
184
185 //------------------------------------------------------------------------------
RequestInformation(vtkInformation * vtkNotUsed (request),vtkInformationVector ** vtkNotUsed (inputVector),vtkInformationVector * vtkNotUsed (outputVector))186 int vtkVolumeOutlineSource::RequestInformation(vtkInformation* vtkNotUsed(request),
187 vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* vtkNotUsed(outputVector))
188 {
189 // Get the mapper's input, since this is the most convenient
190 // place to do so.
191
192 if (!this->VolumeMapper)
193 {
194 vtkWarningMacro("No VolumeMapper has been set.");
195 return 1;
196 }
197
198 vtkInformation* mapInfo = this->VolumeMapper->GetInputInformation();
199
200 if (!mapInfo)
201 {
202 vtkWarningMacro("The VolumeMapper does not have an input set.");
203 return 1;
204 }
205
206 // Don't have to update mapper's input, since it was done in
207 // ComputePipelineMTime.
208 // data->UpdateInformation();
209
210 // Don't call GetBounds because we need WholeExtent, while
211 // GetBounds only returns the bounds for Extent.
212
213 double spacing[3];
214 double origin[3];
215 int extent[6];
216
217 mapInfo->Get(vtkDataObject::SPACING(), spacing);
218 mapInfo->Get(vtkDataObject::ORIGIN(), origin);
219 mapInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), extent);
220
221 for (int i = 0; i < 3; i++)
222 {
223 int j0 = 2 * i;
224 int j1 = j0 + 1;
225
226 if (extent[j0] > extent[j1])
227 {
228 vtkMath::UninitializeBounds(this->Bounds);
229 break;
230 }
231
232 if (spacing[i] > 0)
233 {
234 this->Bounds[j0] = origin[i] + spacing[i] * extent[j0];
235 this->Bounds[j1] = origin[i] + spacing[i] * extent[j1];
236 }
237 else
238 {
239 this->Bounds[j0] = origin[i] + spacing[i] * extent[j1];
240 this->Bounds[j1] = origin[i] + spacing[i] * extent[j0];
241 }
242
243 this->CroppingRegionPlanes[j0] = this->Bounds[j0];
244 this->CroppingRegionPlanes[j1] = this->Bounds[j1];
245 }
246
247 this->CroppingRegionFlags = 0x0002000;
248
249 this->Cropping = this->VolumeMapper->GetCropping();
250 if (this->Cropping)
251 {
252 this->CroppingRegionFlags = this->VolumeMapper->GetCroppingRegionFlags();
253 this->VolumeMapper->GetCroppingRegionPlanes(this->CroppingRegionPlanes);
254 }
255
256 return 1;
257 }
258
259 //------------------------------------------------------------------------------
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** vtkNotUsed (inputVector),vtkInformationVector * outputVector)260 int vtkVolumeOutlineSource::RequestData(vtkInformation* vtkNotUsed(request),
261 vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector)
262 {
263 // get the info object
264 vtkInformation* outInfo = outputVector->GetInformationObject(0);
265
266 // get the output
267 vtkPolyData* output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
268
269 vtkDebugMacro(<< "Creating cropping region outline");
270
271 // For each of the 3 dimensions, there are 4 planes: two bounding planes
272 // on the outside, and two cropping region planes inside.
273 double planes[3][4];
274
275 if (!this->VolumeMapper || !this->VolumeMapper->GetInput() ||
276 !this->ComputeCubePlanes(planes, this->CroppingRegionPlanes, this->Bounds))
277 {
278 // If the bounds or the cropping planes are invalid, clear the data
279 output->SetPoints(nullptr);
280 output->SetLines(nullptr);
281 output->GetCellData()->SetScalars(nullptr);
282
283 return 1;
284 }
285
286 // Compute the tolerance for considering points or planes to be coincident
287 double tol = 0;
288 for (int planeDim = 0; planeDim < 3; planeDim++)
289 {
290 double d = planes[planeDim][3] - planes[planeDim][0];
291 tol += d * d;
292 }
293 tol = sqrt(tol) * 1e-5;
294
295 // Create an array to nudge crop planes over to the bounds if they are
296 // within tolerance of the bounds
297 int tolPtId[3][4];
298 vtkVolumeOutlineSource::NudgeCropPlanesToBounds(tolPtId, planes, tol);
299
300 // The all-important cropping flags
301 int flags = this->CroppingRegionFlags;
302
303 // The active plane, which gets a special color for its scalars
304 int activePlane = this->ActivePlaneId;
305 if (activePlane > 5)
306 {
307 activePlane = -1;
308 }
309
310 // Convert the colors to unsigned char for scalars
311 unsigned char colors[2][3];
312 vtkVolumeOutlineSource::CreateColorValues(colors, this->Color, this->ActivePlaneColor);
313
314 // Create the scalars used to color the lines
315 vtkUnsignedCharArray* scalars = nullptr;
316
317 if (this->GenerateScalars)
318 {
319 scalars = vtkUnsignedCharArray::New();
320 scalars->SetNumberOfComponents(3);
321 }
322
323 // Generate all the lines for the outline.
324 vtkCellArray* lines = nullptr;
325
326 if (this->GenerateOutline)
327 {
328 lines = vtkCellArray::New();
329 vtkVolumeOutlineSource::GenerateLines(lines, scalars, colors, activePlane, flags, tolPtId);
330 }
331
332 // Generate the polys for the outline
333 vtkCellArray* polys = nullptr;
334
335 if (this->GenerateFaces)
336 {
337 polys = vtkCellArray::New();
338 vtkVolumeOutlineSource::GeneratePolys(polys, scalars, colors, activePlane, flags, tolPtId);
339 }
340
341 // Generate the points that are used by the lines.
342 vtkPoints* points = vtkPoints::New();
343 vtkVolumeOutlineSource::GeneratePoints(points, lines, polys, planes, tol);
344
345 output->SetPoints(points);
346 points->Delete();
347
348 output->SetPolys(polys);
349 if (polys)
350 {
351 polys->Delete();
352 }
353
354 output->SetLines(lines);
355 if (lines)
356 {
357 lines->Delete();
358 }
359
360 output->GetCellData()->SetScalars(scalars);
361 if (scalars)
362 {
363 scalars->Delete();
364 }
365
366 return 1;
367 }
368
369 //------------------------------------------------------------------------------
GeneratePolys(vtkCellArray * polys,vtkUnsignedCharArray * scalars,unsigned char colors[2][3],int activePlane,int flags,int tolPtId[3][4])370 void vtkVolumeOutlineSource::GeneratePolys(vtkCellArray* polys, vtkUnsignedCharArray* scalars,
371 unsigned char colors[2][3], int activePlane, int flags, int tolPtId[3][4])
372 {
373 // Loop over the three dimensions and create the face rectangles
374 for (int dim0 = 0; dim0 < 3; dim0++)
375 {
376 // Compute the other two dimension indices
377 int dim1 = (dim0 + 1) % 3;
378 int dim2 = (dim0 + 2) % 3;
379
380 // Indices into the cubes
381 int idx[3];
382
383 // Loop over the "dim+2" dimension
384 for (int i = 0; i < 4; i++)
385 {
386 idx[dim2] = i;
387
388 // Loop over the "dim+1" dimension
389 for (int j = 0; j < 3; j++)
390 {
391 idx[dim1] = j;
392
393 // Make sure that the rect dim is not less than tolerance
394 if ((j == 0 && tolPtId[dim1][1] == 0) || (j == 2 && tolPtId[dim1][2] == 3))
395 {
396 continue;
397 }
398
399 // Loop over rectangle along the "dim" dimension
400 for (int k = 0; k < 3; k++)
401 {
402 idx[dim0] = k;
403
404 // Make sure that the rect dim is not less than tolerance
405 if ((k == 0 && tolPtId[dim0][1] == 0) || (k == 2 && tolPtId[dim0][2] == 3))
406 {
407 continue;
408 }
409
410 // The points in the rectangle, which are nudged over to the
411 // volume bounds if the cropping planes are within tolerance
412 // of the volume bounds.
413 int pointId[4];
414 pointId[0] = (tolPtId[2][idx[2]] * 16 + tolPtId[1][idx[1]] * 4 + tolPtId[0][idx[0]]);
415 idx[dim0] = k + 1;
416 pointId[1] = (tolPtId[2][idx[2]] * 16 + tolPtId[1][idx[1]] * 4 + tolPtId[0][idx[0]]);
417 idx[dim1] = j + 1;
418 pointId[2] = (tolPtId[2][idx[2]] * 16 + tolPtId[1][idx[1]] * 4 + tolPtId[0][idx[0]]);
419 idx[dim0] = k;
420 pointId[3] = (tolPtId[2][idx[2]] * 16 + tolPtId[1][idx[1]] * 4 + tolPtId[0][idx[0]]);
421 idx[dim1] = j;
422
423 // Loop through the two cubes adjacent to the rectangle,
424 // in order to determine whether the rectangle is internal:
425 // only external faces will be drawn. The "bitCheck"
426 // holds a bit for each of these two cubes.
427 int bitCheck = 0;
428 int cidx[3];
429 cidx[dim0] = idx[dim0];
430 cidx[dim1] = idx[dim1];
431 for (int ii = 0; ii < 2; ii++)
432 {
433 // First get idx[dim2]-1, then idx[dim2]
434 cidx[dim2] = idx[dim2] + ii - 1;
435 int flagval = 0;
436 if (cidx[dim2] >= 0 && cidx[dim2] < 3)
437 {
438 int flagbit = cidx[2] * 9 + cidx[1] * 3 + cidx[0];
439 flagval = ((flags >> flagbit) & 1);
440 }
441 bitCheck <<= 1;
442 bitCheck |= flagval;
443 }
444
445 // Whether we need to create a face depends on bitCheck.
446 // Values 00, 11 don't need lines, while 01 and 10 do.
447
448 // If our rect isn't an internal rect
449 if (bitCheck != 0x0 && bitCheck != 0x3)
450 {
451 // Check if the rect is on our active plane
452 int active = 0;
453 if (activePlane >= 0)
454 {
455 int planeDim = (activePlane >> 1); // same as "/ 2"
456 int planeIdx = 1 + (activePlane & 1); // same as "% 2"
457 if (planeDim == dim2 && i == planeIdx)
458 {
459 active = 1;
460 }
461 }
462
463 // Insert the rectangle with the correct sense
464 polys->InsertNextCell(4);
465 if (bitCheck == 0x2)
466 {
467 polys->InsertCellPoint(pointId[0]);
468 polys->InsertCellPoint(pointId[1]);
469 polys->InsertCellPoint(pointId[2]);
470 polys->InsertCellPoint(pointId[3]);
471 }
472 else // (bitCheck == 0x1)
473 {
474 polys->InsertCellPoint(pointId[3]);
475 polys->InsertCellPoint(pointId[2]);
476 polys->InsertCellPoint(pointId[1]);
477 polys->InsertCellPoint(pointId[0]);
478 }
479
480 // Color the face
481 if (scalars)
482 {
483 scalars->InsertNextTypedTuple(colors[active]);
484 }
485 }
486
487 } // loop over k
488 } // loop over j
489 } // loop over i
490 } // loop over dim0
491 }
492
493 //------------------------------------------------------------------------------
GenerateLines(vtkCellArray * lines,vtkUnsignedCharArray * scalars,unsigned char colors[2][3],int activePlane,int flags,int tolPtId[3][4])494 void vtkVolumeOutlineSource::GenerateLines(vtkCellArray* lines, vtkUnsignedCharArray* scalars,
495 unsigned char colors[2][3], int activePlane, int flags, int tolPtId[3][4])
496 {
497 // Loop over the three dimensions and create the lines
498 for (int dim0 = 0; dim0 < 3; dim0++)
499 {
500 // Compute the other two dimension indices
501 int dim1 = (dim0 + 1) % 3;
502 int dim2 = (dim0 + 2) % 3;
503
504 // Indices into the cubes
505 int idx[3];
506
507 // Loop over the "dim+2" dimension
508 for (int i = 0; i < 4; i++)
509 {
510 idx[dim2] = i;
511
512 // Loop over the "dim+1" dimension
513 for (int j = 0; j < 4; j++)
514 {
515 idx[dim1] = j;
516
517 // Loop over line segments along the "dim" dimension
518 for (int k = 0; k < 3; k++)
519 {
520 idx[dim0] = k;
521
522 // Make sure that the segment length is not less than tolerance
523 if ((k == 0 && tolPtId[dim0][1] == 0) || (k == 2 && tolPtId[dim0][2] == 3))
524 {
525 continue;
526 }
527
528 // The endpoints of the segment, which are nudged over to the
529 // volume bounds if the cropping planes are within tolerance
530 // of the volume bounds.
531 int pointId0 = (tolPtId[2][idx[2]] * 16 + tolPtId[1][idx[1]] * 4 + tolPtId[0][idx[0]]);
532 idx[dim0] = k + 1;
533 int pointId1 = (tolPtId[2][idx[2]] * 16 + tolPtId[1][idx[1]] * 4 + tolPtId[0][idx[0]]);
534 idx[dim0] = k;
535
536 // Loop through the four cubes adjacent to the line segment,
537 // in order to determine whether the line segment is on an
538 // edge: only the edge lines will be drawn. The "bitCheck"
539 // holds a bit for each of these four cubes.
540 int bitCheck = 0;
541 int cidx[3];
542 cidx[dim0] = idx[dim0];
543 for (int ii = 0; ii < 2; ii++)
544 {
545 // First get idx[dim1]-1, then idx[dim1]
546 cidx[dim1] = idx[dim1] + ii - 1;
547 for (int jj = 0; jj < 2; jj++)
548 {
549 // First get idx[dim2]-1, then idx[dim2], but reverse
550 // the order when ii loop is on its second iteration
551 cidx[dim2] = idx[dim2] + (ii ^ jj) - 1;
552 int flagval = 0;
553 if (cidx[dim1] >= 0 && cidx[dim1] < 3 && cidx[dim2] >= 0 && cidx[dim2] < 3)
554 {
555 int flagbit = cidx[2] * 9 + cidx[1] * 3 + cidx[0];
556 flagval = ((flags >> flagbit) & 1);
557 }
558 bitCheck <<= 1;
559 bitCheck |= flagval;
560 }
561 }
562
563 // Whether we need a line depends on the value of bitCheck.
564 // Values 0000, 0011, 0110, 1100, 1001, 1111 don't need lines.
565 // Build a bitfield to check our bitfield values against, each
566 // set bit in this new bitfield corresponds to a non-edge case.
567 const int noLineValues =
568 ((1 << 0x0) | (1 << 0x3) | (1 << 0x6) | (1 << 0x9) | (1 << 0xc) | (1 << 0xf));
569
570 // If our line segment is an edge, there is lots of work to do.
571 if (((noLineValues >> bitCheck) & 1) == 0)
572 {
573 // Check if the line segment is on our active plane
574 int active = 0;
575 if (activePlane >= 0)
576 {
577 int planeDim = (activePlane >> 1); // same as "/ 2"
578 int planeIdx = 1 + (activePlane & 1); // same as "% 2"
579 if ((planeDim == dim2 && i == planeIdx) || (planeDim == dim1 && j == planeIdx))
580 {
581 active = 1;
582 }
583 }
584
585 // Check to make sure line segment isn't already there
586 int foundDuplicate = 0;
587 lines->InitTraversal();
588 vtkIdType npts;
589 const vtkIdType* pts;
590 for (int cellId = 0; lines->GetNextCell(npts, pts); cellId++)
591 {
592 if (pts[0] == pointId0 && pts[1] == pointId1)
593 {
594 // Change color if current segment is on active plane
595 if (scalars && active)
596 {
597 scalars->SetTypedTuple(cellId, colors[active]);
598 }
599 foundDuplicate = 1;
600 break;
601 }
602 }
603
604 if (!foundDuplicate)
605 {
606 // Insert the line segment
607 lines->InsertNextCell(2);
608 lines->InsertCellPoint(pointId0);
609 lines->InsertCellPoint(pointId1);
610
611 // Color the line segment
612 if (scalars)
613 {
614 scalars->InsertNextTypedTuple(colors[active]);
615 }
616 }
617 }
618
619 } // loop over k
620 } // loop over j
621 } // loop over i
622 } // loop over dim0
623 }
624
625 //------------------------------------------------------------------------------
GeneratePoints(vtkPoints * points,vtkCellArray * lines,vtkCellArray * polys,double planes[3][4],double tol)626 void vtkVolumeOutlineSource::GeneratePoints(
627 vtkPoints* points, vtkCellArray* lines, vtkCellArray* polys, double planes[3][4], double tol)
628 {
629 // Use a bitfield to store which of the 64 points we need.
630 // Two 32-bit ints are a convenient, portable way to do this.
631 unsigned int pointBits1 = 0;
632 unsigned int pointBits2 = 0;
633
634 vtkIdType npts;
635 const vtkIdType* pts;
636 vtkCellArray* cellArrays[2];
637 cellArrays[0] = lines;
638 cellArrays[1] = polys;
639
640 for (int arrayId = 0; arrayId < 2; arrayId++)
641 {
642 if (cellArrays[arrayId])
643 {
644 cellArrays[arrayId]->InitTraversal();
645 while (cellArrays[arrayId]->GetNextCell(npts, pts))
646 {
647 for (int ii = 0; ii < npts; ii++)
648 {
649 int pointId = pts[ii];
650 if (pointId < 32)
651 {
652 pointBits1 |= (1 << pointId);
653 }
654 else
655 {
656 pointBits2 |= (1 << (pointId - 32));
657 }
658 }
659 }
660 }
661 }
662
663 // Create the array of up to 64 points, and use the pointBits bitfield
664 // to find out which points were used. It is also necessary to go through
665 // and update the cells with the modified point ids.
666 unsigned int pointBits = pointBits1;
667 int ptId = 0;
668 int newPtId = 0;
669
670 vtkNew<vtkIdList> repCell;
671 for (int i = 0; i < 4; i++)
672 {
673 // If we're halfway done, switch over to the next 32 bits
674 if (i == 2)
675 {
676 pointBits = pointBits2;
677 }
678
679 for (int j = 0; j < 4; j++)
680 {
681 for (int k = 0; k < 4; k++)
682 {
683 // Check to see if this point was actually used
684 if ((pointBits & 1))
685 {
686 // Add or subtract tolerance as an offset to help depth check
687 double x = planes[0][k] + tol * (1 - 2 * (k < 2));
688 double y = planes[1][j] + tol * (1 - 2 * (j < 2));
689 double z = planes[2][i] + tol * (1 - 2 * (i < 2));
690
691 points->InsertNextPoint(x, y, z);
692
693 for (int arrayId = 0; arrayId < 2; arrayId++)
694 {
695 // Go through the cells, substitute old Id for new Id
696 vtkCellArray* cells = cellArrays[arrayId];
697 if (cells)
698 {
699 auto cellIter = vtk::TakeSmartPointer(cells->NewIterator());
700 for (cellIter->GoToFirstCell(); !cellIter->IsDoneWithTraversal();
701 cellIter->GoToNextCell())
702 {
703 cellIter->GetCurrentCell(repCell);
704 for (int ii = 0; ii < repCell->GetNumberOfIds(); ii++)
705 {
706 if (repCell->GetId(ii) == ptId)
707 {
708 repCell->SetId(ii, newPtId);
709 }
710 }
711 cellIter->ReplaceCurrentCell(repCell);
712 }
713 }
714 }
715 newPtId++;
716 }
717 pointBits >>= 1;
718 ptId++;
719 }
720 }
721 }
722 }
723
724 //------------------------------------------------------------------------------
NudgeCropPlanesToBounds(int tolPtId[3][4],double planes[3][4],double tol)725 void vtkVolumeOutlineSource::NudgeCropPlanesToBounds(
726 int tolPtId[3][4], double planes[3][4], double tol)
727 {
728 for (int dim = 0; dim < 3; dim++)
729 {
730 tolPtId[dim][0] = 0;
731 tolPtId[dim][1] = 1;
732 tolPtId[dim][2] = 2;
733 tolPtId[dim][3] = 3;
734 if (planes[dim][1] - planes[dim][0] < tol)
735 {
736 tolPtId[dim][1] = 0;
737 }
738 if (planes[dim][3] - planes[dim][2] < tol)
739 {
740 tolPtId[dim][2] = 3;
741 }
742 }
743 }
744
745 //------------------------------------------------------------------------------
CreateColorValues(unsigned char colors[2][3],double color1[3],double color2[3])746 void vtkVolumeOutlineSource::CreateColorValues(
747 unsigned char colors[2][3], double color1[3], double color2[3])
748 {
749 // Convert the two colors to unsigned char
750 double* dcolors[2];
751 dcolors[0] = color1;
752 dcolors[1] = color2;
753
754 for (int i = 0; i < 2; i++)
755 {
756 for (int j = 0; j < 3; j++)
757 {
758 double val = dcolors[i][j];
759 if (val < 0)
760 {
761 val = 0;
762 }
763 if (val > 1)
764 {
765 val = 1;
766 }
767 colors[i][j] = static_cast<unsigned char>(val * 255);
768 }
769 }
770 }
771