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