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

Program:   Visualization Toolkit
Module:    vtkGenericGlyph3DFilter.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 "vtkGenericGlyph3DFilter.h"

#include "vtkGenericDataSet.h"
#include "vtkGenericAttribute.h"
#include "vtkGenericAttributeCollection.h"
#include "vtkGenericPointIterator.h"

#include "vtkCell.h"
#include "vtkDoubleArray.h"
#include "vtkIdList.h"
#include "vtkIdTypeArray.h"

#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkStreamingDemandDrivenPipeline.h"

#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
#include "vtkTransform.h"
#include "vtkTrivialProducer.h"
#include "vtkUnsignedCharArray.h"

vtkStandardNewMacro(vtkGenericGlyph3DFilter);

// Construct object with scaling on, scaling mode is by scalar value,
// scale factor = 1.0, the range is (0,1), orient geometry is on, and
// orientation is by vector. Clamping and indexing are turned off. No
// initial sources are defined.
vtkGenericGlyph3DFilter::vtkGenericGlyph3DFilter()
{
  this->Scaling = 1;
  this->ColorMode = VTK_COLOR_BY_SCALE;
  this->ScaleMode = VTK_SCALE_BY_SCALAR;
  this->ScaleFactor = 1.0;
  this->Range[0] = 0.0;
  this->Range[1] = 1.0;
  this->Orient = 1;
  this->VectorMode = VTK_USE_VECTOR;
  this->Clamping = 0;
  this->IndexMode = VTK_INDEXING_OFF;
//  this->NumberOfRequiredInputs = 1;
  this->GeneratePointIds = 0;
  this->PointIdsName = NULL;
  this->SetPointIdsName("InputPointIds");
  this->InputScalarsSelection = NULL;
  this->InputVectorsSelection = NULL;
  this->InputNormalsSelection = NULL;
  this->SetNumberOfInputPorts(2);
}

//-----------------------------------------------------------------------------
vtkGenericGlyph3DFilter::~vtkGenericGlyph3DFilter()
{
  delete[] this->PointIdsName;
  this->SetInputScalarsSelection(NULL);
  this->SetInputVectorsSelection(NULL);
  this->SetInputNormalsSelection(NULL);
}

//-----------------------------------------------------------------------------
int vtkGenericGlyph3DFilter::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  // get the info objects
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  // get the input and output
  vtkGenericDataSet *input = vtkGenericDataSet::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkPolyData *output = vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));



  vtkPointData *pd = NULL;
  //  vtkDataArray *inScalars;
  //  vtkDataArray *inVectors;
  //  vtkDataArray *inNormals;
  vtkDataArray *sourceNormals = NULL;
  vtkGenericAttribute *inScalars=0;
  vtkGenericAttribute *inVectors=0;
  vtkGenericAttribute *inNormals=0;
  //  vtkGenericAttribute *sourceNormals=0;

  unsigned char* inGhostLevels=0;

  vtkIdType numPts, numSourcePts, numSourceCells, inPtId, i;
  int index;
  vtkPoints *sourcePts = NULL;
  vtkPoints *newPts;
  vtkDataArray *newScalars=NULL;
  vtkDataArray *newVectors=NULL;
  vtkDataArray *newNormals=NULL;
  double x[3], v[3], vNew[3], s = 0.0, vMag = 0.0, value;
  vtkTransform *trans;
  vtkCell *cell;
  vtkIdList *cellPts;
  int npts;
  vtkIdList *pts;
  vtkIdType ptIncr, cellId;
  int haveVectors, haveNormals;
  double scalex,scaley,scalez, den;
  vtkPointData *outputPD = output->GetPointData();
