vtkHyperOctreeDualGridContourFilter.cxx 20.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkHyperOctreeDualGridContourFilter.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkHyperOctreeDualGridContourFilter.h"
16
#include "vtkMarchingCubesTriangleCases.h"
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

#include "vtkHyperOctree.h"
#include "vtkCellArray.h"
#include "vtkCellData.h"
#include "vtkClipVolume.h"
#include "vtkExecutive.h"
#include "vtkDoubleArray.h"
#include "vtkGenericCell.h"
#include "vtkImageData.h"
#include "vtkImplicitFunction.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkIntArray.h"
#include "vtkMergePoints.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkUnsignedCharArray.h"
#include "vtkUnstructuredGrid.h"
#include "vtkHyperOctreeCursor.h"
#include "vtkVoxel.h"
#include "vtkPixel.h"
#include "vtkLine.h"
#include "vtkTetra.h"
#include "vtkPolygon.h"
#include "vtkStreamingDemandDrivenPipeline.h"
Sean McBride's avatar
Sean McBride committed
42
#include <cmath>
43
#include <cassert>
44
#include <set>
45
46
#include "vtkBitArray.h"
#include "vtkTimerLog.h"
47
#include "vtkIncrementalPointLocator.h"
48
49
50
51



//----------------------------------------------------------------------------
52
void vtkHyperOctreeDualGridContourFilter::PrintSelf(ostream& os,
53
54
55
                                                          vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
56

57
58
59
  this->ContourValues->PrintSelf(os,indent.GetNextIndent());

  if ( this->Locator )
60
  {
61
    os << indent << "Locator: " << this->Locator << "\n";
62
  }
63
  else
64
  {
65
    os << indent << "Locator: (none)\n";
66
  }
67
68
69
70
71
72
}


class vtkHyperOctreeIdSet // Pimpl idiom
{
public:
73
  std::set<vtkIdType> Set;
74
75
76
77
78
79
80
81
82
};

vtkStandardNewMacro(vtkHyperOctreeDualGridContourFilter);

//----------------------------------------------------------------------------
// Construct with user-specified implicit function; value
// set to 0.0; and generate cut scalars turned off.
vtkHyperOctreeDualGridContourFilter::vtkHyperOctreeDualGridContourFilter()
{
David E. DeMarle's avatar
David E. DeMarle committed
83
  VTK_LEGACY_BODY(vtkHyperOctree, "VTK 8.1");
84

85
  this->ContourValues = vtkContourValues::New();
86

87
  this->Locator = nullptr;
88

89
90
91
92
93
  this->SetNumberOfOutputPorts(1);

  // by default process active cell scalars
  this->SetInputArrayToProcess(0,0,0,vtkDataObject::FIELD_ASSOCIATION_POINTS,
                               vtkDataSetAttributes::SCALARS);
94

95
96
  this->Input=nullptr;
  this->Output=nullptr;
97

98
  this->NewPolys=nullptr;
99

100
101
  this->InPD=nullptr;
  this->OutPD=nullptr;
102

103
  this->InScalars=nullptr;
104

105
106
107
108
109
110
111
112
113
  // Create the table necessary to move the neighborhhood through the tree.
  this->GenerateTraversalTable();
}

//----------------------------------------------------------------------------
vtkHyperOctreeDualGridContourFilter::~vtkHyperOctreeDualGridContourFilter()
{
  this->ContourValues->Delete();
  if ( this->Locator )
114
  {
115
    this->Locator->UnRegister(this);
116
    this->Locator = nullptr;
117
  }
118
119
120
121
122
}

//----------------------------------------------------------------------------
// Overload standard modified time function. If Cut function is modified,
// then this object is modified as well.
Bill Lorensen's avatar
Bill Lorensen committed
123
vtkMTimeType vtkHyperOctreeDualGridContourFilter::GetMTime()
124
{
Bill Lorensen's avatar
Bill Lorensen committed
125
126
127
  vtkMTimeType mTime=this->Superclass::GetMTime();
  vtkMTimeType contourValuesMTime=this->ContourValues->GetMTime();
  vtkMTimeType time;
128

129
  mTime = ( contourValuesMTime > mTime ? contourValuesMTime : mTime );
130

131
  if ( this->Locator != nullptr )
132
  {
133
134
    time = this->Locator->GetMTime();
    mTime = ( time > mTime ? time : mTime );
135
  }
136
137
138
139
140
141
142
143
144
145
146
147
148
149

  return mTime;
}

