/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkDataSetAttributes.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 "vtkDataSetAttributes.h"
#include "vtkCell.h"
#include "vtkMath.h"
#include "vtkBitArray.h"
#include "vtkCharArray.h"
#include "vtkUnsignedCharArray.h"
#include "vtkShortArray.h"
#include "vtkUnsignedShortArray.h"
#include "vtkIntArray.h"
#include "vtkUnsignedIntArray.h"
#include "vtkLongArray.h"
#include "vtkUnsignedLongArray.h"
#include "vtkDoubleArray.h"
#include "vtkFloatArray.h"
#include "vtkIdTypeArray.h"
#include "vtkObjectFactory.h"

vtkCxxRevisionMacro(vtkDataSetAttributes, "1.4");
vtkStandardNewMacro(vtkDataSetAttributes);

//--------------------------------------------------------------------------
const char vtkDataSetAttributes
::AttributeNames[vtkDataSetAttributes::NUM_ATTRIBUTES][10] =
{ "Scalars",
  "Vectors",
  "Normals",
  "TCoords",
  "Tensors" };

// Construct object with copying turned on for all data.
vtkDataSetAttributes::vtkDataSetAttributes()
{
  for(int attributeType=0; attributeType<NUM_ATTRIBUTES; attributeType++)
    {
    this->AttributeIndices[attributeType] = -1;
    this->CopyAttributeFlags[attributeType] = 1;
    }
  this->TargetIndices=0;
}

// Destructor for the vtkDataSetAttributes objects.
vtkDataSetAttributes::~vtkDataSetAttributes()
{
  this->Initialize();
  delete[] this->TargetIndices;
  this->TargetIndices = 0;
}

// Turn on copying of all data.
void vtkDataSetAttributes::CopyAllOn()
{
  this->vtkFieldData::CopyAllOn();
  this->CopyScalarsOn();
  this->CopyVectorsOn();
  this->CopyNormalsOn();
  this->CopyTCoordsOn();
  this->CopyTensorsOn();
}

// Turn off copying of all data.
void vtkDataSetAttributes::CopyAllOff()
{
  this->vtkFieldData::CopyAllOff();
  this->CopyScalarsOff();
  this->CopyVectorsOff();
  this->CopyNormalsOff();
  this->CopyTCoordsOff();
  this->CopyTensorsOff();
}

// Deep copy of data (i.e., create new data arrays and
// copy from input data). Note that attribute data is
// not copied.
void vtkDataSetAttributes::DeepCopy(vtkFieldData *fd)
{
  this->Initialize(); //free up memory

  vtkDataSetAttributes* dsa = vtkDataSetAttributes::SafeDownCast(fd);
  // If the source is a vtkDataSetAttributes
  if (dsa)
    {
    int numArrays = fd->GetNumberOfArrays();
    int attributeType;
    vtkDataArray *data, *newData;

    // Allocate space for numArrays
    this->AllocateArrays(numArrays);
    for ( int i=0; i < numArrays; i++ )
      {
      data = fd->GetArray(i);
      newData = data->NewInstance(); //instantiate same type of object
      newData->DeepCopy(data);
      newData->SetName(data->GetName());
      if ((attributeType=dsa->IsArrayAnAttribute(i)) != -1)
        {
        // If this array is an attribute in the source, make it so
        // in the target as well.
        this->SetAttribute(newData, attributeType);
        }
      else
        {
        this->AddArray(newData);
        }
      newData->Delete();
      }
    // Copy the copy flags
    for(attributeType=0; attributeType<NUM_ATTRIBUTES; attributeType++)
      {
      this->CopyAttributeFlags[attributeType] = 
        dsa->CopyAttributeFlags[attributeType];
      }
    this->CopyFlags(dsa);
    }
  // If the source is field data, do a field data copy
  else
    {
    this->vtkFieldData::DeepCopy(fd);
    }
          
}

// Shallow copy of data (i.e., use reference counting).
void vtkDataSetAttributes::ShallowCopy(vtkFieldData *fd)
{
  this->Initialize(); //free up memory

  vtkDataSetAttributes* dsa = vtkDataSetAttributes::SafeDownCast(fd);
  // If the source is a vtkDataSetAttributes
  if (dsa)
    {
    int numArrays = fd->GetNumberOfArrays();
    int attributeType;

    // Allocate space for numArrays
    this->AllocateArrays(numArrays);
    this->NumberOfActiveArrays = 0;
    for ( int i=0; i < numArrays; i++ )
      {
      this->NumberOfActiveArrays++;
      this->SetArray(i, fd->GetArray(i));
      if ((attributeType=dsa->IsArrayAnAttribute(i)) != -1)
        {
        // If this array is an attribute in the source, make it so
        // in the target as well.
        this->SetActiveAttribute(i, attributeType);
        }
      }
    // Copy the copy flags
    for(attributeType=0; attributeType<NUM_ATTRIBUTES; attributeType++)
      {
      this->CopyAttributeFlags[attributeType] = 
        dsa->CopyAttributeFlags[attributeType];
      }
    this->CopyFlags(dsa);
    }
  // If the source is field data, do a field data copy
  else
    {
    this->vtkFieldData::ShallowCopy(fd);
    }
}

// Initialize all of the object's data to NULL
void vtkDataSetAttributes::InitializeFields()
{
  this->vtkFieldData::InitializeFields();
  for(int attributeType=0; attributeType<NUM_ATTRIBUTES; attributeType++)
    {
    this->AttributeIndices[attributeType] = -1;
    }
}

// Initialize all of the object's data to NULL
void vtkDataSetAttributes::Initialize()
{
//
// We don't modify ourselves because the "ReleaseData" methods depend upon
// no modification when initialized.
//

// Call superclass' Initialize()
  this->vtkFieldData::Initialize();
//
// Free up any memory
//
  for(int attributeType=0; attributeType<NUM_ATTRIBUTES; attributeType++)
    {
    this->AttributeIndices[attributeType] = -1;
    }
}

