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