//----------------------------------------------------------------------------
// This table is used to move a 3x3x3 neighborhood of cursors through the tree.
void vtkHyperOctreeDualGridContourFilter::GenerateTraversalTable()
{
  int xChild, yChild, zChild;
  int xCursor, yCursor, zCursor;
  int xNeighbor, yNeighbor, zNeighbor;
  int xNewCursor, yNewCursor, zNewCursor;
  int xNewChild, yNewChild, zNewChild;
  int cursor, child, newCursor, newChild;
150

151
  for (zChild = 0; zChild < 2; ++zChild)
152
  {
153
    for (yChild = 0; yChild < 2; ++yChild)
154
    {
155
      for (xChild = 0; xChild < 2; ++xChild)
156
      {
157
        for (zCursor = 0; zCursor < 2; ++zCursor)
158
        {
159
          for (yCursor = 0; yCursor < 2; ++yCursor)
160
          {
161
            for (xCursor = 0; xCursor < 2; ++xCursor)
162
            {
163
              // Compute the x, y, z index into the
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
              // 4x4x4 neighborhood of children.
              xNeighbor = xCursor + xChild;
              yNeighbor = yCursor + yChild;
              zNeighbor = zCursor + zChild;
              // Separate neighbor index into Cursor/Child index.
              xNewCursor = xNeighbor / 2;
              yNewCursor = yNeighbor / 2;
              zNewCursor = zNeighbor / 2;
              xNewChild = xNeighbor - xNewCursor*2;
              yNewChild = yNeighbor - yNewCursor*2;
              zNewChild = zNeighbor - zNewCursor*2;
              // Cursor and traversal child are for index into table.
              cursor = xCursor + 2*yCursor + 4*zCursor;
              child = xChild + 2*yChild + 4*zChild;
              // New cursor and new child are for the value of the table.
              newCursor = xNewCursor + 2*yNewCursor + 4*zNewCursor;
              newChild = xNewChild + 2*yNewChild + 4*zNewChild;
181
182
              this->NeighborhoodTraversalTable[8*child + cursor]
                      = newChild+ 8*newCursor;
183
184
185
186
187
            }
          }
        }
      }
    }
188
  }
189
190
191
192
193
194
195
196
197
198
199
200
201
202
}