// This method is used to determine which arrays
// will be copied to this object after PassData or PassNoReplaceData
vtkFieldData::BasicIterator  vtkDataSetAttributes::ComputeRequiredArrays(
  vtkDataSetAttributes* pd)
{
  // We need to do some juggling to find the number of arrays
  // which will be passed.

  // First, find the number of arrays to be copied because they
  // are in the list of _fields_ to be copied (and the actual data
  // pointer is non-NULL). Also, we keep those indices in a list.
  int* copyFlags = new int[pd->GetNumberOfArrays()];
  int index, i, numArrays = 0;
  for(i=0; i<pd->GetNumberOfArrays(); i++)
    {
    const char* arrayName = pd->GetArrayName(i);
    // If there is no blocker for the given array
    // and both CopyAllOff and CopyOn for that array are not true
    if ( (this->GetFlag(arrayName) != 0) &&
         !(this->DoCopyAllOff && (this->GetFlag(arrayName) != 1)) &&
         pd->GetArray(i))
      {
      copyFlags[numArrays] = i;
      numArrays++;
      }
    }

  // Next, we check the arrays to be copied because they are one of
  // the _attributes_ to be copied (and the data array in non-NULL). 
  // We make sure that we don't count anything twice.
  int alreadyCopied;
  for(int attributeType=0; attributeType<NUM_ATTRIBUTES; attributeType++)
    {
    index = pd->AttributeIndices[attributeType];
    int flag = this->GetFlag(pd->GetArrayName(index));
    // If this attribute is to be copied
    if (this->CopyAttributeFlags[attributeType] && flag)
      {
      // Find out if it is also in the list of fields to be copied
      if (pd->GetArray(index))
        {
        alreadyCopied = 0;
        for(i=0; i<numArrays; i++)
          {
          if ( index == copyFlags[i] )
            {
            alreadyCopied = 1;
            }
          }
        // If not, increment the number of arrays to be copied.
        if (!alreadyCopied)
          {
          copyFlags[numArrays] = index;
          numArrays++;
          }
        }
      }
    // If it is not to be copied and it is in the list (from the
    // previous pass), remove it
    else
      {
      for(i=0; i<numArrays; i++)
        {
        if ( index == copyFlags[i] )
          {
          for(int j=i; j<numArrays-1; j++)
            {
            copyFlags[j] = copyFlags[j+1];
            }
          numArrays--;
          i--;
          }
        }
      }
    }
  vtkFieldData::BasicIterator it(copyFlags, numArrays);
  delete[] copyFlags;
  return it;
}

// Pass entire arrays of input data through to output. Obey the "copy"
// flags.
void vtkDataSetAttributes::PassData(vtkFieldData* fd)
{
  if (!fd)
    {
    return;
    }

  vtkDataSetAttributes* dsa = vtkDataSetAttributes::SafeDownCast(fd);

  if (dsa)
    {
    // Create an iterator to iterate over the fields which will
    // be passed, i.e. fields which are either:
    // 1> in the list of _fields_ to be copied or
    // 2> in the list of _attributes_ to be copied.
    // Note that NULL data arrays are not copied
    vtkFieldData::BasicIterator it = this->ComputeRequiredArrays(dsa);
    
    if ( it.GetListSize() > this->NumberOfArrays )
      {
      this->AllocateArrays(it.GetListSize());
      }
    if (it.GetListSize() == 0)
      {
      return;
      }
    
    // Since we are replacing, remove old attributes
    int attributeType; //will change//
    for(attributeType=0; attributeType<NUM_ATTRIBUTES; attributeType++)
      {
      if (this->CopyAttributeFlags[attributeType])
        {
        this->RemoveArray(this->AttributeIndices[attributeType]);
        this->AttributeIndices[attributeType] = -1;
        }
      }
    
    int i, arrayIndex;
    for(i=it.BeginIndex(); !it.End(); i=it.NextIndex())
      {
      arrayIndex = this->AddArray(dsa->GetArray(i));
      // If necessary, make the array an attribute
      if ( ((attributeType = dsa->IsArrayAnAttribute(i)) != -1 ) && 
           this->CopyAttributeFlags[attributeType] )
        {
        this->SetActiveAttribute(arrayIndex, attributeType);
        }
      }
    }
  else
    {
    this->vtkFieldData::PassData(fd);
    }
}