//  vtkGenericDataSet *input = this->GetInput();
  int numberOfSources = this->GetNumberOfInputConnections(1);
  vtkPolyData *defaultSource = NULL;
  vtkIdTypeArray *pointIds=0;

  vtkGenericAttributeCollection *attributes=0;
  int attrib=-1;

  vtkDebugMacro(<<"Generating glyphs");

  if (!input)
  {
    vtkErrorMacro(<<"No input");
    return 1;
  }

  attributes = input->GetAttributes();
  if((attributes==0) || (attributes->IsEmpty()))
  {
    vtkDebugMacro("No attributes, nothing to do.");
    return 1;
  }
  if (this->InputScalarsSelection!=0)
  {
    attrib=attributes->FindAttribute(this->InputScalarsSelection);
    if(attrib!=-1)
    {
      inScalars = attributes->GetAttribute(attrib);
      if(inScalars->GetNumberOfComponents()!=1)
      {
        inScalars=0;
        vtkDebugMacro("The attribute is not a scalar.");
      }
    }
    else
    {
      vtkDebugMacro("No scalar attribute.");
    }
  }
  if (this->InputVectorsSelection!=0)
  {
    vtkDebugMacro("this->InputVectorsSelection!=0");
    attrib=attributes->FindAttribute(this->InputVectorsSelection);
    vtkDebugMacro("inVectors just set");
    if(attrib!=-1)
    {
      inVectors = attributes->GetAttribute(attrib);
      if(inVectors->GetNumberOfComponents()!=3)
      {
        inVectors=0;
        vtkDebugMacro("The attribute is not a vector.");
      }
      else
      {
        vtkDebugMacro("The attribute is a vector.");
      }
    }
    else
    {
      vtkDebugMacro("No vector attribute.");
    }
  }
  else
  {
    vtkDebugMacro("No input vector selection.");
  }

  if (this->InputNormalsSelection!=0)
  {
    attrib = attributes->FindAttribute(this->InputNormalsSelection);
    if(attrib!=-1)
    {
      inNormals = attributes->GetAttribute(attrib);
      if(inNormals->GetNumberOfComponents()!=3)
      {
        inNormals=0;
        vtkDebugMacro("The attribute is not a normal vector.");
      }
    }
    else
    {
      vtkDebugMacro("No normal attribute.");
    }
  }

  //  pd = input->GetPointData();
  //  inScalars = pd->GetScalars(this->InputScalarsSelection);
  //  inVectors = pd->GetVectors(this->InputVectorsSelection);
  //  inNormals = pd->GetNormals(this->InputNormalsSelection);

  // guru concurrency section
#if 0
  vtkDataArray* temp = 0;
  if (pd)
  {
    temp = pd->GetArray(vtkDataSetAttributes::GhostArrayName());
  }
  if ( (!temp) || (temp->GetDataType() != VTK_UNSIGNED_CHAR)
       || (temp->GetNumberOfComponents() != 1))
  {
    vtkDebugMacro("No appropriate ghost levels field available.");
  }
  else
  {
    inGhostLevels = ((vtkUnsignedCharArray*)temp)->GetPointer(0);
  }