//----------------------------------------------------------------------------
// The purpose of traversing the neighborhood / cells is to visit
// every point and have the cells connected to that point.
void vtkHyperOctreeDualGridContourFilter::TraverseNeighborhoodRecursively(
  vtkHyperOctreeLightWeightCursor* neighborhood,
  unsigned short *xyzIds)
{
  int divide = 0;
  unsigned char childrenToTraverse[8];
  memset(childrenToTraverse,0,8);

  if ( ! neighborhood[0].GetIsLeaf())
203
  { // Main cursor is a node.  Traverse all children.
204
    divide = 1;
205
206
207
    childrenToTraverse[0] = childrenToTraverse[1]
       = childrenToTraverse[2] = childrenToTraverse[3]
       = childrenToTraverse[4] = childrenToTraverse[5]
208
       = childrenToTraverse[6] = childrenToTraverse[7] = 1;
209
  }
210
  else
211
  {
212
    if (! neighborhood[1].GetIsLeaf() )
213
    { // x face
214
215
216
      divide = 1;
      childrenToTraverse[1] = childrenToTraverse[3]
         = childrenToTraverse[5] = childrenToTraverse[7] = 1;
217
    }
218
    if (! neighborhood[2].GetIsLeaf() )
219
    { // y face
220
221
222
      divide = 1;
      childrenToTraverse[2] = childrenToTraverse[3]
         = childrenToTraverse[6] = childrenToTraverse[7] = 1;
223
    }
224
    if (! neighborhood[4].GetIsLeaf() )
225
    { // z face
226
227
228
      divide = 1;
      childrenToTraverse[4] = childrenToTraverse[5]
         = childrenToTraverse[6] = childrenToTraverse[7] = 1;
229
    }
230
    if (! neighborhood[3].GetIsLeaf() )
231
    { // xy edge
232
233
      divide = 1;
      childrenToTraverse[3] = childrenToTraverse[7] = 1;
234
    }
235
    if (! neighborhood[5].GetIsLeaf() )
236
    { // xz edge
237
238
      divide = 1;
      childrenToTraverse[5] = childrenToTraverse[7] = 1;
239
    }
240
    if (! neighborhood[6].GetIsLeaf() )
241
    { // xz edge
242
243
      divide = 1;
      childrenToTraverse[6] = childrenToTraverse[7] = 1;
244
    }
245
    if (! neighborhood[7].GetIsLeaf() )
246
    { // xyz corner
247
248
249
      divide = 1;
      childrenToTraverse[7] = 1;
    }
250
  }
251

252
  if (divide)
253
  {
254
255
256
257
258
259
260
    int child;
    int neighbor;
    unsigned char tChild, tParent;
    unsigned char* traversalTable = this->NeighborhoodTraversalTable;
    vtkHyperOctreeLightWeightCursor newNeighborhood[8];
    // Storing 4 per neighbor for efficiency.
    // This might also be useful for 4d trees :)
261
262
    unsigned short newXYZIds[32];
    for (child = 0; child < 8; ++child)
263
    {
264
      if (childrenToTraverse[child])
265
      {
266
267
268
269
        unsigned short *inId;
        unsigned short *outId = newXYZIds;
        // Move each neighbor down to a child.
        for (neighbor = 0; neighbor < 8; ++neighbor)
270
        {
271
272
273
274
          tChild = (*traversalTable) & 7;
          tParent = ((*traversalTable) & 248)>>3;
          inId = xyzIds+(tParent<<2); // Faster to multiply by 4 than 3.
          if (neighborhood[tParent].GetIsLeaf())
275
          { // Parent is a leaf or this is an empty node.
276
277
            // We can't traverse anymore.
            // equal operator should work for this class.
278
            newNeighborhood[neighbor] = neighborhood[tParent];
279
280
281
282
            *outId++ = *inId++;
            *outId++ = *inId++;
            *outId++ = *inId++;
            // We need an extra increment to skip over unused 4th id.
283
            ++outId;
284
          }
285
          else
286
          { // Move to child.
287
            // equal operator should work for this class.
288
            newNeighborhood[neighbor] = neighborhood[tParent];
289
290
291
292
293
294
295
            newNeighborhood[neighbor].ToChild(tChild);
            // Multiply parent index by two for new level.
            // Increment by 1 if child requires.
            *outId++ = (*inId++ << 1) | (tChild&1);
            *outId++ = (*inId++ << 1) | ((tChild>>1)&1);
            *outId++ = (*inId++ << 1) | ((tChild>>2)&1);
            // We need an extra increment to skip over unused 4th id.
296
            ++outId;
297
          }
298
          ++traversalTable;
299
        }
300
301
        this->TraverseNeighborhoodRecursively(newNeighborhood, newXYZIds);
      }
302
      else
303
      {
304
305
306
        traversalTable += 8;
      }
    }
307
308
    return;
  }
309
310
311

  // All neighbors must be leaves.

312
313
314
315
  // If we are not on the border, create the cell
  // associated with the center point of the neighborhood.
  this->EvaluatePoint(neighborhood, xyzIds);
}
316

