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