[Paraview] Tensor glyph contribution

Milan Frank milan.frank at gmail.com
Mon Mar 26 09:26:25 EST 2007


Hi all,

I would like to offer a small (and my first) contribution to the
ParaView 2.6 source code. It is a tensor glyph made available via
server manager. I am using the filter via Python interface and it
seems working fine.

There is also a little enhancement in the vtkTensorGlyph filter
itself. It is now supporting a COLOR_BY_EIGENORDER coloring mode. In
this mode a scalar value 1.0 is assigned to a glyph representing max
principal, 0.5 with mid principal and 0.0 with min principal
eigenvector.

The vtkPVTensorGlyphFilter is nearly a one to one copy of the
vtkPVGlyphFilter. It seems sufficient as there is very little
difference in the interfaces of vtkGlyph and vtkTensorGlyph.

Please, let me know if there is any interest in such contribution and
what should be done to make it more useful and easier to integrate
with ParaView source code. (By another words: is this the standard
practice to contribute?)

Thanks,
Milan.
-------------- next part --------------
/*=========================================================================

  Program:   Visualization Toolkit
  Module:    $RCSfile: vtkTensorGlyph.cxx,v $

  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 "vtkTensorGlyph.h"

#include "vtkCell.h"
#include "vtkCellArray.h"
#include "vtkDataSet.h"
#include "vtkExecutive.h"
#include "vtkFloatArray.h"
#include "vtkMath.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
#include "vtkTransform.h"

vtkCxxRevisionMacro(vtkTensorGlyph, "$Revision: 1.59 $");
vtkStandardNewMacro(vtkTensorGlyph);

// Construct object with scaling on and scale factor 1.0. Eigenvalues are 
// extracted, glyphs are colored with input scalar data, and logarithmic
// scaling is turned off.
vtkTensorGlyph::vtkTensorGlyph()
{
  this->Scaling = 1;
  this->ScaleFactor = 1.0;
  this->ExtractEigenvalues = 1;
  this->ColorGlyphs = 1;
  this->ColorMode = COLOR_BY_EIGENVALUES;
  this->ClampScaling = 0;
  this->MaxScaleFactor = 100;
  this->ThreeGlyphs = 1;
  this->Symmetric = 0;
  this->Length = 1.0;

  this->SetNumberOfInputPorts(2);

  // by default process active point tensors
  this->SetInputArrayToProcess(0,0,0,vtkDataObject::FIELD_ASSOCIATION_POINTS,
                               vtkDataSetAttributes::TENSORS);
  // by default process active point scalars
  this->SetInputArrayToProcess(1,0,0,vtkDataObject::FIELD_ASSOCIATION_POINTS,
                               vtkDataSetAttributes::SCALARS);
}

//----------------------------------------------------------------------------
vtkTensorGlyph::~vtkTensorGlyph()
{
}

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

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

  vtkDataArray *inTensors;
  double tensor[9];
  vtkDataArray *inScalars;
  vtkIdType numPts, numSourcePts, numSourceCells, inPtId, i;
  int j;
  vtkPoints *sourcePts;
  vtkDataArray *sourceNormals;
  vtkCellArray *sourceCells, *cells;  
  vtkPoints *newPts;
  vtkFloatArray *newScalars=NULL;
  vtkFloatArray *newNormals=NULL;
  double x[3], s;
  vtkTransform *trans;
  vtkCell *cell;
  vtkIdList *cellPts;
  int npts;
  vtkIdType *pts;
  vtkIdType ptIncr, cellId;
  vtkIdType subIncr;
  int numDirs, dir, eigen_dir, symmetric_dir;
  vtkMatrix4x4 *matrix;
  double *m[3], w[3], *v[3];
  double m0[3], m1[3], m2[3];
  double v0[3], v1[3], v2[3];
  double xv[3], yv[3], zv[3];
  double maxScale;
  vtkPointData *pd, *outPD;

  numDirs = (this->ThreeGlyphs?3:1)*(this->Symmetric+1);
  
  pts = new vtkIdType[source->GetMaxCellSize()];
  trans = vtkTransform::New();
  matrix = vtkMatrix4x4::New();
  
  // set up working matrices
  m[0] = m0; m[1] = m1; m[2] = m2; 
  v[0] = v0; v[1] = v1; v[2] = v2; 

  vtkDebugMacro(<<"Generating tensor glyphs");

  pd = input->GetPointData();
  outPD = output->GetPointData();
  inTensors = this->GetInputArrayToProcess(0, inputVector);
  inScalars = this->GetInputArrayToProcess(1, inputVector);
  numPts = input->GetNumberOfPoints();

  if ( !inTensors || numPts < 1 )
    {
    vtkErrorMacro(<<"No data to glyph!");
    return 1;
    }
  //
  // Allocate storage for output PolyData
  //
  sourcePts = source->GetPoints();
  numSourcePts = sourcePts->GetNumberOfPoints();
  numSourceCells = source->GetNumberOfCells();

  newPts = vtkPoints::New();
  newPts->Allocate(numDirs*numPts*numSourcePts);

  // Setting up for calls to PolyData::InsertNextCell()
  if ( (sourceCells=source->GetVerts())->GetNumberOfCells() > 0 )
    {
    cells = vtkCellArray::New();
    cells->Allocate(numDirs*numPts*sourceCells->GetSize());
    output->SetVerts(cells);
    cells->Delete();
    }
  if ( (sourceCells=this->GetSource()->GetLines())->GetNumberOfCells() > 0 )
    {
    cells = vtkCellArray::New();
    cells->Allocate(numDirs*numPts*sourceCells->GetSize());
    output->SetLines(cells);
    cells->Delete();
    }
  if ( (sourceCells=this->GetSource()->GetPolys())->GetNumberOfCells() > 0 )
    {
    cells = vtkCellArray::New();
    cells->Allocate(numDirs*numPts*sourceCells->GetSize());
    output->SetPolys(cells);
    cells->Delete();
    }
  if ( (sourceCells=this->GetSource()->GetStrips())->GetNumberOfCells() > 0 )
    {
    cells = vtkCellArray::New();
    cells->Allocate(numDirs*numPts*sourceCells->GetSize());
    output->SetStrips(cells);
    cells->Delete();
    }

  // only copy scalar data through
  pd = this->GetSource()->GetPointData();
  // generate scalars if eigenvalues are chosen or if scalars exist.
  if (this->ColorGlyphs && 
      ((this->ColorMode == COLOR_BY_EIGENVALUES) || 
       (this->ColorMode == COLOR_BY_EIGENORDER) || 
       (inScalars && (this->ColorMode == COLOR_BY_SCALARS)) ) )
    {
    newScalars = vtkFloatArray::New();
    newScalars->Allocate(numDirs*numPts*numSourcePts);
    }
  else
    {
    outPD->CopyAllOff();
    outPD->CopyScalarsOn();
    outPD->CopyAllocate(pd,numDirs*numPts*numSourcePts);
    }
  if ( (sourceNormals = pd->GetNormals()) )
    {
    newNormals = vtkFloatArray::New();
    newNormals->SetNumberOfComponents(3);
    newNormals->Allocate(numDirs*3*numPts*numSourcePts);
    }
  //
  // First copy all topology (transformation independent)
  //
  for (inPtId=0; inPtId < numPts; inPtId++)
    {
    ptIncr = numDirs * inPtId * numSourcePts;
    for (cellId=0; cellId < numSourceCells; cellId++)
      {
      cell = this->GetSource()->GetCell(cellId);
      cellPts = cell->GetPointIds();
      npts = cellPts->GetNumberOfIds();
      for (dir=0; dir < numDirs; dir++)
        {
        // This variable may be removed, but that 
        // will not improve readability
        subIncr = ptIncr + dir*numSourcePts;
        for (i=0; i < npts; i++)
          {
          pts[i] = cellPts->GetId(i) + subIncr;
          }
        output->InsertNextCell(cell->GetCellType(),npts,pts);
        }
      }
    }
  //
  // Traverse all Input points, transforming glyph at Source points
  //
  trans->PreMultiply();

  for (inPtId=0; inPtId < numPts; inPtId++)
    {
    ptIncr = numDirs * inPtId * numSourcePts;

    // Translation is postponed

    inTensors->GetTuple(inPtId, tensor);

    // compute orientation vectors and scale factors from tensor
    if ( this->ExtractEigenvalues ) // extract appropriate eigenfunctions
      {
      for (j=0; j<3; j++)
        {
        for (i=0; i<3; i++)
          {
          m[i][j] = tensor[i+3*j];
          }
        }
      vtkMath::Jacobi(m, w, v);

      //copy eigenvectors
      xv[0] = v[0][0]; xv[1] = v[1][0]; xv[2] = v[2][0];
      yv[0] = v[0][1]; yv[1] = v[1][1]; yv[2] = v[2][1];
      zv[0] = v[0][2]; zv[1] = v[1][2]; zv[2] = v[2][2];
      }
    else //use tensor columns as eigenvectors
      {
      for (i=0; i<3; i++)
        {
        xv[i] = tensor[i];
        yv[i] = tensor[i+3]; 
        zv[i] = tensor[i+6];
        }
      w[0] = vtkMath::Normalize(xv);
      w[1] = vtkMath::Normalize(yv);
      w[2] = vtkMath::Normalize(zv);
      }

    // compute scale factors
    w[0] *= this->ScaleFactor;
    w[1] *= this->ScaleFactor;
    w[2] *= this->ScaleFactor;

    //printf("eigenvalues: (%0.3f, %0.3f, %0.3f)\n", w[0], w[1], w[2]);
    
    if ( this->ClampScaling )
      {
      for (maxScale=0.0, i=0; i<3; i++)
        {
        if ( maxScale < fabs(w[i]) )
          {
          maxScale = fabs(w[i]);
          }
        }
      if ( maxScale > this->MaxScaleFactor )
        {
        maxScale = this->MaxScaleFactor / maxScale;
        for (i=0; i<3; i++)
          {
          w[i] *= maxScale; //preserve overall shape of glyph
          }
        }
      }

    // normalization is postponed

    // make sure scale is okay (non-zero) and scale data
    for (maxScale=0.0, i=0; i<3; i++)
      {
      if ( w[i] > maxScale )
        {
        maxScale = w[i];
        }
      }
    if ( maxScale == 0.0 )
      {
      maxScale = 1.0;
      }
    for (i=0; i<3; i++)
      {
      if ( w[i] == 0.0 )
        {
        w[i] = maxScale * 1.0e-06;
        }
      }

    // Now do the real work for each "direction"

    for (dir=0; dir < numDirs; dir++) 
      {
      eigen_dir = dir%(this->ThreeGlyphs?3:1);
      symmetric_dir = dir/(this->ThreeGlyphs?3:1);
        
      // Remove previous scales ...
      trans->Identity();

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

      // normalized eigenvectors rotate object for eigen direction 0
      matrix->Element[0][0] = xv[0];
      matrix->Element[0][1] = yv[0];
      matrix->Element[0][2] = zv[0];
      matrix->Element[1][0] = xv[1];
      matrix->Element[1][1] = yv[1];
      matrix->Element[1][2] = zv[1];
      matrix->Element[2][0] = xv[2];
      matrix->Element[2][1] = yv[2];
      matrix->Element[2][2] = zv[2];
      trans->Concatenate(matrix);
        
      if (eigen_dir == 1) 
        {
        trans->RotateZ(90.0);
        }

      if (eigen_dir == 2)
        {
        trans->RotateY(-90.0);
        }

      if (this->ThreeGlyphs) 
        {
        trans->Scale(w[eigen_dir], this->ScaleFactor, this->ScaleFactor);
        }
      else
        {
        trans->Scale(w[0], w[1], w[2]);
        }

      // Mirror second set to the symmetric position
      if (symmetric_dir == 1)
        {
        trans->Scale(-1.,1.,1.);
        }

      // if the eigenvalue is negative, shift to reverse direction.
      // The && is there to ensure that we do not change the 
      // old behaviour of vtkTensorGlyphs (which only used one dir), 
      // in case there is an oriented glyph, e.g. an arrow.
      if (w[eigen_dir] < 0 && numDirs > 1) 
        {
        trans->Translate(-this->Length, 0., 0.);
        }
        
      // multiply points (and normals if available) by resulting
      // matrix
      trans->TransformPoints(sourcePts,newPts); 

      // Apply the transformation to a series of points, 
      // and append the results to outPts.
      if ( newNormals )
        {
        trans->TransformNormals(sourceNormals,newNormals);
        }
        
        // Copy point data from source
      if ( this->ColorGlyphs && inScalars && 
           (this->ColorMode == COLOR_BY_SCALARS) )
        {
        s = inScalars->GetComponent(inPtId, 0);
        for (i=0; i < numSourcePts; i++) 
          {
          newScalars->InsertTuple(ptIncr+i, &s);
          }
        }
      else if (this->ColorGlyphs && 
               (this->ColorMode == COLOR_BY_EIGENVALUES) )
        {
        // If ThreeGlyphs is false we use the first (largest) 
        // eigenvalue as scalar.
        s = w[eigen_dir];
        for (i=0; i < numSourcePts; i++) 
          {
          newScalars->InsertTuple(ptIncr+i, &s);
          }
        }
      else if (this->ColorGlyphs && 
                (this->ColorMode == COLOR_BY_EIGENORDER) )
        {
        // If ThreeGlyphs is false we use the first (largest) 
        // eigenvalue as scalar.
        s = (2 - eigen_dir) * 0.5;
        for (i=0; i < numSourcePts; i++) 
          {
          newScalars->InsertTuple(ptIncr+i, &s);
          }
        }
      else
        {
        for (i=0; i < numSourcePts; i++) 
          {
          //outPD->CopyData(pd,i,ptIncr+i);
          outPD->CopyData(pd,inPtId,ptIncr+i);
          }
        }
      ptIncr += numSourcePts;
      }
    }
  vtkDebugMacro(<<"Generated " << numPts <<" tensor glyphs");
  //
  // Update output and release memory
  //
  delete [] pts;

  output->SetPoints(newPts);
  newPts->Delete();

  if ( newScalars )
    {
    newScalars->SetName("TensorScalars");
    int idx = outPD->AddArray(newScalars);
    outPD->SetActiveAttribute(idx, vtkDataSetAttributes::SCALARS);
    newScalars->Delete();
    }

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

  output->Squeeze();
  trans->Delete();
  matrix->Delete();

  return 1;
}

//----------------------------------------------------------------------------
void vtkTensorGlyph::SetSourceConnection(int id, vtkAlgorithmOutput* algOutput)
{
  if (id < 0)
    {
    vtkErrorMacro("Bad index " << id << " for source.");
    return;
    }

  int numConnections = this->GetNumberOfInputConnections(1);
  if (id < numConnections)
    {
    this->SetNthInputConnection(1, id, algOutput);
    }
  else if (id == numConnections && algOutput)
    {
    this->AddInputConnection(1, algOutput);
    }
  else if (algOutput)
    {
    vtkWarningMacro("The source id provided is larger than the maximum "
                    "source id, using " << numConnections << " instead.");
    this->AddInputConnection(1, algOutput);
    }
}

//----------------------------------------------------------------------------
void vtkTensorGlyph::SetSource(vtkPolyData *source)
{
  this->SetInput(1, source);
}

//----------------------------------------------------------------------------
vtkPolyData *vtkTensorGlyph::GetSource()
{
  if (this->GetNumberOfInputConnections(1) < 1)
    {
    return NULL;
    }
  return vtkPolyData::SafeDownCast(this->GetExecutive()->GetInputData(1, 0));
}

//----------------------------------------------------------------------------
int vtkTensorGlyph::FillInputPortInformation(int port, vtkInformation *info)
{
  if (port == 1)
    {
    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
    return 1;
    }
  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
  return 1;
}

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

  os << indent << "Source: " << this->GetSource() << "\n";
  os << indent << "Scaling: " << (this->Scaling ? "On\n" : "Off\n");
  os << indent << "Scale Factor: " << this->ScaleFactor << "\n";
  os << indent << "Extract Eigenvalues: " << (this->ExtractEigenvalues ? "On\n" : "Off\n");
  os << indent << "Color Glyphs: " << (this->ColorGlyphs ? "On\n" : "Off\n");
  os << indent << "Color Mode: " << this->ColorMode << endl;
  os << indent << "Clamp Scaling: " << (this->ClampScaling ? "On\n" : "Off\n");
  os << indent << "Max Scale Factor: " << this->MaxScaleFactor << "\n";
  os << indent << "Three Glyphs: " << (this->ThreeGlyphs ? "On\n" : "Off\n");
  os << indent << "Symmetric: " << (this->Symmetric ? "On\n" : "Off\n");
  os << indent << "Length: " << this->Length << "\n";
}
-------------- next part --------------
/*=========================================================================

  Program:   Visualization Toolkit
  Module:    $RCSfile: vtkTensorGlyph.h,v $

  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.

=========================================================================*/
// .NAME vtkTensorGlyph - scale and orient glyph(s) according to tensor eigenvalues and eigenvectors
// .SECTION Description
// vtkTensorGlyph is a filter that copies a geometric representation
// (specified as polygonal data) to every input point. The geometric
// representation, or glyph, can be scaled and/or rotated according to
// the tensor at the input point. Scaling and rotation is controlled
// by the eigenvalues/eigenvectors of the tensor as follows. For each
// tensor, the eigenvalues (and associated eigenvectors) are sorted to
// determine the major, medium, and minor eigenvalues/eigenvectors.
//
// If the boolean variable ThreeGlyphs is not set the major eigenvalue 
// scales the glyph in the x-direction, the medium in the y-direction, 
// and the minor in the  z-direction. Then, the glyph is rotated so 
// that the glyph's local x-axis lies along the major eigenvector, 
// y-axis along the medium eigenvector, and z-axis along the minor. 
//
// If the boolean variable ThreeGlyphs is set three glyphs are produced, 
// each of them oriented along an eigenvector and scaled according to the 
// corresponding eigenvector.
//
// If the boolean variable Symmetric is set each glyph is mirrored (2 or 6 
// glyphs will be produced)
//
// The x-axis of the source glyph will correspond to the eigenvector 
// on output. Point (0,0,0) in the source will be placed in the data point.
// Variable Length will normally correspond to the distance from the 
// origin to the tip of the source glyph along the x-axis, 
// but can be changed to produce other results when Symmetric is on,
// e.g. glyphs that do not touch or that overlap.
//
// Please note that when Symmetric is false it will generally be better 
// to place the source glyph from (-0.5,0,0) to (0.5,0,0), i.e. centred
// at the origin. When symmetric is true the placement from (0,0,0) to
// (1,0,0) will generally be more convenient.
//
// A scale factor is provided to control the amount of scaling. Also, you 
// can turn off scaling completely if desired. The boolean variable 
// ClampScaling controls the maximum scaling (in conjunction with
// MaxScaleFactor.) This is useful in certain applications where 
// singularities or large order of magnitude differences exist in 
// the eigenvalues.
//
// If the boolean variable ColorGlyphs is set to true the glyphs are
// colored.  The glyphs can be colored using the input scalars
// (SetColorModeToScalars), which is the default, or colored using the
// eigenvalues (SetColorModeToEigenvalues).
//
// Another instance variable, ExtractEigenvalues, has been provided to
// control extraction of eigenvalues/eigenvectors. If this boolean is
// false, then eigenvalues/eigenvectors are not extracted, and the
// columns of the tensor are taken as the eigenvectors (the norm of
// column, always positive, is the eigenvalue).  This allows
// additional capability over the vtkGlyph3D object. That is, the
// glyph can be oriented in three directions instead of one.