317
//----------------------------------------------------------------------------
Kunda's avatar
Kunda committed
318
// Contour the cell associated with the center point.
319
320
321
322
323
// if it has not already been contoured.
void vtkHyperOctreeDualGridContourFilter::EvaluatePoint(
  vtkHyperOctreeLightWeightCursor* neighborhood,
  unsigned short* xyzIds)
{
324
  // If any neighbor is nullptr, then we are on the border.
325
  // Do nothing if we are on a border.
326
  // We know that neighbor 0 is never nullptr.
327
328
329
330
  if (!neighborhood[1].GetTree() ||
      !neighborhood[2].GetTree() || !neighborhood[3].GetTree() ||
      !neighborhood[4].GetTree() || !neighborhood[5].GetTree() ||
      !neighborhood[6].GetTree() || !neighborhood[7].GetTree())
331
  {
332
    return;
333
  }
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348

  static int edges[12][2] = { {0,1}, {1,2}, {2,3}, {0,3},
                              {4,5}, {5,6}, {6,7}, {4,7},
                              {0,4}, {1,5}, {3,7}, {2,6}};

  static int CASE_MASK[8] = {1,2,4,8,16,32,64,128};
  int vertMap[8];
  // !!!! Notice the translation from Voxel ids to Hex ids.
  vertMap[0] = neighborhood[0].GetLeafIndex();
  vertMap[1] = neighborhood[1].GetLeafIndex();
  vertMap[2] = neighborhood[3].GetLeafIndex();
  vertMap[3] = neighborhood[2].GetLeafIndex();
  vertMap[4] = neighborhood[4].GetLeafIndex();
  vertMap[5] = neighborhood[5].GetLeafIndex();
  vertMap[6] = neighborhood[7].GetLeafIndex();
349
  vertMap[7] = neighborhood[6].GetLeafIndex();
350
351
352
  // We need a map to permute the point ids from voxel to hex.
  // Note: Permutation is its own inverse.  Makes life easy.
  static int HEX_VOX_PERMUTATION[8] = {0,1,3,2,4,5,7,6};
353

354
355
356
  double points[8][3];
  double scalars[8];
  double levelDim;
357
  for (int iter = 0; iter < 8; ++iter)
358
  {
359
360
    // Note: we have to extent points on boundary of tree !!!
    scalars[iter] = this->InScalars->GetComponent(vertMap[iter],0);
361
    levelDim = static_cast<double>(1<<neighborhood[iter].GetLevel());
362
    points[HEX_VOX_PERMUTATION[iter]][0]
363
364
       = this->Origin[0] +
      (static_cast<double>(*xyzIds++)+0.5)*(this->Size[0])/levelDim;
365
    points[HEX_VOX_PERMUTATION[iter]][1]
366
367
       = this->Origin[1] +
      (static_cast<double>(*xyzIds++)+0.5)*(this->Size[1])/levelDim;
368
    points[HEX_VOX_PERMUTATION[iter]][2]
369
370
       = this->Origin[2] +
      (static_cast<double>(*xyzIds++)+0.5)*(this->Size[2])/levelDim;
371
372
    // We need to skip over unused 4th id.
    ++xyzIds;
373
  }
374
375

  int numContours=this->ContourValues->GetNumberOfContours();
376
  for (int iter = 0; iter < numContours; ++iter)
377
  {
378
379
380
381
382
383
384
385
386
387
    double value = this->ContourValues->GetValue(iter);

    // The cell contour method had two problems:
    // You could not switch cell and point data easily,
    // and you had to copy the scalars and points.
    //this->Voxel->Contour(value, this->VoxelScalars, this->Locator,
    //                     this->NewVerts,this->NewLines,this->NewPolys,
    //                     this->InPD, this->OutPD, this->InPD,
    //                     this->InCellCount, this->OutCD);
    // Contour the voxel our self.
Sven Buijssen's avatar
Sven Buijssen committed
388
    // Some voxels will be degenerated with points shared between corners.
389
    // Appropriate faces will always line up.
390
391
392
393
394
395
396
397
398
399
    vtkMarchingCubesTriangleCases *triCase;
    EDGE_LIST  *edge;
    int i, j, index, *vert;
    vtkIdType pts[3];
    double t, x[3];
    double *x1;
    double *x2;

    // Build the case table
    for ( i=0, index = 0; i < 8; i++)
400
    {
401
      if (scalars[i] >= value)
402
      {
403
404
        index |= CASE_MASK[i];
      }
405
    }
406

407
408
409
410
    triCase = vtkMarchingCubesTriangleCases::GetCases() + index;
    edge = triCase->edges;

    for ( ; edge[0] > -1; edge += 3 )
411
    {
412
      for (i=0; i<3; i++) // insert triangle
413
      {
414
415
416
417
418
        vert = edges[edge[i]];
        t = (value - scalars[vert[0]]) / (scalars[vert[1]] - scalars[vert[0]]);
        x1 = (points[vert[0]]);
        x2 = (points[vert[1]]);
        for (j=0; j<3; j++)
419
        {
420
          x[j] = x1[j] + t * (x2[j] - x1[j]);
421
        }
422
        if ( this->Locator->InsertUniquePoint(x, pts[i]) )
423
        {
424
425
426
427
          int p1 = vertMap[vert[0]];
          int p2 = vertMap[vert[1]];
          this->OutPD->InterpolateEdge(this->InPD,pts[i],p1,p2,t);
        }
428
      }
429
430
431
432
      // check for degenerate triangle
      if ( pts[0] != pts[1] &&
           pts[0] != pts[2] &&
           pts[1] != pts[2] )
433
      {
Charles Law's avatar
Charles Law committed
434
        this->NewPolys->InsertNextCell(3,pts);
435
436
437
438
        // We have no point data in the octree that would convert to cell data.
        //outCd->CopyData(inCd,cellId,newCellId);
      }
    }
439
  }
440
441

  // We have passed all the tests, generate the dual cell.
442
443
444
445
446
447
448
449
450
451
452
453
454
455
  /*
  vtkIdType ptIds[2];
  ptIds[0] = neighborhood[c000].GetLeafIndex();
  ptIds[1] = neighborhood[c001].GetLeafIndex();
  lines->InsertNextCell(2, ptIds);
  ptIds[0] = neighborhood[c010].GetLeafIndex();
  ptIds[1] = neighborhood[c011].GetLeafIndex();
  lines->InsertNextCell(2, ptIds);
  ptIds[0] = neighborhood[c100].GetLeafIndex();
  ptIds[1] = neighborhood[c101].GetLeafIndex();
  lines->InsertNextCell(2, ptIds);
  ptIds[0] = neighborhood[c110].GetLeafIndex();
  ptIds[1] = neighborhood[c111].GetLeafIndex();
  lines->InsertNextCell(2, ptIds);
456

457
458
459
460
461
462
463
464
465
466
467
468
  ptIds[0] = neighborhood[c000].GetLeafIndex();
  ptIds[1] = neighborhood[c010].GetLeafIndex();
  lines->InsertNextCell(2, ptIds);
  ptIds[0] = neighborhood[c001].GetLeafIndex();
  ptIds[1] = neighborhood[c011].GetLeafIndex();
  lines->InsertNextCell(2, ptIds);
  ptIds[0] = neighborhood[c100].GetLeafIndex();
  ptIds[1] = neighborhood[c110].GetLeafIndex();
  lines->InsertNextCell(2, ptIds);
  ptIds[0] = neighborhood[c101].GetLeafIndex();
  ptIds[1] = neighborhood[c111].GetLeafIndex();
  lines->InsertNextCell(2, ptIds);
469

470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
  ptIds[0] = neighborhood[c000].GetLeafIndex();
  ptIds[1] = neighborhood[c100].GetLeafIndex();
  lines->InsertNextCell(2, ptIds);
  ptIds[0] = neighborhood[c001].GetLeafIndex();
  ptIds[1] = neighborhood[c101].GetLeafIndex();
  lines->InsertNextCell(2, ptIds);
  ptIds[0] = neighborhood[c010].GetLeafIndex();
  ptIds[1] = neighborhood[c110].GetLeafIndex();
  lines->InsertNextCell(2, ptIds);
  ptIds[0] = neighborhood[c011].GetLeafIndex();
  ptIds[1] = neighborhood[c111].GetLeafIndex();
  lines->InsertNextCell(2, ptIds);
  */
}


