1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkHyperTreeGridToDualGrid.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 "vtkHyperTreeGridToDualGrid.h"
16
17 #include "vtkBitArray.h"
18 #include "vtkCellData.h"
19 #include "vtkCellType.h"
20 #include "vtkHyperTree.h"
21 #include "vtkHyperTreeGrid.h"
22 #include "vtkHyperTreeGridNonOrientedMooreSuperCursor.h"
23 #include "vtkHyperTreeGridOrientedGeometryCursor.h"
24 #include "vtkIdTypeArray.h"
25 #include "vtkInformation.h"
26 #include "vtkInformationVector.h"
27 #include "vtkObjectFactory.h"
28 #include "vtkPointData.h"
29 #include "vtkPoints.h"
30 #include "vtkUnstructuredGrid.h"
31
32 vtkStandardNewMacro(vtkHyperTreeGridToDualGrid);
33
34 static const unsigned int CornerNeighborCursorsTable3D0[8] = { 0, 1, 3, 4, 9, 10, 12, 13 };
35 static const unsigned int CornerNeighborCursorsTable3D1[8] = { 1, 2, 4, 5, 10, 11, 13, 14 };
36 static const unsigned int CornerNeighborCursorsTable3D2[8] = { 3, 4, 6, 7, 12, 13, 15, 16 };
37 static const unsigned int CornerNeighborCursorsTable3D3[8] = { 4, 5, 7, 8, 13, 14, 16, 17 };
38 static const unsigned int CornerNeighborCursorsTable3D4[8] = { 9, 10, 12, 13, 18, 19, 21, 22 };
39 static const unsigned int CornerNeighborCursorsTable3D5[8] = { 10, 11, 13, 14, 19, 20, 22, 23 };
40 static const unsigned int CornerNeighborCursorsTable3D6[8] = { 12, 13, 15, 16, 21, 22, 24, 25 };
41 static const unsigned int CornerNeighborCursorsTable3D7[8] = { 13, 14, 16, 17, 22, 23, 25, 26 };
42 static const unsigned int* CornerNeighborCursorsTable3D[8] = {
43 CornerNeighborCursorsTable3D0,
44 CornerNeighborCursorsTable3D1,
45 CornerNeighborCursorsTable3D2,
46 CornerNeighborCursorsTable3D3,
47 CornerNeighborCursorsTable3D4,
48 CornerNeighborCursorsTable3D5,
49 CornerNeighborCursorsTable3D6,
50 CornerNeighborCursorsTable3D7,
51 };
52
53 //------------------------------------------------------------------------------
vtkHyperTreeGridToDualGrid()54 vtkHyperTreeGridToDualGrid::vtkHyperTreeGridToDualGrid()
55 {
56 // Dual grid corners (primal grid leaf centers)
57 this->Points = nullptr;
58 this->Connectivity = nullptr;
59 }
60
61 //------------------------------------------------------------------------------
~vtkHyperTreeGridToDualGrid()62 vtkHyperTreeGridToDualGrid::~vtkHyperTreeGridToDualGrid()
63 {
64 if (this->Points)
65 {
66 this->Points->Delete();
67 }
68
69 if (this->Connectivity)
70 {
71 this->Connectivity->Delete();
72 }
73 }
74
75 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)76 void vtkHyperTreeGridToDualGrid::PrintSelf(ostream& os, vtkIndent indent)
77 {
78 this->Superclass::PrintSelf(os, indent);
79 os << indent << "Points: " << this->Points << endl;
80 os << indent << "Connectivity: " << this->Connectivity << endl;
81 }
82
83 //------------------------------------------------------------------------------
FillOutputPortInformation(int,vtkInformation * info)84 int vtkHyperTreeGridToDualGrid::FillOutputPortInformation(int, vtkInformation* info)
85 {
86 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkUnstructuredGrid");
87 return 1;
88 }
89
90 //------------------------------------------------------------------------------
ProcessTrees(vtkHyperTreeGrid * input,vtkDataObject * outputDO)91 int vtkHyperTreeGridToDualGrid::ProcessTrees(vtkHyperTreeGrid* input, vtkDataObject* outputDO)
92 {
93 // Downcast output data object to hyper tree grid
94 vtkUnstructuredGrid* output = vtkUnstructuredGrid::SafeDownCast(outputDO);
95 if (!output)
96 {
97 vtkErrorMacro("Incorrect type of output: " << outputDO->GetClassName());
98 return 0;
99 }
100
101 // Check if we can break out early
102 // TODO: this isn't right, we need to trust the pipeline tell us when
103 // we need to reexecute, or upstream grid will change and output of this filter will be stale.
104 if (this->Points)
105 {
106 return 1;
107 }
108
109 // TODO: we shouldn't be using persistent internal Points and Connectivity, just populate the
110 // output.
111 // Create arrays needed by dual mesh
112 this->Points = vtkPoints::New();
113 this->Connectivity = vtkIdTypeArray::New();
114
115 // Primal cell centers are dual points
116 // JB On ne peut pas se reduire a dimensionner le tableau de points au nombre
117 // de Vertices, en effet, surtout si l'on veut conserver le mapping 1:1
118 // entre les noeuds de l'HTG et ces points du maillage dual.
119 // En effet, si l'on definit un GlobalIndex ou un IndexStart specifique
120 // cette ecriture simpliste ne fonctionnait plus... tableau trop petit
121 // car GetGlobalIndex retourne une valeur > this->GetNumberOfVertices().
122 this->Points->SetNumberOfPoints(input->GetGlobalNodeIndexMax() + 1);
123
124 // TODO: find out why we get some uninitialized point coords instead
125 this->Points->GetData()->Fill(0.0);
126
127 int numVerts = 1 << input->GetDimension();
128 this->Connectivity->SetNumberOfComponents(numVerts);
129
130 // Initialize grid depth
131 unsigned int gridDepth = 0;
132
133 // Compute and assign scales of all tree roots
134 // double scale[3] = { 1., 1., 1. };
135
136 // Check whether coordinate arrays match grid size
137 // If coordinates array are complete, compute all tree scales
138 // SEB: int* dims = input->GetDimensions();
139 // SEB: if ( dims[0] == input->GetXCoordinates()->GetNumberOfTuples()
140 // SEB: && dims[1] == input->GetYCoordinates()->GetNumberOfTuples()
141 // SEB: && dims[2] == input->GetZCoordinates()->GetNumberOfTuples() )
142 if (static_cast<int>(input->GetDimensions()[0]) ==
143 input->GetXCoordinates()->GetNumberOfTuples() &&
144 static_cast<int>(input->GetDimensions()[1]) == input->GetYCoordinates()->GetNumberOfTuples() &&
145 static_cast<int>(input->GetDimensions()[2]) == input->GetZCoordinates()->GetNumberOfTuples())
146 {
147 gridDepth = input->GetNumberOfLevels();
148 }
149
150 // Compute and store reduction factors for speed
151 double factor = 1.;
152 for (unsigned int p = 0; p < gridDepth; ++p)
153 {
154 this->ReductionFactors[p] = .5 * factor;
155 factor /= input->GetBranchFactor();
156 } // p
157
158 // Retrieve material mask
159 vtkBitArray* mask = input->HasMask() ? input->GetMask() : nullptr;
160
161 // Iterate over all hyper trees
162 vtkIdType index;
163 vtkHyperTreeGrid::vtkHyperTreeGridIterator it;
164 input->InitializeTreeIterator(it);
165 vtkNew<vtkHyperTreeGridNonOrientedMooreSuperCursor> cursor;
166 while (it.GetNextTree(index))
167 {
168 // Initialize new Moore cursor at root of current tree
169 input->InitializeNonOrientedMooreSuperCursor(cursor, index);
170 // Convert hyper tree into unstructured mesh recursively
171 if (mask)
172 {
173 this->TraverseDualRecursively(cursor, mask, input);
174 }
175 else
176 {
177 this->TraverseDualRecursively(cursor, input);
178 }
179 } // it
180
181 // Adjust dual points as needed to fit the primal boundary
182 for (unsigned int d = 0; d < input->GetDimension(); ++d)
183 {
184 // Iterate over all adjustments for current dimension
185 for (std::map<vtkIdType, double>::const_iterator _it = this->PointShifts[d].begin();
186 _it != this->PointShifts[d].end(); ++_it)
187 {
188 double pt[3];
189
190 assert(_it->first < input->GetNumberOfVertices());
191 this->Points->GetPoint(_it->first, pt);
192
193 pt[d] += _it->second;
194
195 assert(_it->first < input->GetNumberOfVertices());
196 this->Points->SetPoint(_it->first, pt);
197 } // it
198 this->PointShifts[d].clear();
199 } // d
200 this->PointShifted.clear();
201
202 // now populate my output from the mesh internals made above
203 output->SetPoints(this->Points);
204 output->GetPointData()->ShallowCopy(input->GetCellData());
205
206 int numPts = 1 << input->GetDimension();
207 int type = VTK_VOXEL;
208 if (numPts == 4)
209 {
210 type = VTK_PIXEL;
211 }
212 if (numPts == 2)
213 {
214 type = VTK_LINE;
215 }
216 output->Allocate();
217 int numCells = this->Connectivity->GetNumberOfTuples();
218 for (int cellIdx = 0; cellIdx < numCells; cellIdx++)
219 {
220 vtkIdType* ptr = this->Connectivity->GetPointer(0) + cellIdx * numPts;
221 output->InsertNextCell(type, numPts, ptr);
222 }
223
224 return 1;
225 }
226
227 //------------------------------------------------------------------------------
TraverseDualRecursively(vtkHyperTreeGridNonOrientedMooreSuperCursor * cursor,vtkHyperTreeGrid * input)228 void vtkHyperTreeGridToDualGrid::TraverseDualRecursively(
229 vtkHyperTreeGridNonOrientedMooreSuperCursor* cursor, vtkHyperTreeGrid* input)
230 {
231 // TODO - code duplication is evil, fold this with other TraverseDual
232 // Create cell corner if cursor is at leaf
233 if (cursor->IsLeaf())
234 {
235 // Center is a leaf, create dual items depending on dimension
236 switch (input->GetDimension())
237 {
238 case 1:
239 this->GenerateDualCornerFromLeaf1D(cursor, input);
240 break;
241 case 2:
242 this->GenerateDualCornerFromLeaf2D(cursor, input);
243 break;
244 case 3:
245 this->GenerateDualCornerFromLeaf3D(cursor, input);
246 break;
247 } // switch ( this->Dimension )
248 } // if ( cursor->IsLeaf() )
249 else
250 {
251 // Cursor is not at leaf, recurse to all children
252 int numChildren = input->GetNumberOfChildren();
253 for (int child = 0; child < numChildren; ++child)
254 {
255 cursor->ToChild(child);
256 // Recurse
257 this->TraverseDualRecursively(cursor, input);
258 cursor->ToParent();
259 } // child
260 } // else
261 }
262
263 //------------------------------------------------------------------------------
GenerateDualCornerFromLeaf1D(vtkHyperTreeGridNonOrientedMooreSuperCursor * cursor,vtkHyperTreeGrid * input)264 void vtkHyperTreeGridToDualGrid::GenerateDualCornerFromLeaf1D(
265 vtkHyperTreeGridNonOrientedMooreSuperCursor* cursor, vtkHyperTreeGrid* input)
266 {
267 // With d=1:
268 // (d-0)-faces are corners, neighbor cursors are 0 and 2
269 // (d-1)-faces do not exist
270 // (d-2)-faces do not exist
271
272 // Retrieve neighbor (left/right) cursors
273 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorL =
274 cursor->GetOrientedGeometryCursor(0);
275 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorR =
276 cursor->GetOrientedGeometryCursor(2);
277
278 // Retrieve cursor center coordinates
279 double pt[3];
280 cursor->GetPoint(pt);
281
282 // Check across d-face neighbors whether point must be adjusted
283 if (!cursorL->HasTree())
284 {
285 // Move to left corner
286 pt[input->GetOrientation()] -= .5 * cursor->GetSize()[input->GetOrientation()];
287 ;
288 }
289 if (!cursorR->HasTree())
290 {
291 // Move to right corner
292 pt[input->GetOrientation()] += .5 * cursor->GetSize()[input->GetOrientation()];
293 ;
294 }
295
296 // Retrieve global index of center cursor
297 vtkIdType id = cursor->GetGlobalNodeIndex();
298
299 // Insert dual point at center of leaf cell
300 this->Points->SetPoint(id, pt);
301
302 // Storage for edge vertex IDs: dual cell ownership to cursor with higher index
303 vtkIdType ids[2];
304 ids[0] = id;
305
306 // Check whether a dual edge to left neighbor exists
307 if (cursorL->HasTree() && cursorL->IsLeaf())
308 {
309 // If left neighbor is a leaf, always create an edge
310 ids[1] = cursorL->GetGlobalNodeIndex();
311 this->Connectivity->InsertNextTypedTuple(ids);
312 }
313
314 // Check whether a dual edge to right neighbor exists
315 if ((cursorR->HasTree() && cursorR->IsLeaf()) && cursorR->GetLevel() != cursor->GetLevel())
316 {
317 // If right neighbor is a leaf, create an edge only if right cell at higher level
318 ids[1] = cursorR->GetGlobalNodeIndex();
319 this->Connectivity->InsertNextTypedTuple(ids);
320 }
321 }
322
323 //------------------------------------------------------------------------------
GenerateDualCornerFromLeaf2D(vtkHyperTreeGridNonOrientedMooreSuperCursor * cursor,vtkHyperTreeGrid * input)324 void vtkHyperTreeGridToDualGrid::GenerateDualCornerFromLeaf2D(
325 vtkHyperTreeGridNonOrientedMooreSuperCursor* cursor, vtkHyperTreeGrid* input)
326 {
327 // With d=2:
328 // (d-0)-faces are edges, neighbor cursors are 1, 3, 5, 7
329 // (d-1)-faces are corners, neighbor cursors are 0, 2, 6, 8
330 // (d-2)-faces do not exist
331
332 // Retrieve (d-0)-neighbor (south/east/west/north) cursors
333 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorS =
334 cursor->GetOrientedGeometryCursor(1);
335 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorW =
336 cursor->GetOrientedGeometryCursor(3);
337 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorE =
338 cursor->GetOrientedGeometryCursor(5);
339 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorN =
340 cursor->GetOrientedGeometryCursor(7);
341
342 // Retrieve (d-1)-neighbor (southwest/southeast/northwest/northeast) cursors
343 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorSW =
344 cursor->GetOrientedGeometryCursor(0);
345 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorSE =
346 cursor->GetOrientedGeometryCursor(2);
347 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorNW =
348 cursor->GetOrientedGeometryCursor(6);
349 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorNE =
350 cursor->GetOrientedGeometryCursor(8);
351
352 // Retrieve 2D axes (east-west/south-north)
353 unsigned int axisWE = input->GetOrientation() ? 0 : 1;
354 unsigned int axisSN = input->GetOrientation() == 2 ? 1 : 2;
355
356 // Retrieve cursor center coordinates
357 double pt[3];
358 cursor->GetPoint(pt);
359
360 // Compute potential shifts
361 double shift[2];
362 shift[0] = .5 * cursor->GetSize()[axisWE];
363 shift[1] = .5 * cursor->GetSize()[axisSN];
364
365 // Check across edge neighbors whether point must be adjusted
366 if (!cursorS->HasTree())
367 {
368 // Move to south edge
369 pt[axisSN] -= shift[1];
370 }
371 if (!cursorW->HasTree())
372 {
373 // Move to west edge
374 pt[axisWE] -= shift[0];
375 }
376 if (!cursorE->HasTree())
377 {
378 // Move to east edge
379 pt[axisWE] += shift[0];
380 }
381 if (!cursorN->HasTree())
382 {
383 // Move to north edge
384 pt[axisSN] += shift[1];
385 }
386
387 // Retrieve global index of center cursor
388 vtkIdType id = cursor->GetGlobalNodeIndex();
389
390 // Insert dual point at center of leaf cell
391 this->Points->SetPoint(id, pt);
392
393 // Storage for edge vertex IDs: dual cell ownership to cursor with higher index
394 vtkIdType ids[4];
395 ids[0] = id;
396
397 // Retrieve current level to break corner ownership ties
398 unsigned int level = cursor->GetLevel();
399
400 // Check whether a dual cell around SW corner exists
401 if (cursorSW->HasTree() && cursorSW->IsLeaf() && cursorS->HasTree() && cursorS->IsLeaf() &&
402 cursorW->HasTree() && cursorW->IsLeaf())
403 {
404 // If SW, S, and W neighbors are leaves, always create a face
405 ids[1] = cursorW->GetGlobalNodeIndex();
406 ids[2] = cursorS->GetGlobalNodeIndex();
407 ids[3] = cursorSW->GetGlobalNodeIndex();
408 this->Connectivity->InsertNextTypedTuple(ids);
409 }
410
411 // Check whether a dual cell around SE corner exists
412 if (cursorS->HasTree() && cursorS->IsLeaf() && cursorSE->HasTree() && cursorSE->IsLeaf() &&
413 cursorE->HasTree() && cursorE->IsLeaf() && level != cursorE->GetLevel())
414 {
415 // If S, SE, and E neighbors are leaves, create a face if E at higher level
416 ids[1] = cursorE->GetGlobalNodeIndex();
417 ids[2] = cursorS->GetGlobalNodeIndex();
418 ids[3] = cursorSE->GetGlobalNodeIndex();
419 this->Connectivity->InsertNextTypedTuple(ids);
420 }
421
422 // Check whether a dual cell around NE corner exists
423 if (cursorE->HasTree() && cursorE->IsLeaf() && cursorNE->HasTree() && cursorNE->IsLeaf() &&
424 cursorN->HasTree() && cursorN->IsLeaf() && level != cursorE->GetLevel() &&
425 level != cursorNE->GetLevel() && level != cursorN->GetLevel())
426 {
427 // If E, NE, and N neighbors are leaves, create a face if E, NE, N at higher level
428 ids[1] = cursorE->GetGlobalNodeIndex();
429 ids[2] = cursorN->GetGlobalNodeIndex();
430 ids[3] = cursorNE->GetGlobalNodeIndex();
431 this->Connectivity->InsertNextTypedTuple(ids);
432 }
433
434 // Check whether a dual cell around NW corner exists
435 if (cursorW->HasTree() && cursorW->IsLeaf() && cursorN->HasTree() && cursorN->IsLeaf() &&
436 cursorNW->HasTree() && cursorNW->IsLeaf() && level != cursorNW->GetLevel() &&
437 level != cursorN->GetLevel())
438 {
439 // If W, N, and NW neighbors are leaves, create a face if NW and N at higher level
440 ids[1] = cursorW->GetGlobalNodeIndex();
441 ids[2] = cursorN->GetGlobalNodeIndex();
442 ids[3] = cursorNW->GetGlobalNodeIndex();
443 this->Connectivity->InsertNextTypedTuple(ids);
444 }
445 }
446
447 //------------------------------------------------------------------------------
GenerateDualCornerFromLeaf3D(vtkHyperTreeGridNonOrientedMooreSuperCursor * cursor,vtkHyperTreeGrid * vtkNotUsed (input))448 void vtkHyperTreeGridToDualGrid::GenerateDualCornerFromLeaf3D(
449 vtkHyperTreeGridNonOrientedMooreSuperCursor* cursor, vtkHyperTreeGrid* vtkNotUsed(input))
450 {
451 // With d=3:
452 // (d-0)-faces are faces, neighbor cursors are 4, 10, 12, 14, 16, 22
453 // (d-1)-faces are edges, neighbor cursors are 1, 3, 5, 7, 9, 11, 15, 17, 19, 21, 23, 25
454 // (d-2)-faces are corners, neighbor cursors are 0, 2, 6, 8, 18, 20, 24, 26
455
456 // Retrieve cursors
457 std::vector<vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor>> cursors;
458 cursors.resize(27);
459 for (unsigned int c = 0; c < 27; ++c)
460 {
461 cursors[c] = cursor->GetOrientedGeometryCursor(c);
462 }
463
464 // Retrieve cursor center coordinates
465 double pt[3];
466 cursor->GetPoint(pt);
467
468 // Compute potential shifts
469 double shift[3];
470 shift[0] = .5 * cursor->GetSize()[0];
471 shift[1] = .5 * cursor->GetSize()[1];
472 shift[2] = .5 * cursor->GetSize()[2];
473
474 // Index offset relative to center cursor (13)
475 unsigned int offset = 1;
476
477 // Check across face neighbors whether point must be adjusted
478 for (unsigned int axis = 0; axis < 3; ++axis, offset *= 3)
479 {
480 if (!cursors[13 - offset]->HasTree())
481 {
482 // Move to negative side along axis
483 pt[axis] -= shift[axis];
484 }
485 if (!cursors[13 + offset]->HasTree())
486 {
487 // Move to positive side along axis
488 pt[axis] += shift[axis];
489 }
490 } // axis
491
492 // Retrieve global index of center cursor
493 vtkIdType id = cursor->GetGlobalNodeIndex();
494
495 // Insert dual point at center of leaf cell
496 this->Points->SetPoint(id, pt);
497
498 // Storage for edge vertex IDs: dual cell ownership to cursor with higher index
499 vtkIdType ids[8];
500
501 // Retrieve current level to break corner ownership ties
502 unsigned int level = cursor->GetLevel();
503
504 // Iterate over leaf corners
505 for (unsigned int c = 0; c < 8; ++c)
506 {
507 // Assume center cursor leaf owns the corner
508 bool owner = true;
509
510 // Iterate over every leaf touching the corner
511 for (unsigned int l = 0; l < 8 && owner; ++l)
512 {
513 // Retrieve cursor index of touching leaf
514 unsigned int index = CornerNeighborCursorsTable3D[c][l];
515
516 // Compute whether corner is owned by another leaf
517 if (index != 13)
518 {
519 if (!cursors[index]->HasTree() || !cursors[index]->IsLeaf() ||
520 (cursors[index]->GetLevel() == level && index > 13))
521 {
522 // If neighbor leaf is out of bounds or has not been
523 // refined to a leaf, this leaf does not own the corner
524 // A level tie is broken in favor of the largest index
525 owner = false;
526 }
527 else
528 {
529 // Collect the leaf indices for the dual cell
530 ids[l] = cursors[index]->GetGlobalNodeIndex();
531 }
532 }
533 else
534 { // if ( index != 13 )
535 // Collect the leaf indices for the dual cell
536 ids[l] = cursors[index]->GetGlobalNodeIndex();
537 } // else
538 } // l
539
540 // If leaf owns the corner, create dual cell
541 if (owner)
542 {
543 this->Connectivity->InsertNextTypedTuple(ids);
544 } // if ( owner )
545 } // c
546 }
547
548 //------------------------------------------------------------------------------
TraverseDualRecursively(vtkHyperTreeGridNonOrientedMooreSuperCursor * cursor,vtkBitArray * mask,vtkHyperTreeGrid * input)549 void vtkHyperTreeGridToDualGrid::TraverseDualRecursively(
550 vtkHyperTreeGridNonOrientedMooreSuperCursor* cursor, vtkBitArray* mask, vtkHyperTreeGrid* input)
551 {
552 // TODO - code duplication is evil, fold this with other TraverseDual
553 // Create cell corner if cursor is at leaf
554 if (cursor->IsLeaf())
555 {
556 // Cursor is at leaf, retrieve its global index
557 vtkIdType id = cursor->GetGlobalNodeIndex();
558
559 // Center is a leaf, create dual items depending on dimension
560 if (mask->GetValue(id))
561 {
562 switch (input->GetDimension())
563 {
564 case 2:
565 this->ShiftDualCornerFromMaskedLeaf2D(cursor, mask, input);
566 break;
567 case 3:
568 this->ShiftDualCornerFromMaskedLeaf3D(cursor, mask, input);
569 } // switch ( this->Dimension )
570 }
571 else
572 {
573 switch (input->GetDimension())
574 {
575 case 1:
576 this->GenerateDualCornerFromLeaf1D(cursor, input);
577 break;
578 case 2:
579 this->GenerateDualCornerFromLeaf2D(cursor, mask, input);
580 break;
581 case 3:
582 this->GenerateDualCornerFromLeaf3D(cursor, mask, input);
583 } // switch ( this->Dimension )
584 } // else
585 } // if ( cursor->IsLeaf() )
586 else
587 {
588 // Cursor is not at leaf, recurse to all children
589 int numChildren = input->GetNumberOfChildren();
590 for (int child = 0; child < numChildren; ++child)
591 {
592 cursor->ToChild(child);
593 // Recurse
594 this->TraverseDualRecursively(cursor, mask, input);
595 cursor->ToParent();
596 } // child
597 } // else
598 }
599
600 //------------------------------------------------------------------------------
ShiftDualCornerFromMaskedLeaf2D(vtkHyperTreeGridNonOrientedMooreSuperCursor * cursor,vtkBitArray * mask,vtkHyperTreeGrid * input)601 void vtkHyperTreeGridToDualGrid::ShiftDualCornerFromMaskedLeaf2D(
602 vtkHyperTreeGridNonOrientedMooreSuperCursor* cursor, vtkBitArray* mask, vtkHyperTreeGrid* input)
603 {
604 // With d=2:
605 // (d-0)-faces are edges, neighbor cursors are 1, 3, 5, 7
606 // (d-1)-faces are corners, neighbor cursors are 0, 2, 6, 8
607 // (d-2)-faces do not exist
608
609 // Retrieve (d-0)-neighbor (south/east/west/north) cursors
610 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorS =
611 cursor->GetOrientedGeometryCursor(1);
612 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorW =
613 cursor->GetOrientedGeometryCursor(3);
614 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorE =
615 cursor->GetOrientedGeometryCursor(5);
616 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorN =
617 cursor->GetOrientedGeometryCursor(7);
618
619 // Retrieve (d-1)-neighbor (southwest/southeast/northwest/northeast) cursors
620 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorSW =
621 cursor->GetOrientedGeometryCursor(0);
622 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorSE =
623 cursor->GetOrientedGeometryCursor(2);
624 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorNW =
625 cursor->GetOrientedGeometryCursor(6);
626 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorNE =
627 cursor->GetOrientedGeometryCursor(8);
628
629 // Retrieve global indices of non-center cursors
630
631 // Retrieve 2D axes (east-west/south-north)
632 unsigned int axisWE = input->GetOrientation() ? 0 : 1;
633 unsigned int axisSN = input->GetOrientation() == 2 ? 1 : 2;
634
635 // Retrieve current level to break corner ownership ties
636 unsigned int level = cursor->GetLevel();
637
638 // Check whether dual point across S edge must be adjusted
639 if (cursorS->HasTree() && cursorS->IsLeaf() && cursorS->GetLevel() < level)
640 {
641 vtkIdType idS = cursorS->GetGlobalNodeIndex();
642 if (!mask->GetValue(idS))
643 {
644 // Dual point must be adjusted
645 this->PointShifted[idS] = true;
646 this->PointShifts[axisSN][idS] =
647 cursorS->GetTree()->GetScale(axisSN) * this->ReductionFactors[cursorS->GetLevel()];
648 }
649 }
650
651 // Check whether dual point across W edge must be adjusted
652 if (cursorW->HasTree() && cursorW->IsLeaf() && cursorW->GetLevel() < level)
653 {
654 vtkIdType idW = cursorW->GetGlobalNodeIndex();
655 if (!mask->GetValue(idW))
656 {
657 // Dual point must be adjusted
658 this->PointShifted[idW] = true;
659 this->PointShifts[axisWE][idW] =
660 cursorW->GetTree()->GetScale(axisWE) * this->ReductionFactors[cursorW->GetLevel()];
661 }
662 }
663
664 // Check whether dual point across E face must be adjusted
665 if (cursorE->HasTree() && cursorE->IsLeaf() && cursorE->GetLevel() < level)
666 {
667 vtkIdType idE = cursorE->GetGlobalNodeIndex();
668 if (!mask->GetValue(idE))
669 {
670 // Dual point must be adjusted
671 this->PointShifted[idE] = true;
672 this->PointShifts[axisWE][idE] =
673 -cursorE->GetTree()->GetScale(axisWE) * this->ReductionFactors[cursorE->GetLevel()];
674 }
675 }
676
677 // Check whether dual point across N edge must be adjusted
678 if (cursorN->HasTree() && cursorN->IsLeaf() && cursorN->GetLevel() < level)
679 {
680 vtkIdType idN = cursorN->GetGlobalNodeIndex();
681 if (!mask->GetValue(idN))
682 {
683 // Dual point must be adjusted
684 this->PointShifted[idN] = true;
685 this->PointShifts[axisSN][idN] =
686 -cursorN->GetTree()->GetScale(axisSN) * this->ReductionFactors[cursorN->GetLevel()];
687 }
688 }
689
690 // Check whether dual point across SE corner must be adjusted
691 if (cursorSE->HasTree() && cursorSE->IsLeaf() && cursorSE->GetLevel() < level)
692 {
693 vtkIdType idSE = cursorSE->GetGlobalNodeIndex();
694 if (!mask->GetValue(idSE) && !this->PointShifted[idSE])
695 {
696 // Dual point must be adjusted
697 double shift[3];
698 cursorSE->GetTree()->GetScale(shift);
699 double factor = this->ReductionFactors[cursorSE->GetLevel()];
700 this->PointShifts[axisWE][idSE] = factor * shift[axisWE];
701 this->PointShifts[axisSN][idSE] = factor * shift[axisSN];
702 }
703 }
704
705 // Check whether dual point across SW corner must be adjusted
706 if (cursorSW->HasTree() && cursorSW->IsLeaf() && cursorSW->GetLevel() < level)
707 {
708 vtkIdType idSW = cursorSW->GetGlobalNodeIndex();
709 if (!mask->GetValue(idSW) && !this->PointShifted[idSW])
710 {
711 // Dual point must be adjusted
712 double shift[3];
713 cursorSW->GetTree()->GetScale(shift);
714 double factor = this->ReductionFactors[cursorSW->GetLevel()];
715 this->PointShifts[axisWE][idSW] = -factor * shift[axisWE];
716 this->PointShifts[axisSN][idSW] = factor * shift[axisSN];
717 }
718 }
719
720 // Check whether dual point across NW corner must be adjusted
721 if (cursorNW->HasTree() && cursorNW->IsLeaf() && cursorNW->GetLevel() < level)
722 {
723 vtkIdType idNW = cursorNW->GetGlobalNodeIndex();
724 if (!mask->GetValue(idNW) && !this->PointShifted[idNW])
725 {
726 // Dual point must be adjusted
727 double shift[3];
728 cursorNW->GetTree()->GetScale(shift);
729 double factor = this->ReductionFactors[cursorNW->GetLevel()];
730 this->PointShifts[axisWE][idNW] = factor * shift[axisWE];
731 this->PointShifts[axisSN][idNW] = -factor * shift[axisSN];
732 }
733 }
734
735 // Check whether dual point across NE corner must be adjusted
736 if (cursorNE->HasTree() && cursorNE->IsLeaf() && cursorNE->GetLevel() < level)
737 {
738 vtkIdType idNE = cursorNE->GetGlobalNodeIndex();
739 if (!mask->GetValue(idNE) && !this->PointShifted[idNE])
740 {
741 // Dual point must be adjusted
742 double shift[3];
743 cursorNE->GetTree()->GetScale(shift);
744 double factor = this->ReductionFactors[cursorNE->GetLevel()];
745 this->PointShifts[axisWE][idNE] = -factor * shift[axisWE];
746 this->PointShifts[axisSN][idNE] = -factor * shift[axisSN];
747 }
748 }
749 }
750
751 //------------------------------------------------------------------------------
ShiftDualCornerFromMaskedLeaf3D(vtkHyperTreeGridNonOrientedMooreSuperCursor * cursor,vtkBitArray * mask,vtkHyperTreeGrid * vtkNotUsed (input))752 void vtkHyperTreeGridToDualGrid::ShiftDualCornerFromMaskedLeaf3D(
753 vtkHyperTreeGridNonOrientedMooreSuperCursor* cursor, vtkBitArray* mask,
754 vtkHyperTreeGrid* vtkNotUsed(input))
755 {
756 // With d=3:
757 // (d-0)-faces are faces, neighbor cursors are 4, 10, 12, 14, 16, 22
758 // (d-1)-faces are edges, neighbor cursors are 1, 3, 5, 7, 9, 11, 15, 17, 19, 21, 23, 25
759 // (d-2)-faces are corners, neighbor cursors are 0, 2, 6, 8, 18, 20, 24, 26
760
761 // Retrieve current level to break corner ownership ties
762 unsigned int level = cursor->GetLevel();
763
764 // Check whether dual points across face neighbors must be adjusted
765 int offset = 1;
766 for (unsigned int axis = 0; axis < 3; ++axis, offset *= 3)
767 {
768 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorM =
769 cursor->GetOrientedGeometryCursor(13 - offset);
770 if (cursorM->HasTree() && cursorM->IsLeaf() && cursorM->GetLevel() < level)
771 {
772 vtkIdType idM = cursorM->GetGlobalNodeIndex();
773 if (!mask->GetValue(idM))
774 {
775 // Dual point must be adjusted
776 this->PointShifted[idM] = true;
777 this->PointShifts[axis][idM] =
778 cursorM->GetTree()->GetScale(axis) * this->ReductionFactors[cursorM->GetLevel()];
779 }
780 }
781 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorP =
782 cursor->GetOrientedGeometryCursor(13 + offset);
783 if (cursorP->HasTree() && cursorP->IsLeaf() && cursorP->GetLevel() < level)
784 {
785 vtkIdType idP = cursorP->GetGlobalNodeIndex();
786 if (!mask->GetValue(idP))
787 {
788 // Dual point must be adjusted
789 this->PointShifted[idP] = true;
790 this->PointShifts[axis][idP] =
791 -cursorP->GetTree()->GetScale(axis) * this->ReductionFactors[cursorP->GetLevel()];
792 }
793 }
794 } // axis
795
796 // Check whether dual points across edge neighbors must be adjusted
797 int i = 1;
798 for (int axis1 = 0; axis1 < 2; ++axis1, i *= 3)
799 {
800 int j = 3 * i;
801 for (int axis2 = axis1 + 1; axis2 < 3; ++axis2, j *= 3)
802 {
803 for (int o2 = -1; o2 < 2; o2 += 2)
804 {
805 for (int o1 = -1; o1 < 2; o1 += 2)
806 {
807 int index = 13 + o1 * (i * o2 + j);
808 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorE =
809 cursor->GetOrientedGeometryCursor(static_cast<unsigned int>(index));
810 if (cursorE->HasTree() && cursorE->IsLeaf() && cursorE->GetLevel() < level)
811 {
812 vtkIdType idE = cursorE->GetGlobalNodeIndex();
813 if (!mask->GetValue(idE) && !this->PointShifted[idE])
814 {
815 // Dual point must be adjusted
816 this->PointShifted[idE] = true;
817 double shift[3];
818 cursorE->GetTree()->GetScale(shift);
819 double factor = this->ReductionFactors[cursorE->GetLevel()];
820 this->PointShifts[axis1][idE] = -o1 * o2 * factor * shift[axis1];
821 this->PointShifts[axis2][idE] = -o1 * factor * shift[axis2];
822 }
823 }
824 } // o1
825 } // o2
826 } // axis2
827 } // axis1
828
829 // Check whether dual points across corner neighbors must be adjusted
830 for (int o3 = -1; o3 < 2; o3 += 2)
831 {
832 for (int o2 = -1; o2 < 2; o2 += 2)
833 {
834 offset = o2 * (o3 + 3) + 9;
835 for (int o1 = -1; o1 < 2; o1 += 2)
836 {
837 int index = 13 + o1 * offset;
838 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorC =
839 cursor->GetOrientedGeometryCursor(index);
840 if (cursorC->HasTree() && cursorC->IsLeaf() && cursorC->GetLevel() < level)
841 {
842 vtkIdType idC = cursorC->GetGlobalNodeIndex();
843 if (!mask->GetValue(idC) && !this->PointShifted[idC])
844 {
845 // Dual point must be adjusted
846 this->PointShifted[idC] = true;
847 double shift[3];
848 cursorC->GetTree()->GetScale(shift);
849 double factor = this->ReductionFactors[cursorC->GetLevel()];
850 this->PointShifts[0][idC] = -o1 * o2 * o3 * factor * shift[0];
851 this->PointShifts[1][idC] = -o1 * o2 * factor * shift[1];
852 this->PointShifts[2][idC] = -o1 * factor * shift[2];
853 }
854 }
855 } // o1
856 } // o2
857 } // o3
858 }
859
860 //------------------------------------------------------------------------------
GenerateDualCornerFromLeaf2D(vtkHyperTreeGridNonOrientedMooreSuperCursor * cursor,vtkBitArray * mask,vtkHyperTreeGrid * input)861 void vtkHyperTreeGridToDualGrid::GenerateDualCornerFromLeaf2D(
862 vtkHyperTreeGridNonOrientedMooreSuperCursor* cursor, vtkBitArray* mask, vtkHyperTreeGrid* input)
863 {
864 // With d=2:
865 // (d-0)-faces are edges, neighbor cursors are 1, 3, 5, 7
866 // (d-1)-faces are corners, neighbor cursors are 0, 2, 6, 8
867 // (d-2)-faces do not exist
868
869 const unsigned int dS = 1;
870 const unsigned int dW = 3;
871 const unsigned int dE = 5;
872 const unsigned int dN = 7;
873 const unsigned int dSW = 0;
874 const unsigned int dSE = 2;
875 const unsigned int dNW = 6;
876 const unsigned int dNE = 8;
877
878 // Retrieve 2D axes (east-west/south-north)
879 unsigned int axisWE = input->GetOrientation() ? 0 : 1;
880 unsigned int axisSN = input->GetOrientation() == 2 ? 1 : 2;
881
882 // Retrieve cursor center coordinates
883 double pt[3];
884 cursor->GetPoint(pt);
885
886 // Compute potential shifts
887 double shift[2];
888 shift[0] = .5 * cursor->GetSize()[axisWE];
889 shift[1] = .5 * cursor->GetSize()[axisSN];
890
891 // When a mask is present, edge as well as face shifts are possible
892 bool shifted = false;
893
894 // Check across edge neighbors whether point must be adjusted
895 if (!cursor->HasTree(dS))
896 {
897 // Move to south edge
898 pt[axisSN] -= shift[1];
899 shifted = true;
900 }
901 else if (cursor->IsLeaf(dS) && mask->GetValue(cursor->GetGlobalNodeIndex(dS)))
902 {
903 // Move to south edge
904 pt[axisSN] -= shift[1];
905 shifted = true;
906 }
907
908 if (!cursor->HasTree(dW))
909 {
910 // Move to west edge
911 pt[axisWE] -= shift[0];
912 shifted = true;
913 }
914 else if (cursor->IsLeaf(dW) && mask->GetValue(cursor->GetGlobalNodeIndex(dW)))
915 {
916 // Move to west edge
917 pt[axisWE] -= shift[0];
918 shifted = true;
919 }
920
921 if (!cursor->HasTree(dE))
922 {
923 // Move to east edge
924 pt[axisWE] += shift[0];
925 shifted = true;
926 }
927 else if (cursor->IsLeaf(dE) && mask->GetValue(cursor->GetGlobalNodeIndex(dE)))
928 {
929 // Move to east edge
930 pt[axisWE] += shift[0];
931 shifted = true;
932 }
933
934 if (!cursor->HasTree(dN))
935 {
936 // Move to north edge
937 pt[axisSN] += shift[1];
938 shifted = true;
939 }
940 else if (cursor->IsLeaf(dN) && mask->GetValue(cursor->GetGlobalNodeIndex(dN)))
941 {
942 // Move to north edge
943 pt[axisSN] += shift[1];
944 shifted = true;
945 }
946
947 // Only when point was not moved to edge, check corner neighbors
948 if (!shifted)
949 {
950 if (!cursor->HasTree(dSW))
951 {
952 // Move to southwest corner
953 pt[axisWE] -= shift[0];
954 pt[axisSN] -= shift[1];
955 }
956 else if (cursor->IsLeaf(dSW) && mask->GetValue(cursor->GetGlobalNodeIndex(dSW)))
957 {
958 // Move to southwest corner
959 pt[axisWE] -= shift[0];
960 pt[axisSN] -= shift[1];
961 }
962
963 if (!cursor->HasTree(dSE))
964 {
965 // Move to southeast corner
966 pt[axisWE] += shift[0];
967 pt[axisSN] -= shift[1];
968 }
969 else if (cursor->IsLeaf(dSE) && mask->GetValue(cursor->GetGlobalNodeIndex(dSE)))
970 {
971 // Move to southeast corner
972 pt[axisWE] += shift[0];
973 pt[axisSN] -= shift[1];
974 }
975
976 if (!cursor->HasTree(dNW))
977 {
978 // Move to northwest corner
979 pt[axisWE] -= shift[0];
980 pt[axisSN] += shift[1];
981 }
982 else if (cursor->IsLeaf(dNW) && mask->GetValue(cursor->GetGlobalNodeIndex(dNW)))
983 {
984 // Move to northwest corner
985 pt[axisWE] -= shift[0];
986 pt[axisSN] += shift[1];
987 }
988
989 if (!cursor->HasTree(dNE))
990 {
991 // Move to northeast corner
992 pt[axisWE] += shift[0];
993 pt[axisSN] += shift[1];
994 }
995 else if (cursor->IsLeaf(dNE) && mask->GetValue(cursor->GetGlobalNodeIndex(dNE)))
996 {
997 // Move to northeast corner
998 pt[axisWE] += shift[0];
999 pt[axisSN] += shift[1];
1000 }
1001 } // if ( ! shifted )
1002
1003 // Retrieve global index of center cursor
1004 vtkIdType id = cursor->GetGlobalNodeIndex();
1005
1006 // Insert dual point at center of leaf cell
1007 assert(id < input->GetNumberOfVertices());
1008 this->Points->SetPoint(id, pt);
1009
1010 // If cell is masked, terminate recursion, no dual cell will be generated
1011 if (mask->GetValue(id))
1012 {
1013 return;
1014 }
1015
1016 // Storage for edge vertex IDs: dual cell ownership to cursor with higher index
1017 vtkIdType ids[4];
1018 ids[0] = id;
1019
1020 // Retrieve current level to break corner ownership ties
1021 unsigned int level = cursor->GetLevel();
1022
1023 // Check whether a dual cell around SW corner exists
1024 if (cursor->HasTree(dSW) && cursor->HasTree(dS) && cursor->HasTree(dW) && cursor->IsLeaf(dSW) &&
1025 cursor->IsLeaf(dS) && cursor->IsLeaf(dW))
1026 {
1027 vtkIdType idSW, idS, idW;
1028 if (!mask->GetValue(idSW = cursor->GetGlobalNodeIndex(dSW)) &&
1029 !mask->GetValue(idS = cursor->GetGlobalNodeIndex(dS)) &&
1030 !mask->GetValue(idW = cursor->GetGlobalNodeIndex(dW)))
1031 {
1032 // If SW, S, and W neighbors are leaves, always create a face
1033 ids[1] = idW;
1034 ids[2] = idS;
1035 ids[3] = idSW;
1036 this->Connectivity->InsertNextTypedTuple(ids);
1037 }
1038 }
1039
1040 // Check whether a dual cell around SE corner exists
1041 if (cursor->HasTree(dS) && cursor->HasTree(dSE) && cursor->HasTree(dE) && cursor->IsLeaf(dS) &&
1042 cursor->IsLeaf(dSE) && cursor->IsLeaf(dE))
1043 {
1044 vtkIdType idS, idSE, idE;
1045 if (!mask->GetValue(idS = cursor->GetGlobalNodeIndex(dS)) &&
1046 !mask->GetValue(idSE = cursor->GetGlobalNodeIndex(dSE)) &&
1047 !mask->GetValue(idE = cursor->GetGlobalNodeIndex(dE)) && level != cursor->GetLevel(dE))
1048 {
1049 // If S, SE, and E neighbors are leaves, create a face if E at higher level
1050 ids[1] = idE;
1051 ids[2] = idS;
1052 ids[3] = idSE;
1053 this->Connectivity->InsertNextTypedTuple(ids);
1054 }
1055 }
1056
1057 // Check whether a dual cell around NE corner exists
1058 if (cursor->HasTree(dE) && cursor->HasTree(dNE) && cursor->HasTree(dN) && cursor->IsLeaf(dE) &&
1059 cursor->IsLeaf(dNE) && cursor->IsLeaf(dN))
1060 {
1061 vtkIdType idE, idNE, idN;
1062 if (!mask->GetValue(idE = cursor->GetGlobalNodeIndex(dE)) &&
1063 !mask->GetValue(idNE = cursor->GetGlobalNodeIndex(dNE)) &&
1064 !mask->GetValue(idN = cursor->GetGlobalNodeIndex(dN)) && level != cursor->GetLevel(dE) &&
1065 level != cursor->GetLevel(dNE) && level != cursor->GetLevel(dN))
1066 {
1067 // If E, NE, and N neighbors are leaves, create a face if E, NE, N at higher level
1068 ids[1] = idE;
1069 ids[2] = idN;
1070 ids[3] = idNE;
1071 this->Connectivity->InsertNextTypedTuple(ids);
1072 }
1073 }
1074
1075 // Check whether a dual cell around NW corner exists
1076 if (cursor->HasTree(dW) && cursor->HasTree(dN) && cursor->HasTree(dNW) && cursor->IsLeaf(dW) &&
1077 cursor->IsLeaf(dN) && cursor->IsLeaf(dNW))
1078 {
1079 vtkIdType idW, idN, idNW;
1080 if (!mask->GetValue(idW = cursor->GetGlobalNodeIndex(dW)) &&
1081 !mask->GetValue(idN = cursor->GetGlobalNodeIndex(dN)) &&
1082 !mask->GetValue(idNW = cursor->GetGlobalNodeIndex(dNW)) && level != cursor->GetLevel(dNW) &&
1083 level != cursor->GetLevel(dN))
1084 {
1085 // If W, N, and NW neighbors are leaves, create a face if NW and N at higher level
1086 ids[1] = idW;
1087 ids[2] = idN;
1088 ids[3] = idNW;
1089 this->Connectivity->InsertNextTypedTuple(ids);
1090 }
1091 }
1092 }
1093
1094 //------------------------------------------------------------------------------
GenerateDualCornerFromLeaf3D(vtkHyperTreeGridNonOrientedMooreSuperCursor * cursor,vtkBitArray * mask,vtkHyperTreeGrid * vtkNotUsed (input))1095 void vtkHyperTreeGridToDualGrid::GenerateDualCornerFromLeaf3D(
1096 vtkHyperTreeGridNonOrientedMooreSuperCursor* cursor, vtkBitArray* mask,
1097 vtkHyperTreeGrid* vtkNotUsed(input))
1098 {
1099 // With d=3:
1100 // (d-0)-faces are faces, neighbor cursors are 4, 10, 12, 14, 16, 22
1101 // (d-1)-faces are edges, neighbor cursors are 1, 3, 5, 7, 9, 11, 15, 17, 19, 21, 23, 25
1102 // (d-2)-faces are corners, neighbor cursors are 0, 2, 6, 8, 18, 20, 24, 26
1103
1104 // Retrieve cursor center coordinates
1105 double pt[3];
1106 cursor->GetPoint(pt);
1107
1108 // Compute potential shifts
1109 double shift[3];
1110 shift[0] = .5 * cursor->GetSize()[0];
1111 shift[1] = .5 * cursor->GetSize()[1];
1112 shift[2] = .5 * cursor->GetSize()[2];
1113
1114 // When a mask is present, corner, edge, and face shifts are possible
1115 bool shifted = false;
1116
1117 // Check across face neighbors whether point must be adjusted
1118 unsigned int offset = 1;
1119 for (unsigned int axis = 0; axis < 3; ++axis, offset *= 3)
1120 {
1121 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorM =
1122 cursor->GetOrientedGeometryCursor(13 - offset);
1123 if (!cursorM->HasTree())
1124 {
1125 // Move to negative side along axis
1126 pt[axis] -= shift[axis];
1127 shifted = true;
1128 }
1129 else
1130 {
1131 vtkIdType idM = cursorM->GetGlobalNodeIndex();
1132 if (cursorM->IsLeaf() && mask->GetValue(idM))
1133 {
1134 // Move to negative side along axis
1135 pt[axis] -= shift[axis];
1136 shifted = true;
1137 }
1138 }
1139 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorP =
1140 cursor->GetOrientedGeometryCursor(13 + offset);
1141 if (!cursorP->HasTree())
1142 {
1143 // Move to positive side along axis
1144 pt[axis] += shift[axis];
1145 shifted = true;
1146 }
1147 else
1148 {
1149 vtkIdType idP = cursorP->GetGlobalNodeIndex();
1150 if (cursorP->IsLeaf() && mask->GetValue(idP))
1151 {
1152 // Move to positive side along axis
1153 pt[axis] += shift[axis];
1154 shifted = true;
1155 }
1156 }
1157 } // axis
1158
1159 // Only when point was not moved to face, check edge neighbors
1160 if (!shifted)
1161 {
1162 int i = 1;
1163 for (int axis1 = 0; axis1 < 2; ++axis1, i *= 3)
1164 {
1165 int j = 3 * i;
1166 for (int axis2 = axis1 + 1; axis2 < 3; ++axis2, j *= 3)
1167 {
1168 for (int o2 = -1; o2 < 2; o2 += 2)
1169 {
1170 for (int o1 = -1; o1 < 2; o1 += 2)
1171 {
1172 int index = 13 + o1 * (i * o2 + j);
1173 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorE =
1174 cursor->GetOrientedGeometryCursor(static_cast<unsigned int>(index));
1175 if (!cursorE->HasTree())
1176 {
1177 // Move to corresponding edge
1178 pt[axis1] += o1 * o2 * shift[axis1];
1179 pt[axis2] += o1 * shift[axis2];
1180 shifted = true;
1181 }
1182 else
1183 {
1184 vtkIdType idE = cursorE->GetGlobalNodeIndex();
1185 if (cursorE->IsLeaf() && mask->GetValue(idE))
1186 {
1187 // Move to corresponding edge
1188 pt[axis1] += o1 * o2 * shift[axis1];
1189 pt[axis2] += o1 * shift[axis2];
1190 shifted = true;
1191 }
1192 }
1193 } // o1
1194 } // o2
1195 } // axis2
1196 } // axis1
1197 } // if ( ! shifted )
1198
1199 // Only when point was neither moved to face nor to edge, check corners neighbors
1200 if (!shifted)
1201 {
1202 // Iterate over all 8 corners
1203 for (int o3 = -1; o3 < 2; o3 += 2)
1204 {
1205 for (int o2 = -1; o2 < 2; o2 += 2)
1206 {
1207 offset = o2 * (o3 + 3) + 9;
1208 for (int o1 = -1; o1 < 2; o1 += 2)
1209 {
1210 int index = 13 + o1 * static_cast<int>(offset);
1211 vtkSmartPointer<vtkHyperTreeGridOrientedGeometryCursor> cursorC =
1212 cursor->GetOrientedGeometryCursor(static_cast<unsigned int>(index));
1213 if (!cursorC->HasTree())
1214 {
1215 // Move to corresponding corner
1216 pt[0] += o1 * o2 * o3 * shift[0];
1217 pt[1] += o1 * o2 * shift[1];
1218 pt[2] += o1 * shift[2];
1219 }
1220 else
1221 { // if cursor
1222 vtkIdType idC = cursorC->GetGlobalNodeIndex();
1223 if (cursorC->IsLeaf() && mask->GetValue(idC))
1224 {
1225 // Move to corresponding corner
1226 pt[0] += o1 * o2 * o3 * shift[0];
1227 pt[1] += o1 * o2 * shift[1];
1228 pt[2] += o1 * shift[2];
1229 }
1230 } // if cursor
1231 } // o1
1232 } // o2
1233 } // o3
1234 } // if ( ! shifted )
1235
1236 // Retrieve global index of center cursor
1237 vtkIdType id = cursor->GetGlobalNodeIndex();
1238
1239 // Insert dual point at center of leaf cell
1240 // assert ( id < input->GetGlobalNodeIndexMax() + 1 );
1241 this->Points->SetPoint(id, pt);
1242
1243 // Storage for edge vertex IDs: dual cell ownership to cursor with higher index
1244 vtkIdType ids[8];
1245
1246 // Retrieve current level to break corner ownership ties
1247 unsigned int level = cursor->GetLevel();
1248
1249 // Iterate over leaf corners
1250 for (unsigned int c = 0; c < 8; ++c)
1251 {
1252 // Assume center cursor leaf owns the corner
1253 bool owner = true;
1254 unsigned int real_l = 0;
1255
1256 // Iterate over every leaf touching the corner
1257 for (unsigned int l = 0; l < 8 && owner; ++l)
1258 {
1259 // Retrieve cursor index of touching leaf
1260 unsigned int index = CornerNeighborCursorsTable3D[c][l];
1261
1262 // Compute whether corner is owned by another leaf
1263 if (index != 13)
1264 {
1265 if (!cursor->HasTree(index) || !cursor->IsLeaf(index) ||
1266 (cursor->GetLevel(index) == level && index > 13))
1267 {
1268 // If neighbor leaf is out of bounds or has not been
1269 // refined to a leaf, this leaf does not own the corner
1270 // A level tie is broken in favor of the largest index
1271 owner = false;
1272 }
1273 else
1274 {
1275 vtkIdType idglobal = cursor->GetGlobalNodeIndex(index);
1276 if (!mask->GetValue(idglobal))
1277 {
1278 // Collect the leaf indices for the dual cell
1279 ids[real_l++] = cursor->GetGlobalNodeIndex(index);
1280 }
1281 else
1282 {
1283 owner = false;
1284 }
1285 }
1286 }
1287 else
1288 { // if ( index != 13 )
1289 // Collect the leaf indices for the dual cell
1290 ids[real_l++] = id;
1291 } // else
1292 } // l
1293
1294 // If leaf owns the corner, create dual cell
1295 if (owner)
1296 {
1297 if (real_l != 8)
1298 {
1299 if (real_l == 0)
1300 {
1301 continue;
1302 }
1303 vtkIdType last = ids[real_l - 1];
1304 for (; real_l < 8; ++real_l)
1305 {
1306 ids[real_l] = last;
1307 }
1308 }
1309 this->Connectivity->InsertNextTypedTuple(ids);
1310 } // if ( owner )
1311 } // c
1312 }
1313