// .SECTION Thanks
// Thanks to Jose Paulo Moitinho de Almeida for enhancements.

// .SECTION See Also
// vtkGlyph3D vtkPointLoad vtkHyperStreamline

#ifndef __vtkTensorGlyph_h
#define __vtkTensorGlyph_h

#include "vtkPolyDataAlgorithm.h"

// If compiled as standalone application no dllexport prefix required
#ifdef MF_DEBUG
  #undef VTK_GRAPHICS_EXPORT
  #define VTK_GRAPHICS_EXPORT
  #define vtkTensorGlyph vtkTensorGlyphTest
#endif

class VTK_GRAPHICS_EXPORT vtkTensorGlyph : public vtkPolyDataAlgorithm
{
public:
  vtkTypeRevisionMacro(vtkTensorGlyph,vtkPolyDataAlgorithm);
  void PrintSelf(ostream& os, vtkIndent indent);

  // Description
  // Construct object with scaling on and scale factor 1.0. Eigenvalues are 
  // extracted, glyphs are colored with input scalar data, and logarithmic
  // scaling is turned off.
  static vtkTensorGlyph *New();

  // Description:
  // Specify the geometry to copy to each point. Old style. See
  // SetSourceConnection.
  void SetSource(vtkPolyData *source);
  vtkPolyData *GetSource();

