1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkImageAppend.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 "vtkImageAppend.h"
16
17 #include "vtkAlgorithmOutput.h"
18 #include "vtkCellData.h"
19 #include "vtkDataArray.h"
20 #include "vtkImageData.h"
21 #include "vtkInformation.h"
22 #include "vtkInformationVector.h"
23 #include "vtkObjectFactory.h"
24 #include "vtkPointData.h"
25 #include "vtkStreamingDemandDrivenPipeline.h"
26
27
28 vtkStandardNewMacro(vtkImageAppend);
29
30 //----------------------------------------------------------------------------
vtkImageAppend()31 vtkImageAppend::vtkImageAppend()
32 {
33 this->AppendAxis = 0;
34 this->Shifts = nullptr;
35 this->PreserveExtents = 0;
36 }
37
38 //----------------------------------------------------------------------------
~vtkImageAppend()39 vtkImageAppend::~vtkImageAppend()
40 {
41 delete [] this->Shifts;
42 }
43
44 //----------------------------------------------------------------------------
ReplaceNthInputConnection(int idx,vtkAlgorithmOutput * input)45 void vtkImageAppend::ReplaceNthInputConnection(int idx,
46 vtkAlgorithmOutput *input)
47 {
48 if (idx < 0 || idx >= this->GetNumberOfInputConnections(0))
49 {
50 vtkErrorMacro("Attempt to replace connection idx " << idx
51 << " of input port " << 0 << ", which has only "
52 << this->GetNumberOfInputConnections(0)
53 << " connections.");
54 return;
55 }
56
57 if (!input || !input->GetProducer())
58 {
59 vtkErrorMacro("Attempt to replace connection index " << idx
60 << " for input port " << 0 << " with " <<
61 (!input ? "a null input." : "an input with no producer."));
62 return;
63 }
64
65 this->SetNthInputConnection(0, idx, input);
66 }
67
68 //----------------------------------------------------------------------------
69 // The default vtkImageAlgorithm semantics are that SetInput() puts
70 // each input on a different port, we want all the image inputs to
71 // go on the first port.
SetInputData(int idx,vtkDataObject * input)72 void vtkImageAppend::SetInputData(int idx, vtkDataObject *input)
73 {
74 this->SetInputDataInternal(idx, input);
75 }
76
77 //----------------------------------------------------------------------------
GetInput(int idx)78 vtkDataObject *vtkImageAppend::GetInput(int idx)
79 {
80 if (this->GetNumberOfInputConnections(0) <= idx)
81 {
82 return nullptr;
83 }
84 return vtkImageData::SafeDownCast(
85 this->GetExecutive()->GetInputData(0, idx));
86 }
87
88 //----------------------------------------------------------------------------
89 // This method tells the output it will have more components
RequestInformation(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * outputVector)90 int vtkImageAppend::RequestInformation (
91 vtkInformation * vtkNotUsed(request),
92 vtkInformationVector **inputVector,
93 vtkInformationVector *outputVector)
94 {
95 // get the info objects
96 vtkInformation* outInfo = outputVector->GetInformationObject(0);
97 vtkInformation *inInfo;
98
99 int idx;
100 int min, max, size, tmp;
101 int *inExt, outExt[6];
102 int unionExt[6];
103
104 // Initialize the union.
105 unionExt[0] = unionExt[2] = unionExt[4] = VTK_INT_MAX;
106 unionExt[1] = unionExt[3] = unionExt[5] = -VTK_INT_MAX;
107
108 // Initialize the shifts.
109 delete [] this->Shifts;
110 this->Shifts = new int [this->GetNumberOfInputConnections(0)];
111
112 // Find the outMin/max of the appended axis for this input.
113 inInfo = inputVector[0]->GetInformationObject(0);
114 inExt = inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT());
115 min = tmp = inExt[this->AppendAxis * 2];
116 for (idx = 0; idx < this->GetNumberOfInputConnections(0); ++idx)
117 {
118 inInfo = inputVector[0]->GetInformationObject(idx);
119 inExt = inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT());
120
121 if (this->PreserveExtents)
122 {
123 // Compute union for preserving extents.
124 if (inExt[0] < unionExt[0])
125 {
126 unionExt[0] = inExt[0];
127 }
128 if (inExt[1] > unionExt[1])
129 {
130 unionExt[1] = inExt[1];
131 }
132 if (inExt[2] < unionExt[2])
133 {
134 unionExt[2] = inExt[2];
135 }
136 if (inExt[3] > unionExt[3])
137 {
138 unionExt[3] = inExt[3];
139 }
140 if (inExt[4] < unionExt[4])
141 {
142 unionExt[4] = inExt[4];
143 }
144 if (inExt[5] > unionExt[5])
145 {
146 unionExt[5] = inExt[5];
147 }
148 this->Shifts[idx] = 0;
149 }
150 else
151 {
152 // Compute shifts if we are not preserving extents.
153 this->Shifts[idx] = tmp - inExt[this->AppendAxis*2];
154 size = inExt[this->AppendAxis*2 + 1] - inExt[this->AppendAxis*2] + 1;
155 tmp += size;
156 }
157 }
158
159 if (this->PreserveExtents)
160 {
161 outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),unionExt,6);
162 }
163 else
164 {
165 inInfo = inputVector[0]->GetInformationObject(0);
166 inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),outExt);
167 max = tmp - 1;
168 outExt[this->AppendAxis*2] = min;
169 outExt[this->AppendAxis*2 + 1] = max;
170 outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),outExt,6);
171 }
172
173 return 1;
174 }
175
176 //----------------------------------------------------------------------------
InternalComputeInputUpdateExtent(int * inExt,int * outExt,int * inWextent,int whichInput)177 void vtkImageAppend::InternalComputeInputUpdateExtent(
178 int *inExt, int *outExt, int *inWextent, int whichInput)
179 {
180 int min, max, shift, tmp, idx;
181
182 // default input extent will be that of output extent
183 memcpy(inExt,outExt,sizeof(int)*6);
184
185 shift = 0;
186 if ( ! this->PreserveExtents)
187 {
188 shift = this->Shifts[whichInput];
189 }
190 min = inWextent[this->AppendAxis*2] + shift;
191 max = inWextent[this->AppendAxis*2 + 1] + shift;
192
193 // now clip the outExtent against the outExtent for this input (intersect)
194 tmp = outExt[this->AppendAxis*2];
195 if (min < tmp)
196 {
197 min = tmp;
198 }
199 tmp = outExt[this->AppendAxis*2 + 1];
200 if (max > tmp)
201 {
202 max = tmp;
203 }
204
205 // now if min > max, we do not need the input at all. I assume
206 // the pipeline will interpret this extent this way.
207
208 // convert back into input coordinates.
209 inExt[this->AppendAxis*2] = min - shift;
210 inExt[this->AppendAxis*2 + 1] = max - shift;
211
212 // for robustness (in the execute method),
213 // do not ask for more than the whole extent of the other axes.
214 for (idx = 0; idx < 3; ++idx)
215 {
216 if (inExt[idx*2] < inWextent[idx*2])
217 {
218 inExt[idx*2] = inWextent[idx*2];
219 }
220 if (inExt[idx*2 + 1] > inWextent[idx*2 + 1])
221 {
222 inExt[idx*2 + 1] = inWextent[idx*2 + 1];
223 }
224 }
225 }
226
227 //----------------------------------------------------------------------------
RequestUpdateExtent(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * outputVector)228 int vtkImageAppend::RequestUpdateExtent(
229 vtkInformation * vtkNotUsed(request),
230 vtkInformationVector **inputVector,
231 vtkInformationVector *outputVector)
232 {
233 // get the outInfo object
234 vtkInformation* outInfo = outputVector->GetInformationObject(0);
235
236 // default input extent will be that of output extent
237 int inExt[6];
238 outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(),inExt);
239 int *outExt =
240 outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT());
241
242 for (int whichInput = 0; whichInput < this->GetNumberOfInputConnections(0);
243 whichInput++)
244 {
245 int *inWextent;
246
247 // Find the outMin/max of the appended axis for this input.
248 vtkInformation *inInfo = inputVector[0]->GetInformationObject(whichInput);
249 inWextent = inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT());
250
251 this->InternalComputeInputUpdateExtent(inExt, outExt,
252 inWextent, whichInput);
253
254 inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(),inExt,6);
255 }
256
257 return 1;
258 }
259
260 //----------------------------------------------------------------------------
vtkImageAppendGetContinuousIncrements(int wExtent[6],int sExtent[6],vtkIdType nComp,bool forCells,vtkIdType & incX,vtkIdType & incY,vtkIdType & incZ)261 static void vtkImageAppendGetContinuousIncrements
262 (int wExtent[6], int sExtent[6], vtkIdType nComp, bool forCells,
263 vtkIdType &incX,
264 vtkIdType &incY,
265 vtkIdType &incZ)
266 {
267 //I can not use the one in vtkImageData, since that assumes point scalars
268 //and I need it to work for any point or cell array
269
270 int e0, e1, e2, e3;
271 incX = 0;
272 e0 = sExtent[0];
273 if (e0 < wExtent[0])
274 {
275 e0 = wExtent[0];
276 }
277 e1 = sExtent[1];
278 if (e1 > wExtent[1])
279 {
280 e1 = wExtent[1];
281 }
282 e2 = sExtent[2];
283 if (e2 < wExtent[2])
284 {
285 e2 = wExtent[2];
286 }
287 e3 = sExtent[3];
288 if (e3 > wExtent[3])
289 {
290 e3 = wExtent[3];
291 }
292
293 int ptAdjust = (forCells?0:1);
294 int idx;
295 vtkIdType increments[3];
296 int wholeJump;
297 for (idx = 0; idx < 3; ++idx)
298 {
299 increments[idx] = nComp;
300 wholeJump = wExtent[idx*2+1] - wExtent[idx*2] + ptAdjust;
301 if (wholeJump == 0)
302 {
303 wholeJump = 1;
304 }
305 nComp *= wholeJump;
306 }
307
308 //cerr << "INCS "
309 // << increments[0] << " " << increments[1] << " " << increments[2] << endl;
310 int dx = (e1-e0 + ptAdjust);
311 if (dx == 0) dx = 1;
312 int dy = (e3-e2 + ptAdjust);
313 if (dy == 0) dy = 1;
314
315 incY = increments[1] - dx*increments[0];
316 incZ = increments[2] - dy*increments[1];
317
318 //cerr << "RETURN " << incX << " " << incY << " " << incZ << endl;
319 }
320
321 //----------------------------------------------------------------------------
322 // This templated function executes the filter for any type of data.
323 template <class T>
vtkImageAppendExecute(vtkImageAppend * self,int id,int inExt[6],vtkImageData * inData,T * inPtr,int outExt[6],vtkImageData * outData,T * outPtr,vtkIdType numComp,bool forCells,int nArrays)324 void vtkImageAppendExecute(vtkImageAppend *self, int id,
325 int inExt[6], vtkImageData *inData, T *inPtr,
326 int outExt[6], vtkImageData *outData, T *outPtr,
327 vtkIdType numComp,
328 bool forCells,
329 int nArrays)
330 {
331 int idxR, idxY, idxZ;
332 int maxX, maxY, maxZ;
333 vtkIdType inIncX, inIncY, inIncZ;
334 vtkIdType outIncX, outIncY, outIncZ;
335 int rowLength;
336 unsigned long count = 0;
337 unsigned long target;
338 double dnArrays = (double)nArrays;
339
340 vtkImageAppendGetContinuousIncrements(
341 inData->GetExtent(), inExt, numComp, forCells, inIncX, inIncY, inIncZ);
342
343 //cerr << "IN INCS " << inIncX << " " << inIncY << " " << inIncZ << endl;
344 vtkImageAppendGetContinuousIncrements(
345 outData->GetExtent(), outExt, numComp, forCells, outIncX, outIncY, outIncZ);
346 //cerr << "OUT INCS " << outIncX << " " << outIncY << " " << outIncZ << endl;
347
348 int ptAdjust = (forCells?0:1);
349 // find the region to loop over
350 maxX = inExt[1]-inExt[0]+ptAdjust;
351 if (maxX == 0)
352 {
353 maxX = 1;
354 }
355 rowLength = maxX*numComp;
356 maxY = inExt[3] - inExt[2] + ptAdjust;
357 if (maxY == 0)
358 {
359 maxY = 1;
360 }
361 maxZ = inExt[5] - inExt[4] + ptAdjust;
362 if (maxZ == 0)
363 {
364 maxZ = 1;
365 }
366 //cerr << "SETUP " << endl;
367 //cerr << "IE0:" << inExt[0] << " IE1:" << inExt[1] << endl;
368 //cerr << "IE2:" << inExt[2] << " IE2:" << inExt[3] << endl;
369 //cerr << "IE4:" << inExt[4] << " IE5:" << inExt[5] << endl;
370 //cerr << "PTS:" << ptAdjust << " NCOMP:" << numComp << " RL:" << rowLength << endl;
371
372 target = static_cast<unsigned long>((maxZ+ptAdjust)*(maxY+ptAdjust)/50.0/dnArrays);
373 target++;
374
375 // Loop through input pixels
376 for (idxZ = 0; idxZ < maxZ; idxZ++)
377 {
378 for (idxY = 0; !self->AbortExecute && idxY < maxY; idxY++)
379 {
380 if (!id)
381 {
382 if (!(count%target))
383 {
384 self->UpdateProgress(count/(50.0*target));
385 }
386 count++;
387 }
388 //cerr << "PTRS " << inPtr << " " << outPtr << endl;
389 for (idxR = 0; idxR < rowLength; idxR++)
390 {
391 // Pixel operation
392 //cerr << idxZ << "," << idxY << "," << idxR << " " << *inPtr << endl;
393 *outPtr = *inPtr;
394 outPtr++;
395 inPtr++;
396 }
397 outPtr += outIncY;
398 inPtr += inIncY;
399 }
400 outPtr += outIncZ;
401 inPtr += inIncZ;
402 }
403 }
404
405 //----------------------------------------------------------------------------
InitOutput(int outExt[6],vtkImageData * outData)406 void vtkImageAppend::InitOutput(int outExt[6], vtkImageData *outData)
407 {
408 int idxY, idxZ;
409 int maxY, maxZ;
410 vtkIdType outIncY, outIncZ;
411 int rowLength;
412 int typeSize;
413 unsigned char *outPtrZ, *outPtrY;
414
415 // This method needs to clear all point-data for the update-extent.
416
417 vtkPointData* pd = outData->GetPointData();
418 for (int arrayIdx=0; arrayIdx < pd->GetNumberOfArrays(); arrayIdx++)
419 {
420 vtkDataArray* array = pd->GetArray(arrayIdx);
421 if (!array)
422 {
423 continue;
424 }
425
426 typeSize = vtkDataArray::GetDataTypeSize(array->GetDataType());
427 outPtrZ = static_cast<unsigned char *>(
428 outData->GetArrayPointerForExtent(array, outExt));
429
430 // Get increments to march through data
431 vtkIdType increments[3];
432 outData->GetArrayIncrements(array, increments);
433 outIncY = increments[1];
434 outIncZ = increments[2];
435
436 outIncY *= typeSize;
437 outIncZ *= typeSize;
438
439 // Find the region to loop over
440 rowLength = (outExt[1] - outExt[0]+1)* array->GetNumberOfComponents();
441 rowLength *= typeSize;
442 maxY = outExt[3] - outExt[2];
443 maxZ = outExt[5] - outExt[4];
444
445 // Loop through input pixels
446 for (idxZ = 0; idxZ <= maxZ; idxZ++)
447 {
448 outPtrY = outPtrZ;
449 for (idxY = 0; idxY <= maxY; idxY++)
450 {
451 memset(outPtrY, 0, rowLength);
452 outPtrY += outIncY;
453 }
454 outPtrZ += outIncZ;
455 }
456 }
457 }
458
459 //----------------------------------------------------------------------------
460 // This method is passed a input and output regions, and executes the filter
461 // algorithm to fill the output from the inputs.
462 // It just executes a switch statement to call the correct function for
463 // the regions data types.
ThreadedRequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * vtkNotUsed (outputVector),vtkImageData *** inData,vtkImageData ** outData,int outExt[6],int id)464 void vtkImageAppend::ThreadedRequestData (
465 vtkInformation * vtkNotUsed( request ),
466 vtkInformationVector** inputVector,
467 vtkInformationVector * vtkNotUsed( outputVector ),
468 vtkImageData ***inData,
469 vtkImageData **outData,
470 int outExt[6], int id)
471 {
472 int idx1;
473 int inExt[6], cOutExt[6];
474 int c_in[3], c_out[3];
475 void *inPtr;
476 void *outPtr;
477 int nArrays;
478
479 this->InitOutput(outExt, outData[0]);
480
481 for (idx1 = 0; idx1 < this->GetNumberOfInputConnections(0); ++idx1)
482 {
483 //cerr << "INPUT " << idx1 << endl;
484
485 if (inData[0][idx1] != nullptr)
486 {
487 nArrays = inData[0][idx1]->GetPointData()->GetNumberOfArrays() +
488 inData[0][idx1]->GetCellData()->GetNumberOfArrays();
489
490 // Get the input extent and output extent
491 // the real out extent for this input may be clipped.
492 vtkInformation *inInfo =
493 inputVector[0]->GetInformationObject(idx1);
494 int *inWextent =
495 inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT());
496
497 this->InternalComputeInputUpdateExtent(inExt, outExt, inWextent, idx1);
498
499 memcpy(cOutExt, inExt, 6*sizeof(int));
500 cOutExt[this->AppendAxis*2] =
501 inExt[this->AppendAxis*2] + this->Shifts[idx1];
502 cOutExt[this->AppendAxis*2 + 1] =
503 inExt[this->AppendAxis*2 + 1] + this->Shifts[idx1];
504
505 c_in[0] = inExt[0];
506 c_in[1] = inExt[2];
507 c_in[2] = inExt[4];
508
509 c_out[0] = cOutExt[0];
510 c_out[1] = cOutExt[2];
511 c_out[2] = cOutExt[4];
512
513 // do a quick check to see if the input is used at all.
514 if (inExt[0] <= inExt[1] &&
515 inExt[2] <= inExt[3] &&
516 inExt[4] <= inExt[5])
517 {
518 vtkIdType ai;
519 vtkDataArray *inArray;
520 vtkDataArray *outArray;
521 vtkIdType numComp;
522
523 //do point associated arrays
524 for (ai = 0;
525 ai < inData[0][idx1]->GetPointData()->GetNumberOfArrays();
526 ai++)
527 {
528 //cerr << "POINT ARRAY " << ai << endl;
529
530 inArray = inData[0][idx1]->GetPointData()->GetArray(ai);
531 outArray = outData[0]->GetPointData()->GetArray(ai);
532
533 numComp = inArray->GetNumberOfComponents();
534 if (numComp != outArray->GetNumberOfComponents())
535 {
536 vtkErrorMacro("Components of the inputs do not match");
537 return;
538 }
539
540 // this filter expects that input is the same type as output.
541 if (inArray->GetDataType() != outArray->GetDataType())
542 {
543 vtkErrorMacro(<< "Execute: input" << idx1 << " ScalarType ("
544 << inArray->GetDataType()
545 << "), must match output ScalarType ("
546 << outArray->GetDataType() << ")");
547 return;
548 }
549
550 inPtr = inData[0][idx1]->GetArrayPointerForExtent(inArray, inExt);
551 outPtr = outData[0]->GetArrayPointerForExtent(outArray, cOutExt);
552
553 //cerr << "INITIAL PTRS " << inPtr << " " << outPtr << endl;
554 switch (inArray->GetDataType())
555 {
556 vtkTemplateMacro(
557 vtkImageAppendExecute(this, id,
558 inExt, inData[0][idx1],
559 static_cast<VTK_TT *>(inPtr),
560 cOutExt, outData[0],
561 static_cast<VTK_TT *>(outPtr),
562 numComp,
563 false,
564 nArrays));
565 default:
566 vtkErrorMacro(<< "Execute: Unknown ScalarType");
567 return;
568 }
569 }
570
571 //do cell associated arrays
572 for (ai = 0;
573 ai < inData[0][idx1]->GetCellData()->GetNumberOfArrays();
574 ai++)
575 {
576 //cerr << "CELL ARRAY " << ai << endl;
577
578 inArray = inData[0][idx1]->GetCellData()->GetArray(ai);
579 outArray = outData[0]->GetCellData()->GetArray(ai);
580
581 numComp = inArray->GetNumberOfComponents();
582 if (numComp != outArray->GetNumberOfComponents())
583 {
584 vtkErrorMacro("Components of the inputs do not match");
585 return;
586 }
587
588 // this filter expects that input is the same type as output.
589 if (inArray->GetDataType() != outArray->GetDataType())
590 {
591 vtkErrorMacro(<< "Execute: input" << idx1 << " ScalarType ("
592 << inArray->GetDataType()
593 << "), must match output ScalarType ("
594 << outArray->GetDataType() << ")");
595 return;
596 }
597
598 vtkIdType cellId;
599 cellId = vtkStructuredData::ComputeCellIdForExtent(inExt, c_in);
600 inPtr = inArray->GetVoidPointer(cellId*numComp);
601 cellId = vtkStructuredData::ComputeCellIdForExtent(outExt, c_out);
602 outPtr = outArray->GetVoidPointer(cellId*numComp);
603 //cerr << "INITIAL PTRS " << inPtr << " " << outPtr << " "
604 // << c_out[0] << "," << c_out[1] << "," << c_out[2] << ":"
605 // << outExt[0] << " " << outExt[1] << ", "
606 // << outExt[2] << " " << outExt[3] << ", "
607 // << outExt[4] << " " << outExt[5] << endl;
608
609 switch (inArray->GetDataType())
610 {
611 vtkTemplateMacro(
612 vtkImageAppendExecute(this, id,
613 inExt, inData[0][idx1],
614 static_cast<VTK_TT *>(inPtr),
615 cOutExt, outData[0],
616 static_cast<VTK_TT *>(outPtr),
617 numComp,
618 true,
619 nArrays));
620 default:
621 vtkErrorMacro(<< "Execute: Unknown ScalarType");
622 return;
623 }
624 }
625 }
626 }
627 }
628 }
629
630
631 //----------------------------------------------------------------------------
FillInputPortInformation(int i,vtkInformation * info)632 int vtkImageAppend::FillInputPortInformation(int i, vtkInformation* info)
633 {
634 info->Set(vtkAlgorithm::INPUT_IS_REPEATABLE(), 1);
635 return this->Superclass::FillInputPortInformation(i,info);
636 }
637
638 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)639 void vtkImageAppend::PrintSelf(ostream& os, vtkIndent indent)
640 {
641 this->Superclass::PrintSelf(os, indent);
642
643 os << indent << "AppendAxis: " << this->AppendAxis << endl;
644 os << indent << "PreserveExtents: " << this->PreserveExtents << endl;
645 }
646
647 //----------------------------------------------------------------------------
AllocateOutputData(vtkImageData * output,vtkInformation *,int * uExtent)648 void vtkImageAppend::AllocateOutputData(vtkImageData *output,
649 vtkInformation*,
650 int *uExtent)
651 {
652 output->SetExtent(uExtent);
653
654 //compute number of cells and points in the uExtent
655 vtkIdType numpts = 1;
656 vtkIdType numcells = 1;
657 for (int i = 0; i < 3; i++)
658 {
659 if (uExtent[i*2+1] >= uExtent[i*2])
660 {
661 vtkIdType dim = uExtent[i*2+1]-uExtent[i*2];
662 numpts = numpts*(dim+1);
663 if (dim != 0)
664 {
665 numcells = numcells*dim;
666 }
667 }
668 }
669
670 //get a hold of any of my inputs to get arrays
671 vtkImageData *in = vtkImageData::SafeDownCast(this->GetInputDataObject(0,0));
672
673 vtkDataSetAttributes *ifd, *ofd;
674 ifd = in->GetPointData();
675 ofd = output->GetPointData();
676 if (ifd && ofd)
677 {
678 ofd->CopyAllOn();
679 ofd->CopyAllocate(ifd, numpts);
680 ofd->SetNumberOfTuples(numpts);
681 }
682 ifd = in->GetCellData();
683 ofd = output->GetCellData();
684 if (ifd && ofd)
685 {
686 ofd->CopyAllOn();
687 ofd->CopyAllocate(ifd, numcells);
688 ofd->SetNumberOfTuples(numcells);
689 }
690 }
691
692 //----------------------------------------------------------------------------
AllocateOutputData(vtkDataObject * output,vtkInformation * outInfo)693 vtkImageData *vtkImageAppend::AllocateOutputData(vtkDataObject *output,
694 vtkInformation* outInfo)
695 {
696 // set the extent to be the update extent
697 vtkImageData *out = vtkImageData::SafeDownCast(output);
698 if (out)
699 {
700 int* uExtent = outInfo->Get(
701 vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT());
702 this->AllocateOutputData(out, outInfo, uExtent);
703 }
704 return out;
705 }
706
707 //----------------------------------------------------------------------------
CopyAttributeData(vtkImageData * vtkNotUsed (input),vtkImageData * vtkNotUsed (output),vtkInformationVector ** vtkNotUsed (inputVector))708 void vtkImageAppend::CopyAttributeData(vtkImageData *vtkNotUsed(input),
709 vtkImageData *vtkNotUsed(output),
710 vtkInformationVector **vtkNotUsed(inputVector))
711 {
712 //Do not simply shallow copy forward the data as other imaging filters do.
713 //We have to append instead.
714 }
715