1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkHyperTreeGridAxisCut.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 "vtkHyperTreeGridAxisCut.h"
16 
17 #include "vtkBitArray.h"
18 #include "vtkCellData.h"
19 #include "vtkDataSetAttributes.h"
20 #include "vtkDoubleArray.h"
21 #include "vtkHyperTree.h"
22 #include "vtkHyperTreeCursor.h"
23 #include "vtkHyperTreeGrid.h"
24 #include "vtkHyperTreeGridCursor.h"
25 #include "vtkIdTypeArray.h"
26 #include "vtkInformation.h"
27 #include "vtkInformationVector.h"
28 #include "vtkObjectFactory.h"
29 #include "vtkNew.h"
30 #include "vtkPointData.h"
31 
32 vtkStandardNewMacro(vtkHyperTreeGridAxisCut);
33 
34 //-----------------------------------------------------------------------------
vtkHyperTreeGridAxisCut()35 vtkHyperTreeGridAxisCut::vtkHyperTreeGridAxisCut()
36 {
37   // Default normal axis is Z
38   this->PlaneNormalAxis = 0;
39 
40   // Default place intercept is 0
41   this->PlanePosition = 0.;
42 
43   // Default mask is empty
44   this->MaterialMask = nullptr;
45 
46   // Output indices begin at 0
47   this->CurrentId = 0;
48 }
49 
50 //-----------------------------------------------------------------------------
~vtkHyperTreeGridAxisCut()51 vtkHyperTreeGridAxisCut::~vtkHyperTreeGridAxisCut()
52 {
53   if( this->MaterialMask )
54   {
55     this->MaterialMask->Delete();
56     this->MaterialMask = nullptr;
57   }
58 }
59 
60 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)61 void vtkHyperTreeGridAxisCut::PrintSelf( ostream& os, vtkIndent indent )
62 {
63   this->Superclass::PrintSelf( os, indent );
64 
65   os << indent << "PlaneNormalAxis : " << this->PlaneNormalAxis << endl;
66   os << indent << "PlanePosition : " << this->PlanePosition << endl;
67   os << indent << "MaterialMask: " << this->MaterialMask << endl;
68   os << indent << "CurrentId: " << this->CurrentId << endl;
69 }
70 
71 //-----------------------------------------------------------------------------
FillOutputPortInformation(int,vtkInformation * info)72 int vtkHyperTreeGridAxisCut::FillOutputPortInformation( int, vtkInformation *info )
73 {
74   info->Set( vtkDataObject::DATA_TYPE_NAME(), "vtkHyperTreeGrid" );
75   return 1;
76 }
77 
78 //-----------------------------------------------------------------------------
ProcessTrees(vtkHyperTreeGrid * input,vtkDataObject * outputDO)79 int vtkHyperTreeGridAxisCut::ProcessTrees( vtkHyperTreeGrid* input,
80                                            vtkDataObject* outputDO )
81 {
82   // Skip empty trees
83   if (input->GetNumberOfLeaves() == 0)
84   {
85     return 1;
86   }
87 
88   // Downcast output data object to hyper tree grid
89   vtkHyperTreeGrid* output = vtkHyperTreeGrid::SafeDownCast( outputDO );
90   if ( ! output )
91   {
92     vtkErrorMacro( "Incorrect type of output: "
93                    << outputDO->GetClassName() );
94     return 0;
95   }
96 
97   // This filter works only with 3D grids
98   if ( input->GetDimension() != 3 )
99   {
100     vtkErrorMacro (<< "Bad input dimension:"
101                    << input->GetDimension());
102     return 0;
103   }
104   output->SetDimension( 2 );
105 
106   // Retrieve normal axis and intercept of cut plane
107   int axis = this->PlaneNormalAxis;
108   double inter = this->PlanePosition;
109 
110   // Set output orientation
111   output->SetOrientation( axis );
112 
113   // Set output grid sizes; must be 1 in the direction of cut plane normal
114   unsigned int size[3];
115   input->GetGridSize( size );
116   size[axis] = 1;
117   output->SetGridSize( size );
118 
119   // Duplicate coordinates along plane axes; set to zeros along normal
120   vtkNew<vtkDoubleArray> zeros;
121   zeros->SetNumberOfValues( 2 );
122   zeros->SetValue( 0, inter );
123   zeros->SetValue( 1, inter );
124   switch ( axis )
125   {
126     case 0:
127       // Cut along yz-plane
128       output->SetXCoordinates( zeros );
129       output->SetYCoordinates( input->GetYCoordinates() );
130       output->SetZCoordinates( input->GetZCoordinates());
131       break;
132     case 1:
133       // Cut along xz-plane
134       output->SetXCoordinates( input->GetXCoordinates() );
135       output->SetYCoordinates( zeros );
136       output->SetZCoordinates( input->GetZCoordinates());
137       break;
138     case 2:
139       // Cut along xz-plane
140       output->SetXCoordinates( input->GetXCoordinates() );
141       output->SetYCoordinates( input->GetYCoordinates() );
142       output->SetZCoordinates( zeros );
143       break;
144     default:
145       return 0;
146   }
147 
148   // Other grid parameters are identical
149   output->SetTransposedRootIndexing( input->GetTransposedRootIndexing() );
150   output->SetBranchFactor( input->GetBranchFactor() );
151   output->SetHasInterface( input->GetHasInterface() );
152   output->SetInterfaceNormalsName( input->GetInterfaceNormalsName() );
153   output->SetInterfaceInterceptsName( input->GetInterfaceInterceptsName() );
154 
155   // Initialize output point data
156   this->InData = input->GetPointData();
157   this->OutData = output->GetPointData();
158   this->OutData->CopyAllocate( this->InData );
159 
160   // Output indices begin at 0
161   this->CurrentId = 0;
162 
163   // Create material mask bit array if one is present on input
164   if( input->HasMaterialMask() )
165   {
166     this->MaterialMask = vtkBitArray::New();
167   }
168 
169   // Retrieve material mask
170   vtkBitArray* mask
171     = this->MaterialMask ? input->GetMaterialMask() : nullptr;
172 
173   // Storage for root cell Cartesian coordinates
174   unsigned int i,j,k;
175 
176   // Storage for material mask indices computed together with output grid
177   vtkNew<vtkIdTypeArray> position;
178 
179   // Iterate over all input hyper trees
180   vtkIdType inIndex;
181   vtkIdType outIndex = 0;
182   vtkHyperTreeGrid::vtkHyperTreeGridIterator it;
183   input->InitializeTreeIterator( it );
184   while ( it.GetNextTree( inIndex ) )
185   {
186     // Initialize new geometric cursor at root of current input tree
187     vtkHyperTreeGridCursor* inCursor = input->NewGeometricCursor( inIndex );
188 
189     // Retrieve geometric features of input cursor
190     double* origin = inCursor->GetOrigin();
191     double* _size = inCursor->GetSize();
192 
193     // Check whether root cell is intersected by plane
194     if ( origin[axis] <= inter && ( origin[axis] + _size[axis] >= inter ) )
195     {
196       // Root is intersected by plane, descend into current child
197       input->GetLevelZeroCoordinatesFromIndex( inIndex, i, j, k );
198 
199       // Get root index into output hyper tree grid, depending on cut axes
200       switch ( axis )
201       {
202         case 0:
203           output->GetIndexFromLevelZeroCoordinates( outIndex, 0, j, k );
204           break;
205         case 1:
206           output->GetIndexFromLevelZeroCoordinates( outIndex, i, 0, k );
207           break;
208         case 2:
209           output->GetIndexFromLevelZeroCoordinates( outIndex, i, j, 0);
210           break;
211         default:
212           vtkErrorMacro( "Incorrect orientation of output: "
213                          << axis );
214           return 0;
215       } // switch ( axis )
216 
217       // Initialize new cursor at root of current output tree
218       vtkHyperTreeCursor* outCursor = output->NewCursor( outIndex, true );
219       outCursor->ToRoot();
220 
221       // Cut tree recursively
222       this->RecursivelyProcessTree( inCursor, outCursor, mask );
223 
224       // Store current output index then increment it
225       position->InsertNextValue( outIndex );
226       ++ outIndex;
227 
228       // Clean up
229       outCursor->Delete();
230     } // if origin
231 
232     // Clean up
233     inCursor->Delete();
234   } // it
235 
236   // Set material mask index
237   output->SetMaterialMaskIndex( position );
238 
239   // Squeeze and set output material mask if necessary
240   if( this->MaterialMask )
241   {
242     this->MaterialMask->Squeeze();
243     output->SetMaterialMask( this->MaterialMask );
244   }
245 
246   return 1;
247 }
248 
249 //----------------------------------------------------------------------------
RecursivelyProcessTree(vtkHyperTreeGridCursor * inCursor,vtkHyperTreeCursor * outCursor,vtkBitArray * mask)250 void vtkHyperTreeGridAxisCut::RecursivelyProcessTree( vtkHyperTreeGridCursor* inCursor,
251                                                       vtkHyperTreeCursor* outCursor,
252                                                       vtkBitArray* mask )
253 {
254   // Retrieve input grid
255   vtkHyperTreeGrid* input = inCursor->GetGrid();
256 
257   // Retrieve global index of input cursor
258   vtkIdType inId = inCursor->GetGlobalNodeIndex();
259 
260   // Increase index count on output: postfix is intended
261   vtkIdType outId = this->CurrentId ++;
262 
263   // Retrieve output tree and set global index of output cursor
264   vtkHyperTree* outTree = outCursor->GetTree();
265   outTree->SetGlobalIndexFromLocal( outCursor->GetVertexId(), outId );
266 
267   // Update material mask if relevant
268   if( mask )
269   {
270     this->MaterialMask->InsertValue( outId, mask->GetValue( inId )  );
271   }
272 
273   // Copy output cell data from that of input cell
274   this->OutData->CopyData( this->InData, inId, outId );
275 
276   // Descend further into input trees only if cursor is not at leaf
277   if ( ! inCursor->IsLeaf() )
278   {
279     // Cursor is not at leaf, subdivide output tree one level further
280     outTree->SubdivideLeaf( outCursor );
281 
282     // Initialize output children index
283     int outChild = 0;
284 
285     // If cursor is not at leaf, recurse to all children
286     int numChildren = input->GetNumberOfChildren();
287     for ( int inChild = 0; inChild < numChildren; ++ inChild )
288     {
289       // Create child cursor from parent
290       vtkHyperTreeGridCursor* childCursor = inCursor->Clone();
291       childCursor->ToChild( inChild );
292 
293       // Retrieve normal axis and intercept of plane
294       int axis = this->PlaneNormalAxis;
295       double inter = this->PlanePosition;
296 
297       // Retrieve geometric features of input cursor
298       double* origin = childCursor->GetOrigin();
299       double* size = childCursor->GetSize();
300 
301       // Check whether child is intersected by plane
302       if ( origin[axis] <= inter && ( origin[axis] + size[axis] > inter ) )
303       {
304         // Child is intersected by plane, descend into current child
305         outCursor->ToChild( outChild );
306 
307         // Recurse
308         this->RecursivelyProcessTree( childCursor, outCursor, mask );
309 
310         // Return to parent
311         outCursor->ToParent();
312 
313         // Increment output children count
314         ++ outChild;
315       }
316 
317       // Clean up
318       childCursor->Delete();
319       childCursor = nullptr;
320     } // inChild
321   } // if ( ! cursor->IsLeaf() )
322 }
323