//----------------------------------------------------------------------------
//
// Cut through data generating surface.
//
int vtkHyperOctreeDualGridContourFilter::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  // get the info objects
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);
498

499
500
501
  // get the input
  this->Input = vtkHyperOctree::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
502

503
  if(this->Input->GetNumberOfLevels()==1)
504
  {
505
506
    // just the root. There is absolutely no chance
    // to get an isosurface here.
507
    this->Input=nullptr;
508
    return 1;
509
  }
510

511
  if (this->Input->GetDimension() != 3)
512
  {
513
514
    vtkErrorMacro("This class only handles 3d Octree's");
    return 1;
515
  }
516

517
  this->InScalars=this->GetInputArrayToProcess(0,inputVector);
518
  if(this->InScalars==nullptr)
519
  {
520
    vtkDebugMacro(<<"No data to contour");
521
    this->Input=nullptr;
522
    return 1;
523
  }
524

525
526
  int numContours=this->ContourValues->GetNumberOfContours();
  if(numContours==0)
527
  {
528
    vtkDebugMacro(<<"No contour");
529
    this->Input=nullptr;
530
    return 1;
531
  }
532

533
  double *values=this->ContourValues->GetValues();
534

535
536
  // If all the contour values are out of the range of the input scalar
  // there is no chance to get a contour, just exit.
