1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkAdaptiveDataSetSurfaceFilter.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 "vtkAdaptiveDataSetSurfaceFilter.h"
16 
17 #include "vtkBitArray.h"
18 #include "vtkCamera.h"
19 #include "vtkCellData.h"
20 #include "vtkDataSetAttributes.h"
21 #include "vtkHyperTreeGrid.h"
22 #include "vtkInformation.h"
23 #include "vtkInformationVector.h"
24 #include "vtkPointData.h"
25 #include "vtkPolyData.h"
26 #include "vtkRenderer.h"
27 #include "vtkUnsignedCharArray.h"
28 
29 #include "vtkIncrementalPointLocator.h"
30 #include "vtkMergePoints.h"
31 
32 #include "vtkHyperTreeGridNonOrientedGeometryCursor.h"
33 #include "vtkHyperTreeGridNonOrientedVonNeumannSuperCursorLight.h"
34 
35 static const unsigned int VonNeumannCursors3D[] = { 0, 1, 2, 4, 5, 6 };
36 static const unsigned int VonNeumannOrientations3D[] = { 2, 1, 0, 0, 1, 2 };
37 static const unsigned int VonNeumannOffsets3D[] = { 0, 0, 0, 1, 1, 1 };
38 
39 vtkStandardNewMacro(vtkAdaptiveDataSetSurfaceFilter);
40 
41 //------------------------------------------------------------------------------
vtkAdaptiveDataSetSurfaceFilter()42 vtkAdaptiveDataSetSurfaceFilter::vtkAdaptiveDataSetSurfaceFilter()
43 {
44   this->InData = nullptr;
45   this->OutData = nullptr;
46   this->Points = nullptr;
47   this->Cells = nullptr;
48 
49   // Default dimension is 0
50   this->Dimension = 0;
51 
52   // Default orientation is 0
53   this->Orientation = 0;
54 
55   this->Renderer = nullptr;
56 
57   this->LevelMax = -1;
58 
59   this->ViewPointDepend = true;
60 
61   this->ParallelProjection = false;
62   this->LastRendererSize[0] = 0;
63   this->LastRendererSize[1] = 0;
64   this->LastCameraFocalPoint[0] = 0.0;
65   this->LastCameraFocalPoint[1] = 0.0;
66   this->LastCameraFocalPoint[2] = 0.0;
67   this->LastCameraParallelScale = 0;
68 
69   this->Scale = 1;
70 
71   this->CircleSelection = true;
72   this->BBSelection = false;
73   this->FixedLevelMax = -1;
74   this->DynamicDecimateLevelMax = 0;
75 
76   // Default Locator is 0
77   this->Merging = false;
78 
79   // vtkGeometryFilter allows an optional 2nd input. Need to
80   // disable this.
81   this->SetNumberOfInputPorts(1);
82 }
83 
84 //------------------------------------------------------------------------------
85 vtkAdaptiveDataSetSurfaceFilter::~vtkAdaptiveDataSetSurfaceFilter() = default;
86 
87 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)88 void vtkAdaptiveDataSetSurfaceFilter::PrintSelf(ostream& os, vtkIndent indent)
89 {
90   this->Superclass::PrintSelf(os, indent);
91 
92   if (this->InData)
93   {
94     os << indent << "InData:\n";
95     this->InData->PrintSelf(os, indent.GetNextIndent());
96   }
97   else
98   {
99     os << indent << "InData: ( none )\n";
100   }
101 
102   if (this->OutData)
103   {
104     os << indent << "OutData:\n";
105     this->OutData->PrintSelf(os, indent.GetNextIndent());
106   }
107   else
108   {
109     os << indent << "OutData: ( none )\n";
110   }
111 
112   if (this->Points)
113   {
114     os << indent << "Points:\n";
115     this->Points->PrintSelf(os, indent.GetNextIndent());
116   }
117   else
118   {
119     os << indent << "Points: ( none )\n";
120   }
121 
122   if (this->Cells)
123   {
124     os << indent << "Cells:\n";
125     this->Cells->PrintSelf(os, indent.GetNextIndent());
126   }
127   else
128   {
129     os << indent << "Cells: ( none )\n";
130   }
131 
132   os << indent << "Dimension: " << this->Dimension << endl;
133   os << indent << "Orientation: " << this->Orientation << endl;
134   os << indent << "Axis1: " << this->Axis1 << endl;
135   os << indent << "Axis2: " << this->Axis2 << endl;
136   os << indent << "Radius: " << this->Radius << endl;
137   os << indent << "LevelMax: " << this->LevelMax << endl;
138   os << indent << "ViewPointDepend: " << this->ViewPointDepend << endl;
139   os << indent << "ParallelProjection: " << this->ParallelProjection << endl;
140   os << indent << "Scale: " << this->Scale << endl;
141   os << indent << "FixedLevelMax: " << this->FixedLevelMax << endl;
142   os << indent << "DynamicDecimateLevelMax: " << this->DynamicDecimateLevelMax << endl;
143   os << indent << "LastCameraParallelScale: " << this->LastCameraParallelScale << endl;
144   os << indent << "LastRendererSize: " << this->LastRendererSize[0] << ", "
145      << this->LastRendererSize[1] << endl;
146   os << indent << "LastCameraFocalPoint: " << this->LastCameraFocalPoint[0] << ", "
147      << this->LastCameraFocalPoint[1] << ", " << this->LastCameraFocalPoint[2] << endl;
148 }
149 
150 //------------------------------------------------------------------------------
RequestData(vtkInformation * request,vtkInformationVector ** inputVector,vtkInformationVector * outputVector)151 int vtkAdaptiveDataSetSurfaceFilter::RequestData(
152   vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector)
153 {
154   // Get the info objects
155   vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
156   vtkInformation* outInfo = outputVector->GetInformationObject(0);
157 
158   // Get the input and output
159   vtkDataObject* input = vtkDataObject::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT()));
160   vtkPolyData* output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
161 
162   int MeshType = input->GetDataObjectType();
163   if (MeshType != VTK_HYPER_TREE_GRID)
164   {
165     return this->Superclass::RequestData(request, inputVector, outputVector);
166   }
167 
168   return this->DataObjectExecute(input, output);
169 }
170 
171 //------------------------------------------------------------------------------
DataObjectExecute(vtkDataObject * inputDS,vtkPolyData * output)172 int vtkAdaptiveDataSetSurfaceFilter::DataObjectExecute(vtkDataObject* inputDS, vtkPolyData* output)
173 {
174   // Retrieve input grid
175   vtkHyperTreeGrid* input = vtkHyperTreeGrid::SafeDownCast(inputDS);
176   if (!input)
177   {
178     // DDM&&JB Nous perdons cette facilite d'appeler ce service par defaut qui nous
179     // redirige ensuite vers un service plus adapte si pas HTG
180     // return vtkDataSetSurfaceFilter::DataSetExecute( inputDS, output );
181     vtkErrorMacro("pre: input_not_HyperTreeGrid: " << inputDS->GetClassName());
182     return 0;
183   }
184 
185   // Retrieve useful grid parameters for speed of access
186   this->Dimension = input->GetDimension();
187   this->Orientation = input->GetOrientation();
188 
189   // Initialize output cell data
190   this->InData = static_cast<vtkDataSetAttributes*>(input->GetCellData());
191   this->OutData = static_cast<vtkDataSetAttributes*>(output->GetCellData());
192   this->OutData->CopyAllocate(this->InData);
193 
194   // DDM&&JB Nous perdons aussi cette fonctionnalite sous cette nouvelle forme
195   /*
196   if ( this->PassThroughCellIds )
197   {
198     this->OriginalCellIds = vtkIdTypeArray::New();
199     this->OriginalCellIds->SetName( this->GetOriginalCellIdsName() );
200     this->OriginalCellIds->SetNumberOfComponents( 1 );
201     this->OutData->AddArray( this->OriginalCellIds );
202   }
203   */
204 
205   // Init renderer information
206   if (this->ViewPointDepend && this->ParallelProjection && this->Renderer)
207   {
208     // Generate planes XY, XZ o YZ
209     unsigned int gridSize[3];
210     input->GetCellDims(gridSize);
211 
212     bool isInit = false;
213     if (this->Dimension == 2) // JB A verifier
214     {
215       input->Get2DAxes(this->Axis1, this->Axis2);
216       isInit = true;
217     }
218 
219     // Compute the zoom of the camera
220     vtkCamera* cam = this->Renderer->GetActiveCamera();
221 
222     // Compute the bounding box
223     double bounds[6];
224     input->GetBounds(bounds);
225 
226     // JB Recupere le branch factor
227     int f = input->GetBranchFactor();
228 
229     // JB Le calcul qui suit a pour objet de determiner le niveau de parcours en profondeur utile
230     // pour l'affichage
231     // JB en fonction de la distance
232     if (isInit)
233     {
234       // JB Taille Moyenne d'une maille du niveau 0 dans les coordonnees reelles suivant chaque
235       // direction
236       double worldCellAverageScaleAxis1 = (bounds[2 * this->Axis1 + 1] - bounds[2 * this->Axis1]) /
237         (double)(gridSize[this->Axis1]) / this->Scale;
238       double worldCellAverageScaleAxis2 = (bounds[2 * this->Axis2 + 1] - bounds[2 * this->Axis2]) /
239         (double)(gridSize[this->Axis2]) / this->Scale;
240 
241       // JB Taille de la fenetre dans les coordonnees reelles (GetParallelScale) suivant chaque
242       // direction
243       double worldWindScaleAxis1 =
244         cam->GetParallelScale() * this->LastRendererSize[0] / (double)(this->LastRendererSize[1]);
245       double worldWindScaleAxis2 = cam->GetParallelScale();
246 
247       // JB Taille de la fenetre en pixel, ecran, suivant chaque direction
248       double windScaleAxis1 = this->LastRendererSize[0];
249       double windScaleAxis2 = this->LastRendererSize[1];
250 
251       // JB Compute how many levels of the tree we should process by direction
252       // JB 1) application du theoreme de Thales ; le rapport taille d'une maille de niveau 0 par la
253       // taille de la fenetre est identique si le
254       // JB calcul se fait en coordonnees reelles ou en coordonnees ecran (pixel)
255       // JB 2) la taille d'une maille de niveau L vaut la taille d'une maille de niveau 0 divisee
256       // par le facteur de raffinement eleve a la puissance L
257       // JB 3) au final, le calcul qui suit a pour objet de determiner quand une maille fera un
258       // pixel
259       double levelMaxiAxis1 =
260         (log(windScaleAxis1) + log(worldCellAverageScaleAxis1) - log(worldWindScaleAxis1)) / log(f);
261       double levelMaxiAxis2 =
262         (log(windScaleAxis2) + log(worldCellAverageScaleAxis2) - log(worldWindScaleAxis2)) / log(f);
263 
264       // JB On opte pour le niveau le plus eleve
265       this->LevelMax = std::ceil(std::max(levelMaxiAxis1, levelMaxiAxis2));
266     }
267     else
268     {
269       // JB En 3D, par defaut, on prend tous les niveaux
270       this->LevelMax = 65536;
271     }
272 
273     // JB Par option, on peut reduire cette valeur... tres utile pour avoir un LOD leger.
274     this->LevelMax -= this->DynamicDecimateLevelMax;
275     if (this->LevelMax < 0)
276     {
277       this->LevelMax = 0;
278     }
279 
280     // JB Par option, on peut fixer le niveau max independemment du calcul dynamique realise
281     // precedemment
282     if (this->FixedLevelMax >= 0)
283     {
284       this->LevelMax = this->FixedLevelMax;
285     }
286 
287     // JB Le calcul qui suit a pour objet de determiner le rayon du cercle dans les coordonnees
288     // reelles incluant la projection
289     // JB de la fenetre. L'activation de CircleSelection permettra de ne produire que les mailles
290     // intersectant ce cercle centre
291     // JB au camera focal point.
292     // JB LastCameraFocalPoint retourne le centre de l'ecran dans les coordonnees reelles
293     double ratio = this->LastRendererSize[0] / (double)(this->LastRendererSize[1]);
294     this->Radius = cam->GetParallelScale() * sqrt(1 + pow(ratio, 2));
295 
296     // JB Le calcul qui suit a pour objet de determiner la boite englobante dans les coordonnees
297     // reelles (et sans tenir compte
298     // JB d'un point de vue qui aurait tourne) incluant la projection de la fenetre. L'activation de
299     // BBSelection permettra de ne
300     // JB produire que les mailles intersectant cette boite englobante.
301     this->WindowBounds[0] = this->LastCameraFocalPoint[0] - cam->GetParallelScale() * ratio;
302     this->WindowBounds[1] = this->LastCameraFocalPoint[0] + cam->GetParallelScale() * ratio;
303     this->WindowBounds[2] = this->LastCameraFocalPoint[1] - cam->GetParallelScale();
304     this->WindowBounds[3] = this->LastCameraFocalPoint[1] + cam->GetParallelScale();
305 
306 #ifndef NDEBUG
307     this->NbRejectByCircle = 0;
308     this->NbRejectByBB = 0;
309 
310     std::cerr << "LevelMax        " << this->LevelMax << std::endl;
311     std::cerr << "CircleSelection " << this->CircleSelection << std::endl;
312     std::cerr << "Circle R        " << this->Radius << std::endl;
313     std::cerr << "       CX       " << this->LastCameraFocalPoint[this->Axis1] << std::endl;
314     std::cerr << "       CY       " << this->LastCameraFocalPoint[this->Axis2] << std::endl;
315     std::cerr << "BBSelection     " << this->BBSelection << std::endl;
316     std::cerr << "Bounds X        " << this->WindowBounds[0] << " : " << this->WindowBounds[1]
317               << std::endl;
318     std::cerr << "       Y        " << this->WindowBounds[2] << " : " << this->WindowBounds[3]
319               << std::endl;
320 #endif
321   }
322   else
323   {
324     // Recurse all the tree
325     this->LevelMax = -1;
326   }
327 
328   // Extract geometry from hyper tree grid
329   this->ProcessTrees(input, output);
330 
331   this->UpdateProgress(1.);
332 
333   return 1;
334 }
335 
336 //------------------------------------------------------------------------------
FillInputPortInformation(int,vtkInformation * info)337 int vtkAdaptiveDataSetSurfaceFilter::FillInputPortInformation(int, vtkInformation* info)
338 {
339   info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataObject");
340   return 1;
341 }
342 
343 //------------------------------------------------------------------------------
ProcessTrees(vtkHyperTreeGrid * input,vtkPolyData * output)344 void vtkAdaptiveDataSetSurfaceFilter::ProcessTrees(vtkHyperTreeGrid* input, vtkPolyData* output)
345 {
346   if (this->Points)
347   {
348     this->Points->Delete();
349   }
350   // Create storage for corners of leaf cells
351   this->Points = vtkPoints::New();
352 
353   // Create storage for untructured leaf cells
354   if (this->Cells)
355   {
356     this->Cells->Delete();
357   }
358   this->Cells = vtkCellArray::New();
359 
360   // JB Initialize a Locator
361   if (this->Merging)
362   {
363     this->Locator = vtkMergePoints::New();
364     this->Locator->InitPointInsertion(this->Points, input->GetBounds());
365   }
366 
367   // Retrieve material mask
368   this->Mask = input->HasMask() ? input->GetMask() : nullptr;
369 
370   //
371   vtkUnsignedCharArray* ghost = nullptr; // DDM input->GetPointGhostArray();
372   if (ghost)
373   {
374     this->OutData->CopyFieldOff(vtkDataSetAttributes::GhostArrayName());
375   }
376 
377   // Iterate over all hyper trees
378   if (this->Dimension == 3)
379   {
380     vtkIdType index;
381     vtkHyperTreeGrid::vtkHyperTreeGridIterator it;
382     input->InitializeTreeIterator(it);
383     vtkNew<vtkHyperTreeGridNonOrientedVonNeumannSuperCursorLight> cursor;
384     while (it.GetNextTree(index))
385     {
386       // In 3 dimensions, von Neumann neighborhood information is needed
387       input->InitializeNonOrientedVonNeumannSuperCursorLight(cursor, index);
388       // If this is not a ghost tree
389       if (!ghost || !ghost->GetTuple1(cursor->GetGlobalNodeIndex()))
390       {
391         // Build geometry recursively
392         this->RecursivelyProcessTree3D(cursor, 0);
393       }
394     } // it
395   }   // if ( this->Dimension == 3 )
396   else
397   {
398     vtkIdType index;
399     vtkHyperTreeGrid::vtkHyperTreeGridIterator it;
400     input->InitializeTreeIterator(it);
401     vtkNew<vtkHyperTreeGridNonOrientedGeometryCursor> cursor;
402     while (it.GetNextTree(index))
403     {
404       // Otherwise, geometric properties of the cells suffice
405       input->InitializeNonOrientedGeometryCursor(cursor, index);
406       // If this is not a ghost tree
407       if (!ghost || !ghost->GetTuple1(cursor->GetGlobalNodeIndex()))
408       {
409         // Build geometry recursively
410         this->RecursivelyProcessTreeNot3D(cursor, 0);
411       }
412     } // it
413   }   // else
414 
415   // Set output geometry and topology
416   output->SetPoints(this->Points);
417   if (this->Dimension == 1)
418   {
419     output->SetLines(this->Cells);
420   }
421   else
422   {
423     output->SetPolys(this->Cells);
424   }
425 
426 #ifndef NDEBUG
427   std::cerr << "vtkAdaptiveDataSetSurfaceFilter #Points            "
428             << this->Points->GetNumberOfPoints() << std::endl;
429   std::cerr << "                                #Cells             "
430             << this->Cells->GetNumberOfCells() << std::endl;
431   std::cerr << "                                #Type&Connectivity "
432             << this->Cells->GetNumberOfConnectivityIds() << std::endl;
433   std::cerr << "                          Cells #NbRejectByBB      " << this->NbRejectByBB
434             << std::endl;
435   std::cerr << "                                #NbRejectByCircle  " << this->NbRejectByCircle
436             << std::endl;
437 #endif
438   std::cerr << "vtkAdaptiveDataSetSurfaceFilter #Points            "
439             << this->Points->GetNumberOfPoints() << std::endl;
440   std::cerr << "                                #Cells             "
441             << this->Cells->GetNumberOfCells() << std::endl;
442   std::cerr << "                                #Type&Connectivity "
443             << this->Cells->GetNumberOfConnectivityIds() << std::endl;
444 
445   this->Points->Delete();
446   this->Points = nullptr;
447   this->Cells->Delete();
448   this->Cells = nullptr;
449 
450   if (this->Locator)
451   {
452     this->Locator->UnRegister(this);
453     this->Locator = nullptr;
454   }
455 }
456 
457 //------------------------------------------------------------------------------
RecursivelyProcessTreeNot3D(vtkHyperTreeGridNonOrientedGeometryCursor * cursor,int level)458 void vtkAdaptiveDataSetSurfaceFilter::RecursivelyProcessTreeNot3D(
459   vtkHyperTreeGridNonOrientedGeometryCursor* cursor, int level)
460 {
461   bool insideBB = (this->LevelMax == -1);
462   if (!insideBB && (this->CircleSelection || this->BBSelection))
463   {
464     double originAxis1 = cursor->GetOrigin()[this->Axis1];
465     double originAxis2 = cursor->GetOrigin()[this->Axis2];
466     double halfAxis1 = cursor->GetSize()[this->Axis1] / 2;
467     double halfAxis2 = cursor->GetSize()[this->Axis2] / 2;
468     if (this->CircleSelection)
469     {
470       // JB On determine si la maille correspondant au current node of the tree
471       // JB is going to be rendered.
472       // JB Pour cela, on fait une premiere approximation en considerant la maille
473       // JB carre qui l'englobe en conservant la meme origine et en fixant sa demi-largeur
474       // JB a la valeur maximale entre les valeurs de demi-largeur et demi-longueur.
475       double half = std::max(halfAxis1, halfAxis2);
476       // JB This cell must be rendered si le centre de cette maille se trouve a moins de
477       // JB Radius + half * sqrt(2) du camera focal point. Radius est le rayon minimal du cercle
478       // JB centre sur la camera focal point couvrant la fenetre de rendu.
479       // JB Le centre de la maille se trouve a Origin + half, par direction.
480       // JB La comparaison se fait sur les distances au carre afin d'eviter le calcul
481       // JB couteux de racines carres.
482       insideBB = (pow(originAxis1 + half - this->LastCameraFocalPoint[this->Axis1], 2) +
483                    pow(originAxis2 + half - this->LastCameraFocalPoint[this->Axis2], 2)) <
484         // pow( this->Radius + half * sqrt(2.), 2 );
485         pow(this->Radius + half * 1.414213562, 2);
486     }
487     else
488     {
489       insideBB = true;
490     }
491 
492     if (insideBB && this->BBSelection)
493     {
494       // JB On determine si la maille correspondant au current node of the tree
495       // JB is going to be rendered.
496       // JB Pour cela, on verifie si la maille est dans une boite englobante correspondant a la
497       // JB projection de l'ecran dans le monde du maillage.
498       insideBB = ((originAxis1 + 2 * halfAxis1 >= this->WindowBounds[0]) &&
499         (originAxis1 <= this->WindowBounds[1]) &&
500         (originAxis2 + 2 * halfAxis2 >= this->WindowBounds[2]) &&
501         (originAxis2 <= this->WindowBounds[3]));
502 #ifndef NDEBUG
503       if (!insideBB)
504       {
505         this->NbRejectByBB++;
506       }
507     }
508     else
509     {
510       this->NbRejectByCircle++;
511 #endif
512     }
513   }
514   if (insideBB)
515   {
516     // We only process those nodes than are going to be rendered
517     if (cursor->IsLeaf() || (this->LevelMax != -1 && level >= this->LevelMax))
518     {
519       if (this->Dimension == 2)
520       {
521         this->ProcessLeaf2D(cursor);
522       }
523       else
524       {
525         this->ProcessLeaf1D(cursor);
526       } // else
527     }   // if ( cursor->IsLeaf() || ( this->LevelMax!=-1 && level >= this->LevelMax ) )
528     else
529     {
530       // Cursor is not at leaf, recurse to all children
531       int numChildren = cursor->GetNumberOfChildren();
532       for (int ichild = 0; ichild < numChildren; ++ichild)
533       {
534         cursor->ToChild(ichild);
535         // Recurse
536         this->RecursivelyProcessTreeNot3D(cursor, level + 1);
537         cursor->ToParent();
538       } // ichild
539     }   // else
540   }     // if( insideBB )
541 }
542 
543 //------------------------------------------------------------------------------
ProcessLeaf1D(vtkHyperTreeGridNonOrientedGeometryCursor * cursor)544 void vtkAdaptiveDataSetSurfaceFilter::ProcessLeaf1D(
545   vtkHyperTreeGridNonOrientedGeometryCursor* cursor)
546 {
547   // In 1D the geometry is composed of edges, create storage for endpoint IDs
548   vtkIdType id[2];
549 
550   // First endpoint is at origin of cursor
551   const double* origin = cursor->GetOrigin();
552   id[0] = this->Points->InsertNextPoint(origin);
553 
554   // Second endpoint is at origin of cursor plus its length
555   double pt[3];
556   memcpy(pt, origin, 3 * sizeof(double));
557   switch (this->Orientation)
558   {
559     case 3: // 1 + 2
560       pt[2] += cursor->GetSize()[2];
561       break;
562     case 5: // 1 + 4
563       pt[1] += cursor->GetSize()[1];
564       break;
565     case 6: // 2 + 4
566       pt[0] += cursor->GetSize()[0];
567       break;
568   } // switch
569   id[1] = this->Points->InsertNextPoint(pt);
570 
571   // Insert edge into 1D geometry
572   this->Cells->InsertNextCell(2, id);
573 }
574 
575 //------------------------------------------------------------------------------
ProcessLeaf2D(vtkHyperTreeGridNonOrientedGeometryCursor * cursor)576 void vtkAdaptiveDataSetSurfaceFilter::ProcessLeaf2D(
577   vtkHyperTreeGridNonOrientedGeometryCursor* cursor)
578 
579 {
580   // Cell at cursor center is a leaf, retrieve its global index
581   vtkIdType id = cursor->GetGlobalNodeIndex();
582   if (id < 0)
583   {
584     return;
585   }
586 
587   // In 2D all unmasked faces are generated
588   if (!this->Mask || !this->Mask->GetValue(id))
589   {
590     // Insert face into 2D geometry depending on orientation
591     this->AddFace(id, cursor->GetOrigin(), cursor->GetSize(), 0, this->Orientation);
592   }
593 }
594 
595 //------------------------------------------------------------------------------
RecursivelyProcessTree3D(vtkHyperTreeGridNonOrientedVonNeumannSuperCursorLight * cursor,int level)596 void vtkAdaptiveDataSetSurfaceFilter::RecursivelyProcessTree3D(
597   vtkHyperTreeGridNonOrientedVonNeumannSuperCursorLight* cursor, int level)
598 {
599   // Create geometry output if cursor is at leaf
600   if (cursor->IsLeaf())
601   {
602     this->ProcessLeaf3D(cursor);
603   } // if ( cursor->IsLeaf() )
604   else
605   {
606     // Cursor is not at leaf, recurse to all children
607     int numChildren = cursor->GetNumberOfChildren();
608     for (int ichild = 0; ichild < numChildren; ++ichild)
609     {
610       cursor->ToChild(ichild);
611       // Recurse
612       this->RecursivelyProcessTree3D(cursor, level + 1);
613       cursor->ToParent();
614     } // child
615   }   // else
616 }
617 
618 //------------------------------------------------------------------------------
ProcessLeaf3D(vtkHyperTreeGridNonOrientedVonNeumannSuperCursorLight * superCursor)619 void vtkAdaptiveDataSetSurfaceFilter::ProcessLeaf3D(
620   vtkHyperTreeGridNonOrientedVonNeumannSuperCursorLight* superCursor)
621 {
622   // Cell at super cursor center is a leaf, retrieve its global index, level, and mask
623   vtkIdType idcenter = superCursor->GetGlobalNodeIndex();
624   unsigned level = superCursor->GetLevel();
625   int masked = this->Mask ? this->Mask->GetValue(idcenter) : 0;
626 
627   // Iterate over all cursors of Von Neumann neighborhood around center
628   unsigned int nc = superCursor->GetNumberOfCursors() - 1;
629   for (unsigned int c = 0; c < nc; ++c)
630   {
631     // Retrieve cursor to neighbor across face
632     // Retrieve tree, leaf flag, and mask of neighbor cursor
633     unsigned int levelN;
634     bool leafN;
635     vtkIdType idN;
636     vtkHyperTree* treeN = superCursor->GetInformation(VonNeumannCursors3D[c], levelN, leafN, idN);
637 
638     int maskedN = 1;
639     if (treeN)
640     {
641       maskedN = this->Mask ? this->Mask->GetValue(idN) : 0;
642     }
643 
644     // In 3D masked and unmasked cells are handled differently:
645     // . If cell is unmasked, and face neighbor is a masked leaf, or no such neighbor
646     //   exists, then generate face.
647     // . If cell is masked, and face neighbor exists and is an unmasked leaf, then
648     //   generate face, breaking ties at same level. This ensures that faces between
649     //   unmasked and masked cells will be generated once and only once.
650     if ((!masked && (!treeN || (leafN && maskedN))) ||
651       (masked && treeN && leafN && levelN < level && !maskedN))
652     {
653       // Generate face with corresponding normal and offset
654       this->AddFace(idcenter, superCursor->GetOrigin(), superCursor->GetSize(),
655         VonNeumannOffsets3D[c], VonNeumannOrientations3D[c]);
656     }
657   } // c
658 }
659 
660 //------------------------------------------------------------------------------
AddFace(vtkIdType inId,const double * origin,const double * size,int offset,unsigned int orientation)661 void vtkAdaptiveDataSetSurfaceFilter::AddFace(
662   vtkIdType inId, const double* origin, const double* size, int offset, unsigned int orientation)
663 {
664   // Storage for point coordinates
665   double pt[] = { 0., 0., 0. };
666 
667   // Storage for face vertex IDs
668   vtkIdType ids[4];
669 
670   // First cell vertex is always at origin of cursor
671   memcpy(pt, origin, 3 * sizeof(double));
672 
673   if (this->Locator)
674   {
675     if (offset)
676     {
677       // Offset point coordinate as needed
678       pt[orientation] += size[orientation];
679     }
680     this->Locator->InsertUniquePoint(pt, ids[0]);
681     // Create other face vertices depending on orientation
682     unsigned int axis1 = orientation ? 0 : 1;
683     unsigned int axis2 = orientation == 2 ? 1 : 2;
684     pt[axis1] += size[axis1];
685     this->Locator->InsertUniquePoint(pt, ids[1]);
686     pt[axis2] += size[axis2];
687     this->Locator->InsertUniquePoint(pt, ids[2]);
688     pt[axis1] = origin[axis1];
689     this->Locator->InsertUniquePoint(pt, ids[3]);
690   }
691   else
692   {
693     if (offset)
694     {
695       // Offset point coordinate as needed
696       pt[orientation] += size[orientation];
697     }
698     ids[0] = this->Points->InsertNextPoint(pt);
699 
700     // Create other face vertices depending on orientation
701     unsigned int axis1 = orientation ? 0 : 1;
702     unsigned int axis2 = orientation == 2 ? 1 : 2;
703     pt[axis1] += size[axis1];
704     ids[1] = this->Points->InsertNextPoint(pt);
705     pt[axis2] += size[axis2];
706     ids[2] = this->Points->InsertNextPoint(pt);
707     pt[axis1] = origin[axis1];
708     ids[3] = this->Points->InsertNextPoint(pt);
709   }
710 
711   // Insert next face
712   vtkIdType outId = this->Cells->InsertNextCell(4, ids);
713 
714   // Copy face data from that of the cell from which it comes
715   this->OutData->CopyData(this->InData, inId, outId);
716 }
717 
718 //------------------------------------------------------------------------------
SetRenderer(vtkRenderer * ren)719 void vtkAdaptiveDataSetSurfaceFilter::SetRenderer(vtkRenderer* ren)
720 {
721   if (ren != this->Renderer)
722   {
723     this->Renderer = ren;
724     this->Modified();
725   }
726 }
727 
728 //------------------------------------------------------------------------------
GetMTime()729 vtkMTimeType vtkAdaptiveDataSetSurfaceFilter::GetMTime()
730 {
731   // Check for minimal changes
732   if (this->Renderer)
733   {
734     vtkCamera* cam = this->Renderer->GetActiveCamera();
735     if (cam)
736     {
737       // Check & Update parallel projection
738       bool para = (cam->GetParallelProjection() != 0);
739 
740       if (this->ParallelProjection != para)
741       {
742         this->ParallelProjection = para;
743         this->Modified();
744       }
745 
746       // Check & Update renderer size
747       const int* sz = this->Renderer->GetSize();
748       if (this->LastRendererSize[0] != sz[0] || this->LastRendererSize[1] != sz[1])
749       {
750         this->LastRendererSize[0] = sz[0];
751         this->LastRendererSize[1] = sz[1];
752         this->Modified();
753       }
754 
755       // Check & Update camera focal point
756       double* fp = cam->GetFocalPoint();
757       if (this->LastCameraFocalPoint[0] != fp[0] || this->LastCameraFocalPoint[1] != fp[1] ||
758         this->LastCameraFocalPoint[2] != fp[2])
759       {
760         this->LastCameraFocalPoint[0] = fp[0];
761         this->LastCameraFocalPoint[1] = fp[1];
762         this->LastCameraFocalPoint[2] = fp[2];
763         this->Modified();
764       }
765 
766       // Check & Update camera scale
767       double scale = cam->GetParallelScale();
768       if (this->LastCameraParallelScale != scale)
769       {
770         this->LastCameraParallelScale = scale;
771         this->Modified();
772       }
773     } // if ( cam )
774   }   // if ( this->Renderer )
775   return this->Superclass::GetMTime();
776 }
777