//----------------------------------------------------------------------------
// This is used in the imaging pipeline for copying arrays.
// CopyAllocate needs to be called before this method. 
void vtkDataSetAttributes::CopyStructuredData(vtkDataSetAttributes *fromPd,
                                          const int *inExt, const int *outExt)
{
  int i;
  
  for(i=this->RequiredArrays.BeginIndex(); !this->RequiredArrays.End(); 
      i=this->RequiredArrays.NextIndex())
    {
    vtkDataArray *inArray = fromPd->Data[i];
    vtkDataArray *outArray = this->Data[this->TargetIndices[i]];
    unsigned char *inPtr;
    unsigned char *outPtr;
    unsigned char *inZPtr;
    unsigned char *outZPtr;
    int inIncs[3];
    int outIncs[3];
    int rowLength;
    int yIdx, zIdx;

    // Compute increments
    inIncs[0] = inArray->GetDataTypeSize() * inArray->GetNumberOfComponents();
    inIncs[1] = inIncs[0] * (inExt[1]-inExt[0]+1);
    inIncs[2] = inIncs[1] * (inExt[3]-inExt[2]+1);
    outIncs[0] = inIncs[0];
    outIncs[1] = outIncs[0] * (outExt[1]-outExt[0]+1);
    outIncs[2] = outIncs[1] * (outExt[3]-outExt[2]+1);
    // Length of continuous data to copy (one row).
    rowLength = (outExt[1]-outExt[0]+1)*outIncs[0];

    // Make sure the input extents match the actual array lengths.
    zIdx = (inExt[1]-inExt[0]+1)*(inExt[3]-inExt[2]+1)*(inExt[5]-inExt[4]+1);
    if (inArray->GetNumberOfTuples() != zIdx)
      {
      vtkErrorMacro("Input extent (" << inExt[0] << ", " << inExt[1] << ", " 
                    << inExt[2] << ", " << inExt[3] << ", " << inExt[4] << ", " 
                    << inExt[5] << ") does not match array length: " << zIdx);
      // Skip copying this array.
      continue;
      }
    // Make sure the output extents match the actual array lengths.
    zIdx = (outExt[1]-outExt[0]+1)*(outExt[3]-outExt[2]+1)*(outExt[5]-outExt[4]+1);
    if (outArray->GetNumberOfTuples() != zIdx)
      {
      // The "CopyAllocate" method only sets the size, not the number of tuples.
      outArray->SetNumberOfTuples(zIdx);
      }

    // Get the starting input pointer.
    inZPtr = (unsigned char*)(inArray->GetVoidPointer(0));
    // Shift to the start of the subextent.
    inZPtr += (outExt[0]-outExt[0])*inIncs[0] +
      (outExt[2] - outExt[2])*inIncs[1] +
      (outExt[4] - outExt[4])*inIncs[2];

    // Get output pointer.
    outZPtr = (unsigned char*)(outArray->GetVoidPointer(0));

    // Loop over z axis.
    for (zIdx = outExt[4]; zIdx <= outExt[5]; ++zIdx)
      {
      inPtr = inZPtr;
      outPtr = outZPtr;
      for (yIdx = outExt[2]; yIdx <= outExt[3]; ++yIdx)
        {
        memcpy(outPtr, inPtr, rowLength);
        inPtr += inIncs[1];
        outPtr += outIncs[1];
        }
      inZPtr += inIncs[2];
      outZPtr += outIncs[2];
      }
    }
}





// Allocates point data for point-by-point (or cell-by-cell) copy operation.  
// If sze=0, then use the input DataSetAttributes to create (i.e., find 
// initial size of) new objects; otherwise use the sze variable.
void vtkDataSetAttributes::CopyAllocate(vtkDataSetAttributes* pd, 
                                        vtkIdType sze, vtkIdType ext)
{
  vtkDataArray* newDA;
  int i;

  // Create various point data depending upon input
  //
  if ( !pd )
    {
    return;
    }

  this->RequiredArrays = this->ComputeRequiredArrays(pd);
  if (this->RequiredArrays.GetListSize() == 0)
    {
    return;
    }
  delete[] this->TargetIndices;
  this->TargetIndices = new int[pd->GetNumberOfArrays()];
  for(i=0; i<pd->GetNumberOfArrays(); i++)
    {
    this->TargetIndices[i] = -1;
    }

  vtkDataArray* da=0;
  // If we are not copying on self
  if ( pd != this )
    {
    int attributeType;

    for(i=this->RequiredArrays.BeginIndex(); !this->RequiredArrays.End(); 
        i=this->RequiredArrays.NextIndex())
      {
      // Create all required arrays
      da = pd->GetArray(i);
      newDA = da->NewInstance();
      newDA->SetNumberOfComponents(da->GetNumberOfComponents());
      newDA->SetName(da->GetName());
      if ( sze > 0 )
        {
        newDA->Allocate(sze*da->GetNumberOfComponents(),ext);
        }
      else
        {
        newDA->Allocate(da->GetNumberOfTuples());
        }
      newDA->SetLookupTable(da->GetLookupTable());
      this->TargetIndices[i] = this->AddArray(newDA);
      // If necessary, make the array an attribute
      if ( ((attributeType = pd->IsArrayAnAttribute(i)) != -1 ) && 
           this->CopyAttributeFlags[attributeType] )
        {
        this->SetActiveAttribute(this->TargetIndices[i], attributeType);
        }
      newDA->Delete();
      }
    }
  else
    {
    // If copying on self, resize the arrays and initialize
    // TargetIndices
    for(i=this->RequiredArrays.BeginIndex(); !this->RequiredArrays.End(); 
        i=this->RequiredArrays.NextIndex())
      {
      da = pd->GetArray(i);
      da->Resize(sze);
      this->TargetIndices[i] = i;
      }
    }
}

void vtkDataSetAttributes::RemoveArray(int index)
{
  if ( (index<0) || (index>=this->NumberOfActiveArrays))
    {
    return;
    }
  this->vtkFieldData::RemoveArray(index);
  int attributeType;
  for(attributeType = 0; attributeType < NUM_ATTRIBUTES; attributeType++)
    {
    if (this->AttributeIndices[attributeType] == index)
      {
      this->AttributeIndices[attributeType] = -1;
      }
    else if (this->AttributeIndices[attributeType] > index)
      {
      this->AttributeIndices[attributeType]--;
      }
    }
}

// Copy the attribute data from one id to another. Make sure CopyAllocate() has
// been invoked before using this method.
void vtkDataSetAttributes::CopyData(vtkDataSetAttributes* fromPd,
                                    vtkIdType fromId, vtkIdType toId)
{
  int i;
  for(i=this->RequiredArrays.BeginIndex(); !this->RequiredArrays.End(); 
      i=this->RequiredArrays.NextIndex())
    {
    this->CopyTuple(fromPd->Data[i], this->Data[this->TargetIndices[i]], 
                    fromId, toId);
    }
}

// Initialize point interpolation method.
void vtkDataSetAttributes::InterpolateAllocate(vtkDataSetAttributes* pd,
                                               vtkIdType sze, vtkIdType ext)
{
  this->CopyAllocate(pd, sze, ext);
}