#endif

  numPts = input->GetNumberOfPoints();
  if (numPts < 1)
  {
    vtkDebugMacro(<<"No points to glyph!");
    return 1;
  }
  else
  {
    pts = vtkIdList::New();
    pts->Allocate(VTK_CELL_SIZE);
    trans=vtkTransform::New();
  }

  // Check input for consistency
  //
  if ( (den = this->Range[1] - this->Range[0]) == 0.0 )
  {
    den = 1.0;
  }
  if ( this->VectorMode != VTK_VECTOR_ROTATION_OFF &&
       ((this->VectorMode == VTK_USE_VECTOR && inVectors != NULL) ||
        (this->VectorMode == VTK_USE_NORMAL && inNormals != NULL)) )
  {
    haveVectors = 1;
  }
  else
  {
    haveVectors = 0;
  }

  if ( (this->IndexMode == VTK_INDEXING_BY_SCALAR && !inScalars) ||
       (this->IndexMode == VTK_INDEXING_BY_VECTOR &&
        ((!inVectors && this->VectorMode == VTK_USE_VECTOR) ||
         (!inNormals && this->VectorMode == VTK_USE_NORMAL))) )
  {
    if ( this->GetSource(0) == NULL )
    {
      vtkErrorMacro(<<"Indexing on but don't have data to index with");
      pts->Delete();
      trans->Delete();
      return 1;
    }
    else
    {
      vtkWarningMacro(<<"Turning indexing off: no data to index with");
      this->IndexMode = VTK_INDEXING_OFF;
    }
  }

  // Allocate storage for output PolyData
  //
  outputPD->CopyVectorsOff();
  outputPD->CopyNormalsOff();

  if (!this->GetSource(0))
  {
    defaultSource = vtkPolyData::New();
    defaultSource->Allocate();
    vtkPoints *defaultPoints = vtkPoints::New();
    defaultPoints->Allocate(6);
    defaultPoints->InsertNextPoint(0, 0, 0);
    defaultPoints->InsertNextPoint(1, 0, 0);
    vtkIdType defaultPointIds[2];
    defaultPointIds[0] = 0;
    defaultPointIds[1] = 1;
    defaultSource->SetPoints(defaultPoints);
    defaultSource->InsertNextCell(VTK_LINE, 2, defaultPointIds);
    defaultSource->Delete();
    defaultSource = NULL;
    defaultPoints->Delete();
    defaultPoints = NULL;
  }

  if ( this->IndexMode != VTK_INDEXING_OFF )
  {
    pd = NULL;
    haveNormals = 1;
    for (numSourcePts=numSourceCells=i=0; i < numberOfSources; i++)
    {
      if ( this->GetSource(i) != NULL )
      {
        if (this->GetSource(i)->GetNumberOfPoints() > numSourcePts)
        {
          numSourcePts = this->GetSource(i)->GetNumberOfPoints();
        }
        if (this->GetSource(i)->GetNumberOfCells() > numSourceCells)
        {
          numSourceCells = this->GetSource(i)->GetNumberOfCells();
        }
        if ( !(sourceNormals = this->GetSource(i)->GetPointData()->GetNormals()) )
        {
          haveNormals = 0;
        }
      }
    }
  }
  else
  {
    sourcePts = this->GetSource(0)->GetPoints();
    numSourcePts = sourcePts->GetNumberOfPoints();
    numSourceCells = this->GetSource(0)->GetNumberOfCells();

    sourceNormals = this->GetSource(0)->GetPointData()->GetNormals();
    if ( sourceNormals )
    {
      haveNormals = 1;
    }
    else
    {
      haveNormals = 0;
    }

    // Prepare to copy output.
    //    pd = input->GetPointData();
    //    outputPD->CopyAllocate(pd,numPts*numSourcePts); // AddArray ?
  }

  newPts = vtkPoints::New();
  newPts->Allocate(numPts*numSourcePts);
  if ( this->GeneratePointIds )
  {
    pointIds = vtkIdTypeArray::New();
    pointIds->SetName(this->PointIdsName);
    pointIds->Allocate(numPts*numSourcePts);
    outputPD->AddArray(pointIds);
  }
  if ( this->ColorMode == VTK_COLOR_BY_SCALAR && inScalars )
  {
    //    newScalars = inScalars->NewInstance();
    newScalars=vtkDoubleArray::New();
    newScalars->SetNumberOfComponents(inScalars->GetNumberOfComponents());
    newScalars->Allocate(inScalars->GetNumberOfComponents()*numPts*numSourcePts);
    newScalars->SetName(inScalars->GetName());
  }
  else if ( (this->ColorMode == VTK_COLOR_BY_SCALE) && inScalars)
  {
    newScalars = vtkDoubleArray::New();
    newScalars->Allocate(numPts*numSourcePts);
    newScalars->SetName("GlyphScale");
    if (this->ScaleMode== VTK_SCALE_BY_SCALAR)
    {
      newScalars->SetName(inScalars->GetName());
    }
  }
  else if ( (this->ColorMode == VTK_COLOR_BY_VECTOR) && haveVectors)
  {
    newScalars = vtkDoubleArray::New();
    newScalars->Allocate(numPts*numSourcePts);
    newScalars->SetName("VectorMagnitude");
  }
  if ( haveVectors )
  {
    newVectors = vtkDoubleArray::New();
    newVectors->SetNumberOfComponents(3);
    newVectors->Allocate(3*numPts*numSourcePts);
    newVectors->SetName("GlyphVector");
  }
  if ( haveNormals )
  {
    newNormals = vtkDoubleArray::New();
    newNormals->SetNumberOfComponents(3);
    newNormals->Allocate(3*numPts*numSourcePts);
    newNormals->SetName("Normals");
  }

  // Setting up for calls to PolyData::InsertNextCell()
  if (this->IndexMode != VTK_INDEXING_OFF )
  {
    output->Allocate(3*numPts*numSourceCells,numPts*numSourceCells);
  }
  else
  {
    output->Allocate(this->GetSource(0),3*numPts*numSourceCells,numPts*numSourceCells);
  }

  // Traverse all Input points, transforming Source points and copying
  // point attributes.
  //
  ptIncr=0;
  inPtId=0; // used only for the progress information