  // Description:
  // Specify a source object at a specified table location. New style.
  // Source connection is stored in port 1. This method is equivalent
  // to SetInputConnection(1, id, outputPort).
  void SetSourceConnection(int id, vtkAlgorithmOutput* algOutput);
  void SetSourceConnection(vtkAlgorithmOutput* algOutput)
    {
      this->SetSourceConnection(0, algOutput);
    }

  // Description:
  // Turn on/off scaling of glyph with eigenvalues.
  vtkSetMacro(Scaling,int);
  vtkGetMacro(Scaling,int);
  vtkBooleanMacro(Scaling,int);

  // Description:
  // Specify scale factor to scale object by. (Scale factor always affects
  // output even if scaling is off.)
  vtkSetMacro(ScaleFactor,double);
  vtkGetMacro(ScaleFactor,double);

  // Description:
  // Turn on/off drawing three glyphs
  vtkSetMacro(ThreeGlyphs,int);
  vtkGetMacro(ThreeGlyphs,int);
  vtkBooleanMacro(ThreeGlyphs,int);

  // Description:
  // Turn on/off drawing a mirror of each glyph
  vtkSetMacro(Symmetric,int);
  vtkGetMacro(Symmetric,int);
  vtkBooleanMacro(Symmetric,int);

  // Description:
  // Set/Get the distance, along x, from the origin to the end of the 
  // source glyph. It is used to draw the symmetric glyphs.
  vtkSetMacro(Length,double);
  vtkGetMacro(Length,double);