// Interpolate data from points and interpolation weights. Make sure that the 
// method InterpolateAllocate() has been invoked before using this method.
void vtkDataSetAttributes::InterpolatePoint(vtkDataSetAttributes *fromPd, 
                                            vtkIdType toId, vtkIdList *ptIds, 
                                            double *weights)
{
  int i;
  for(i=this->RequiredArrays.BeginIndex(); !this->RequiredArrays.End(); 
      i=this->RequiredArrays.NextIndex())
    {
    this->InterpolateTuple(fromPd->Data[i], 
                           this->Data[this->TargetIndices[i]], 
                           toId, ptIds, weights);
    }
}

// Interpolate data from the two points p1,p2 (forming an edge) and an 
// interpolation factor, t, along the edge. The weight ranges from (0,1), 
// with t=0 located at p1. Make sure that the method InterpolateAllocate() 
// has been invoked before using this method.
void vtkDataSetAttributes::InterpolateEdge(vtkDataSetAttributes *fromPd, 
                                           vtkIdType toId, vtkIdType p1,
                                           vtkIdType p2, double t)
{
  int i;
  for(i=this->RequiredArrays.BeginIndex(); !this->RequiredArrays.End(); 
      i=this->RequiredArrays.NextIndex())
    {
    this->InterpolateTuple(fromPd->Data[i], 
                           this->Data[this->TargetIndices[i]], 
                           toId, p1, p2, t);
    }
}

// Interpolate data from the two points p1,p2 (forming an edge) and an 
// interpolation factor, t, along the edge. The weight ranges from (0,1), 
// with t=0 located at p1. Make sure that the method InterpolateAllocate() 
// has been invoked before using this method.
void vtkDataSetAttributes::InterpolateTime(vtkDataSetAttributes *from1,
                                           vtkDataSetAttributes *from2,
                                           vtkIdType id, double t)
{
  for(int attributeType=0; attributeType<NUM_ATTRIBUTES; attributeType++)
    {
    // If this attribute is to be copied
    if (this->CopyAttributeFlags[attributeType])
      {
      if (from1->GetAttribute(attributeType) && 
          from2->GetAttribute(attributeType))
        {
        this->InterpolateTuple(from1->GetAttribute(attributeType), 
                               from2->GetAttribute(attributeType),
                               this->GetAttribute(attributeType), id, t);
        }
      }
    }
}

template <class T>
void vtkDataSetAttributesCopyTuple(T* from, T* to, int numComp)
{
  for(int i=0; i < numComp; ++i)
    {
    *to++ = *from++;
    }
}

// Copy a tuple of data from one data array to another. This method (and
// following ones) assume that the fromData and toData objects are of the
// same type, and have the same number of components. This is true if you
// invoke CopyAllocate() or InterpolateAllocate().
void vtkDataSetAttributes::CopyTuple(vtkDataArray *fromData,
                                     vtkDataArray *toData, vtkIdType fromId,
                                     vtkIdType toId)
{
  int i;
  int numComp=fromData->GetNumberOfComponents();
  switch (fromData->GetDataType())
    {
    vtkTemplateMacro(
      void* vto = toData->WriteVoidPointer(toId*numComp, numComp);
      void* vfrom = fromData->GetVoidPointer(fromId*numComp);
      vtkDataSetAttributesCopyTuple(static_cast<VTK_TT*>(vfrom),
                                    static_cast<VTK_TT*>(vto), numComp)
      );
    case VTK_BIT:
      {
      vtkBitArray *from=(vtkBitArray *)fromData;
      vtkBitArray *to=(vtkBitArray *)toData;
      for (i=0; i<numComp; i++)
        {
        to->InsertValue(toId+i, from->GetValue(fromId+i));
        }
      }
      break;
    default:
      vtkErrorMacro("Unsupported data type " << fromData->GetDataType()
                    << " during copy!");
    }
}

template <class T>
void vtkDataSetAttributesInterpolateTuple(T* from, T* to, int numComp,
                                          vtkIdType* ids, vtkIdType numIds,
                                          double* weights)
{
  for(int i=0; i < numComp; ++i)
    {
    double c = 0;
    for(vtkIdType j=0; j < numIds; ++j)
      {
      c += weights[j]*from[ids[j]*numComp+i];
      }
    *to++ = static_cast<T>(c);
    }
}

// double versions
void vtkDataSetAttributes::InterpolateTuple(vtkDataArray *fromData, 
                                            vtkDataArray *toData, 
                                            vtkIdType toId, vtkIdList *ptIds, 
                                            double *weights)
{
  int numComp=fromData->GetNumberOfComponents(), i;
  vtkIdType j, numIds=ptIds->GetNumberOfIds();
  vtkIdType *ids=ptIds->GetPointer(0);
  vtkIdType idx=toId*numComp;
  double c;
  
  switch (fromData->GetDataType())
    {
    case VTK_BIT:
      {
      vtkBitArray *from=(vtkBitArray *)fromData;
      vtkBitArray *to=(vtkBitArray *)toData;
      for (i=0; i<numComp; i++)
        {
        for (c=0, j=0; j<numIds; j++)
          {
          c += weights[j]*from->GetValue(ids[j]*numComp+i);
          }
        to->InsertValue(idx+i, (int)c);
        }
      }
      break;
    vtkTemplateMacro(
      void* vfrom = fromData->GetVoidPointer(0);
      void* vto = toData->WriteVoidPointer(idx, numComp);
      vtkDataSetAttributesInterpolateTuple(static_cast<VTK_TT*>(vfrom),
                                           static_cast<VTK_TT*>(vto),
                                           numComp, ids, numIds, weights)
      );
    default:
      vtkErrorMacro("Unsupported data type " << fromData->GetDataType()
                    << " during interpolation!");
    }
}

