You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
460 lines
12 KiB
460 lines
12 KiB
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: $RCSfile: vtkArcPlotter.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 "vtkArcPlotter.h"
|
|
|
|
#include "vtkCamera.h"
|
|
#include "vtkCellArray.h"
|
|
#include "vtkFloatArray.h"
|
|
#include "vtkMath.h"
|
|
#include "vtkInformation.h"
|
|
#include "vtkInformationVector.h"
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkPlane.h"
|
|
#include "vtkPointData.h"
|
|
#include "vtkPolyData.h"
|
|
|
|
vtkCxxRevisionMacro(vtkArcPlotter, "$Revision: 1.25 $");
|
|
vtkStandardNewMacro(vtkArcPlotter);
|
|
|
|
vtkCxxSetObjectMacro(vtkArcPlotter,Camera,vtkCamera);
|
|
|
|
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;
|
|
}
|
|
if ( this->Camera )
|
|
{
|
|
this->Camera->UnRegister (this);
|
|
this->Camera = NULL;
|
|
}
|
|
}
|
|
|
|
int vtkArcPlotter::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 ouptut
|
|
vtkPolyData *input = vtkPolyData::SafeDownCast(
|
|
inInfo->Get(vtkDataObject::DATA_OBJECT()));
|
|
vtkPolyData *output = vtkPolyData::SafeDownCast(
|
|
outInfo->Get(vtkDataObject::DATA_OBJECT()));
|
|
|
|
vtkPointData *inPD;
|
|
vtkPoints *inPts;
|
|
vtkCellArray *inLines;
|
|
int j;
|
|
vtkIdType numPts, i;
|
|
double x[3], normal[3], point[3], aveNormal[3];
|
|
int id;
|
|
vtkIdType *pts = 0;
|
|
vtkIdType npts = 0;
|
|
double x1[3], x2[3], x21[3], n[3];
|
|
vtkFloatArray *lineNormals;
|
|
vtkPoints *newPts;
|
|
vtkCellArray *newLines;
|
|
double *range, offset;
|
|
int plotNum, compNum;
|
|
vtkPoints *projPts;
|
|
|
|
inPD = input->GetPointData();
|
|
|
|
// Initialize
|
|
//
|
|
vtkDebugMacro(<<"Plotting along arc");
|
|
|
|
if ( !(inPts=input->GetPoints()) ||
|
|
(numPts=inPts->GetNumberOfPoints()) < 1 ||
|
|
!(inLines=input->GetLines()) || inLines->GetNumberOfCells() < 1 )
|
|
{
|
|
vtkErrorMacro(<< "No input data!");
|
|
return 0;
|
|
}
|
|
|
|
// Process attribute data to determine ranges, number of components, etc.
|
|
if ( this->ProcessComponents(numPts, inPD) <= 0 )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// 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 )
|
|
{
|
|
double 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 = vtkFloatArray::New();
|
|
lineNormals->SetNumberOfComponents(3);
|
|
|
|
newLines = vtkCellArray::New();
|
|
newLines->Allocate(inLines->GetSize());
|
|
|
|
for (inLines->InitTraversal(); inLines->GetNextCell(npts,pts); )
|
|
{
|
|
lineNormals->SetNumberOfTuples(npts);
|
|
if ( !this->Camera || this->UseDefaultNormal )
|
|
{//use default normal
|
|
for (i=0; i < npts; i++)
|
|
{
|
|
lineNormals->SetTuple(i,normal);
|
|
}
|
|
}
|
|
else //generate normals
|
|
{
|
|
// Compute normals on each line segment perpendicular to view normal
|
|
for (i=0; i < (npts-1); i++)
|
|
{
|
|
projPts->GetPoint(pts[i], x1);
|
|
projPts->GetPoint(pts[i+1], x2);
|
|
for (j=0; j<3; j++)
|
|
{
|
|
x21[j] = x2[j] - x1[j];
|
|
}
|
|
vtkMath::Cross(normal,x21,n);
|
|
vtkMath::Normalize(n);
|
|
lineNormals->SetTuple(i,n);
|
|
}
|
|
lineNormals->SetTuple(npts-1,n);
|
|
}
|
|
|
|
// Now average the normal calculation to get smoother results
|
|
//
|
|
vtkIdType 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->GetTuple(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->GetTuple(i+window,n);
|
|
aveNormal[0] += n[0]; aveNormal[1] += n[1]; aveNormal[2] += n[2];
|
|
}
|
|
if ( (i-window) >= 0 )
|
|
{
|
|
lineNormals->GetTuple(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->SetTuple(i, n);
|
|
}
|
|
this->UpdateProgress(0.50);
|
|
|
|
// 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->GetTuple(i,n);
|
|
id = this->OffsetPoint(pts[i], inPts, n, newPts,
|
|
offset, range, this->Tuple[compNum]);
|
|
newLines->InsertCellPoint(id);
|
|
}
|
|
} //for all components
|
|
} //for all polylines
|
|
this->UpdateProgress(0.90);
|
|
|
|
lineNormals->Delete();
|
|
if ( projPts != inPts )
|
|
{
|
|
projPts->Delete();
|
|
}
|
|
|
|
// Update output
|
|
output->SetPoints(newPts);
|
|
newPts->Delete();
|
|
output->SetLines(newLines);
|
|
newLines->Delete();
|
|
|
|
return 1;
|
|
}
|
|
|
|
int vtkArcPlotter::ProcessComponents(vtkIdType numPts, vtkPointData *pd)
|
|
{
|
|
vtkIdType i;
|
|
int j;
|
|
double *range;
|
|
|
|
this->Data = NULL;
|
|
switch (this->PlotMode)
|
|
{
|
|
case VTK_PLOT_SCALARS:
|
|
if ( pd->GetScalars() )
|
|
{
|
|
this->Data = pd->GetScalars();
|
|
}
|
|
break;
|
|
case VTK_PLOT_VECTORS:
|
|
if ( pd->GetVectors() )
|
|
{
|
|
this->Data = pd->GetVectors();
|
|
}
|
|
break;
|
|
case VTK_PLOT_NORMALS:
|
|
if ( pd->GetNormals() )
|
|
{
|
|
this->Data = pd->GetNormals();
|
|
}
|
|
break;
|
|
case VTK_PLOT_TCOORDS:
|
|
if ( pd->GetTCoords() )
|
|
{
|
|
this->Data = pd->GetTCoords();
|
|
}
|
|
break;
|
|
case VTK_PLOT_TENSORS:
|
|
if ( pd->GetTensors() )
|
|
{
|
|
this->Data = pd->GetTensors();
|
|
}
|
|
break;
|
|
case VTK_PLOT_FIELD_DATA:
|
|
int arrayNum = (this->FieldDataArray < pd->GetNumberOfArrays() ?
|
|
this->FieldDataArray : pd->GetNumberOfArrays() - 1);
|
|
this->Data = pd->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 double [2*this->NumberOfComponents];
|
|
this->Tuple = new double [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(vtkIdType ptId, vtkPoints *inPts, double n[3],
|
|
vtkPoints *newPts, double offset,
|
|
double *range, double v)
|
|
{
|
|
double x[3], xNew[3];
|
|
int i;
|
|
double median = (range[0] + range[1])/2.0;
|
|
double 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->Superclass::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)
|
|
{
|
|
this->Superclass::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";
|
|
}
|
|
|