  // Description:
  // Turn on/off extraction of eigenvalues from tensor.
  vtkSetMacro(ExtractEigenvalues,int);
  vtkBooleanMacro(ExtractEigenvalues,int);
  vtkGetMacro(ExtractEigenvalues,int);

  // Description:
  // Turn on/off coloring of glyph with input scalar data or
  // eigenvalues. If false, or input scalar data not present, then the
  // scalars from the source object are passed through the filter.
  vtkSetMacro(ColorGlyphs,int);
  vtkGetMacro(ColorGlyphs,int);
  vtkBooleanMacro(ColorGlyphs,int);

//BTX
  enum
  {
      COLOR_BY_SCALARS,
      COLOR_BY_EIGENVALUES,
      COLOR_BY_EIGENORDER
  };
//ETX

  // Description:
  // Set the color mode to be used for the glyphs.  This can be set to
  // use the input scalars (default) or to use the eigenvalues at the
  // point.  If ThreeGlyphs is set and the eigenvalues are chosen for
  // coloring then each glyph is colored by the corresponding
  // eigenvalue and if not set the color corresponding to the largest
  // eigenvalue is chosen.  The recognized values are:
  // COLOR_BY_SCALARS = 0 (default)
  // COLOR_BY_EIGENVALUES = 1
  // COLOR_BY_EIGENORDER = 2
  // vtkSetClampMacro(ColorMode, int, COLOR_BY_SCALARS, COLOR_BY_EIGENVALUES);
  vtkSetMacro(ColorMode, int);
  vtkGetMacro(ColorMode, int);
  void SetColorModeToScalars()
    {this->SetColorMode(COLOR_BY_SCALARS);};
  void SetColorModeToEigenvalues()
    {this->SetColorMode(COLOR_BY_EIGENVALUES);};  
  void SetColorModeToEigenorder()
    {this->SetColorMode(COLOR_BY_EIGENORDER);};  