//  vtkGenericAdaptorCell *acell=0;
//  vtkCellIterator *it=input->NewVertexIterator();
  vtkGenericPointIterator *it=input->NewPointIterator();
  it->Begin();
  while(!it->IsAtEnd())
  {
    scalex = scaley = scalez = 1.0;
    if ( ! (inPtId % 10000) )
    {
      this->UpdateProgress(static_cast<double>(inPtId)/numPts);
      if (this->GetAbortExecute())
      {
        break;
      }
    }

//    acell=it->GetCell();
    // Get the scalar and vector data
    if ( inScalars )
    {
      inScalars->GetTuple(it,&s);
      //      s = inScalars->GetComponent(inPtId, 0);
      if ( this->ScaleMode == VTK_SCALE_BY_SCALAR ||
           this->ScaleMode == VTK_DATA_SCALING_OFF )
      {
        scalex = scaley = scalez = s;
      }
    }

    if ( haveVectors )
    {
      if ( this->VectorMode == VTK_USE_NORMAL )
      {
        //          inNormals->GetTuple(inPtId, v);
        inNormals->GetTuple(it,v);
      }
      else
      {
        inVectors->GetTuple(it,v);
        //          inVectors->GetTuple(inPtId, v);
      }
      vMag = vtkMath::Norm(v);
      if ( this->ScaleMode == VTK_SCALE_BY_VECTORCOMPONENTS )
      {
        scalex = v[0];
        scaley = v[1];
        scalez = v[2];
      }
      else if ( this->ScaleMode == VTK_SCALE_BY_VECTOR )
      {
        scalex = scaley = scalez = vMag;
      }
    }

    // Clamp data scale if enabled
    if ( this->Clamping )
    {
      scalex = (scalex < this->Range[0] ? this->Range[0] :
                (scalex > this->Range[1] ? this->Range[1] : scalex));
      scalex = (scalex - this->Range[0]) / den;
      scaley = (scaley < this->Range[0] ? this->Range[0] :
                (scaley > this->Range[1] ? this->Range[1] : scaley));
      scaley = (scaley - this->Range[0]) / den;
      scalez = (scalez < this->Range[0] ? this->Range[0] :
                (scalez > this->Range[1] ? this->Range[1] : scalez));
      scalez = (scalez - this->Range[0]) / den;
    }

    // Compute index into table of glyphs
    if ( this->IndexMode == VTK_INDEXING_OFF )
    {
      index = 0;
    }
    else
    {
      if ( this->IndexMode == VTK_INDEXING_BY_SCALAR )
      {
        value = s;
      }
      else
      {
        value = vMag;
      }

      index = static_cast<int>(
        static_cast<double>(value - this->Range[0]) * numberOfSources / den);
      index = (index < 0 ? 0 :
               (index >= numberOfSources ? (numberOfSources-1) : index));

      if ( this->GetSource(index) != NULL )
      {
        sourcePts = this->GetSource(index)->GetPoints();
        sourceNormals = this->GetSource(index)->GetPointData()->GetNormals();
        numSourcePts = sourcePts->GetNumberOfPoints();
        numSourceCells = this->GetSource(index)->GetNumberOfCells();
      }
    }

    // Make sure we're not indexing into empty glyph
    if ( this->GetSource(index) == NULL )
    {
      continue;
    }

    // Check ghost points.
    // If we are processing a piece, we do not want to duplicate
    // glyphs on the borders.
    if (inGhostLevels &&
        inGhostLevels[inPtId] & vtkDataSetAttributes::DUPLICATEPOINT)
    {
      continue;
    }

    // Now begin copying/transforming glyph
    trans->Identity();

    // Copy all topology (transformation independent)
    for (cellId=0; cellId < numSourceCells; cellId++)
    {
      cell = this->GetSource(index)->GetCell(cellId);
      cellPts = cell->GetPointIds();
      npts = cellPts->GetNumberOfIds();
      for (pts->Reset(), i=0; i < npts; i++)
      {
        pts->InsertId(i,cellPts->GetId(i) + ptIncr);
      }
      output->InsertNextCell(cell->GetCellType(),pts);
    }

    // translate Source to Input point
    //    input->GetPoint(inPtId, x);
    it->GetPosition(x);
    trans->Translate(x[0], x[1], x[2]);

    if ( haveVectors )
    {
      // Copy Input vector
      for (i=0; i < numSourcePts; i++)
      {
        newVectors->InsertTuple(i+ptIncr, v);
      }
      if (this->Orient && (vMag > 0.0))
      {
        // if there is no y or z component
        if ( v[1] == 0.0 && v[2] == 0.0 )
        {
          if (v[0] < 0) //just flip x if we need to
          {
            trans->RotateWXYZ(180.0,0,1,0);
          }
        }
        else
        {
          vNew[0] = (v[0]+vMag) / 2.0;
          vNew[1] = v[1] / 2.0;
          vNew[2] = v[2] / 2.0;
          trans->RotateWXYZ(static_cast<double>(180.0),vNew[0],vNew[1],
                            vNew[2]);
        }
      }
    }

    // determine scale factor from scalars if appropriate
    if ( inScalars )
    {
      // Copy scalar value
      if (this->ColorMode == VTK_COLOR_BY_SCALE)
      {
        for (i=0; i < numSourcePts; i++)
        {
          newScalars->InsertTuple(i+ptIncr, &scalex); // = scaley = scalez
        }
      }
      else if (this->ColorMode == VTK_COLOR_BY_SCALAR)
      {
        for (i=0; i < numSourcePts; i++)
        {
          //          outputPD->CopyTuple(inScalars, newScalars, inPtId, ptIncr+i);
          newScalars->InsertTuple(i+ptIncr, &s);
        }
      }
    }
    if (haveVectors && this->ColorMode == VTK_COLOR_BY_VECTOR)
    {
      for (i=0; i < numSourcePts; i++)
      {
        newScalars->InsertTuple(i+ptIncr, &vMag);
      }
    }

    // scale data if appropriate
    if ( this->Scaling )
    {
      if ( this->ScaleMode == VTK_DATA_SCALING_OFF )
      {
        scalex = scaley = scalez = this->ScaleFactor;
      }
      else
      {
        scalex *= this->ScaleFactor;
        scaley *= this->ScaleFactor;
        scalez *= this->ScaleFactor;
      }

      if ( scalex == 0.0 )
      {
        scalex = 1.0e-10;
      }
      if ( scaley == 0.0 )
      {
        scaley = 1.0e-10;
      }
      if ( scalez == 0.0 )
      {
        scalez = 1.0e-10;
      }
      trans->Scale(scalex,scaley,scalez);
    }

    // multiply points and normals by resulting matrix
    trans->TransformPoints(sourcePts,newPts);

    if ( haveNormals )
    {
      trans->TransformNormals(sourceNormals,newNormals);
    }

    // Copy point data from source (if possible): WRONG to from source but
    // from input.
    if ( pd )
    {
      for (i=0; i < numSourcePts; i++)
      {
        outputPD->CopyData(pd,inPtId,ptIncr+i);
      }
    }

    // If point ids are to be generated, do it here
    if ( this->GeneratePointIds )
    {
      for (i=0; i < numSourcePts; i++)
      {
        pointIds->InsertNextValue(inPtId);
      }
    }
    it->Next();
    ptIncr += numSourcePts;
    inPtId++;
  }
  it->Delete();

  // Update ourselves and release memory
  //
  output->SetPoints(newPts);
  newPts->Delete();

  if (newScalars)
  {
    int idx = outputPD->AddArray(newScalars);
    outputPD->SetActiveAttribute(idx, vtkDataSetAttributes::SCALARS);
    newScalars->Delete();
  }

  if (newVectors)
  {
    outputPD->SetVectors(newVectors);
    newVectors->Delete();
  }

  if (newNormals)
  {
    outputPD->SetNormals(newNormals);
    newNormals->Delete();
  }

  output->Squeeze();
  trans->Delete();
  pts->Delete();
  return 1;
}

