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