  // Description:
  // Turn on/off scalar clamping. If scalar clamping is on, the ivar
  // MaxScaleFactor is used to control the maximum scale factor. (This is
  // useful to prevent uncontrolled scaling near singularities.)
  vtkSetMacro(ClampScaling,int);
  vtkGetMacro(ClampScaling,int);
  vtkBooleanMacro(ClampScaling,int);

  // Description:
  // Set/Get the maximum allowable scale factor. This value is compared to the
  // combination of the scale factor times the eigenvalue. If less, the scale
  // factor is reset to the MaxScaleFactor. The boolean ClampScaling has to 
  // be "on" for this to work.
  vtkSetMacro(MaxScaleFactor,double);
  vtkGetMacro(MaxScaleFactor,double);

protected:
  vtkTensorGlyph();
  ~vtkTensorGlyph();

  virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *);
  virtual int FillInputPortInformation(int port, vtkInformation *info);

  int Scaling; // Determine whether scaling of geometry is performed
  double ScaleFactor; // Scale factor to use to scale geometry
  int ExtractEigenvalues; // Boolean controls eigenfunction extraction
  int ColorGlyphs; // Boolean controls coloring with input scalar data
  int ColorMode; // The coloring mode to use for the glyphs.
  int ClampScaling; // Boolean controls whether scaling is clamped.
  double MaxScaleFactor; // Maximum scale factor (ScaleFactor*eigenvalue)
  int ThreeGlyphs; // Boolean controls drawing 1 or 3 glyphs
  int Symmetric; // Boolean controls drawing a "mirror" of each glyph
  double Length; // Distance, in x, from the origin to the end of the glyph
private:
  vtkTensorGlyph(const vtkTensorGlyph&);  // Not implemented.
  void operator=(const vtkTensorGlyph&);  // Not implemented.
};