template <class T>
void vtkDataSetAttributesInterpolateTuple(T* from, T* to, int numComp,
                                          vtkIdType idx1, vtkIdType idx2,
                                          double t)
{
  for(int i=0; i < numComp; ++i)
    {
    double c = (1.0 - t) * from[idx1+i] + t * from[idx2+i];
    *to++ = static_cast<T>(c);
    }
}

void vtkDataSetAttributes::InterpolateTuple(vtkDataArray *fromData,
                                            vtkDataArray *toData,
                                            vtkIdType toId, vtkIdType id1,
                                            vtkIdType id2, double t)
{
  int i, numComp=fromData->GetNumberOfComponents();
  vtkIdType idx=toId*numComp;
  vtkIdType idx1=id1*numComp, idx2=id2*numComp;
  double c;
  
  switch (fromData->GetDataType())
    {
    case VTK_BIT:
      {
      vtkBitArray *from=(vtkBitArray *)fromData;
      vtkBitArray *to=(vtkBitArray *)toData;
      for (i=0; i<numComp; i++)
        {
        c = from->GetValue(idx1+i)+ t * (from->GetValue(idx2+i) - from->GetValue(idx1+i));
        to->InsertValue(idx+i, (int)c);
        }
      }
      break;
    vtkTemplateMacro(
      void* vfrom = fromData->GetVoidPointer(0);
      void* vto = toData->WriteVoidPointer(idx, numComp);
      vtkDataSetAttributesInterpolateTuple(static_cast<VTK_TT*>(vfrom),
                                           static_cast<VTK_TT*>(vto),
                                           numComp, idx1, idx2, t)
      );
    default:
      vtkErrorMacro("Unsupported data type " << fromData->GetDataType()
                    << " during interpolation!");
    }
}

template <class T>
void vtkDataSetAttributesInterpolateTuple(T* from1, T* from2, T* to,
                                          int numComp, vtkIdType idx, double t)
{
  for(int i=0; i < numComp; ++i)
    {
    vtkIdType ii = idx + i;
    double c = (1.0 - t) * from1[ii] + t * from2[ii];
    *to++ = static_cast<T>(c);
    }
}

void vtkDataSetAttributes::InterpolateTuple(vtkDataArray *fromData1,
                                            vtkDataArray *fromData2, 
                                            vtkDataArray *toData, vtkIdType id,
                                            double t)
{
  int i, numComp=fromData1->GetNumberOfComponents();
  vtkIdType idx=id*numComp, ii;
  double c;

  switch (fromData1->GetDataType())
    {
    case VTK_BIT:
      {
      vtkBitArray *from1=(vtkBitArray *)fromData1;
      vtkBitArray *from2=(vtkBitArray *)fromData2;
      vtkBitArray *to=(vtkBitArray *)toData;
      for (i=0; i<numComp; i++)
        {
        ii = idx + i;
        c = from1->GetValue(ii) + t * (from2->GetValue(ii) - from1->GetValue(ii));
        to->InsertValue(ii, (int)c);
        }
      }
      break;
    vtkTemplateMacro(
      void* vfrom1 = fromData1->GetVoidPointer(0);
      void* vfrom2 = fromData2->GetVoidPointer(0);
      void* vto = toData->WriteVoidPointer(idx, numComp);
      vtkDataSetAttributesInterpolateTuple(static_cast<VTK_TT*>(vfrom1),
                                           static_cast<VTK_TT*>(vfrom2),
                                           static_cast<VTK_TT*>(vto),
                                           numComp, idx, t)
      );
    default:
      vtkErrorMacro("Unsupported data type " << fromData1->GetDataType()
                    << " during interpolation!");
    }
}

int vtkDataSetAttributes::SetScalars(vtkDataArray* da) 
{ 
  return this->SetAttribute(da, SCALARS); 
}

int vtkDataSetAttributes::SetActiveScalars(const char* name)
{ 
  return this->SetActiveAttribute(name, SCALARS); 
}

int vtkDataSetAttributes::SetActiveAttribute(const char* name,
                                             int attributeType)
{
  int index; 
  this->GetArray(name, index);
  return this->SetActiveAttribute(index, attributeType);
}

vtkDataArray* vtkDataSetAttributes::GetScalars() 
{ 
  return this->GetAttribute(SCALARS); 
}

int vtkDataSetAttributes::SetVectors(vtkDataArray* da) 
{ 
return this->SetAttribute(da, VECTORS); 
}

int vtkDataSetAttributes::SetActiveVectors(const char* name)
{ 
  return this->SetActiveAttribute(name, VECTORS); 
}

vtkDataArray* vtkDataSetAttributes::GetVectors() 
{ 
  return this->GetAttribute(VECTORS); 
}

int vtkDataSetAttributes::SetNormals(vtkDataArray* da) 
{ 
  return this->SetAttribute(da, NORMALS); 
}

int vtkDataSetAttributes::SetActiveNormals(const char* name)
{ 
  return this->SetActiveAttribute(name, NORMALS); 
}

vtkDataArray* vtkDataSetAttributes::GetNormals() 
{ 
  return this->GetAttribute(NORMALS); 
}

int vtkDataSetAttributes::SetTCoords(vtkDataArray* da) 
{ 
  return this->SetAttribute(da, TCOORDS); 
}

int vtkDataSetAttributes::SetActiveTCoords(const char* name)
{ 
  return this->SetActiveAttribute(name, TCOORDS); 
}
vtkDataArray* vtkDataSetAttributes::GetTCoords() 
{ 
  return this->GetAttribute(TCOORDS); 
}

int vtkDataSetAttributes::SetTensors(vtkDataArray* da) 
{ 
  return this->SetAttribute(da, TENSORS); 
}