//----------------------------------------------------------------------------
// Since indexing determines size of outputs, EstimatedWholeMemorySize is
// truly an estimate.  Ignore Indexing (although for a best estimate we
// should average the size of the sources instead of using 0).
int vtkGenericGlyph3DFilter::RequestInformation(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **vtkNotUsed(inputVector),
  vtkInformationVector *vtkNotUsed(outputVector))
{
  // get the info objects
//  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
//  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  if (this->GetInput() == NULL)
  {
    vtkErrorMacro("Missing input");
    return 1;
  }
  return 1;
}

//-----------------------------------------------------------------------------
// Specify a source object at a specified table location.
void vtkGenericGlyph3DFilter::SetSourceData(int id, vtkPolyData *pd)
{
  int numConnections = this->GetNumberOfInputConnections(1);

  if (id < 0 || id > numConnections)
  {
    vtkErrorMacro("Bad index " << id << " for source.");
    return;
  }

  vtkTrivialProducer* tp = 0;
  if (pd)
  {
    tp = vtkTrivialProducer::New();
    tp->SetOutput(pd);
  }

  if (id < numConnections)
  {
    if (tp)
    {
      this->SetNthInputConnection(1, id, tp->GetOutputPort());
    }
    else
    {
      this->SetNthInputConnection(1, id, 0);
    }
  }
  else if (id == numConnections && tp)
  {
    this->AddInputConnection(1, tp->GetOutputPort());
  }

  if (tp)
  {
    tp->Delete();
  }

}