#endif
-------------- next part --------------
/*=========================================================================

  Program:   ParaView
  Module:    $RCSfile: vtkPVTensorGlyphFilter.cxx,v $

  Copyright (c) Kitware, Inc.
  All rights reserved.
  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html 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 "vtkPVTensorGlyphFilter.h"

#include "vtkAppendPolyData.h"
#include "vtkCompositeDataPipeline.h"
#include "vtkCompositeDataIterator.h"
#include "vtkCompositeDataSet.h"
#include "vtkGarbageCollector.h"
#include "vtkHierarchicalBoxDataSet.h"
#include "vtkMultiGroupDataInformation.h"
#include "vtkMultiGroupDataSet.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkMaskPoints.h"
#include "vtkMath.h"
#include "vtkMultiProcessController.h"
#include "vtkObjectFactory.h"
#include "vtkPolyData.h"
#include "vtkProcessModule.h"
#include "vtkUniformGrid.h"

vtkCxxRevisionMacro(vtkPVTensorGlyphFilter, "$Revision: 1.26.10.2 $");
vtkStandardNewMacro(vtkPVTensorGlyphFilter);

//-----------------------------------------------------------------------------
vtkPVTensorGlyphFilter::vtkPVTensorGlyphFilter()
{
  this->MaskPoints = vtkMaskPoints::New();
  this->RandomMode = this->MaskPoints->GetRandomMode();
  this->MaximumNumberOfPoints = 5000;
  this->NumberOfProcesses = vtkMultiProcessController::GetGlobalController() ?
    vtkMultiProcessController::GetGlobalController()->GetNumberOfProcesses() : 1;
  this->UseMaskPoints = 1;
  this->InputIsUniformGrid = 0;

  this->BlockOnRatio = 0;
  this->BlockMaxNumPts = 0;
  this->BlockPointCounter = 0;
  this->BlockNumPts = 0;
}

//-----------------------------------------------------------------------------
vtkPVTensorGlyphFilter::~vtkPVTensorGlyphFilter()
{
  if(this->MaskPoints)
    {
    this->MaskPoints->Delete();
    }
}

//-----------------------------------------------------------------------------
void vtkPVTensorGlyphFilter::SetRandomMode(int mode)
{
  if ( mode == this->MaskPoints->GetRandomMode() )
    {
    return;
    }
  this->MaskPoints->SetRandomMode(mode);
  // Store random mode to so that we don't have to call
  // MaskPoints->GetRandomMode() in tight loop.
  this->RandomMode = mode;
  this->Modified();
}

//-----------------------------------------------------------------------------
int vtkPVTensorGlyphFilter::GetRandomMode()
{
  return this->MaskPoints->GetRandomMode();
}

//----------------------------------------------------------------------------
int vtkPVTensorGlyphFilter::FillInputPortInformation(int port,
                                               vtkInformation* info)
{
  if(!this->Superclass::FillInputPortInformation(port, info))
    {
    return 0;
    }
  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataObject");

  return 1;
}

//----------------------------------------------------------------------------
vtkExecutive* vtkPVTensorGlyphFilter::CreateDefaultExecutive()
{
  return vtkCompositeDataPipeline::New();
}

//-----------------------------------------------------------------------------
vtkIdType vtkPVTensorGlyphFilter::GatherTotalNumberOfPoints(vtkIdType localNumPts)
{
  // Although this is not perfectly process invariant, it is better
  // than we had before (divide by number of processes).
  vtkIdType totalNumPts = localNumPts;
  vtkMultiProcessController *controller = 
    vtkMultiProcessController::GetGlobalController();
  if (controller)
    {
    vtkIdType tmp;
    // This could be done much easier with MPI specific calls.
    if (controller->GetLocalProcessId() == 0)
      {
      int i;
      // Sum points on all processes.
      for (i = 1; i < controller->GetNumberOfProcesses(); ++i)
        {
        controller->Receive(&tmp, 1, i, vtkProcessModule::GlyphNPointsGather);
        totalNumPts += tmp;
        }
      // Send results back to all processes.
      for (i = 1; i < controller->GetNumberOfProcesses(); ++i)
        {
        controller->Send(&totalNumPts, 1, 
                         i, vtkProcessModule::GlyphNPointsScatter);
        }
      }
    else
      {
      controller->Send(&localNumPts, 1, 
                       0, vtkProcessModule::GlyphNPointsGather);
      controller->Receive(&totalNumPts, 1, 
                          0, vtkProcessModule::GlyphNPointsScatter);
      }
    }

  return totalNumPts;
}

//-----------------------------------------------------------------------------
int vtkPVTensorGlyphFilter::RequestData(
  vtkInformation *request,
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  this->BlockOnRatio = 0;

  vtkMath::RandomSeed(123456);
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkDataObject* input = inInfo->Get(vtkDataObject::DATA_OBJECT());
  vtkCompositeDataSet *hdInput = 
    vtkCompositeDataSet::SafeDownCast(input);
  if (hdInput) 
    {
    return this->RequestCompositeData(request, inputVector, outputVector);
    }

  vtkDataSet* dsInput = vtkDataSet::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));

  if (!dsInput)
    {
    if (input)
      {
      vtkErrorMacro("This filter cannot process input of type: "
                    << input->GetClassName());
      }
    return 0;
    }

  if (!this->UseMaskPoints)
    {
    return this->Superclass::RequestData(request, inputVector, outputVector);
    }

  vtkIdType maxNumPts = this->MaximumNumberOfPoints;
  vtkIdType numPts = dsInput->GetNumberOfPoints();

  vtkIdType totalNumPts = this->GatherTotalNumberOfPoints(numPts);

  // What fraction of the points will this processes get allocated?
  maxNumPts = (vtkIdType)(
    (double)(maxNumPts)*(double)(numPts)/(double)(totalNumPts));
  
  maxNumPts = (maxNumPts < 1) ? 1 : maxNumPts;

  vtkInformationVector* inputVs[2];
  
  vtkInformationVector* inputV = inputVector[0];
  inputVs[0] = vtkInformationVector::New();
  inputVs[0]->SetNumberOfInformationObjects(1);
  vtkInformation* newInInfo = vtkInformation::New();
  newInInfo->Copy(inputV->GetInformationObject(0));
  inputVs[0]->SetInformationObject(0, newInInfo);
  newInInfo->Delete();
  inputVs[1] = inputVector[1];
  
  int retVal = this->MaskAndExecute(numPts, maxNumPts, dsInput,
                                    request, inputVs, outputVector);
  inputVs[0]->Delete();
  return retVal;
}

//----------------------------------------------------------------------------
int vtkPVTensorGlyphFilter::MaskAndExecute(vtkIdType numPts, vtkIdType maxNumPts,
                                     vtkDataSet* input,
                                     vtkInformation* request,
                                     vtkInformationVector **inputVector,
                                     vtkInformationVector *outputVector)

{
  vtkDataSet* inputCopy = input->NewInstance();
  inputCopy->ShallowCopy(input);
  this->MaskPoints->SetInput(inputCopy);
  inputCopy->Delete();

  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  this->MaskPoints->SetMaximumNumberOfPoints(maxNumPts);
  this->MaskPoints->SetOnRatio(numPts / maxNumPts);

  vtkInformation *maskPointsInfo =
    this->MaskPoints->GetExecutive()->GetOutputInformation(0);
  maskPointsInfo->Set(
    vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES(),
    outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES()));
  maskPointsInfo->Set(
    vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER(),
    outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()));
  maskPointsInfo->Set(
    vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS(),
    outInfo->Get(
      vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS()));
  this->MaskPoints->Update();

  vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
  inInfo->Set(vtkDataObject::DATA_OBJECT(), this->MaskPoints->GetOutput());

  return this->Superclass::RequestData(request, inputVector, outputVector);
}

//----------------------------------------------------------------------------
int vtkPVTensorGlyphFilter::IsPointVisible(vtkDataSet* ds, vtkIdType ptId)
{
  if (this->BlockOnRatio == 0)
    {
    return 1;
    }

  if (this->InputIsUniformGrid)
    {
    vtkUniformGrid* ug = static_cast<vtkUniformGrid*>(ds);
    if(!ug->IsPointVisible(ptId))
      {
      return 0;
      }
    }

  if (this->BlockNumPts < this->BlockMaxNumPts &&
      this->BlockPointCounter++ == this->BlockNextPoint)
    {
    this->BlockNumPts++;
    if (this->RandomMode)
      {
      this->BlockNextPoint += static_cast<vtkIdType>(
        1+2*vtkMath::Random()*this->BlockOnRatio);
      }
    else
      {
      this->BlockNextPoint += static_cast<vtkIdType>(this->BlockOnRatio);
      }
    return 1;
    }

  return 0;
}

//----------------------------------------------------------------------------
int vtkPVTensorGlyphFilter::RequestCompositeData(vtkInformation* request,
                                           vtkInformationVector** inputVector,
                                           vtkInformationVector* outputVector)
{
  vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);

  vtkMultiGroupDataSet *hdInput = vtkMultiGroupDataSet::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));

  vtkInformation* info = outputVector->GetInformationObject(0);
  vtkPolyData *output = vtkPolyData::SafeDownCast(
    info->Get(vtkDataObject::DATA_OBJECT()));
  if (!output) {return 0;}

  vtkIdType maxNumPts = this->MaximumNumberOfPoints;
  vtkIdType numPts = hdInput->GetNumberOfPoints();
  vtkIdType totalNumPts = this->GatherTotalNumberOfPoints(numPts);

  vtkAppendPolyData* append = vtkAppendPolyData::New();
  int numInputs = 0;

  vtkInformationVector* inputVs[2];
  
  vtkInformationVector* inputV = inputVector[0];
  inputVs[0] = vtkInformationVector::New();
  inputVs[0]->SetNumberOfInformationObjects(1);
  vtkInformation* newInInfo = vtkInformation::New();
  newInInfo->Copy(inputV->GetInformationObject(0));
  inputVs[0]->SetInformationObject(0, newInInfo);
  newInInfo->FastDelete();
  inputVs[1] = inputVector[1];

  int retVal = 1;
  this->InputIsUniformGrid = 0;

  vtkCompositeDataIterator* iter = hdInput->NewIterator();

  while(!iter->IsDoneWithTraversal())
    {
    vtkDataSet* ds = vtkDataSet::SafeDownCast(iter->GetCurrentDataObject());
    if (ds)
      {
      vtkPolyData* tmpOut = vtkPolyData::New();
      
      if (ds->IsA("vtkUniformGrid"))
        {
        this->InputIsUniformGrid = 1;
        }
      else
        {
        this->InputIsUniformGrid = 0;
        }
      
      vtkIdType numBlankedPts = 0;
      vtkInformation* blockInfo = iter->GetCurrentInformationObject();
      if (blockInfo)
        {
        if (blockInfo->Has(
              vtkHierarchicalBoxDataSet::NUMBER_OF_BLANKED_POINTS()))
          {
          numBlankedPts = blockInfo->Get(
            vtkHierarchicalBoxDataSet::NUMBER_OF_BLANKED_POINTS());
          }
        }
      vtkIdType blockNumPts = ds->GetNumberOfPoints() - numBlankedPts;
      // What fraction of the points will this processes get allocated?
      vtkIdType blockMaxNumPts = (vtkIdType)(
        (double)(maxNumPts)*(double)(blockNumPts)/(double)(totalNumPts));
      this->BlockMaxNumPts = (blockMaxNumPts < 1) ? 1 : blockMaxNumPts;
      if (this->UseMaskPoints)
        {
        this->BlockOnRatio = blockNumPts/this->BlockMaxNumPts;
        }
      this->BlockPointCounter = 0;
      this->BlockNumPts = 0;
      if (this->MaskPoints->GetRandomMode())
        {
        this->BlockNextPoint = static_cast<vtkIdType>(
          1+vtkMath::Random()*this->BlockOnRatio);
        }
      else
        {
        this->BlockNextPoint = static_cast<vtkIdType>(1+this->BlockOnRatio);
        }
        
      retVal = this->MaskAndExecute(blockNumPts, blockMaxNumPts, ds, request, inputVs, outputVector);
      //newInInfo->Set(vtkDataObject::DATA_OBJECT(), ds);
      //retVal = 
      //  this->Superclass::RequestData(request, inputVs, outputVector);
      
      tmpOut->ShallowCopy(output);
      
      append->AddInput(tmpOut);
      
      // Call FastDelete() instead of Delete() to avoid garbage
      // collection checks. This improves the preformance significantly
      tmpOut->FastDelete();
      if (!retVal)
        {
        break;
        }
      numInputs++;
      }
    iter->GoToNextItem();
    }
  iter->Delete();
  inputVs[0]->Delete();

  if (retVal)
    {
    if (numInputs > 0)
      {
      append->Update();
      }
    
    output->ShallowCopy(append->GetOutput());
    
    append->Delete();
    }

  return retVal;
}

//-----------------------------------------------------------------------------
void vtkPVTensorGlyphFilter::ReportReferences(vtkGarbageCollector* collector)
{
  this->Superclass::ReportReferences(collector);
  vtkGarbageCollectorReport(collector, this->MaskPoints, "MaskPoints");
}

//-----------------------------------------------------------------------------
void vtkPVTensorGlyphFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  
  os << indent << "MaximumNumberOfPoints: " << this->GetMaximumNumberOfPoints()
     << endl;

  os << indent << "UseMaskPoints: " << (this->UseMaskPoints?"on":"off") << endl;

  os << indent << "NumberOfProcesses: " << this->NumberOfProcesses << endl;
}
-------------- next part --------------
/*=========================================================================

  Program:   ParaView
  Module:    $RCSfile: vtkPVTensorGlyphFilter.h,v $

  Copyright (c) Kitware, Inc.
  All rights reserved.
  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html 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.

=========================================================================*/
// .NAME vtkPVTensorGlyphFilter - Glyph filter
//
// .SECTION Description
// This is a subclass of vtkGlyph3D that allows selection of input scalars

