Commit b2943322 authored by Will Schroeder's avatar Will Schroeder

ENH:Plot data along arbitary arcs

parent 6c5ba8e8
......@@ -22,6 +22,7 @@ ABSTRACT = \
vtkWarpTransform
CONCRETE = \
vtkArcPlotter \
vtkDEMReader \
vtkEarthSource \
vtkImageReslice \
......
/*=========================================================================
Program: Visualization Toolkit
Module: vtkArcPlotter.cxx
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) 1993-2000 Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
of any contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
* Modified source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=========================================================================*/
#include "vtkArcPlotter.h"
#include "vtkMath.h"
#include "vtkPlane.h"
vtkArcPlotter::vtkArcPlotter()
{
this->Camera = NULL;
this->PlotMode = VTK_PLOT_SCALARS;
this->PlotComponent = (-1); //plot all components
this->Radius = 0.5;
this->Height = 0.5;
this->Offset = 0.0;
this->DefaultNormal[0] = this->DefaultNormal[1] = 0.0;
this->DefaultNormal[2] = 1.0;
this->UseDefaultNormal = 0;
this->FieldDataArray = 0;
this->DataRange = NULL;
this->Tuple = NULL;
this->ActiveComponent = 0;
this->NumberOfComponents = 0;
}
vtkArcPlotter::~vtkArcPlotter()
{
if ( this->DataRange )
{
delete [] this->DataRange;
delete [] this->Tuple;
}
}
void vtkArcPlotter::Execute()
{
vtkPolyData *input=this->GetInput();
vtkPolyData *output=this->GetOutput();
vtkPointData *inPD=input->GetPointData();
vtkPointData *outPD=output->GetPointData();
vtkPoints *inPts;
vtkCellArray *inLines;
int numPts, i, j;
float x[3], normal[3], point[3], aveNormal[3];
int npts, *pts, id;
float *x1, *x2, x21[3], n[3];
vtkNormals *lineNormals;
vtkPoints *newPts;
vtkCellArray *newLines;
float *range, offset;
int plotNum, compNum;
vtkPoints *projPts;
// Initialize
//
vtkDebugMacro(<<"Plotting along arc");
if ( !(inPts=input->GetPoints()) ||
(numPts = inPts->GetNumberOfPoints()) < 1 ||
!(inLines = input->GetLines()) || inLines->GetNumberOfCells() < 1 )
{
vtkErrorMacro(<< "No input data!");
return;
}
// Process attribute data to determine ranges, cumber of components, etc.
if ( this->ProcessComponents(numPts, inPD) <= 0 )
{
return;
}
// Allocate points for projection
//
// Determine the projection plane. Project to a plane if camera is available
// and defulat normal is not desired.
if ( this->Camera && ! this->UseDefaultNormal )
{
float xProj[3];
projPts = vtkPoints::New();
projPts->SetNumberOfPoints(numPts);
this->Camera->GetViewPlaneNormal(normal);
this->Camera->GetFocalPoint(point);
vtkMath::Normalize(normal);
for ( i=0; i < numPts; i++ )
{
inPts->GetPoint(i, x);
vtkPlane::ProjectPoint(x, point, normal, xProj);
projPts->SetPoint(i,xProj);
}
}
else
{
normal[0] = this->DefaultNormal[0];
normal[1] = this->DefaultNormal[1];
normal[2] = this->DefaultNormal[2];
vtkMath::Normalize(normal);
projPts = inPts; //use existing points
}
// For each polyline, compute a normal that lies in the
// projection plane and is roughly perpendicular to the projected
// polyline. Then generate the arc.
//
newPts = vtkPoints::New();
newPts->Allocate(numPts,numPts);
lineNormals = vtkNormals::New();
newLines = vtkCellArray::New();
newLines->Allocate(inLines->GetSize());
for (inLines->InitTraversal(); inLines->GetNextCell(npts,pts); )
{
lineNormals->SetNumberOfNormals(npts);
if ( !this->Camera || this->UseDefaultNormal )
{//use default normal
for (i=0; i < npts; i++)
{
lineNormals->SetNormal(i,normal);
}
}
else //generate normals
{
// Compute normals on each line segment perpendicular to view normal
for (i=0; i < (npts-1); i++)
{
x1 = projPts->GetPoint(pts[i]);
x2 = projPts->GetPoint(pts[i+1]);
for (j=0; j<3; j++)
{
x21[j] = x2[j] - x1[j];
}
vtkMath::Cross(normal,x21,n);
vtkMath::Normalize(n);
lineNormals->SetNormal(i,n);
}
lineNormals->SetNormal(npts-1,n);
}
// Now average the normal calculation to get smoother results
//
int window = npts / 100;
if ( window < 5 )
{
window = 5;
}
// Start by computing an initial average normal
aveNormal[0] = aveNormal[1] = aveNormal[2] = 0.0;
for (i=0; i < npts && i < window; i++)
{
lineNormals->GetNormal(i,n);
aveNormal[0] += n[0]; aveNormal[1] += n[1]; aveNormal[2] += n[2];
}
for (i=0; i < npts; i++)
{
if ( (i+window) < npts )
{
lineNormals->GetNormal(i+window,n);
aveNormal[0] += n[0]; aveNormal[1] += n[1]; aveNormal[2] += n[2];
}
if ( (i-window) >= 0 )
{
lineNormals->GetNormal(i-window,n);
aveNormal[0] -= n[0]; aveNormal[1] -= n[1]; aveNormal[2] -= n[2];
}
n[0] = aveNormal[0]; n[1] = aveNormal[1]; n[2] = aveNormal[2];
vtkMath::Normalize(n);
lineNormals->SetNormal(i, n);
}
// For each component, create an offset plot.
for (plotNum=0, compNum=this->StartComp; compNum <= this->EndComp;
compNum++, plotNum++)
{
offset = this->Radius + plotNum*this->Offset;
range = this->DataRange + 2*compNum;
newLines->InsertNextCell(npts);
// Continue average normal computation using sliding window
for (i=0; i < npts; i++)
{
this->Data->GetTuple(pts[i], this->Tuple);
lineNormals->GetNormal(i,n);
id = this->OffsetPoint(pts[i], inPts, n, newPts,
offset, range, this->Tuple[compNum]);
newLines->InsertCellPoint(id);
}
} //for all components
} //for all polylines
lineNormals->Delete();
if ( projPts != inPts )
{
projPts->Delete();
}
// Update output
output->SetPoints(newPts);
newPts->Delete();
output->SetLines(newLines);
newLines->Delete();
}
int vtkArcPlotter::ProcessComponents(int numPts, vtkPointData *pd)
{
int i, j;
float *range;
vtkFieldData *fd;
this->Data = NULL;
switch (this->PlotMode)
{
case VTK_PLOT_SCALARS:
if ( pd->GetScalars() )
{
this->Data = pd->GetScalars()->GetData();
}
break;
case VTK_PLOT_VECTORS:
if ( pd->GetVectors() )
{
this->Data = pd->GetVectors()->GetData();
}
break;
case VTK_PLOT_NORMALS:
if ( pd->GetNormals() )
{
this->Data = pd->GetNormals()->GetData();
}
break;
case VTK_PLOT_TCOORDS:
if ( pd->GetTCoords() )
{
this->Data = pd->GetTCoords()->GetData();
}
break;
case VTK_PLOT_TENSORS:
if ( pd->GetTensors() )
{
this->Data = pd->GetTensors()->GetData();
}
break;
case VTK_PLOT_FIELD_DATA:
if ( (fd=pd->GetFieldData()) )
{
int arrayNum = (this->FieldDataArray < fd->GetNumberOfArrays() ?
this->FieldDataArray : fd->GetNumberOfArrays() - 1);
this->Data = pd->GetFieldData()->GetArray(arrayNum);
}
break;
}
// Determine the number of components
if ( this->Data )
{
this->NumberOfComponents = this->Data->GetNumberOfComponents();
if ( this->PlotComponent >= 0 )
{
this->ActiveComponent = (this->PlotComponent < this->NumberOfComponents ?
this->PlotComponent : this->NumberOfComponents - 1);
this->StartComp = this->EndComp = this->ActiveComponent;
}
else
{
this->StartComp = 0;
this->EndComp = this->NumberOfComponents - 1;
}
}
else
{
vtkErrorMacro(<<"Need input data to plot");
return 0;
}
// Get the range of the components (for scaling the plot later)
if ( this->DataRange )
{
delete [] this->DataRange;
delete [] this->Tuple;
}
this->DataRange = new float [2*this->NumberOfComponents];
this->Tuple = new float [this->NumberOfComponents];
for (i=this->StartComp; i <= this->EndComp; i++)
{
range = this->DataRange + 2*i;
range[0] = VTK_LARGE_FLOAT;
range[1] = -VTK_LARGE_FLOAT;
}
for (i=0; i<numPts; i++)
{
this->Data->GetTuple(i, this->Tuple);
for (j=this->StartComp; j <= this->EndComp; j++)
{
range = this->DataRange + 2*j;
if ( this->Tuple[j] < range[0] )
{
range[0] = this->Tuple[j];
}
if ( this->Tuple[j] > range[1] )
{
range[1] = this->Tuple[j];
}
}
}
return this->NumberOfComponents;
}
int vtkArcPlotter::OffsetPoint(int ptId, vtkPoints *inPts, float n[3],
vtkPoints *newPts, float offset, float *range, float v)
{
float x[3], xNew[3];
int i;
float median = (range[0] + range[1])/2.0;
float denom = range[1] - range[0];
inPts->GetPoint(ptId, x);
for (i=0; i<3; i++)
{
xNew[i] = x[i] + n[i] * (offset + ((v - median)/denom)*this->Height);
}
return newPts->InsertNextPoint(xNew);
}
unsigned long vtkArcPlotter::GetMTime()
{
unsigned long mTime=this->vtkPolyDataToPolyDataFilter::GetMTime();
unsigned long cameraMTime;
if ( this->Camera && ! this->UseDefaultNormal )
{
cameraMTime = this->Camera->GetMTime();
return (cameraMTime > mTime ? cameraMTime : mTime);
}
else
{
return mTime;
}
}
void vtkArcPlotter::PrintSelf(ostream& os, vtkIndent indent)
{
vtkPolyDataToPolyDataFilter::PrintSelf(os,indent);
if ( this->Camera )
{
os << indent << "Camera:\n";
this->Camera->PrintSelf(os,indent.GetNextIndent());
}
else
{
os << indent << "Camera: (none)\n";
}
os << indent << "Plot Mode: ";
if ( this->PlotMode == VTK_PLOT_SCALARS )
{
os << "Plot Scalars\n";
}
else if ( this->PlotMode == VTK_PLOT_VECTORS )
{
os << "Plot Vectors\n";
}
else if ( this->PlotMode == VTK_PLOT_NORMALS )
{
os << "Plot Normals\n";
}
else if ( this->PlotMode == VTK_PLOT_TCOORDS )
{
os << "Plot TCoords\n";
}
else if ( this->PlotMode == VTK_PLOT_TENSORS )
{
os << "Plot Tensors\n";
}
else
{
os << "Plot Field Data\n";
}
os << indent << "Plot Component: ";
if ( this->PlotComponent < 0 )
{
os << "(All Components)\n";
}
else
{
os << this->PlotComponent << "\n";
}
os << indent << "Field Data Array: " << this->FieldDataArray << "\n";
os << indent << "Use Default Normal: "
<< (this->UseDefaultNormal ? "On\n" : "Off\n");
os << indent << "Default Normal: " << "( " << this->DefaultNormal[0]
<< ", " << this->DefaultNormal[1] << ", " << this->DefaultNormal[2]
<< " )\n";
os << indent << "Radius: " << this->Radius << "\n";
os << indent << "Height: " << this->Height << "\n";
os << indent << "Offset: " << this->Offset << "\n";
}
/*=========================================================================
Program: Visualization Toolkit
Module: vtkArcPlotter.h
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) 1993-2000 Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
of any contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
* Modified source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=========================================================================*/
// .NAME vtkArcPlotter - plot data along an arbitrary polyline
// .SECTION Description
// vtkArcPlotter performs plotting of attribute data along polylines defined
// with an input vtkPolyData data object. Any type of attribute data can be
// plotted including scalars, vectors, tensors, normals, texture coordinates,
// and field data. Either one or multiple data components can be plotted.
//
// To use this class you must specify an input data set that contains one or
// more polylines, and some attribute data including which component of the
// attribute data. (By default, this class processes the first component of
// scalar data.) You will also need to set an offset radius (the distance
// of the polyline to the median line of the plot), a width for the plot
// (the distance that the minimum and maximum plot values are mapped into),
// an possibly an offset (used to offset attribute data with multiple
// components).
//
// Normally the filter automatically computes normals for generating the
// offset arc plot. However, you can specify a default normal and use that
// instead.
// .SECTION See Also
// vtkXYPlotActor
#ifndef __vtkArcPlotter_h
#define __vtkArcPlotter_h
#include "vtkPolyDataToPolyDataFilter.h"
#include "vtkCamera.h"
#define VTK_PLOT_SCALARS 1
#define VTK_PLOT_VECTORS 2
#define VTK_PLOT_NORMALS 3
#define VTK_PLOT_TCOORDS 4
#define VTK_PLOT_TENSORS 5
#define VTK_PLOT_FIELD_DATA 6
class VTK_EXPORT vtkArcPlotter : public vtkPolyDataToPolyDataFilter
{
public:
// Description:
// Instantiate with no default camera and plot mode set to
// VTK_SCALARS.
static vtkArcPlotter *New() {return new vtkArcPlotter;};
vtkTypeMacro(vtkArcPlotter,vtkPolyDataToPolyDataFilter);
void PrintSelf(ostream& os, vtkIndent indent);
// Description:
// Specify a camera used to orient the plot along the arc. If no camera
// is specified, then the orientation of the plot is arbitrary.
vtkSetObjectMacro(Camera,vtkCamera);
vtkGetObjectMacro(Camera,vtkCamera);
// Description:
// Specify which data to plot: scalars, vectors, normals, texture coords,
// tensors, or field data. If the data has more than one component, use
// the method SetPlotComponent to control which component to plot.
vtkSetMacro(PlotMode, int);
vtkGetMacro(PlotMode, int);
void SetPlotModeToPlotScalars() {this->SetPlotMode(VTK_PLOT_SCALARS);};
void SetPlotModeToPlotVectors() {this->SetPlotMode(VTK_PLOT_VECTORS);};
void SetPlotModeToPlotNormals() {this->SetPlotMode(VTK_PLOT_NORMALS);};
void SetPlotModeToPlotTCoords() {this->SetPlotMode(VTK_PLOT_TCOORDS);};
void SetPlotModeToPlotTensors() {this->SetPlotMode(VTK_PLOT_TENSORS);};
void SetPlotModeToPlotFieldData()
{this->SetPlotMode(VTK_PLOT_FIELD_DATA);};
// Description:
// Set/Get the component number to plot if the data has more than one
// component. If the value of the plot component is == (-1), then all
// the components will be plotted.
vtkSetMacro(PlotComponent,int);
vtkGetMacro(PlotComponent,int);
// Description:
// Set the radius of the "median" value of the first plotted component.
vtkSetClampMacro(Radius,float,0.0,VTK_LARGE_FLOAT);
vtkGetMacro(Radius,float);
// Description:
// Set the height of the plot. (The radius combined with the height
// define the location of the plot relative to the generating polyline.)
vtkSetClampMacro(Height,float,0.0,VTK_LARGE_FLOAT);
vtkGetMacro(Height,float);
// Description:
// Specify an offset that translates each subsequent plot (if there is
// more than one component plotted) from the defining arc (i.e., polyline).
vtkSetClampMacro(Offset, float, 0.0, VTK_LARGE_FLOAT);
vtkGetMacro(Offset, float);
// Description:
// Set a boolean to control whether to use default normals.
// By default, normals are automatically computed from the generating
// polyline and camera.
vtkSetMacro(UseDefaultNormal,int);
vtkGetMacro(UseDefaultNormal,int);
vtkBooleanMacro(UseDefaultNormal,int);
// Description:
// Set the default normal to use if you do not wish automatic normal
// calculation. The arc plot will be generated using this normal.
vtkSetVector3Macro(DefaultNormal,float);
vtkGetVectorMacro(DefaultNormal,float,3);
// Description:
// Set/Get the field data array to plot. This instance variable is
// only applicable if field data is plotted.
vtkSetClampMacro(FieldDataArray,int,0,VTK_LARGE_INTEGER);
vtkGetMacro(FieldDataArray,int);
// Description:
// New GetMTime because of camera dependency.
unsigned long GetMTime();
protected:
vtkArcPlotter();
~vtkArcPlotter();
vtkArcPlotter(const vtkArcPlotter&) {};
void operator=(const vtkArcPlotter&) {};