537

538
539
540
541
542
  double range[2];
  this->InScalars->GetRange(range);
  int i=0;
  int allOut=1;
  while(allOut && i<numContours)
543
  {
544
545
    allOut=(values[i]<range[0]) || (values[i]>range[1]);
    ++i;
546
  }
547
  if(allOut)
548
  {
549
    // empty output
550
    this->Input=nullptr;
551
    return 1;
552
  }
553

554
555
556
557
  this->Output=vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));
  this->Input->GetOrigin(this->Origin);
  this->Input->GetSize(this->Size);
558

559
560
  // Assumes that the DataSet API returns dual.
  vtkIdType numLeaves = this->Input->GetNumberOfPoints();
561
562
  //cout << numLeaves << " leaves\n";

563
  vtkIdType estimatedSize = numLeaves / 2;
564

565
566
  vtkPoints *newPoints = vtkPoints::New();
  newPoints->Allocate(estimatedSize,estimatedSize/2);
567

568
569
  this->NewPolys = vtkCellArray::New();
  this->NewPolys->Allocate(estimatedSize,estimatedSize/2);
570

571
  // locator used to merge potentially duplicate points
572
  if ( this->Locator == nullptr )
573
  {
574
    this->CreateDefaultLocator();
575
  }
576

577
578
  this->Locator->InitPointInsertion (newPoints, this->Input->GetBounds());

579
580
  this->InPD=this->Input->GetLeafData();
  this->OutPD=this->Output->GetPointData();
581
  this->OutPD->CopyAllocate(this->InPD,estimatedSize,estimatedSize/2);
582
583
584
585
586
587
588
589
590
591
592
593
594
595

  // Create an array of cursors that occupy 1 2x2x2 neighborhhod.  This
  // will traverse the tree as one.
  vtkHyperOctreeLightWeightCursor neighborhood[8];
  neighborhood[0].Initialize(this->Input);
  // Index of node in uniform grid (x,y,z) for each neighbor.
  // Storing 4 indexes per neighbor for efficiency.
  // Could also be useful for 4d trees :)
  unsigned short xyzId[32];
  memset(xyzId,0,32*sizeof(unsigned short));
  this->TraverseNeighborhoodRecursively(neighborhood, xyzId);

  this->Output->SetPolys(this->NewPolys);
  this->NewPolys->Delete();
596
  this->NewPolys = nullptr;
597
598
599
  // Points were added by the locator.
  this->Output->SetPoints(newPoints);
  newPoints->Delete();
600
  newPoints = nullptr;
601
602

  return 1;
603
604
605
606
607
}



//----------------------------------------------------------------------------
608
// Specify a spatial locator for merging points. By default,
609
// an instance of vtkMergePoints is used.
610
void vtkHyperOctreeDualGridContourFilter::SetLocator(vtkIncrementalPointLocator *locator)
611
612
{
  if ( this->Locator == locator)
613
  {
614
    return;
615
  }
616

617
  if ( this->Locator )
618
  {
619
    this->Locator->UnRegister(this);
620
    this->Locator = nullptr;
621
  }
622
623

  if ( locator )
624
  {
625
    locator->Register(this);
626
  }
627
628
629
630
631
632
633
634

  this->Locator = locator;
  this->Modified();
}

//----------------------------------------------------------------------------
void vtkHyperOctreeDualGridContourFilter::CreateDefaultLocator()
{
635
  if ( this->Locator == nullptr )
636
  {
637
638
639
    this->Locator = vtkMergePoints::New();
    this->Locator->Register(this);
    this->Locator->Delete();
640
  }
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
}

//----------------------------------------------------------------------------
int vtkHyperOctreeDualGridContourFilter::RequestUpdateExtent(
  vtkInformation *,
  vtkInformationVector **inputVector,
  vtkInformationVector *)
{
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  inInfo->Set(vtkStreamingDemandDrivenPipeline::EXACT_EXTENT(), 1);
  return 1;
}

//----------------------------------------------------------------------------
int vtkHyperOctreeDualGridContourFilter::FillInputPortInformation(int,
                                                          vtkInformation *info)
{
  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkHyperOctree");
  return 1;
}