int vtkDataSetAttributes::SetActiveTensors(const char* name)
{ 
  return this->SetActiveAttribute(name, TENSORS); 
}

vtkDataArray* vtkDataSetAttributes::GetTensors() 
{ 
  return this->GetAttribute(TENSORS); 
}

vtkDataArray* vtkDataSetAttributes::GetScalars(const char* name)
{
  if (name == NULL || name[0] == '\0')
    {
    return this->GetScalars();
    }
  return this->GetArray(name);
}

vtkDataArray* vtkDataSetAttributes::GetVectors(const char* name)
{
  if (name == NULL || name[0] == '\0')
    {
    return this->GetVectors();
    }
  return this->GetArray(name);
}

vtkDataArray* vtkDataSetAttributes::GetNormals(const char* name)
{
  if (name == NULL || name[0] == '\0')
    {
    return this->GetNormals();
    }
  return this->GetArray(name);
}

vtkDataArray* vtkDataSetAttributes::GetTCoords(const char* name)
{
  if (name == NULL || name[0] == '\0')
    {
    return this->GetTCoords();
    }
  return this->GetArray(name);
}

vtkDataArray* vtkDataSetAttributes::GetTensors(const char* name)
{
  if (name == NULL || name[0] == '\0')
    {
    return this->GetTensors();
    }
  return this->GetArray(name);
}

int vtkDataSetAttributes::SetActiveAttribute(int index, int attributeType)
{
  if ( (index >= 0) && (index < this->GetNumberOfArrays()))
    {
    if (!this->CheckNumberOfComponents(this->Data[index], attributeType))
      {
      vtkWarningMacro("Can not set attribute " 
                      << vtkDataSetAttributes::AttributeNames[attributeType]
                      << ". Incorrect number of components.");
      return -1;
      }
    this->AttributeIndices[attributeType] = index;
    this->Modified();
    return index;
    }
  else if (index == -1)
    {
    this->AttributeIndices[attributeType] = index;
    this->Modified();
    }

  return -1;
}

const int vtkDataSetAttributes
::NumberOfAttributeComponents[vtkDataSetAttributes::NUM_ATTRIBUTES] =
{ 0,
  3,
  3,
  3,
  9};

// Scalars set to NOLIMIT 
const int vtkDataSetAttributes
::AttributeLimits[vtkDataSetAttributes::NUM_ATTRIBUTES] =
{ NOLIMIT,
  EXACT,
  EXACT,
  MAX,
  EXACT };

int vtkDataSetAttributes::CheckNumberOfComponents(vtkDataArray* da,
                                                  int attributeType)
{
  int numComp = da->GetNumberOfComponents();
  
  if ( vtkDataSetAttributes::AttributeLimits[attributeType] == MAX )
    {
    if ( numComp > 
         vtkDataSetAttributes::NumberOfAttributeComponents[attributeType] )
      {
      return 0;
      }
    else
      {
      return 1;
      }
    }
  else if ( vtkDataSetAttributes::AttributeLimits[attributeType] == EXACT )
    {
    if ( numComp != 
         vtkDataSetAttributes::NumberOfAttributeComponents[attributeType] )
      {
      return 0;
      }
    else
      {
      return 1;
      }
    }
  else if ( vtkDataSetAttributes::AttributeLimits[attributeType] == NOLIMIT )
    {
    return 1;
    }
  else
    {
    return 0;
    }
}

vtkDataArray* vtkDataSetAttributes::GetAttribute(int attributeType)
{
  int index = this->AttributeIndices[attributeType];
  if (index == -1)
    {
    return 0;
    }
  else
    {
    return this->Data[index];
    }
}

// This method lets the user add an array and make it the current
// scalars, vectors etc... (this is determined by the attribute type
// which is an enum defined vtkDataSetAttributes)
int vtkDataSetAttributes::SetAttribute(vtkDataArray* da, int attributeType)
{
  if (da && !this->CheckNumberOfComponents(da, attributeType))
    {
    vtkWarningMacro("Can not set attribute " 
                    << vtkDataSetAttributes::AttributeNames[attributeType]
                    << ". Incorrect number of components.");
    return -1;
    }

  int currentAttribute = this->AttributeIndices[attributeType];

  // If there is an existing attribute, replace it
  if ( (currentAttribute >= 0) && 
       (currentAttribute < this->GetNumberOfArrays()) )
    {
    if (this->GetArray(currentAttribute) == da)
      {
      return currentAttribute;
      }
    this->RemoveArray(currentAttribute);
    }

  if (da)
    {
    // Add the array
    currentAttribute = this->AddArray(da);
    this->AttributeIndices[attributeType] = currentAttribute;
    }
  else
    {
    this->AttributeIndices[attributeType] = -1; //attribute of this type doesn't exist
    }
  this->Modified();
  return this->AttributeIndices[attributeType];
}

void vtkDataSetAttributes::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  // Print the copy flags
  os << indent << "Copy Flags: ( ";
  for (int i=0; i<NUM_ATTRIBUTES; i++)
    {
    os << this->CopyAttributeFlags[i] << " ";
    }
  os << ")" << endl;
  
  // Now print the various attributes
  vtkDataArray* da;
  int attributeType;
  for (attributeType=0; attributeType<NUM_ATTRIBUTES; attributeType++)
    {
    os << indent << vtkDataSetAttributes::AttributeNames[attributeType]
       << ": ";
    if ( (da=this->GetAttribute(attributeType)) )
      {
      os << endl;
      da->PrintSelf(os, indent.GetNextIndent());
      }
    else
      {
      os << "(none)" << endl;
      }
    }

}

void vtkDataSetAttributes::GetAttributeIndices(int* indexArray)
{
  for(int i=0; i<NUM_ATTRIBUTES; i++)
    {
    indexArray[i] = this->AttributeIndices[i];
    }
}

