1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkExtractCTHPart.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 "vtkExtractCTHPart.h"
16 
17 #include "vtkAppendPolyData.h"
18 #include "vtkBoundingBox.h"
19 #include "vtkCellArray.h"
20 #include "vtkCellData.h"
21 #include "vtkCharArray.h"
22 #include "vtkClipPolyData.h"
23 #include "vtkCompositeDataIterator.h"
24 #include "vtkCompositeDataPipeline.h"
25 #include "vtkCompositeDataSet.h"
26 #include "vtkContourFilter.h"
27 #include "vtkCutter.h"
28 #include "vtkDataSetSurfaceFilter.h"
29 #include "vtkDoubleArray.h"
30 #include "vtkExecutive.h"
31 #include "vtkExtractCTHPart.h"
32 #include "vtkGarbageCollector.h"
33 #include "vtkImageData.h"
34 #include "vtkInformation.h"
35 #include "vtkInformationVector.h"
36 #include "vtkMultiBlockDataSet.h"
37 #include "vtkMultiProcessController.h"
38 #include "vtkNew.h"
39 #include "vtkObjectFactory.h"
40 #include "vtkPlaneCollection.h"
41 #include "vtkPlane.h"
42 #include "vtkPointData.h"
43 #include "vtkPolyData.h"
44 #include "vtkRectilinearGrid.h"
45 #include "vtkSmartPointer.h"
46 #include "vtkTimerLog.h"
47 #include "vtkToolkits.h"
48 #include "vtkUniformGrid.h"
49 
50 #include <algorithm>
51 #include <cassert>
52 #include <math.h>
53 #include <string>
54 #include <vector>
55 
56 vtkStandardNewMacro(vtkExtractCTHPart);
57 vtkCxxSetObjectMacro(vtkExtractCTHPart,ClipPlane,vtkPlane);
58 vtkCxxSetObjectMacro(vtkExtractCTHPart,Controller,vtkMultiProcessController);
59 
60 const double CTH_AMR_SURFACE_VALUE=0.499;
61 const double CTH_AMR_SURFACE_VALUE_FLOAT=1;
62 const double CTH_AMR_SURFACE_VALUE_UNSIGNED_CHAR=255;
63 
64 //-----------------------------------------------------------------------------
65 //=============================================================================
66 class vtkExtractCTHPartInternal
67 {
68 public:
69   typedef std::vector<std::string> VolumeArrayNamesType;
70   VolumeArrayNamesType VolumeArrayNames;
71   vtkBoundingBox GlobalInputBounds;
72 
73   // Counter used to scale progress events.
74   int TotalNumberOfDatasets;
75 };
76 
77 class vtkExtractCTHPart::VectorOfFragments :
78   public std::vector<vtkSmartPointer<vtkPolyData> >
79 {
80 };
81 
82 class vtkExtractCTHPart::ScaledProgress
83 {
84   vtkExtractCTHPart* Self;
85   double Shift;
86   double Scale;
87 public:
ScaledProgress(double shift,double scale,vtkExtractCTHPart * self)88   ScaledProgress(double shift, double scale, vtkExtractCTHPart* self)
89     {
90     assert((self != NULL) &&
91       (shift >= 0.0) && (shift <= 1.0) &&
92       (scale >= 0.0) && (scale <= 1.0));
93 
94     this->Self = self;
95     this->Shift = self->ProgressShift;
96     this->Scale = self->ProgressScale;
97 
98     self->ProgressShift += shift * self->ProgressScale;
99     self->ProgressScale *= scale;
100     //cout << "Shift-Scale Push: " << self->ProgressShift << ", " <<
101     //  self->ProgressScale << endl;
102     }
103 
~ScaledProgress()104   ~ScaledProgress()
105     {
106     this->WorkDone();
107     }
108 
WorkDone()109   void WorkDone()
110     {
111     if (this->Self)
112       {
113       this->Self->ProgressScale = this->Scale;
114       this->Self->ProgressShift = this->Shift;
115       //cout << "Shift-Scale Pop: " << this->Self->ProgressShift << ", " <<
116       //  this->Self->ProgressScale << endl;
117       this->Self = NULL;
118       }
119     }
120 };
121 
122 
123 //=============================================================================
124 //-----------------------------------------------------------------------------
125 
126 //-----------------------------------------------------------------------------
vtkExtractCTHPart()127 vtkExtractCTHPart::vtkExtractCTHPart()
128 {
129   this->Internals = new vtkExtractCTHPartInternal();
130   this->ClipPlane = NULL;
131   this->GenerateTriangles = true;
132   this->Capping = true;
133   this->RemoveGhostCells = true;
134   this->VolumeFractionSurfaceValueInternal = CTH_AMR_SURFACE_VALUE;
135   this->VolumeFractionSurfaceValue = CTH_AMR_SURFACE_VALUE;
136   this->ProgressScale = 1.0;
137   this->ProgressShift = 0.0;
138 
139   this->Controller = 0;
140   this->SetController(vtkMultiProcessController::GetGlobalController());
141 }
142 
143 //-----------------------------------------------------------------------------
~vtkExtractCTHPart()144 vtkExtractCTHPart::~vtkExtractCTHPart()
145 {
146   this->SetController(NULL);
147   this->SetClipPlane(NULL);
148 
149   delete this->Internals;
150   this->Internals = 0;
151 }
152 
153 //-----------------------------------------------------------------------------
154 // Overload standard modified time function. If clip plane is modified,
155 // then this object is modified as well.
GetMTime()156 unsigned long vtkExtractCTHPart::GetMTime()
157 {
158   unsigned long mTime= this->Superclass::GetMTime();
159   if (this->ClipPlane)
160     {
161     unsigned long time = this->ClipPlane->GetMTime();
162     return time > mTime? time : mTime;
163     }
164 
165   return mTime;
166 }
167 
168 //-----------------------------------------------------------------------------
RemoveVolumeArrayNames()169 void vtkExtractCTHPart::RemoveVolumeArrayNames()
170 {
171   this->Internals->VolumeArrayNames.clear();
172   this->Modified();
173 }
174 
175 //-----------------------------------------------------------------------------
AddVolumeArrayName(const char * arrayName)176 void vtkExtractCTHPart::AddVolumeArrayName(const char* arrayName)
177 {
178   if (arrayName !=0 &&
179     arrayName[0] != 0 &&
180     std::find(this->Internals->VolumeArrayNames.begin(),
181       this->Internals->VolumeArrayNames.end(), std::string(arrayName))==
182     this->Internals->VolumeArrayNames.end())
183     {
184     this->Internals->VolumeArrayNames.push_back(arrayName);
185 
186     // ensure that the volume arrays are in determinate order. I should just
187     // change the code to use a std::set.
188     std::sort(this->Internals->VolumeArrayNames.begin(),
189       this->Internals->VolumeArrayNames.end());
190     this->Modified();
191     }
192 }
193 
194 //-----------------------------------------------------------------------------
GetNumberOfVolumeArrayNames()195 int vtkExtractCTHPart::GetNumberOfVolumeArrayNames()
196 {
197   return static_cast<int>(this->Internals->VolumeArrayNames.size());
198 }
199 
200 //-----------------------------------------------------------------------------
GetVolumeArrayName(int idx)201 const char* vtkExtractCTHPart::GetVolumeArrayName(int idx)
202 {
203   if ( idx < 0 ||
204        idx > static_cast<int>(this->Internals->VolumeArrayNames.size()) )
205     {
206     return 0;
207     }
208 
209   return this->Internals->VolumeArrayNames[idx].c_str();
210 }
211 
212 //----------------------------------------------------------------------------
FillInputPortInformation(int port,vtkInformation * info)213 int vtkExtractCTHPart::FillInputPortInformation(
214   int port, vtkInformation *info)
215 {
216   if (!this->Superclass::FillInputPortInformation(port,info))
217     {
218     return 0;
219     }
220 
221   info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkNonOverlappingAMR");
222   info->Append(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkMultiBlockDataSet");
223   info->Append(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkRectilinearGrid");
224   return 1;
225 }
226 
227 //-----------------------------------------------------------------------------
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * outputVector)228 int vtkExtractCTHPart::RequestData(vtkInformation *vtkNotUsed(request),
229   vtkInformationVector **inputVector, vtkInformationVector *outputVector)
230 {
231   const int number_of_volume_arrays = static_cast<int>(this->Internals->VolumeArrayNames.size());
232   if (number_of_volume_arrays == 0)
233     {
234     // nothing to do.
235     return 1;
236     }
237 
238   vtkDataObject* inputDO = vtkDataObject::GetData(inputVector[0], 0);
239   vtkSmartPointer<vtkCompositeDataSet> inputCD = vtkCompositeDataSet::SafeDownCast(inputDO);
240   vtkRectilinearGrid* inputRG = vtkRectilinearGrid::SafeDownCast(inputDO);
241   assert(inputCD != NULL || inputRG != NULL);
242 
243   if (inputRG)
244     {
245     vtkNew<vtkMultiBlockDataSet> mb;
246     mb->SetBlock(0, inputRG);
247     inputCD = mb.GetPointer();
248     }
249 
250   vtkMultiBlockDataSet* output = vtkMultiBlockDataSet::GetData(outputVector, 0);
251 
252   // initialize output multiblock-dataset. It will always have as many blocks as
253   // the number-of-volume arrays requested.
254   output->SetNumberOfBlocks(number_of_volume_arrays);
255 
256   // Compute global bounds for the input dataset. This is used to generate
257   // external surface for the dataset.
258   if (!this->ComputeGlobalBounds(inputCD))
259     {
260     vtkErrorMacro("Failed to compute global bounds.");
261     return 0;
262     }
263 
264   if (!this->Internals->GlobalInputBounds.IsValid())
265     {
266     // empty input, do nothing.
267     return 1;
268     }
269 
270   unsigned int array_index = 0;
271   for (vtkExtractCTHPartInternal::VolumeArrayNamesType::iterator iter =
272     this->Internals->VolumeArrayNames.begin();
273     iter != this->Internals->VolumeArrayNames.end(); ++iter, ++array_index)
274     {
275     // this loop is doing the 1/(num-arrays)'th work for the entire task.
276     ScaledProgress sp(
277       array_index * 1.0 / this->Internals->VolumeArrayNames.size(),
278       1.0/this->Internals->VolumeArrayNames.size(),
279       this);
280 
281     output->GetMetaData(array_index)->Set(vtkCompositeDataSet::NAME(), iter->c_str());
282 
283     vtkNew<vtkPolyData> contour;
284     vtkGarbageCollector::DeferredCollectionPush();
285     if (this->ExtractContour(contour.GetPointer(), inputCD, iter->c_str()) &&
286       (contour->GetNumberOfPoints() > 0))
287       {
288       // Add extra arrays.
289       vtkNew<vtkIntArray> partArray;
290       partArray->SetName("Part Index");
291       partArray->SetNumberOfComponents(1);
292       partArray->SetNumberOfTuples(contour->GetNumberOfPoints());
293       partArray->FillComponent(0, static_cast<double>(array_index));
294       contour->GetPointData()->AddArray(partArray.GetPointer());
295 
296       // I'm not adding the "Name" array that was added in previous
297       // implementation. Don't think that's much of use.
298 
299       output->SetBlock(array_index, contour.GetPointer());
300       }
301     vtkGarbageCollector::DeferredCollectionPop();
302     }
303   return 1;
304 }
305 
306 //-----------------------------------------------------------------------------
ComputeGlobalBounds(vtkCompositeDataSet * input)307 bool vtkExtractCTHPart::ComputeGlobalBounds(vtkCompositeDataSet *input)
308 {
309   assert("pre: input_exists" && input!=0);
310   this->Internals->GlobalInputBounds.Reset();
311 
312   this->Internals->TotalNumberOfDatasets = 0;
313 
314   vtkCompositeDataIterator* iter = input->NewIterator();
315   for (iter->InitTraversal(); !iter->IsDoneWithTraversal(); iter->GoToNextItem())
316     {
317     vtkDataSet *ds = vtkDataSet::SafeDownCast(iter->GetCurrentDataObject());
318     if (!ds)// can be null if on another processor
319       {
320       continue;
321       }
322     double realBounds[6];
323     ds->GetBounds(realBounds);
324     this->Internals->GlobalInputBounds.AddBounds(realBounds);
325 
326     ++this->Internals->TotalNumberOfDatasets;
327     }
328   iter->Delete();
329 
330   // Here we have the bounds according to our local datasets.
331   // If we are not running in parallel then the local
332   // bounds are the global bounds
333   if (!this->Controller || this->Controller->GetNumberOfProcesses() <= 1)
334     {
335     return true;
336     }
337 
338   const double *min_point = this->Internals->GlobalInputBounds.GetMinPoint();
339   const double *max_point = this->Internals->GlobalInputBounds.GetMaxPoint();
340   double min_result[3], max_result[3];
341 
342   if (!this->Controller->AllReduce(
343       min_point, min_result, 3, vtkCommunicator::MIN_OP))
344     {
345     return false;
346     }
347   if (!this->Controller->AllReduce(
348       max_point, max_result, 3, vtkCommunicator::MAX_OP))
349     {
350     return false;
351     }
352 
353   this->Internals->GlobalInputBounds.SetBounds(
354     min_result[0], max_result[0], min_result[1], max_result[1],
355     min_result[2], max_result[2]);
356   // At this point, the global bounds is set in each processor.
357   return true;
358 }
359 
360 //-----------------------------------------------------------------------------
361 // return false on error.
ExtractContour(vtkPolyData * output,vtkCompositeDataSet * input,const char * arrayName)362 bool vtkExtractCTHPart::ExtractContour(
363   vtkPolyData* output, vtkCompositeDataSet* input, const char*arrayName)
364 {
365   assert(output!=0 && input!=0 && arrayName!=0 && arrayName[0]!=0);
366 
367   bool warn_once = true;
368   vtkSmartPointer<vtkCompositeDataIterator> iter;
369   iter.TakeReference(input->NewIterator());
370 
371   // this loop is first 95% of the work.
372   ScaledProgress sp1(0.0, 0.95, this);
373 
374   int counter = 0;
375   vtkExtractCTHPart::VectorOfFragments fragments;
376   for (iter->InitTraversal(); !iter->IsDoneWithTraversal(); iter->GoToNextItem(), ++counter)
377     {
378     // each iteration is 1/(total num of datasets)'th for the work.
379     ScaledProgress sp(
380       counter * 1.0/this->Internals->TotalNumberOfDatasets,
381       1.0/this->Internals->TotalNumberOfDatasets, this);
382 
383     if (counter % 1000 == 0)
384       {
385       this->TriggerProgressEvent(0.0);
386       }
387 
388     vtkDataObject *dataObj = iter->GetCurrentDataObject();
389     vtkRectilinearGrid* rg = vtkRectilinearGrid::SafeDownCast(dataObj);
390     vtkUniformGrid* ug = vtkUniformGrid::SafeDownCast(dataObj);
391 
392     if (ug)
393       {
394       if (!this->ExtractClippedContourOnBlock<vtkUniformGrid>(fragments, ug, arrayName))
395         {
396         return false;
397         }
398       }
399     else if (rg)
400       {
401       if (!this->ExtractClippedContourOnBlock<vtkRectilinearGrid>(fragments, rg, arrayName))
402         {
403         return false;
404         }
405       }
406     else if (warn_once && dataObj)
407       {
408       warn_once = false;
409       vtkWarningMacro(<< dataObj->GetClassName() << " will be ignored.");
410       }
411     if ((counter % 1000) == 0)
412       {
413       this->TriggerProgressEvent(1.0);
414       }
415     }
416 
417   if (fragments.size() == 0)
418     {
419     // empty contour. Not an error though, hence we don't return false.
420     return true;
421     }
422   sp1.WorkDone();
423 
424   // Now, the last .05 % of the work.
425   ScaledProgress sp2(0.95, 0.05, this);
426   this->TriggerProgressEvent(0.0);
427   vtkNew<vtkAppendPolyData> appender;
428   for (size_t cc=0; cc < fragments.size(); cc++)
429     {
430     appender->AddInputData(fragments[cc].GetPointer());
431     }
432   appender->Update();
433   output->ShallowCopy(appender->GetOutputDataObject(0));
434   this->TriggerProgressEvent(1.0);
435   return true;
436 }
437 
438 //-----------------------------------------------------------------------------
439 template <class T>
ExtractClippedContourOnBlock(vtkExtractCTHPart::VectorOfFragments & fragments,T * dataset,const char * arrayName)440 bool vtkExtractCTHPart::ExtractClippedContourOnBlock(
441   vtkExtractCTHPart::VectorOfFragments& fragments, T* dataset, const char* arrayName)
442 {
443   assert(arrayName!=0 && arrayName[0]!=0 && dataset != 0);
444 
445   vtkDataArray* volumeFractionArray = dataset->GetCellData()->GetArray(arrayName);
446   if (!volumeFractionArray)
447     {
448     // skip this block.
449     return true;
450     }
451 
452   // determine the true value to use for the contour based on the data-type.
453   switch (volumeFractionArray->GetDataType())
454     {
455   case VTK_UNSIGNED_CHAR:
456     this->VolumeFractionSurfaceValueInternal =
457       CTH_AMR_SURFACE_VALUE_UNSIGNED_CHAR * this->VolumeFractionSurfaceValue;
458     break;
459 
460   default:
461     this->VolumeFractionSurfaceValueInternal =
462       CTH_AMR_SURFACE_VALUE_FLOAT * this->VolumeFractionSurfaceValue;
463     }
464 
465   // We create a clone so we can modify the dataset (i.e. add new arrays to it).
466   vtkNew<T> inputClone;
467   inputClone->ShallowCopy(dataset);
468 
469   // Convert cell-data-2-point-data so we can contour.
470   vtkNew<vtkDoubleArray> pointVolumeFractionArray;
471   this->ExecuteCellDataToPointData(volumeFractionArray,
472     pointVolumeFractionArray.GetPointer(), inputClone->GetDimensions());
473   inputClone->GetPointData()->SetScalars(pointVolumeFractionArray.GetPointer());
474 
475   VectorOfFragments blockFragments;
476   if (!this->ExtractContourOnBlock<T>(blockFragments, inputClone.GetPointer(), arrayName))
477     {
478     return false;
479     }
480 
481   if (!this->ClipPlane)
482     {
483     fragments.insert(fragments.end(),
484       blockFragments.begin(), blockFragments.end());
485     return true;
486     }
487 
488   // Clip-n-cap the fragments using the clip plane.
489 
490   // for the clip.
491   for (size_t cc=0; cc < blockFragments.size(); cc++)
492     {
493     vtkNew<vtkClipPolyData> clipper;
494     clipper->SetClipFunction(this->ClipPlane);
495     clipper->SetInputDataObject(blockFragments[cc]);
496     clipper->Update();
497     fragments.push_back(clipper->GetOutput());
498     }
499 
500   //// for the cap.
501   if (this->Capping)
502     {
503     vtkNew<vtkCutter> cutter;
504     cutter->SetCutFunction(this->ClipPlane);
505     cutter->SetGenerateTriangles(this->GenerateTriangles? 1 : 0);
506     cutter->SetInputDataObject(inputClone.GetPointer());
507 
508     vtkNew<vtkClipPolyData> scalarClipper;
509     scalarClipper->SetInputConnection(cutter->GetOutputPort());
510     scalarClipper->SetValue(this->VolumeFractionSurfaceValueInternal);
511     scalarClipper->Update();
512     fragments.push_back(scalarClipper->GetOutput());
513     }
514   return true;
515 }
516 
517 //-----------------------------------------------------------------------------
518 template <class T>
ExtractContourOnBlock(vtkExtractCTHPart::VectorOfFragments & fragments,T * dataset,const char * arrayName)519 bool vtkExtractCTHPart::ExtractContourOnBlock(
520   vtkExtractCTHPart::VectorOfFragments& fragments, T* dataset, const char* arrayName)
521 {
522   assert(arrayName!=0 && arrayName[0]!=0 && dataset != 0);
523 
524   vtkDataArray* volumeFractionArray = dataset->GetPointData()->GetArray(arrayName);
525   assert(volumeFractionArray !=0);
526   assert(dataset->GetPointData()->GetArray(arrayName) !=0);
527 
528   // Contour only if necessary.
529   double range[2];
530   volumeFractionArray->GetRange(range);
531   if (range[1] < this->VolumeFractionSurfaceValueInternal)
532     {
533     // this block doesn't have the material of interest.
534     return true;
535     }
536 
537   // Extract exterior surface. Adds the surface polydata to fragments, if any.
538   if (this->Capping)
539     {
540     this->ExtractExteriorSurface(fragments, dataset);
541     }
542 
543   if (this->ClipPlane == NULL && range[0] > this->VolumeFractionSurfaceValueInternal)
544     {
545     // no need to extract contour.
546     return true;
547     }
548 
549   // Extract contour.
550   vtkNew<vtkContourFilter> contourer;
551   contourer->SetInputData(dataset);
552   contourer->SetValue(0, this->VolumeFractionSurfaceValueInternal);
553   contourer->SetComputeScalars(0);
554   contourer->SetGenerateTriangles(this->GenerateTriangles? 1: 0);
555   contourer->SetInputArrayToProcess(0, 0, 0,
556     vtkDataObject::FIELD_ASSOCIATION_POINTS, arrayName);
557   contourer->Update();
558 
559   vtkPolyData* output =
560     vtkPolyData::SafeDownCast(contourer->GetOutputDataObject(0));
561   if (!output && output->GetNumberOfPoints()== 0)
562     {
563     return true;
564     }
565   if (!this->RemoveGhostCells &&
566     output->GetCellData()->GetArray("vtkGhostLevels"))
567     {
568     output->GetCellData()->GetArray("vtkGhostLevels")->SetName("OriginalGhostLevels");
569     }
570 
571   fragments.push_back(output);
572   return true;
573 }
574 
575 //-----------------------------------------------------------------------------
576 // Description:
577 // Append quads for faces of the block that actually on the bounds
578 // of the hierarchical dataset. Deals with ghost cells.
579 template <class T>
ExtractExteriorSurface(vtkExtractCTHPart::VectorOfFragments & fragments,T * input)580 void vtkExtractCTHPart::ExtractExteriorSurface(
581   vtkExtractCTHPart::VectorOfFragments& fragments, T* input)
582 {
583   assert("pre: valid_input" && input!=0 && input->CheckAttributes()==0);
584 
585   int result=0;
586 #if 1
587   int dims[3];
588   input->GetDimensions(dims);
589   int ext[6];
590   int originalExtents[6];
591   input->GetExtent(ext);
592   input->GetExtent(originalExtents);
593 
594 //  vtkUnsignedCharArray *ghostArray=static_cast<vtkUnsignedCharArray *>(input->GetCellData()->GetArray("vtkGhostLevels"));
595 
596   // bounds without taking ghost cells into account
597   double bounds[6];
598 
599   input->GetBounds(bounds);
600 
601 #if 0
602   // block face min x
603   if(this->IsGhostFace(0,0,dims,ghostArray))
604     {
605     // downsize this!
606     bounds[0]+=spacing[0];
607     ++ext[0];
608     }
609   if(this->IsGhostFace(0,1,dims,ghostArray))
610     {
611     // downsize this!
612     bounds[1]-=spacing[0];
613     --ext[1];
614     }
615   if(this->IsGhostFace(1,0,dims,ghostArray))
616     {
617     // downsize this!
618     bounds[2]+=spacing[1];
619     ++ext[2];
620     }
621   if(this->IsGhostFace(1,1,dims,ghostArray))
622     {
623     // downsize this!
624     bounds[3]-=spacing[1];
625     --ext[3];
626     }
627   if(this->IsGhostFace(2,0,dims,ghostArray))
628     {
629     // downsize this!
630     bounds[4]+=spacing[2];
631     ++ext[4];
632     }
633   if(this->IsGhostFace(2,1,dims,ghostArray))
634     {
635     // downsize this!
636     bounds[5]-=spacing[2];
637     --ext[5];
638     }
639 #endif
640   // here, bounds are real block bounds without ghostcells.
641 
642   const double *minP = this->Internals->GlobalInputBounds.GetMinPoint();
643   const double *maxP = this->Internals->GlobalInputBounds.GetMaxPoint();
644 #if 0
645   const double epsilon=0.001;
646   int doFaceMinX=fabs(bounds[0]- minP[0])<epsilon;
647   int doFaceMaxX=fabs(bounds[1]- maxP[0])<epsilon;
648   int doFaceMinY=fabs(bounds[2]- minP[1])<epsilon;
649   int doFaceMaxY=fabs(bounds[3]- maxP[1])<epsilon;
650   int doFaceMinZ=fabs(bounds[4]- minP[2])<epsilon;
651   int doFaceMaxZ=fabs(bounds[5]- maxP[2])<epsilon;
652 #endif
653 
654 #if 1
655   int doFaceMinX=bounds[0]<= minP[0];
656   int doFaceMaxX=bounds[1]>= maxP[0];
657   int doFaceMinY=bounds[2]<= minP[1];
658   int doFaceMaxY=bounds[3]>= maxP[1];
659   int doFaceMinZ=bounds[4]<= minP[2];
660   int doFaceMaxZ=bounds[5]>= maxP[2];
661 #endif
662 #if 0
663   int doFaceMinX=1;
664   int doFaceMaxX=1;
665   int doFaceMinY=1;
666   int doFaceMaxY=1;
667   int doFaceMinZ=1;
668   int doFaceMaxZ=1;
669 #endif
670 #if 0
671   int doFaceMinX=0;
672   int doFaceMaxX=0;
673   int doFaceMinY=0;
674   int doFaceMaxY=0;
675   int doFaceMinZ=0;
676   int doFaceMaxZ=0;
677 #endif
678 #if 0
679   doFaceMaxX=0;
680   doFaceMaxY=0;
681   doFaceMaxZ=0;
682 #endif
683 
684   result=doFaceMinX||doFaceMaxX||doFaceMinY||doFaceMaxY||doFaceMinZ
685     ||doFaceMaxZ;
686 
687   if(result)
688     {
689     vtkSmartPointer<vtkPolyData> output = vtkSmartPointer<vtkPolyData>::New();
690 
691     vtkIdType numPoints=0;
692     vtkIdType cellArraySize=0;
693 
694 //  input->GetExtent(ext);
695 
696     // Compute an upper bound for the number of points and cells.
697     // xMin face
698     if (doFaceMinX && ext[2] != ext[3] && ext[4] != ext[5] && ext[0] != ext[1])
699       {
700       cellArraySize += 2*(ext[3]-ext[2]+1)*(ext[5]-ext[4]+1);
701       numPoints += (ext[3]-ext[2]+1)*(ext[5]-ext[4]+1);
702       }
703     // xMax face
704     if (doFaceMaxX && ext[2] != ext[3] && ext[4] != ext[5])
705       {
706       cellArraySize += 2*(ext[3]-ext[2]+1)*(ext[5]-ext[4]+1);
707       numPoints += (ext[3]-ext[2]+1)*(ext[5]-ext[4]+1);
708       }
709     // yMin face
710     if (doFaceMinY && ext[0] != ext[1] && ext[4] != ext[5] && ext[2] != ext[3])
711       {
712       cellArraySize += 2*(ext[1]-ext[0]+1)*(ext[5]-ext[4]+1);
713       numPoints += (ext[1]-ext[0]+1)*(ext[5]-ext[4]+1);
714       }
715     // yMax face
716     if (doFaceMaxY && ext[0] != ext[1] && ext[4] != ext[5])
717       {
718       cellArraySize += 2*(ext[1]-ext[0]+1)*(ext[5]-ext[4]+1);
719       numPoints += (ext[1]-ext[0]+1)*(ext[5]-ext[4]+1);
720       }
721     // zMin face
722     if (doFaceMinZ && ext[0] != ext[1] && ext[2] != ext[3] && ext[4] != ext[5])
723       {
724       cellArraySize += 2*(ext[1]-ext[0]+1)*(ext[3]-ext[2]+1);
725       numPoints += (ext[1]-ext[0]+1)*(ext[3]-ext[2]+1);
726       }
727     // zMax face
728     if (doFaceMaxZ && ext[0] != ext[1] && ext[2] != ext[3])
729       {
730       cellArraySize += 2*(ext[1]-ext[0]+1)*(ext[3]-ext[2]+1);
731       numPoints += (ext[1]-ext[0]+1)*(ext[3]-ext[2]+1);
732       }
733 
734     vtkCellArray *outPolys = vtkCellArray::New();
735     outPolys->Allocate(cellArraySize);
736     output->SetPolys(outPolys);
737     outPolys->Delete();
738 
739     vtkPoints *outPoints = vtkPoints::New();
740     outPoints->Allocate(numPoints);
741     output->SetPoints(outPoints);
742     outPoints->Delete();
743 
744     // Allocate attributes for copying.
745     output->GetPointData()->CopyAllocate(input->GetPointData());
746     output->GetCellData()->CopyAllocate(input->GetCellData());
747 
748     // Extents are already corrected for ghostcells.
749 
750     // make each face that is actually on the ds boundary
751     if(doFaceMinX)
752       {
753       this->ExecuteFaceQuads(input,output,0,originalExtents,ext,0,1,2);
754       }
755     if(doFaceMaxX)
756       {
757       this->ExecuteFaceQuads(input,output,1,originalExtents,ext,0,2,1);
758       }
759     if(doFaceMinY)
760       {
761       this->ExecuteFaceQuads(input,output,0,originalExtents,ext,1,2,0);
762       }
763     if(doFaceMaxY)
764       {
765       this->ExecuteFaceQuads(input,output,1,originalExtents,ext,1,0,2);
766       }
767     if(doFaceMinZ)
768       {
769       this->ExecuteFaceQuads(input,output,0,originalExtents,ext,2,0,1);
770       }
771     if(doFaceMaxZ)
772       {
773       this->ExecuteFaceQuads(input,output,1,originalExtents,ext,2,1,0);
774       }
775     output->Squeeze();
776     assert(output->CheckAttributes() == 0);
777 
778     vtkNew<vtkClipPolyData> clipper;
779     clipper->SetInputData(output);
780     clipper->SetValue(this->VolumeFractionSurfaceValueInternal);
781     clipper->Update();
782     fragments.push_back(clipper->GetOutput());
783     }
784 #endif
785 // result=>valid_surface: A=>B !A||B
786 }
787 
788 //----------------------------------------------------------------------------
789 // Description:
790 // Is block face on axis0 (either min or max depending on the maxFlag)
791 // composed of only ghost cells?
IsGhostFace(int axis0,int maxFlag,int dims[3],vtkUnsignedCharArray * ghostArray)792 int vtkExtractCTHPart::IsGhostFace(int axis0,
793                                    int maxFlag,
794                                    int dims[3],
795                                    vtkUnsignedCharArray *ghostArray)
796 {
797   assert("pre: valid_axis0" && axis0>=0 && axis0<=2);
798 
799   int axis1=axis0+1;
800   if(axis1>2)
801     {
802     axis1=0;
803     }
804   int axis2=axis0+2;
805   if(axis2>2)
806     {
807     axis2=0;
808     }
809 
810   int ijk[3]; // index of the cell.
811 
812   if(maxFlag)
813     {
814     ijk[axis0]=dims[axis0]-2;
815     }
816   else
817     {
818     ijk[axis0]=0;
819     }
820 
821   // We test the center cell of the block face.
822   // in the worst case (2x2 cells), we need to know if at least
823   // three cells are ghost to say that the face is a ghost face.
824 
825   ijk[axis1]=dims[axis1]/2-1; // (dims[axis1]-2)/2
826   ijk[axis2]=dims[axis2]/2-1; // (dims[axis2]-2)/2
827   int result=ghostArray->GetValue(vtkStructuredData::ComputeCellId(dims,ijk));
828 
829   if(dims[axis1]==3)
830     {
831     // axis1 requires 2 cells to be tested.
832     // if so, axis1index=0 and axis1index+1=1
833     ijk[axis1]=1;
834     result=result &&
835       ghostArray->GetValue(vtkStructuredData::ComputeCellId(dims,ijk));
836     }
837 
838   if(dims[axis2]==3)
839     {
840     // herem axis1 may have moved from the previous test.
841     // axis2 requires 2 cells to be tested.
842     // if so, axis2index=0 and axis2index+1=1
843     ijk[axis2]=1;
844     result=result &&
845       ghostArray->GetValue(vtkStructuredData::ComputeCellId(dims,ijk));
846     }
847   return result;
848 }
849 
850 //----------------------------------------------------------------------------
851 // Description:
852 // Merly the same implementation than in vtkDataSetSurfaceFilter, without
853 // dealing with the whole extents.
ExecuteFaceQuads(vtkDataSet * input,vtkPolyData * output,int maxFlag,int originalExtents[6],int ext[6],int aAxis,int bAxis,int cAxis)854 void vtkExtractCTHPart::ExecuteFaceQuads(vtkDataSet *input,
855                                          vtkPolyData *output,
856                                          int maxFlag,
857                                          int originalExtents[6],
858                                          int ext[6],
859                                          int aAxis,
860                                          int bAxis,
861                                          int cAxis)
862 {
863   assert("pre: input_exists" && input!=0);
864   assert("pre: output_exists" && output!=0);
865   assert("pre: originalExtents_exists" && originalExtents!=0);
866   assert("pre: ext_exists" && ext!=0);
867   assert("pre: valid_axes"
868          && aAxis>=0 && aAxis<=2
869          && bAxis>=0 && bAxis<=2
870          && cAxis>=0 && cAxis<=2
871          && aAxis!=bAxis
872          && aAxis!=cAxis
873          && bAxis!=cAxis);
874 
875   vtkPoints    *outPts;
876   vtkCellArray *outPolys;
877   vtkPointData *inPD, *outPD;
878   vtkCellData  *inCD, *outCD;
879   int          pInc[3];
880   int          qInc[3];
881   int          cOutInc;
882   double        pt[3];
883   vtkIdType    inStartPtId;
884   vtkIdType    inStartCellId;
885   vtkIdType    outStartPtId;
886   vtkIdType    outPtId;
887   vtkIdType    inId, outId;
888   int          ib, ic;
889   int          aA2, bA2, cA2;
890 
891   outPts = output->GetPoints();
892   outPD = output->GetPointData();
893   inPD = input->GetPointData();
894   outCD = output->GetCellData();
895   inCD = input->GetCellData();
896 
897   pInc[0] = 1;
898   pInc[1] = (originalExtents[1]-originalExtents[0]+1);
899   pInc[2] = (originalExtents[3]-originalExtents[2]+1) * pInc[1];
900   // quad increments (cell incraments, but cInc could be confused with c axis).
901   qInc[0] = 1;
902   qInc[1] = originalExtents[1]-originalExtents[0];
903   // The conditions are for when we have one or more degenerate axes (2d or 1d cells).
904   if (qInc[1] == 0)
905     {
906     qInc[1] = 1;
907     }
908   qInc[2] = (originalExtents[3]-originalExtents[2]) * qInc[1];
909   if (qInc[2] == 0)
910     {
911     qInc[2] = qInc[1];
912     }
913 
914   // Temporary variables to avoid many multiplications.
915   aA2 = aAxis<<1; // * 2;
916   bA2 = bAxis<<1; // * 2;
917   cA2 = cAxis<<1; //  * 2;
918 
919   // We might as well put the test for this face here.
920   if (ext[bA2] == ext[bA2+1] || ext[cA2] == ext[cA2+1])
921     {
922     return;
923     }
924 #if 0
925   if (maxFlag)
926     {
927     if (ext[aA2+1] < wholeExt[aA2+1])
928       {
929       return;
930       }
931     }
932   else
933     { // min faces have a slightly different condition to avoid coincident faces.
934     if (ext[aA2] == ext[aA2+1] || ext[aA2] > wholeExt[aA2])
935       {
936       return;
937       }
938     }
939 #endif
940 
941   if(!maxFlag)
942     {
943     if (ext[aA2] == ext[aA2+1])
944       {
945       return;
946       }
947     }
948 
949   // Assuming no ghost cells ...
950 //  inStartPtId = inStartCellId = 0;
951   inStartPtId=0; //ext[aA2];
952   inStartCellId=0; //ext[aA2];
953 
954 
955   // I put this confusing conditional to fix a regression test.
956   // If we are creating a maximum face, then we indeed have to offset the input cell Ids.
957   // However, vtkGeometryFilter created a 2d image as a max face, but the cells are copied
958   // as a min face (no offset).  Hence maxFlag = 1 and there should be no offset.
959   if (maxFlag && ext[aA2] < ext[1+aA2])
960     {
961     inStartPtId = pInc[aAxis]*(ext[aA2+1]-originalExtents[aA2]); // -ext[aA2]
962     inStartCellId = qInc[aAxis]*(ext[aA2+1]-originalExtents[aA2]-1); // -ext[aA2]
963     }
964 
965   outStartPtId = outPts->GetNumberOfPoints();
966   // Make the points for this face.
967   for (ic = ext[cA2]; ic <= ext[cA2+1]; ++ic)
968     {
969     for (ib = ext[bA2]; ib <= ext[bA2+1]; ++ib)
970       {
971 //      inId = inStartPtId + (ib-ext[bA2]+originExtents[bAxis])*pInc[bAxis]
972 //                         + (ic-ext[cA2]+originExtents[cAxis])*pInc[cAxis];
973 
974       inId = inStartPtId + (ib-originalExtents[bA2])*pInc[bAxis]
975         + (ic-originalExtents[cA2])*pInc[cAxis];
976 
977       input->GetPoint(inId, pt);
978       outId = outPts->InsertNextPoint(pt);
979       // Copy point data.
980       outPD->CopyData(inPD,inId,outId);
981       }
982     }
983 
984   // Do the cells.
985   cOutInc = ext[bA2+1] - ext[bA2] + 1;
986 
987   outPolys = output->GetPolys();
988 
989   // Old method for creating quads (needed for cell data.).
990   for (ic = ext[cA2]; ic < ext[cA2+1]; ++ic)
991     {
992     for (ib = ext[bA2]; ib < ext[bA2+1]; ++ib)
993       {
994       outPtId = outStartPtId + (ib-ext[bA2]) + (ic-ext[cA2])*cOutInc;
995 //      inId = inStartCellId + (ib-ext[bA2]+originExtents[bAxis])*qInc[bAxis] + (ic-ext[cA2]+originExtents[cAxis])*qInc[cAxis];
996 
997       inId = inStartCellId + (ib-originalExtents[bA2])*qInc[bAxis] + (ic-originalExtents[cA2])*qInc[cAxis];
998 
999       outId = outPolys->InsertNextCell(4);
1000       outPolys->InsertCellPoint(outPtId);
1001       outPolys->InsertCellPoint(outPtId+cOutInc);
1002       outPolys->InsertCellPoint(outPtId+cOutInc+1);
1003       outPolys->InsertCellPoint(outPtId+1);
1004 
1005       // Copy cell data.
1006       outCD->CopyData(inCD,inId,outId);
1007       }
1008     }
1009 }
1010 
1011 //-----------------------------------------------------------------------------
ExecuteCellDataToPointData(vtkDataArray * cellVolumeFraction,vtkDoubleArray * pointVolumeFraction,const int * dims)1012 void vtkExtractCTHPart::ExecuteCellDataToPointData(
1013   vtkDataArray *cellVolumeFraction, vtkDoubleArray *pointVolumeFraction, const int *dims)
1014 {
1015   int count;
1016   int i, j, k;
1017   int iEnd, jEnd, kEnd;
1018   int jInc, kInc;
1019   double *pPoint;
1020 
1021   pointVolumeFraction->SetName(cellVolumeFraction->GetName());
1022   pointVolumeFraction->SetNumberOfTuples(dims[0]*dims[1]*dims[2]);
1023 
1024   iEnd = dims[0]-1;
1025   jEnd = dims[1]-1;
1026   kEnd = dims[2]-1;
1027 
1028   // Deals with none 3D images, otherwise it will never enter into the loop.
1029   // And then the data will be not initialized and the output of the contour
1030   // will be empty.
1031 
1032   int dimensionality=3;
1033 
1034   if(kEnd==0)
1035     {
1036     --dimensionality;
1037     kEnd=1;
1038     }
1039 
1040   // Increments are for the point array.
1041   jInc = dims[0];
1042   kInc = (dims[1]) * jInc;
1043 
1044   pPoint = pointVolumeFraction->GetPointer(0);
1045 //  pCell = static_cast<double*>(cellVolumeFraction->GetVoidPointer(0));
1046 
1047   // Initialize the point data to 0.
1048   memset(pPoint, 0,  dims[0]*dims[1]*dims[2]*sizeof(double));
1049 
1050 #ifndef NDEBUG
1051   // for debugging and check out of range.
1052   double *endPtr=pPoint+dims[0]*dims[1]*dims[2];
1053 #endif
1054 
1055 //  float delProgress = (maxProgress - minProgress) / (kEnd*jEnd*iEnd) / 2;
1056 //  vtkIdType counter = 0;
1057 
1058   int index=0;
1059   // Loop thorugh the cells.
1060   for (k = 0; k < kEnd; ++k)
1061     {
1062     for (j = 0; j < jEnd; ++j)
1063       {
1064       for (i = 0; i < iEnd; ++i)
1065         {
1066         //if (counter % 1000 == 0 && reportProgress)
1067         //  {
1068         //  this->UpdateProgress(minProgress + delProgress*(i+j*iEnd+k*iEnd*jEnd));
1069         //  }
1070         //counter++;
1071         // Add cell value to all points of cell.
1072         double value=cellVolumeFraction->GetTuple1(index);
1073 
1074         assert("check: valid_range" && pPoint<endPtr);
1075         assert("check: valid_range" && pPoint+1<endPtr);
1076         assert("check: valid_range" && pPoint+jInc<endPtr);
1077         assert("check: valid_range" && pPoint+jInc+1<endPtr);
1078 
1079         *pPoint += value;
1080         pPoint[1] += value;
1081         pPoint[jInc] += value;
1082         pPoint[1+jInc] += value;
1083 
1084         if(dimensionality==3)
1085           {
1086           assert("check: valid_range" && pPoint+kInc<endPtr);
1087           assert("check: valid_range" && pPoint+kInc+1<endPtr);
1088           assert("check: valid_range" && pPoint+kInc+jInc<endPtr);
1089           assert("check: valid_range" && pPoint+kInc+jInc+1<endPtr);
1090 
1091           pPoint[kInc] += value;
1092           pPoint[kInc+1] += value;
1093           pPoint[kInc+jInc] += value;
1094           pPoint[kInc+jInc+1] += value;
1095           }
1096 
1097         // Increment pointers
1098         ++pPoint;
1099         ++index;
1100         }
1101       // Skip over last point to the start of the next row.
1102       ++pPoint;
1103       }
1104     // Skip over the last row to the start of the next plane.
1105     pPoint += jInc;
1106     }
1107 
1108   // Now a second pass to normalize the point values.
1109   // Loop through the points.
1110   count = 1;
1111   pPoint = pointVolumeFraction->GetPointer(0);
1112 
1113   // because we eventually modified iEnd, jEnd, kEnd to handle the
1114   // 2D image case, we have to recompute them.
1115   iEnd = dims[0]-1;
1116   jEnd = dims[1]-1;
1117   kEnd = dims[2]-1;
1118 
1119   // counter = 0;
1120   for (k = 0; k <= kEnd; ++k)
1121     {
1122     // Just a fancy fast way to compute the number of cell neighbors of a
1123     // point.
1124     if (k == 1)
1125       {
1126       count = count << 1;
1127       }
1128     if (k == kEnd && kEnd>0)
1129       {
1130       // only in 3D case, otherwise count may become zero
1131       // and be involved in a division by zero later on
1132       count = count >> 1;
1133       }
1134     for (j = 0; j <= jEnd; ++j)
1135       {
1136       // Just a fancy fast way to compute the number of cell neighbors of a
1137       // point.
1138       if (j == 1)
1139         {
1140         count = count << 1;
1141         }
1142       if (j == jEnd)
1143         {
1144         count = count >> 1;
1145         }
1146       for (i = 0; i <= iEnd; ++i)
1147         {
1148         //if (counter % 1000 == 0 && reportProgress)
1149         //  {
1150         //  this->UpdateProgress(minProgress + delProgress/2 + delProgress*(i+j*iEnd+k*iEnd*jEnd));
1151         //  }
1152         //counter++;
1153         // Just a fancy fast way to compute the number of cell neighbors of a
1154         // point.
1155         if (i == 1)
1156           {
1157           count = count << 1;
1158           }
1159         if (i == iEnd)
1160           {
1161           count = count >> 1;
1162           }
1163         assert("check: valid_range" && pPoint<endPtr);
1164         assert("check: strictly_positive_count" && count>0);
1165         *pPoint = *pPoint / static_cast<double>(count);
1166         ++pPoint;
1167         }
1168       }
1169     }
1170 }
1171 
1172 //-----------------------------------------------------------------------------
TriggerProgressEvent(double val)1173 void vtkExtractCTHPart::TriggerProgressEvent(double val)
1174 {
1175   double progress = this->ProgressShift + val*this->ProgressScale;
1176   //cout << "Progress: " << progress << endl;
1177   this->UpdateProgress(progress);
1178 }
1179 
1180 //-----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)1181 void vtkExtractCTHPart::PrintSelf(ostream& os, vtkIndent indent)
1182 {
1183   this->Superclass::PrintSelf(os,indent);
1184 
1185   os << indent << "VolumeArrayNames: \n";
1186   vtkIndent i2 = indent.GetNextIndent();
1187   std::vector<std::string>::iterator it;
1188   for ( it = this->Internals->VolumeArrayNames.begin();
1189     it != this->Internals->VolumeArrayNames.end();
1190     ++ it )
1191     {
1192     os << i2 << it->c_str() << endl;
1193     }
1194   os << indent << "VolumeFractionSurfaceValue: "
1195     << this->VolumeFractionSurfaceValue << endl;
1196   os << indent << "Capping: " << this->Capping << endl;
1197   os << indent << "GenerateTriangles: " << this->GenerateTriangles << endl;
1198   os << indent << "RemoveGhostCells: " << this->RemoveGhostCells << endl;
1199 
1200   if (this->ClipPlane)
1201     {
1202     os << indent << "ClipPlane:\n";
1203     this->ClipPlane->PrintSelf(os, indent.GetNextIndent());
1204     }
1205   else
1206     {
1207     os << indent << "ClipPlane: NULL\n";
1208     }
1209 
1210   if ( this->Controller!=0)
1211     {
1212     os << "Controller:" << endl;
1213     this->Controller->PrintSelf(os, indent.GetNextIndent());
1214     }
1215   else
1216     {
1217     os << "No Controller." << endl;
1218     }
1219 }
1220