//-----------------------------------------------------------------------------
// Get a pointer to a source object at a specified table location.
vtkPolyData *vtkGenericGlyph3DFilter::GetSource(int id)
{
  if ( id < 0 || id >= this->GetNumberOfInputConnections(1) )
  {
    return NULL;
  }
  else
  {
    return vtkPolyData::SafeDownCast(
    this->GetExecutive()->GetInputData(1, id));
  }
}

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

  os << indent << "Generate Point Ids "
     << (this->GeneratePointIds ? "On\n" : "Off\n");

  os << indent << "PointIdsName: " << (this->PointIdsName ? this->PointIdsName
                                       : "(none)") << "\n";

  os << indent << "Color Mode: " << this->GetColorModeAsString() << endl;

  if ( this->GetNumberOfInputConnections(1) < 2 )
  {
    if ( this->GetSource(0) != NULL )
    {
      os << indent << "Source: (" << this->GetSource(0) << ")\n";
    }
    else
    {
      os << indent << "Source: (none)\n";
    }
  }
  else
  {
    os << indent << "A table of " << this->GetNumberOfInputConnections(1) << " glyphs has been defined\n";
  }

  os << indent << "Scaling: " << (this->Scaling ? "On\n" : "Off\n");

  os << indent << "Scale Mode: ";
  if ( this->ScaleMode == VTK_SCALE_BY_SCALAR )
  {
    os << "Scale by scalar\n";
  }
  else if ( this->ScaleMode == VTK_SCALE_BY_VECTOR )
  {
    os << "Scale by vector\n";
  }
  else
  {
    os << "Data scaling is turned off\n";
  }

  os << indent << "Scale Factor: " << this->ScaleFactor << "\n";
  os << indent << "Clamping: " << (this->Clamping ? "On\n" : "Off\n");
  os << indent << "Range: (" << this->Range[0] << ", " << this->Range[1] << ")\n";
  os << indent << "Orient: " << (this->Orient ? "On\n" : "Off\n");
  os << indent << "Orient Mode: " << (this->VectorMode == VTK_USE_VECTOR ?
                                      "Orient by vector\n" : "Orient by normal\n");
  os << indent << "Index Mode: ";
  if ( this->IndexMode == VTK_INDEXING_BY_SCALAR )
  {
    os << "Index by scalar value\n";
  }
  else if ( this->IndexMode == VTK_INDEXING_BY_VECTOR )
  {
    os << "Index by vector value\n";
  }
  else
  {
    os << "Indexing off\n";
  }
  os << indent << "InputScalarsSelection: "
     << (this->InputScalarsSelection ? this->InputScalarsSelection : "(none)") << "\n";
  os << indent << "InputVectorsSelection: "
     << (this->InputVectorsSelection ? this->InputVectorsSelection : "(none)") << "\n";
  os << indent << "InputNormalsSelection: "
     << (this->InputNormalsSelection ? this->InputNormalsSelection : "(none)") << "\n";
}

//-----------------------------------------------------------------------------
int vtkGenericGlyph3DFilter::RequestUpdateExtent(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  // get the info objects
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  vtkInformation *sourceInfo = inputVector[1]->GetInformationObject(0);


  if (sourceInfo)
  {
    sourceInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER(),
                    0);
    sourceInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES(),
                    1);
    sourceInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS(),
                    0);
  }
  inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER(),
              outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()));
  inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES(),
              outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES()));
  inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS(),
              outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS()));
  inInfo->Set(vtkStreamingDemandDrivenPipeline::EXACT_EXTENT(), 1);

  return 1;
}

//----------------------------------------------------------------------------
int vtkGenericGlyph3DFilter
::FillInputPortInformation(int port, vtkInformation* info)
{
   if(!this->Superclass::FillInputPortInformation(port, info))
   {
    return 0;
   }
  if (port == 1)
  {
    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
  }
  else
  {
    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkGenericDataSet");
  }
  return 1;
}