#ifndef __vtkPVTensorGlyphFilter_h
#define __vtkPVTensorGlyphFilter_h

#include "vtkTensorGlyph.h"

class vtkMaskPoints;

class VTK_EXPORT vtkPVTensorGlyphFilter : public vtkTensorGlyph
{
public:
  vtkTypeRevisionMacro(vtkPVTensorGlyphFilter,vtkTensorGlyph);
  void PrintSelf(ostream& os, vtkIndent indent);

  // Description
  static vtkPVTensorGlyphFilter *New();

  // Description:
  // Limit the number of points to glyph
  vtkSetMacro(MaximumNumberOfPoints, int);
  vtkGetMacro(MaximumNumberOfPoints, int);

  // Description:
  // Get the number of processes used to run this filter.
  vtkGetMacro(NumberOfProcesses, int);
  
  // Description:
  // Set/get whether to mask points
  vtkSetMacro(UseMaskPoints, int);
  vtkGetMacro(UseMaskPoints, int);

  // Description:
  // Set/get flag to cause randomization of which points to mask.
  void SetRandomMode(int mode);
  int GetRandomMode();

  // Description:
  // In processing composite datasets, will check if a point
  // is visible as long as the dataset being process if a
  // vtkUniformGrid.
  virtual int IsPointVisible(vtkDataSet* ds, vtkIdType ptId);

protected:
  vtkPVTensorGlyphFilter();
  ~vtkPVTensorGlyphFilter();

