1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkImplicitModeller.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 "vtkImplicitModeller.h"
16
17 #include "vtkCell.h"
18 #include "vtkCellLocator.h"
19 #include "vtkClipPolyData.h"
20 #include "vtkCommand.h"
21 #include "vtkFloatArray.h"
22 #include "vtkGenericCell.h"
23 #include "vtkImageData.h"
24 #include "vtkImageIterator.h"
25 #include "vtkImageProgressIterator.h"
26 #include "vtkInformation.h"
27 #include "vtkInformationVector.h"
28 #include "vtkMath.h"
29 #include "vtkMultiThreader.h"
30 #include "vtkObjectFactory.h"
31 #include "vtkPlane.h"
32 #include "vtkPointData.h"
33 #include "vtkPolyData.h"
34 #include "vtkRectilinearGrid.h"
35 #include "vtkStreamingDemandDrivenPipeline.h"
36 #include "vtkStructuredGrid.h"
37 #include "vtkUnstructuredGrid.h"
38
39 #include <cmath>
40
41 vtkStandardNewMacro(vtkImplicitModeller);
42
43 struct vtkImplicitModellerAppendInfo
44 {
45 vtkImplicitModeller* Modeller;
46 vtkDataSet** Input;
47 double MaximumDistance;
48 };
49
50 //------------------------------------------------------------------------------
51 // Construct with sample dimensions=(50,50,50), and so that model bounds are
52 // automatically computed from the input. Capping is turned on with CapValue
53 // equal to a large positive number.
vtkImplicitModeller()54 vtkImplicitModeller::vtkImplicitModeller()
55 {
56 this->MaximumDistance = 0.1;
57
58 this->ModelBounds[0] = 0.0;
59 this->ModelBounds[1] = 0.0;
60 this->ModelBounds[2] = 0.0;
61 this->ModelBounds[3] = 0.0;
62 this->ModelBounds[4] = 0.0;
63 this->ModelBounds[5] = 0.0;
64 this->BoundsComputed = 0;
65
66 this->SampleDimensions[0] = 50;
67 this->SampleDimensions[1] = 50;
68 this->SampleDimensions[2] = 50;
69
70 this->Capping = 1;
71 this->OutputScalarType = VTK_FLOAT;
72 this->CapValue = this->GetScalarTypeMax(this->OutputScalarType);
73 this->ScaleToMaximumDistance = 0; // only used for non-float output type
74
75 this->DataAppended = 0;
76 this->AdjustBounds = 1;
77 this->AdjustDistance = 0.0125;
78
79 this->ProcessMode = VTK_CELL_MODE;
80 this->LocatorMaxLevel = 5;
81
82 this->Threader = vtkMultiThreader::New();
83 this->NumberOfThreads = this->Threader->GetNumberOfThreads();
84 }
85
~vtkImplicitModeller()86 vtkImplicitModeller::~vtkImplicitModeller()
87 {
88 if (this->Threader)
89 {
90 this->Threader->Delete();
91 }
92 }
93
SetOutputScalarType(int type)94 void vtkImplicitModeller::SetOutputScalarType(int type)
95 {
96 double scalarMax;
97
98 vtkDebugMacro(<< this->GetClassName() << " (" << this << "): setting OutputScalarType to "
99 << type);
100
101 scalarMax = this->GetScalarTypeMax(type);
102 if (scalarMax) // legal type
103 {
104 int modified = 0;
105 if (this->CapValue != scalarMax)
106 {
107 this->CapValue = scalarMax;
108 modified = 1;
109 }
110 if (this->OutputScalarType != type)
111 {
112 this->OutputScalarType = type;
113 modified = 1;
114 }
115 if (modified)
116 {
117 this->Modified();
118 }
119 }
120 }
121
SetCapValue(double value)122 void vtkImplicitModeller::SetCapValue(double value)
123 {
124 vtkDebugMacro(<< this->GetClassName() << " (" << this << "): setting CapValue to " << value);
125 // clamp to between 0 and max for scalar type
126 double max = this->GetScalarTypeMax(this->OutputScalarType);
127 if (this->CapValue != (value < 0 ? 0 : (value > max ? max : value)))
128 {
129 this->CapValue = (value < 0 ? 0 : (value > max ? max : value));
130 this->Modified();
131 }
132 }
133
GetScalarTypeMax(int type)134 double vtkImplicitModeller::GetScalarTypeMax(int type)
135 {
136 switch (type)
137 {
138 case VTK_UNSIGNED_CHAR:
139 return (double)VTK_UNSIGNED_CHAR_MAX;
140 case VTK_CHAR:
141 return (double)VTK_CHAR_MAX;
142 case VTK_UNSIGNED_SHORT:
143 return (double)VTK_UNSIGNED_SHORT_MAX;
144 case VTK_SHORT:
145 return (double)VTK_SHORT_MAX;
146 case VTK_UNSIGNED_INT:
147 return (double)VTK_UNSIGNED_INT_MAX;
148 case VTK_INT:
149 return (double)VTK_INT_MAX;
150 case VTK_UNSIGNED_LONG:
151 return (double)VTK_UNSIGNED_LONG_MAX;
152 case VTK_LONG:
153 return (double)VTK_LONG_MAX;
154 case VTK_FLOAT:
155 return (double)VTK_FLOAT_MAX;
156 case VTK_DOUBLE:
157 return (double)VTK_DOUBLE_MAX;
158 default:
159 return 0;
160 }
161 }
162
163 //------------------------------------------------------------------------------
164 // Initialize the filter for appending data. You must invoke the
165 // StartAppend() method before doing successive Appends(). It's also a
166 // good idea to manually specify the model bounds; otherwise the input
167 // bounds for the data will be used.
StartAppend()168 void vtkImplicitModeller::StartAppend()
169 {
170 this->StartAppend(0);
171 }
172
StartAppend(int internal)173 void vtkImplicitModeller::StartAppend(int internal)
174 {
175 vtkIdType numPts;
176 vtkIdType i;
177 double maxDistance;
178
179 if (!internal)
180 {
181 // we must call update information because we can't be sure that
182 // it has been called.
183 this->UpdateInformation();
184 }
185 vtkInformation* outInfo = this->GetOutputInformation(0);
186 outInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(),
187 vtkStreamingDemandDrivenPipeline::GetWholeExtent(outInfo), 6);
188
189 vtkDebugMacro(<< "Initializing data");
190 this->AllocateOutputData(this->GetOutput(), this->GetOutputInformation(0));
191 this->UpdateProgress(0.0);
192 this->DataAppended = 1;
193
194 numPts = this->SampleDimensions[0] * this->SampleDimensions[1] * this->SampleDimensions[2];
195
196 // initialize output to CapValue at each location
197 maxDistance = this->CapValue;
198 vtkDataArray* newScalars = this->GetOutput()->GetPointData()->GetScalars();
199 for (i = 0; i < numPts; i++)
200 {
201 newScalars->SetComponent(i, 0, maxDistance);
202 }
203 }
204
205 template <class OT>
SetOutputDistance(double distance,OT * outputValue,double capValue,double scaleFactor)206 void SetOutputDistance(double distance, OT* outputValue, double capValue, double scaleFactor)
207 {
208 // for now, just doing "normal" cast... could consider doing round?
209 if (scaleFactor) // need to scale the distance
210 {
211 *outputValue = static_cast<OT>(distance * scaleFactor);
212 }
213 else
214 {
215 if (capValue && distance > capValue) // clamping iff non-float type
216 {
217 distance = capValue;
218 }
219 *outputValue = static_cast<OT>(distance);
220 }
221 }
222
223 // Convert distance as stored in output (could be scaled and/or non-double
224 // type) to double distance with correct scaling
225 template <class OT>
ConvertToDoubleDistance(const OT & inDistance,double & distance,double & distance2,double scaleFactor)226 void ConvertToDoubleDistance(
227 const OT& inDistance, double& distance, double& distance2, double scaleFactor)
228 {
229 if (scaleFactor)
230 {
231 distance = inDistance * scaleFactor;
232 }
233 else
234 {
235 distance = inDistance;
236 }
237 distance2 = distance * distance;
238 }
239
240 //------------------------------------------------------------------------------
241 // Templated append for VTK_VOXEL_MODE process mode and any type of output data
242 template <class OT>
vtkImplicitModellerAppendExecute(vtkImplicitModeller * self,vtkDataSet * input,vtkImageData * outData,int outExt[6],double maxDistance,vtkCellLocator * locator,int id,OT *)243 void vtkImplicitModellerAppendExecute(vtkImplicitModeller* self, vtkDataSet* input,
244 vtkImageData* outData, int outExt[6], double maxDistance, vtkCellLocator* locator, int id, OT*)
245 {
246 int i, j, k;
247 int subId;
248 vtkIdType cellId;
249 double pcoords[3];
250 double *spacing, *origin;
251 double maxDistance2 = maxDistance * maxDistance;
252 double x[3], prevDistance, prevDistance2, distance2, betterDistance;
253 double closestPoint[3], mDist;
254
255 // allocate weights for the EvaluatePosition
256 double* weights = new double[input->GetMaxCellSize()];
257
258 // Traverse each voxel; using CellLocator to find the closest point
259 vtkGenericCell* cell = vtkGenericCell::New();
260
261 spacing = outData->GetSpacing();
262 origin = outData->GetOrigin();
263
264 vtkImageProgressIterator<OT> outIt(outData, outExt, self, id);
265
266 // so we know how to scale if desired
267 double scaleFactor = 0; // 0 used to indicate not scaling
268 double toDoubleScaleFactor = 0; // 0 used to indicate not scaling
269 double capValue = 0; // 0 used to indicate not clamping (float or double)
270 if (self->GetOutputScalarType() != VTK_FLOAT && self->GetOutputScalarType() != VTK_DOUBLE)
271 {
272 capValue = self->GetCapValue();
273 if (self->GetScaleToMaximumDistance())
274 {
275 scaleFactor = capValue / maxDistance;
276 toDoubleScaleFactor = maxDistance / capValue;
277 }
278 }
279
280 int testIndex = 0;
281 for (k = outExt[4]; k <= outExt[5]; k++)
282 {
283 x[2] = spacing[2] * k + origin[2];
284 for (j = outExt[2]; j <= outExt[3]; j++)
285 {
286 cellId = -1;
287 x[1] = spacing[1] * j + origin[1];
288 OT* outSI = outIt.BeginSpan();
289 for (i = outExt[0]; i <= outExt[1]; i++, testIndex++)
290 {
291 x[0] = spacing[0] * i + origin[0];
292 ConvertToDoubleDistance(*outSI, prevDistance, prevDistance2, toDoubleScaleFactor);
293 betterDistance = -1;
294
295 if (cellId != -1)
296 {
297 cell->EvaluatePosition(x, closestPoint, subId, pcoords, distance2, weights);
298 if (distance2 <= maxDistance2 && distance2 < prevDistance2)
299 {
300 mDist = sqrt(distance2);
301 betterDistance = mDist;
302 }
303 else if (prevDistance2 < maxDistance2)
304 {
305 mDist = prevDistance;
306 }
307 else
308 {
309 mDist = maxDistance;
310 }
311 }
312 else if (prevDistance2 < maxDistance2)
313 {
314 mDist = prevDistance;
315 }
316 else
317 {
318 mDist = maxDistance;
319 }
320
321 if (locator->FindClosestPointWithinRadius(
322 x, mDist, closestPoint, cell, cellId, subId, distance2))
323 {
324 if (distance2 <= prevDistance2)
325 {
326 betterDistance = sqrt(distance2);
327 }
328 }
329 else
330 {
331 cellId = -1;
332 }
333
334 if (betterDistance != -1)
335 {
336 SetOutputDistance(betterDistance, outSI, capValue, scaleFactor);
337 }
338
339 outSI++;
340 }
341 outIt.NextSpan();
342 }
343 }
344 cell->Delete();
345 delete[] weights;
346 }
347
348 //------------------------------------------------------------------------------
349 // This is the multithreaded piece of the append when doing per voxel
350 // processing - it is called once for each thread, with each thread
351 // taking a different slab of the output to work on. The actual work is done
352 // in vtkImplicitModellerAppendExecute; here we just setup for the per voxel
353 // processing.
vtkImplicitModeller_ThreadedAppend(void * arg)354 static VTK_THREAD_RETURN_TYPE vtkImplicitModeller_ThreadedAppend(void* arg)
355 {
356 int threadCount;
357 int threadId;
358 vtkImplicitModellerAppendInfo* userData;
359 vtkImageData* output;
360 double maxDistance;
361 int i;
362 double adjBounds[6];
363 double* spacing;
364 double* origin;
365 int slabSize, slabMin, slabMax;
366 int outExt[6];
367
368 threadId = ((vtkMultiThreader::ThreadInfo*)(arg))->ThreadID;
369 threadCount = ((vtkMultiThreader::ThreadInfo*)(arg))->NumberOfThreads;
370 userData = (vtkImplicitModellerAppendInfo*)(((vtkMultiThreader::ThreadInfo*)(arg))->UserData);
371
372 if (userData->Input[threadId] == nullptr)
373 {
374 return VTK_THREAD_RETURN_VALUE;
375 }
376
377 maxDistance = userData->MaximumDistance;
378
379 output = userData->Modeller->GetOutput();
380 spacing = output->GetSpacing();
381 origin = output->GetOrigin();
382
383 int* sampleDimensions = userData->Modeller->GetSampleDimensions();
384 if (!output->GetPointData()->GetScalars())
385 {
386 vtkGenericWarningMacro("Sanity check failed.");
387 return VTK_THREAD_RETURN_VALUE;
388 }
389
390 // break up into slabs based on threadId and threadCount
391 slabSize = sampleDimensions[2] / threadCount;
392 if (slabSize == 0) // in case threadCount > sampleDimensions[2]
393 {
394 slabSize = 1;
395 }
396 slabMin = threadId * slabSize;
397 if (slabMin >= sampleDimensions[2])
398 {
399 return VTK_THREAD_RETURN_VALUE;
400 }
401 slabMax = slabMin + slabSize - 1;
402 if (threadId == threadCount - 1)
403 {
404 slabMax = sampleDimensions[2] - 1;
405 }
406
407 const double* bounds = userData->Input[threadId]->GetBounds();
408 for (i = 0; i < 3; i++)
409 {
410 adjBounds[2 * i] = bounds[2 * i] - maxDistance;
411 adjBounds[2 * i + 1] = bounds[2 * i + 1] + maxDistance;
412 }
413
414 // compute dimensional bounds in data set
415 for (i = 0; i < 3; i++)
416 {
417 outExt[i * 2] = (int)((double)(adjBounds[2 * i] - origin[i]) / spacing[i]);
418 outExt[i * 2 + 1] = (int)((double)(adjBounds[2 * i + 1] - origin[i]) / spacing[i]);
419 if (outExt[i * 2] < 0)
420 {
421 outExt[i * 2] = 0;
422 }
423 if (outExt[i * 2 + 1] >= sampleDimensions[i])
424 {
425 outExt[i * 2 + 1] = sampleDimensions[i] - 1;
426 }
427 }
428
429 // input not close enough to effect this slab
430 if (outExt[4] > slabMax || outExt[5] < slabMin)
431 {
432 return VTK_THREAD_RETURN_VALUE;
433 }
434
435 // adjust min/max to match slab
436 if (outExt[4] < slabMin)
437 {
438 outExt[4] = slabMin;
439 }
440 if (outExt[5] > slabMax)
441 {
442 outExt[5] = slabMax;
443 }
444
445 vtkCellLocator* locator = vtkCellLocator::New();
446
447 // Set up the cell locator.
448 // If AutomaticOff, then NumberOfCellsPerBucket only used for allocating
449 // memory. If AutomaticOn, then NumberOfCellsPerBucket is used to guess
450 // the depth for the uniform octree required to support
451 // NumberOfCellsPerBucket (assuming uniform distribution of cells).
452 locator->SetDataSet(userData->Input[threadId]);
453 locator->AutomaticOff();
454 locator->SetMaxLevel(userData->Modeller->GetLocatorMaxLevel());
455 locator->SetNumberOfCellsPerBucket(1);
456 locator->CacheCellBoundsOn();
457 locator->BuildLocator();
458
459 switch (userData->Modeller->GetOutputScalarType())
460 {
461 vtkTemplateMacro(vtkImplicitModellerAppendExecute(userData->Modeller, userData->Input[threadId],
462 output, outExt, userData->MaximumDistance, locator, threadId, static_cast<VTK_TT*>(nullptr)));
463 default:
464 vtkGenericWarningMacro("Execute: Unknown output ScalarType");
465 return VTK_THREAD_RETURN_VALUE;
466 }
467
468 locator->Delete();
469 return VTK_THREAD_RETURN_VALUE;
470 }
471
472 //------------------------------------------------------------------------------
473 // Templated append for VTK_CELL_MODE process mode and any type of output data
474 template <class OT>
vtkImplicitModellerAppendExecute(vtkImplicitModeller * self,vtkDataSet * input,vtkImageData * outData,double maxDistance,OT *)475 void vtkImplicitModellerAppendExecute(
476 vtkImplicitModeller* self, vtkDataSet* input, vtkImageData* outData, double maxDistance, OT*)
477 {
478 int i, j, k, updateTime;
479 vtkIdType cellNum;
480 double adjBounds[6];
481 double pcoords[3];
482 int outExt[6];
483 double x[3], prevDistance2, distance, distance2;
484 int subId;
485 double closestPoint[3];
486 double* weights = new double[input->GetMaxCellSize()];
487 double maxDistance2;
488 double *spacing, *origin;
489
490 spacing = outData->GetSpacing();
491 origin = outData->GetOrigin();
492
493 maxDistance2 = maxDistance * maxDistance;
494 int* sampleDimensions = self->GetSampleDimensions();
495
496 // so we know how to scale if desired
497 double scaleFactor = 0; // 0 used to indicate not scaling
498 double toDoubleScaleFactor = 0; // 0 used to indicate not scaling
499 double capValue = 0; // 0 used to indicate not clamping (float or double)
500 if (self->GetOutputScalarType() != VTK_FLOAT && self->GetOutputScalarType() != VTK_DOUBLE)
501 {
502 capValue = self->GetCapValue();
503 if (self->GetScaleToMaximumDistance())
504 {
505 scaleFactor = capValue / maxDistance;
506 toDoubleScaleFactor = maxDistance / capValue;
507 }
508 }
509
510 //
511 // Traverse all cells; computing distance function on volume points.
512 //
513 vtkCell* cell;
514 updateTime = input->GetNumberOfCells() / 50; // update every 2%
515 if (updateTime < 1)
516 {
517 updateTime = 1;
518 }
519
520 for (cellNum = 0; cellNum < input->GetNumberOfCells(); cellNum++)
521 {
522 cell = input->GetCell(cellNum);
523 const double* bounds = cell->GetBounds();
524 for (i = 0; i < 3; i++)
525 {
526 adjBounds[2 * i] = bounds[2 * i] - maxDistance;
527 adjBounds[2 * i + 1] = bounds[2 * i + 1] + maxDistance;
528 }
529
530 // compute dimensional bounds in data set
531 for (i = 0; i < 3; i++)
532 {
533 outExt[i * 2] = (int)((double)(adjBounds[2 * i] - origin[i]) / spacing[i]);
534 outExt[i * 2 + 1] = (int)((double)(adjBounds[2 * i + 1] - origin[i]) / spacing[i]);
535 if (outExt[i * 2] < 0)
536 {
537 outExt[i * 2] = 0;
538 }
539 if (outExt[i * 2 + 1] >= sampleDimensions[i])
540 {
541 outExt[i * 2 + 1] = sampleDimensions[i] - 1;
542 }
543 }
544
545 vtkImageIterator<OT> outIt(outData, outExt);
546
547 for (k = outExt[4]; k <= outExt[5]; k++)
548 {
549 x[2] = spacing[2] * k + origin[2];
550 for (j = outExt[2]; j <= outExt[3]; j++)
551 {
552 x[1] = spacing[1] * j + origin[1];
553 OT* outSI = outIt.BeginSpan();
554 for (i = outExt[0]; i <= outExt[1]; i++)
555 {
556 x[0] = spacing[0] * i + origin[0];
557
558 ConvertToDoubleDistance(*outSI, distance, prevDistance2, toDoubleScaleFactor);
559
560 // union combination of distances
561 if (cell->EvaluatePosition(x, closestPoint, subId, pcoords, distance2, weights) != -1 &&
562 distance2 < prevDistance2 && distance2 <= maxDistance2)
563 {
564 distance = sqrt(distance2);
565 SetOutputDistance(distance, outSI, capValue, scaleFactor);
566 }
567 outSI++;
568 }
569 outIt.NextSpan();
570 }
571 }
572
573 if (cellNum % updateTime == 0)
574 {
575 self->UpdateProgress(double(cellNum + 1) / input->GetNumberOfCells());
576 }
577 }
578 delete[] weights;
579 }
580
581 // Append a data set to the existing output. To use this function,
582 // you'll have to invoke the StartAppend() method before doing
583 // successive appends. It's also a good idea to specify the model
584 // bounds; otherwise the input model bounds is used. When you've
585 // finished appending, use the EndAppend() method.
Append(vtkDataSet * input)586 void vtkImplicitModeller::Append(vtkDataSet* input)
587 {
588 vtkDebugMacro(<< "Appending data");
589
590 vtkImageData* output = this->GetOutput();
591
592 if (!this->BoundsComputed)
593 {
594 this->ComputeModelBounds(input);
595 }
596
597 if (this->ProcessMode == VTK_CELL_MODE)
598 {
599 if (!output->GetPointData()->GetScalars())
600 {
601 vtkErrorMacro("Sanity check failed.");
602 return;
603 }
604
605 switch (this->OutputScalarType)
606 {
607 vtkTemplateMacro(vtkImplicitModellerAppendExecute(
608 this, input, output, this->InternalMaxDistance, static_cast<VTK_TT*>(nullptr)));
609 }
610 }
611 else
612 {
613 vtkImplicitModellerAppendInfo info;
614 double minZ, maxZ;
615 int slabMin, slabMax, slabSize, i;
616 vtkClipPolyData **minClipper = nullptr, **maxClipper = nullptr;
617 vtkPlane **minPlane = nullptr, **maxPlane = nullptr;
618 double *spacing, *origin;
619
620 spacing = output->GetSpacing();
621 origin = output->GetOrigin();
622
623 // Use a MultiThreader here, splitting the volume into slabs to be processed
624 // by the separate threads
625
626 // Set the number of threads to use,
627 // then set the execution method and do it.
628 this->Threader->SetNumberOfThreads(this->NumberOfThreads);
629
630 // set up the info object for the thread
631 info.Modeller = this;
632 info.MaximumDistance = this->InternalMaxDistance;
633
634 info.Input = new vtkDataSet*[this->NumberOfThreads];
635 if (this->NumberOfThreads == 1)
636 {
637 info.Input[0] = input;
638 }
639 else
640 {
641 // if not PolyData, then copy the input for each thread
642 if (input->GetDataObjectType() != VTK_POLY_DATA)
643 {
644 for (i = 0; i < this->NumberOfThreads; i++)
645 {
646 switch (input->GetDataObjectType())
647 {
648 case VTK_STRUCTURED_GRID:
649 info.Input[i] = vtkStructuredGrid::New();
650 break;
651 case VTK_IMAGE_DATA:
652 info.Input[i] = vtkImageData::New();
653 break;
654 case VTK_UNSTRUCTURED_GRID:
655 info.Input[i] = vtkUnstructuredGrid::New();
656 break;
657 case VTK_RECTILINEAR_GRID:
658 info.Input[i] = vtkRectilinearGrid::New();
659 break;
660 default:
661 vtkErrorMacro(<< "Unexpected DataSet type!");
662 delete[] info.Input;
663 return;
664 }
665 info.Input[i]->CopyStructure(input);
666 }
667 }
668 else // break up the input data into slabs to help ensure thread safety
669
670 {
671 minClipper = new vtkClipPolyData*[this->NumberOfThreads];
672 maxClipper = new vtkClipPolyData*[this->NumberOfThreads];
673 minPlane = new vtkPlane*[this->NumberOfThreads];
674 maxPlane = new vtkPlane*[this->NumberOfThreads];
675
676 slabSize = this->SampleDimensions[2] / this->NumberOfThreads;
677 if (slabSize == 0) // in case threadCount > SampleDimensions[2]
678 {
679 slabSize = 1;
680 }
681
682 for (i = 0; i < this->NumberOfThreads; i++)
683 {
684 minPlane[i] = maxPlane[i] = nullptr;
685 //////////////////////////////////////////////////
686 // do the 1st clip
687 slabMin = i * slabSize;
688 if (slabMin >= this->SampleDimensions[2])
689 {
690 break;
691 }
692
693 // get/clip input cells in this slab + maxDistance+
694 minZ = spacing[2] * slabMin + origin[2] - this->InternalMaxDistance * 1.00001;
695 if (minZ < this->ModelBounds[4])
696 {
697 minZ = this->ModelBounds[4];
698 }
699
700 minPlane[i] = vtkPlane::New();
701 minPlane[i]->SetNormal(0.0, 0.0, -1.0);
702 minPlane[i]->SetOrigin(0.0, 0.0, minZ);
703
704 minClipper[i] = vtkClipPolyData::New();
705 minClipper[i]->SetInputData((vtkPolyData*)input);
706 minClipper[i]->SetClipFunction(minPlane[i]);
707 minClipper[i]->SetValue(0.0);
708 minClipper[i]->InsideOutOn();
709 minClipper[i]->Update();
710
711 if (minClipper[i]->GetOutput()->GetNumberOfCells() == 0)
712 {
713 info.Input[i] = nullptr;
714 maxPlane[i] = nullptr;
715 continue;
716 }
717 minClipper[i]->ReleaseDataFlagOn();
718
719 //////////////////////////////////////////////////
720 // do the 2nd clip
721 slabMax = slabMin + slabSize - 1;
722 if (i == this->NumberOfThreads - 1)
723 {
724 slabMax = this->SampleDimensions[2] - 1;
725 }
726
727 maxZ = spacing[2] * slabMax + origin[2] + this->InternalMaxDistance * 1.00001;
728 if (maxZ > this->ModelBounds[5])
729 {
730 maxZ = this->ModelBounds[5];
731 }
732 maxPlane[i] = vtkPlane::New();
733 maxPlane[i]->SetNormal(0.0, 0.0, 1.0);
734 maxPlane[i]->SetOrigin(0.0, 0.0, maxZ);
735
736 maxClipper[i] = vtkClipPolyData::New();
737 maxClipper[i]->SetInputConnection(minClipper[i]->GetOutputPort());
738 maxClipper[i]->SetClipFunction(maxPlane[i]);
739 maxClipper[i]->SetValue(0.0);
740 maxClipper[i]->InsideOutOn();
741 maxClipper[i]->Update();
742
743 if (maxClipper[i]->GetOutput()->GetNumberOfCells() == 0)
744 {
745 info.Input[i] = nullptr;
746 }
747 else
748 {
749 info.Input[i] = maxClipper[i]->GetOutput();
750 }
751 }
752 for (i++; i < this->NumberOfThreads; i++)
753 {
754 minPlane[i] = maxPlane[i] = nullptr;
755 }
756 }
757 }
758
759 this->Threader->SetSingleMethod(vtkImplicitModeller_ThreadedAppend, (void*)&info);
760 this->Threader->SingleMethodExecute();
761
762 // cleanup
763 if (this->NumberOfThreads > 1)
764 {
765 if (input->GetDataObjectType() != VTK_POLY_DATA)
766 {
767 for (i = 0; i < this->NumberOfThreads; i++)
768 {
769 info.Input[i]->Delete();
770 }
771 }
772 else
773 {
774 for (i = 0; i < this->NumberOfThreads; i++)
775 {
776 if (minPlane[i])
777 {
778 minPlane[i]->Delete();
779 minClipper[i]->Delete();
780 }
781 if (maxPlane[i])
782 {
783 maxPlane[i]->Delete();
784 maxClipper[i]->Delete();
785 }
786 }
787 delete[] minPlane;
788 delete[] maxPlane;
789 delete[] minClipper;
790 delete[] maxClipper;
791 }
792 }
793 delete[] info.Input;
794 }
795 }
796
797 //------------------------------------------------------------------------------
798 // Method completes the append process (does the capping if requested).
EndAppend()799 void vtkImplicitModeller::EndAppend()
800 {
801 vtkDataArray* newScalars;
802 vtkDebugMacro(<< "End append");
803
804 if (!(newScalars = this->GetOutput()->GetPointData()->GetScalars()))
805 {
806 vtkErrorMacro("Sanity check failed.");
807 return;
808 }
809
810 if (this->Capping)
811 {
812 this->Cap(newScalars);
813 }
814 this->UpdateProgress(1.0);
815 }
816
817 //------------------------------------------------------------------------------
RequestInformation(vtkInformation * vtkNotUsed (request),vtkInformationVector ** vtkNotUsed (inputVector),vtkInformationVector * outputVector)818 int vtkImplicitModeller::RequestInformation(vtkInformation* vtkNotUsed(request),
819 vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector)
820 {
821 // get the info objects
822 vtkInformation* outInfo = outputVector->GetInformationObject(0);
823
824 int i;
825 double ar[3], origin[3];
826
827 vtkDataObject::SetPointDataActiveScalarInfo(outInfo, this->OutputScalarType, 1);
828
829 outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), 0, this->SampleDimensions[0] - 1,
830 0, this->SampleDimensions[1] - 1, 0, this->SampleDimensions[2] - 1);
831
832 for (i = 0; i < 3; i++)
833 {
834 origin[i] = this->ModelBounds[2 * i];
835 if (this->SampleDimensions[i] <= 1)
836 {
837 ar[i] = 1;
838 }
839 else
840 {
841 ar[i] =
842 (this->ModelBounds[2 * i + 1] - this->ModelBounds[2 * i]) / (this->SampleDimensions[i] - 1);
843 }
844 }
845 outInfo->Set(vtkDataObject::ORIGIN(), origin, 3);
846 outInfo->Set(vtkDataObject::SPACING(), ar, 3);
847
848 return 1;
849 }
850
851 //------------------------------------------------------------------------------
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * vtkNotUsed (outputVector))852 int vtkImplicitModeller::RequestData(vtkInformation* vtkNotUsed(request),
853 vtkInformationVector** inputVector, vtkInformationVector* vtkNotUsed(outputVector))
854 {
855 // get the input
856 vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
857 vtkDataSet* input = vtkDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT()));
858
859 vtkDebugMacro(<< "Executing implicit model");
860
861 if (input == nullptr)
862 {
863 // we do not want to release the data because user might
864 // have called Append ...
865 return 0;
866 }
867
868 this->StartAppend(1);
869 this->Append(input);
870 this->EndAppend();
871
872 return 1;
873 }
874
875 // Compute ModelBounds from input geometry.
ComputeModelBounds(vtkDataSet * input)876 double vtkImplicitModeller::ComputeModelBounds(vtkDataSet* input)
877 {
878 const double* bounds;
879 double maxDist;
880 int i;
881 vtkImageData* output = this->GetOutput();
882 double tempd[3];
883
884 // compute model bounds if not set previously
885 if (this->ModelBounds[0] >= this->ModelBounds[1] ||
886 this->ModelBounds[2] >= this->ModelBounds[3] || this->ModelBounds[4] >= this->ModelBounds[5])
887 {
888 if (input != nullptr)
889 {
890 bounds = input->GetBounds();
891 }
892 else
893 {
894 vtkDataSet* dsInput = vtkDataSet::SafeDownCast(this->GetInput());
895 if (dsInput != nullptr)
896 {
897 bounds = dsInput->GetBounds();
898 }
899 else
900 {
901 vtkErrorMacro(<< "An input must be specified to Compute the model bounds.");
902 return VTK_FLOAT_MAX;
903 }
904 }
905 }
906 else
907 {
908 bounds = this->ModelBounds;
909 }
910
911 for (maxDist = 0.0, i = 0; i < 3; i++)
912 {
913 if ((bounds[2 * i + 1] - bounds[2 * i]) > maxDist)
914 {
915 maxDist = bounds[2 * i + 1] - bounds[2 * i];
916 }
917 }
918
919 // adjust bounds so model fits strictly inside (only if not set previously)
920 if (this->AdjustBounds)
921 {
922 for (i = 0; i < 3; i++)
923 {
924 this->ModelBounds[2 * i] = bounds[2 * i] - maxDist * this->AdjustDistance;
925 this->ModelBounds[2 * i + 1] = bounds[2 * i + 1] + maxDist * this->AdjustDistance;
926 }
927 }
928 else // to handle problem case where bounds not specified and AdjustBounds
929 // not on; will be setting ModelBounds to self if previosusly set
930 {
931 for (i = 0; i < 3; i++)
932 {
933 this->ModelBounds[2 * i] = bounds[2 * i];
934 this->ModelBounds[2 * i + 1] = bounds[2 * i + 1];
935 }
936 }
937
938 maxDist *= this->MaximumDistance;
939
940 // Set volume origin and data spacing
941 output->SetOrigin(this->ModelBounds[0], this->ModelBounds[2], this->ModelBounds[4]);
942
943 for (i = 0; i < 3; i++)
944 {
945 tempd[i] =
946 (this->ModelBounds[2 * i + 1] - this->ModelBounds[2 * i]) / (this->SampleDimensions[i] - 1);
947 }
948 output->SetSpacing(tempd);
949
950 vtkInformation* outInfo = this->GetExecutive()->GetOutputInformation(0);
951 outInfo->Set(
952 vtkDataObject::ORIGIN(), this->ModelBounds[0], this->ModelBounds[2], this->ModelBounds[4]);
953 outInfo->Set(vtkDataObject::SPACING(), tempd, 3);
954
955 this->BoundsComputed = 1;
956 this->InternalMaxDistance = maxDist;
957
958 return maxDist;
959 }
960
961 //------------------------------------------------------------------------------
962 // Set the i-j-k dimensions on which to sample the distance function.
SetSampleDimensions(int i,int j,int k)963 void vtkImplicitModeller::SetSampleDimensions(int i, int j, int k)
964 {
965 int dim[3];
966
967 dim[0] = i;
968 dim[1] = j;
969 dim[2] = k;
970
971 this->SetSampleDimensions(dim);
972 }
973
974 //------------------------------------------------------------------------------
SetSampleDimensions(int dim[3])975 void vtkImplicitModeller::SetSampleDimensions(int dim[3])
976 {
977 int dataDim, i;
978
979 vtkDebugMacro(<< " setting SampleDimensions to (" << dim[0] << "," << dim[1] << "," << dim[2]
980 << ")");
981
982 if (dim[0] != this->SampleDimensions[0] || dim[1] != this->SampleDimensions[1] ||
983 dim[2] != this->SampleDimensions[2])
984 {
985 if (dim[0] < 1 || dim[1] < 1 || dim[2] < 1)
986 {
987 vtkErrorMacro(<< "Bad Sample Dimensions, retaining previous values");
988 return;
989 }
990
991 for (dataDim = 0, i = 0; i < 3; i++)
992 {
993 if (dim[i] > 1)
994 {
995 dataDim++;
996 }
997 }
998
999 if (dataDim < 3)
1000 {
1001 vtkErrorMacro(<< "Sample dimensions must define a volume!");
1002 return;
1003 }
1004
1005 for (i = 0; i < 3; i++)
1006 {
1007 this->SampleDimensions[i] = dim[i];
1008 }
1009
1010 this->Modified();
1011 }
1012 }
1013
1014 //------------------------------------------------------------------------------
Cap(vtkDataArray * s)1015 void vtkImplicitModeller::Cap(vtkDataArray* s)
1016 {
1017 int i, j, k;
1018 int idx;
1019 int d01 = this->SampleDimensions[0] * this->SampleDimensions[1];
1020
1021 // i-j planes
1022 for (j = 0; j < this->SampleDimensions[1]; j++)
1023 {
1024 for (i = 0; i < this->SampleDimensions[0]; i++)
1025 {
1026 s->SetComponent(i + j * this->SampleDimensions[0], 0, this->CapValue);
1027 }
1028 }
1029 k = this->SampleDimensions[2] - 1;
1030 idx = k * d01;
1031 for (j = 0; j < this->SampleDimensions[1]; j++)
1032 {
1033 for (i = 0; i < this->SampleDimensions[0]; i++)
1034 {
1035 s->SetComponent(idx + i + j * this->SampleDimensions[0], 0, this->CapValue);
1036 }
1037 }
1038 // j-k planes
1039 for (k = 0; k < this->SampleDimensions[2]; k++)
1040 {
1041 for (j = 0; j < this->SampleDimensions[1]; j++)
1042 {
1043 s->SetComponent(j * this->SampleDimensions[0] + k * d01, 0, this->CapValue);
1044 }
1045 }
1046 i = this->SampleDimensions[0] - 1;
1047 for (k = 0; k < this->SampleDimensions[2]; k++)
1048 {
1049 for (j = 0; j < this->SampleDimensions[1]; j++)
1050 {
1051 s->SetComponent(i + j * this->SampleDimensions[0] + k * d01, 0, this->CapValue);
1052 }
1053 }
1054 // i-k planes
1055 for (k = 0; k < this->SampleDimensions[2]; k++)
1056 {
1057 for (i = 0; i < this->SampleDimensions[0]; i++)
1058 {
1059 s->SetComponent(i + k * d01, 0, this->CapValue);
1060 }
1061 }
1062 j = this->SampleDimensions[1] - 1;
1063 idx = j * this->SampleDimensions[0];
1064 for (k = 0; k < this->SampleDimensions[2]; k++)
1065 {
1066 for (i = 0; i < this->SampleDimensions[0]; i++)
1067 {
1068 s->SetComponent(idx + i + k * d01, 0, this->CapValue);
1069 }
1070 }
1071 }
1072
1073 //------------------------------------------------------------------------------
GetProcessModeAsString()1074 const char* vtkImplicitModeller::GetProcessModeAsString()
1075 {
1076 if (this->ProcessMode == VTK_CELL_MODE)
1077 {
1078 return "PerCell";
1079 }
1080 else
1081 {
1082 return "PerVoxel";
1083 }
1084 }
1085
1086 //------------------------------------------------------------------------------
FillInputPortInformation(int vtkNotUsed (port),vtkInformation * info)1087 int vtkImplicitModeller::FillInputPortInformation(int vtkNotUsed(port), vtkInformation* info)
1088 {
1089 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
1090 info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 1);
1091 return 1;
1092 }
1093
1094 //------------------------------------------------------------------------------
ProcessRequest(vtkInformation * request,vtkInformationVector ** inputVector,vtkInformationVector * outputVector)1095 vtkTypeBool vtkImplicitModeller::ProcessRequest(
1096 vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector)
1097 {
1098 // If we have no input then we will not generate the output because
1099 // the user already called StartAppend/Append/EndAppend.
1100 if (request->Has(vtkDemandDrivenPipeline::REQUEST_DATA_NOT_GENERATED()))
1101 {
1102 if (inputVector[0]->GetNumberOfInformationObjects() == 0)
1103 {
1104 vtkInformation* outInfo = outputVector->GetInformationObject(0);
1105 outInfo->Set(vtkDemandDrivenPipeline::DATA_NOT_GENERATED(), 1);
1106 }
1107 return 1;
1108 }
1109 else if (request->Has(vtkDemandDrivenPipeline::REQUEST_DATA()))
1110 {
1111 if (inputVector[0]->GetNumberOfInformationObjects() == 0)
1112 {
1113 return 1;
1114 }
1115 }
1116 return this->Superclass::ProcessRequest(request, inputVector, outputVector);
1117 }
1118
PrintSelf(ostream & os,vtkIndent indent)1119 void vtkImplicitModeller::PrintSelf(ostream& os, vtkIndent indent)
1120 {
1121 this->Superclass::PrintSelf(os, indent);
1122
1123 os << indent << "Maximum Distance: " << this->MaximumDistance << "\n";
1124 os << indent << "OutputScalarType: " << this->OutputScalarType << "\n";
1125 os << indent << "Sample Dimensions: (" << this->SampleDimensions[0] << ", "
1126 << this->SampleDimensions[1] << ", " << this->SampleDimensions[2] << ")\n";
1127 os << indent << "ModelBounds: \n";
1128 os << indent << " Xmin,Xmax: (" << this->ModelBounds[0] << ", " << this->ModelBounds[1] << ")\n";
1129 os << indent << " Ymin,Ymax: (" << this->ModelBounds[2] << ", " << this->ModelBounds[3] << ")\n";
1130 os << indent << " Zmin,Zmax: (" << this->ModelBounds[4] << ", " << this->ModelBounds[5] << ")\n";
1131
1132 os << indent << "ScaleToMaximumDistance: " << (this->ScaleToMaximumDistance ? "On\n" : "Off\n");
1133 os << indent << "AdjustBounds: " << (this->AdjustBounds ? "On\n" : "Off\n");
1134 os << indent << "Adjust Distance: " << this->AdjustDistance << "\n";
1135 os << indent << "Process Mode: " << this->ProcessMode << "\n";
1136 os << indent << "Locator Max Level: " << this->LocatorMaxLevel << "\n";
1137
1138 os << indent << "Capping: " << (this->Capping ? "On\n" : "Off\n");
1139 os << indent << "Cap Value: " << this->CapValue << "\n";
1140 os << indent << "Process Mode: " << this->GetProcessModeAsString() << endl;
1141 os << indent << "Number Of Threads (for PerVoxel mode): " << this->NumberOfThreads << endl;
1142 }
1143