int vtkDataSetAttributes::IsArrayAnAttribute(int idx)
{
  for (int i=0; i<NUM_ATTRIBUTES; i++)
    {
    if ( idx == this->AttributeIndices[i] )
      {
      return i;
      }
    }
  return -1;
}

void vtkDataSetAttributes::SetCopyAttribute (int index, int value) 
{ 
  if (this->CopyAttributeFlags[ index ] != value) 
    { 
    this->CopyAttributeFlags[ index ] = value; 
    this->Modified(); 
    } 
} 

void vtkDataSetAttributes::SetCopyScalars(int i) 
{ 
  this->SetCopyAttribute(SCALARS, i); 
}
int vtkDataSetAttributes::GetCopyScalars() { 
  return this->CopyAttributeFlags[SCALARS]; 
}

void vtkDataSetAttributes::SetCopyVectors(int i) 
{ 
  this->SetCopyAttribute(VECTORS, i); 
}
int vtkDataSetAttributes::GetCopyVectors() 
{ 
  return this->CopyAttributeFlags[VECTORS]; 
}

void vtkDataSetAttributes::SetCopyNormals(int i) 
{ 
  this->SetCopyAttribute(NORMALS, i); 
}
int vtkDataSetAttributes::GetCopyNormals() 
{ 
  return this->CopyAttributeFlags[NORMALS]; 
}

void vtkDataSetAttributes::SetCopyTCoords(int i) 
{ 
  this->SetCopyAttribute(TCOORDS, i); 
}
int vtkDataSetAttributes::GetCopyTCoords() 
{ 
  return this->CopyAttributeFlags[TCOORDS]; 
}

void vtkDataSetAttributes::SetCopyTensors(int i) 
{ 
  this->SetCopyAttribute(TENSORS, i); 
}
int vtkDataSetAttributes::GetCopyTensors() { 
  return this->CopyAttributeFlags[TENSORS]; 
}

void vtkDataSetAttributes::RemoveArray(const char *name)
{
  int i;
  this->GetArray(name, i);
  this->RemoveArray(i);
}

void vtkDataSetAttributes::CopyAllocate(vtkDataSetAttributes::FieldList& list, 
                                        vtkIdType sze, vtkIdType ext)
{
  vtkDataArray* newDA=0;
  int i;

  // Allocate attributes if any
  for (i=0; i < list.NumberOfFields; i++)
    {
    if ( list.FieldIndices[i] >= 0 )
      {
      newDA = vtkDataArray::CreateDataArray(list.FieldTypes[i]);
      newDA->SetName(list.Fields[i]);
      newDA->SetNumberOfComponents(list.FieldComponents[i]);

      if ( sze > 0 )
        {
        newDA->Allocate(sze,ext);
        }
      else
        {
        newDA->Allocate(list.NumberOfTuples,ext);
        }
      newDA->SetLookupTable(list.LUT[i]);

      // If attribute data, do something extra
      if ( i < NUM_ATTRIBUTES )
        {
        if ( this->CopyAttributeFlags[i] )
          {
          list.FieldIndices[i] = this->AddArray(newDA);
          this->SetActiveAttribute(list.FieldIndices[i], i);
          }
        else
          {
          list.FieldIndices[i] = -1;
          }
        }
      else //check if this field is to be copied
        {
        if ( (this->GetFlag(list.Fields[i]) != 0) &&
             !(this->DoCopyAllOff && (this->GetFlag(list.Fields[i]) != 1)) )
          {
          list.FieldIndices[i] = this->AddArray(newDA);
          }
        else
          {
          list.FieldIndices[i] = -1;
          }
        }

      newDA->Delete(); //okay, reference counting
      }//data array defined
    }
}

// Description:
// A special form of CopyData() to be used with FieldLists. Use it when you are
// copying data from a set of vtkDataSetAttributes. Make sure that you have
// called the special form of CopyAllocate that accepts FieldLists.
void vtkDataSetAttributes::CopyData(vtkDataSetAttributes::FieldList& list, 
                                    vtkDataSetAttributes* fromDSA,
                                    int idx, vtkIdType fromId, vtkIdType toId)
{
  vtkDataArray *fromDA;
  vtkDataArray *toDA;
  
  for (int i=0; i < list.NumberOfFields; i++)
    {
    if ( list.FieldIndices[i] >= 0 )
      {
      toDA = this->GetArray(list.FieldIndices[i]);
      fromDA = fromDSA->GetArray(list.DSAIndices[idx][i]);
      this->CopyTuple(fromDA, toDA, fromId, toId);
      }
    }
}

// FieldList support ---------------------------------------------------------
// To perform intersection of attribute data, use IntializeFieldList() to grab
// an initial vtkDataSetAttributes. Then use IntersectFieldList() to add (and 
// intersect) additional vtkDataSetAttributes.
void vtkDataSetAttributes::FieldList::InitializeFieldList(vtkDataSetAttributes* dsa)
{
  int i, idx;

  this->ClearFields();

  // Allocate space for the arrays plus five attributes
  this->NumberOfFields = dsa->GetNumberOfArrays() + NUM_ATTRIBUTES;
  this->Fields = new char*[this->NumberOfFields];
  this->FieldTypes = new int [this->NumberOfFields];
  this->FieldComponents = new int [this->NumberOfFields];
  this->FieldIndices = new int [this->NumberOfFields];
  this->LUT = new vtkLookupTable* [this->NumberOfFields];
  for(i=0; i < this->NumberOfFields; i++)
    {
    this->Fields[i] = 0;
    this->FieldTypes[i] = -1;
    this->FieldComponents[i] = 0;
    this->FieldIndices[i] = -1;
    }
  this->CurrentInput = 0;
  this->NumberOfTuples = 0;
  
  //there may be no data hence dsa->Data
  for(i=0; dsa->Data && i < dsa->GetNumberOfArrays(); i++) 
    {
    if ( (idx=dsa->IsArrayAnAttribute(i)) >= 0 ) //it's an attribute
      {
      this->FieldIndices[idx] = idx;
      this->SetField(idx, dsa->Data[i]);
      }
    else
      {
      this->FieldIndices[NUM_ATTRIBUTES+i] = i;
      this->SetField(NUM_ATTRIBUTES+i, dsa->Data[i]);
      }
    }
  
  // The first dataset is added to the field list
  this->IntersectFieldList(dsa);
}