  virtual int RequestData(vtkInformation *, 
                          vtkInformationVector **, 
                          vtkInformationVector *);
  virtual int RequestCompositeData(vtkInformation* request,
                                   vtkInformationVector** inputVector,
                                   vtkInformationVector* outputVector);

  virtual int FillInputPortInformation(int, vtkInformation*);

  // Create a default executive.
  virtual vtkExecutive* CreateDefaultExecutive();
  
  vtkIdType GatherTotalNumberOfPoints(vtkIdType localNumPts);

  int MaskAndExecute(vtkIdType numPts, vtkIdType maxNumPts,
                     vtkDataSet* input,
                     vtkInformation* request,
                     vtkInformationVector** inputVector,
                     vtkInformationVector* outputVector);

  vtkMaskPoints *MaskPoints;
  int MaximumNumberOfPoints;
  int NumberOfProcesses;
  int UseMaskPoints;
  int InputIsUniformGrid;
  
  vtkIdType BlockMaxNumPts;
  vtkIdType BlockOnRatio;
  vtkIdType BlockPointCounter;
  vtkIdType BlockNextPoint;
  vtkIdType BlockNumPts;

  int RandomMode;

  virtual void ReportReferences(vtkGarbageCollector*);
private:
  vtkPVTensorGlyphFilter(const vtkPVTensorGlyphFilter&);  // Not implemented.
  void operator=(const vtkPVTensorGlyphFilter&);  // Not implemented.
};

#endif
-------------- next part --------------
A non-text attachment was scrubbed...
Name: filters_tensorglyph.xml
Type: text/xml
Size: 6958 bytes
Desc: not available
Url : http://public.kitware.com/pipermail/paraview/attachments/20070326/fcf0c846/filters_tensorglyph-0001.bin


More information about the ParaView mailing list