void vtkDataSetAttributes::FieldList::IntersectFieldList(vtkDataSetAttributes* dsa)
{
  int i;
  vtkDataArray *da;
  
  // Initialize the indices for this dataset
  this->DSAIndices[this->CurrentInput] = new int [this->NumberOfFields];
  for (i=0; i < this->NumberOfFields; i++)
    {
    this->DSAIndices[this->CurrentInput][i]= -1;
    }

  // Keep a running total of the number of tuples...might be useful
  // for later allocation.
  if ( (da=dsa->GetArray(0)) ) 
    {
    this->NumberOfTuples += da->GetNumberOfTuples();
    }
  
  // Intersect the attributes
  int attributeIndices[NUM_ATTRIBUTES];
  dsa->GetAttributeIndices(attributeIndices);
  for(i=0; i < NUM_ATTRIBUTES; i++)
    {
    if ( this->FieldIndices[i] >= 0 )
      {
      da = dsa->GetAttribute(i);
      if ((da) && (da->GetDataType() == this->FieldTypes[i]) && 
          (da->GetNumberOfComponents() == this->FieldComponents[i]))
        {
        this->DSAIndices[this->CurrentInput][i] = attributeIndices[i];
        }
      else
        {
        this->FieldIndices[i] = -1; //Attribute not present
        }
      }
    }
  // Intersect the fields
  int index;
  for(i=NUM_ATTRIBUTES; i < this->NumberOfFields; i++)
    {
    if (this->FieldIndices[i] >= 0)
      {
      da = dsa->GetArray(this->Fields[i], index);
      if ((da) && (da->GetDataType() == this->FieldTypes[i]) &&
          (da->GetNumberOfComponents() == this->FieldComponents[i]))
        {
        this->DSAIndices[this->CurrentInput][i] = index;
        }
      else
        {
        this->FieldIndices[i] = -1; //Field not present
        }
      }
    }

    
  this->CurrentInput++;
}

int vtkDataSetAttributes::FieldList::IsAttributePresent(int attrType)
{
  return this->FieldIndices[attrType];
}


vtkDataSetAttributes::FieldList::FieldList(int numInputs)
{
  this->Fields = 0;
  this->FieldTypes = 0;
  this->FieldComponents = 0;
  this->FieldIndices = 0;
  this->NumberOfFields = 0;
  this->LUT = 0;
  this->NumberOfDSAIndices = numInputs;
  this->DSAIndices = new int*[numInputs];
  for (int i=0; i<numInputs; i++)
    {
    this->DSAIndices[i] = 0;
    }
}

vtkDataSetAttributes::FieldList::~FieldList()
{
  this->ClearFields();
  delete [] this->DSAIndices;
  this->DSAIndices = 0;
}

void vtkDataSetAttributes::FieldList::ClearFields()
{
  if ( this->Fields )
    {
    for (int i=0; i<this->NumberOfFields; i++)
      {
      delete [] this->Fields[i];
      this->Fields[i] = 0;
      }
    }
  if ( this->DSAIndices )
    {
    for (int i=0; i<this->NumberOfDSAIndices; i++)
      {
      delete[] this->DSAIndices[i];
      this->DSAIndices[i] = 0;
      }
    }
  delete [] this->LUT;
  this->LUT = 0;
  delete [] this->Fields;
  this->Fields = 0;
  delete [] this->FieldTypes;
  this->FieldTypes = 0;
  delete [] this->FieldComponents;
  this->FieldComponents = 0;
  delete [] this->FieldIndices;
  this->FieldIndices = 0;
  
  this->NumberOfFields = 0;
  this->CurrentInput = 0;
}

void vtkDataSetAttributes::FieldList::SetField(int index, vtkDataArray *da)
{
  const char* name=da->GetName();
  int dataType=da->GetDataType();
  vtkLookupTable *lut=da->GetLookupTable();
  
  if ( this->Fields[index] )
    {
    delete [] this->Fields[index];
    this->Fields[index] = 0;
    }
  
  this->FieldTypes[index] = dataType;
  this->FieldComponents[index] = da->GetNumberOfComponents();
  this->LUT[index] = lut;
  if (name)
    {
    int len = static_cast<int>(strlen(name));
    if (len > 0)
      {
      this->Fields[index] = new char[len+1];
      strcpy(this->Fields[index], name);
      }
    }
  else
    {
    this->Fields[index] = 0;
    }
    
}

void vtkDataSetAttributes::FieldList::RemoveField(const char *name)
{
  if ( !name )
    {
    return;
    }

  for (int i=NUM_ATTRIBUTES; i < this->NumberOfFields; i++)
    {
    if ( this->Fields[i] && !strcmp(this->Fields[i],name) )
      {
      delete [] this->Fields[i];
      this->Fields[i] = 0;
      this->FieldIndices[i] = -1;
      return;
      }
    }
}


const char* vtkDataSetAttributes::GetAttributeTypeAsString(int attributeType)
{
  if (attributeType < 0 || attributeType >= NUM_ATTRIBUTES)
    {
    vtkGenericWarningMacro("Bad attribute type.");
    return NULL;
    }
  return vtkDataSetAttributes::AttributeNames[attributeType];
}


