Cloned library of VTK-5.0.0 with extra build files for internal package management.
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.
 
 
 
 
 
 

1433 lines
42 KiB

/*=========================================================================
Program: Visualization Toolkits
Module: $RCSfile: vtkGenericStreamTracer.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 "vtkGenericStreamTracer.h"
#include "vtkCellArray.h"
#include "vtkCellData.h"
#include "vtkDoubleArray.h"
#include "vtkGenericInterpolatedVelocityField.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
#include "vtkPolyLine.h"
#include "vtkRungeKutta2.h"
#include "vtkRungeKutta4.h"
#include "vtkRungeKutta45.h"
#include "vtkGenericDataSet.h"
#include "vtkGenericAttributeCollection.h"
#include "vtkGenericAttribute.h"
#include "vtkGenericAdaptorCell.h"
#include <assert.h>
#include "vtkInformation.h"
#include "vtkExecutive.h" // for GetExecutive()
#include "vtkInformationVector.h"
vtkCxxRevisionMacro(vtkGenericStreamTracer, "$Revision: 1.3 $");
vtkStandardNewMacro(vtkGenericStreamTracer);
vtkCxxSetObjectMacro(vtkGenericStreamTracer,Integrator,vtkInitialValueProblemSolver);
vtkCxxSetObjectMacro(vtkGenericStreamTracer,InterpolatorPrototype,vtkGenericInterpolatedVelocityField);
const double vtkGenericStreamTracer::EPSILON = 1.0E-12;
//-----------------------------------------------------------------------------
vtkGenericStreamTracer::vtkGenericStreamTracer()
{
this->SetNumberOfInputPorts(2);
this->Integrator = vtkRungeKutta2::New();
this->IntegrationDirection = FORWARD;
for(int i=0; i<3; i++)
{
this->StartPosition[i] = 0.0;
}
this->MaximumPropagation.Unit = LENGTH_UNIT;
this->MaximumPropagation.Interval = 1.0;
this->MinimumIntegrationStep.Unit = CELL_LENGTH_UNIT;
this->MinimumIntegrationStep.Interval = 1.0E-2;
this->MaximumIntegrationStep.Unit = CELL_LENGTH_UNIT;
this->MaximumIntegrationStep.Interval = 1.0;
this->InitialIntegrationStep.Unit = CELL_LENGTH_UNIT;
this->InitialIntegrationStep.Interval = 0.5;
this->MaximumError = 1.0e-6;
this->MaximumNumberOfSteps = 2000;
this->TerminalSpeed = EPSILON;
this->ComputeVorticity = 1;
this->RotationScale = 1.0;
this->InputVectorsSelection = 0;
this->LastUsedTimeStep = 0.0;
this->GenerateNormalsInIntegrate = 1;
this->InterpolatorPrototype = 0;
}
//-----------------------------------------------------------------------------
vtkGenericStreamTracer::~vtkGenericStreamTracer()
{
this->SetIntegrator(0);
this->SetInputVectorsSelection(0);
this->SetInterpolatorPrototype(0);
}
//-----------------------------------------------------------------------------
void vtkGenericStreamTracer::SetSource(vtkDataSet *source)
{
this->SetInputConnection(1, source->GetProducerPort());
}
//-----------------------------------------------------------------------------
vtkDataSet *vtkGenericStreamTracer::GetSource()
{
if (this->GetNumberOfInputConnections(1) < 1) // because the port is optional
{
return 0;
}
return static_cast<vtkDataSet *>(this->GetExecutive()->GetInputData(1, 0));
}
//-----------------------------------------------------------------------------
void vtkGenericStreamTracer::AddInput(vtkGenericDataSet* input)
{
this->Superclass::AddInput(input);
}
//----------------------------------------------------------------------------
int vtkGenericStreamTracer
::FillInputPortInformation(int port, vtkInformation* info)
{
if(!this->Superclass::FillInputPortInformation(port, info))
{
return 0;
}
if(port==1)
{
info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(),1);
}
else
{
info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkGenericDataSet");
}
return 1;
}
//-----------------------------------------------------------------------------
int vtkGenericStreamTracer::GetIntegratorType()
{
if (!this->Integrator)
{
return NONE;
}
if (!strcmp(this->Integrator->GetClassName(), "vtkRungeKutta2"))
{
return RUNGE_KUTTA2;
}
if (!strcmp(this->Integrator->GetClassName(), "vtkRungeKutta4"))
{
return RUNGE_KUTTA4;
}
if (!strcmp(this->Integrator->GetClassName(), "vtkRungeKutta45"))
{
return RUNGE_KUTTA45;
}
return UNKNOWN;
}
//-----------------------------------------------------------------------------
void vtkGenericStreamTracer::SetIntegratorType(int type)
{
vtkInitialValueProblemSolver* ivp=0;
switch (type)
{
case RUNGE_KUTTA2:
ivp = vtkRungeKutta2::New();
break;
case RUNGE_KUTTA4:
ivp = vtkRungeKutta4::New();
break;
case RUNGE_KUTTA45:
ivp = vtkRungeKutta45::New();
break;
default:
vtkWarningMacro("Unrecognized integrator type. Keeping old one.");
break;
}
if (ivp)
{
this->SetIntegrator(ivp);
ivp->Delete();
}
}
//-----------------------------------------------------------------------------
void vtkGenericStreamTracer::SetIntervalInformation(
int unit,
vtkGenericStreamTracer::IntervalInformation& currentValues)
{
if ( unit == currentValues.Unit )
{
return;
}
if ( (unit < TIME_UNIT) || (unit > CELL_LENGTH_UNIT) )
{
vtkWarningMacro("Unrecognized unit. Using TIME_UNIT instead.");
currentValues.Unit = TIME_UNIT;
}
else
{
currentValues.Unit = unit;
}
this->Modified();
}
//-----------------------------------------------------------------------------
void vtkGenericStreamTracer::SetIntervalInformation(
int unit,
double interval, vtkGenericStreamTracer::IntervalInformation& currentValues)
{
if ( (unit == currentValues.Unit) && (interval == currentValues.Interval) )
{
return;
}
this->SetIntervalInformation(unit, currentValues);
currentValues.Interval = interval;
this->Modified();
}
//-----------------------------------------------------------------------------
void vtkGenericStreamTracer::SetMaximumPropagation(int unit, double max)
{
this->SetIntervalInformation(unit, max, this->MaximumPropagation);
}
//-----------------------------------------------------------------------------
void vtkGenericStreamTracer::SetMaximumPropagation( double max)
{
if ( max == this->MaximumPropagation.Interval )
{
return;
}
this->MaximumPropagation.Interval = max;
this->Modified();
}
//-----------------------------------------------------------------------------
void vtkGenericStreamTracer::SetMaximumPropagationUnit(int unit)
{
this->SetIntervalInformation(unit, this->MaximumPropagation);
}
//-----------------------------------------------------------------------------
int vtkGenericStreamTracer::GetMaximumPropagationUnit()
{
return this->MaximumPropagation.Unit;
}
//-----------------------------------------------------------------------------
double vtkGenericStreamTracer::GetMaximumPropagation()
{
return this->MaximumPropagation.Interval;
}
//-----------------------------------------------------------------------------
void vtkGenericStreamTracer::SetMinimumIntegrationStep(int unit, double step)
{
this->SetIntervalInformation(unit, step, this->MinimumIntegrationStep);
}
//-----------------------------------------------------------------------------
void vtkGenericStreamTracer::SetMinimumIntegrationStepUnit(int unit)
{
this->SetIntervalInformation(unit, this->MinimumIntegrationStep);
}
//-----------------------------------------------------------------------------
void vtkGenericStreamTracer::SetMinimumIntegrationStep(double step)
{
if ( step == this->MinimumIntegrationStep.Interval )
{
return;
}
this->MinimumIntegrationStep.Interval = step;
this->Modified();
}
//-----------------------------------------------------------------------------
int vtkGenericStreamTracer::GetMinimumIntegrationStepUnit()
{
return this->MinimumIntegrationStep.Unit;
}
//-----------------------------------------------------------------------------
double vtkGenericStreamTracer::GetMinimumIntegrationStep()
{
return this->MinimumIntegrationStep.Interval;
}
//-----------------------------------------------------------------------------
void vtkGenericStreamTracer::SetMaximumIntegrationStep(int unit, double step)
{
this->SetIntervalInformation(unit, step, this->MaximumIntegrationStep);
}
//-----------------------------------------------------------------------------
void vtkGenericStreamTracer::SetMaximumIntegrationStepUnit(int unit)
{
this->SetIntervalInformation(unit, this->MaximumIntegrationStep);
}
//-----------------------------------------------------------------------------
void vtkGenericStreamTracer::SetMaximumIntegrationStep(double step)
{
if ( step == this->MaximumIntegrationStep.Interval )
{
return;
}
this->MaximumIntegrationStep.Interval = step;
this->Modified();
}
//-----------------------------------------------------------------------------
int vtkGenericStreamTracer::GetMaximumIntegrationStepUnit()
{
return this->MaximumIntegrationStep.Unit;
}
//-----------------------------------------------------------------------------
double vtkGenericStreamTracer::GetMaximumIntegrationStep()
{
return this->MaximumIntegrationStep.Interval;
}
//-----------------------------------------------------------------------------
void vtkGenericStreamTracer::SetInitialIntegrationStep(int unit, double step)
{
this->SetIntervalInformation(unit, step, this->InitialIntegrationStep);
}
//-----------------------------------------------------------------------------
void vtkGenericStreamTracer::SetInitialIntegrationStepUnit(int unit)
{
this->SetIntervalInformation(unit, this->InitialIntegrationStep);
}
//-----------------------------------------------------------------------------
void vtkGenericStreamTracer::SetInitialIntegrationStep(double step)
{
if ( step == this->InitialIntegrationStep.Interval )
{
return;
}
this->InitialIntegrationStep.Interval = step;
this->Modified();
}
//-----------------------------------------------------------------------------
int vtkGenericStreamTracer::GetInitialIntegrationStepUnit()
{
return this->InitialIntegrationStep.Unit;
}
//-----------------------------------------------------------------------------
double vtkGenericStreamTracer::GetInitialIntegrationStep()
{
return this->InitialIntegrationStep.Interval;
}
//-----------------------------------------------------------------------------
double vtkGenericStreamTracer::ConvertToTime(
vtkGenericStreamTracer::IntervalInformation& interval,
double cellLength,
double speed)
{
double retVal = 0.0;
switch (interval.Unit)
{
case TIME_UNIT:
retVal = interval.Interval;
break;
case LENGTH_UNIT:
retVal = interval.Interval/speed;
break;
case CELL_LENGTH_UNIT:
retVal = interval.Interval*cellLength/speed;
break;
}
return retVal;
}
//-----------------------------------------------------------------------------
double vtkGenericStreamTracer::ConvertToLength(
vtkGenericStreamTracer::IntervalInformation& interval,
double cellLength,
double speed)
{
double retVal = 0.0;
switch (interval.Unit)
{
case TIME_UNIT:
retVal = interval.Interval * speed;
break;
case LENGTH_UNIT:
retVal = interval.Interval;
break;
case CELL_LENGTH_UNIT:
retVal = interval.Interval*cellLength;
break;
}
return retVal;
}
//-----------------------------------------------------------------------------
double vtkGenericStreamTracer::ConvertToCellLength(
vtkGenericStreamTracer::IntervalInformation& interval,
double cellLength,
double speed)
{
double retVal = 0.0;
switch (interval.Unit)
{
case TIME_UNIT:
retVal = (interval.Interval * speed)/cellLength;
break;
case LENGTH_UNIT:
retVal = interval.Interval/cellLength;
break;
case CELL_LENGTH_UNIT:
retVal = interval.Interval;
break;
}
return retVal;
}
//-----------------------------------------------------------------------------
double vtkGenericStreamTracer::ConvertToUnit(
vtkGenericStreamTracer::IntervalInformation& interval,
int unit,
double cellLength,
double speed)
{
double retVal = 0.0;
switch (unit)
{
case TIME_UNIT:
retVal = ConvertToTime(interval, cellLength, speed);
break;
case LENGTH_UNIT:
retVal = ConvertToLength(interval, cellLength, speed);
break;
case CELL_LENGTH_UNIT:
retVal = ConvertToCellLength(interval, cellLength, speed);
break;
}
return retVal;
}
//-----------------------------------------------------------------------------
void vtkGenericStreamTracer::ConvertIntervals(double& step,
double& minStep,
double& maxStep,
int direction,
double cellLength,
double speed)
{
step = direction * this->ConvertToTime(
this->InitialIntegrationStep, cellLength, speed);
if ( this->MinimumIntegrationStep.Interval <= 0.0 )
{
minStep = step;
}
else
{
minStep = this->ConvertToTime(this->MinimumIntegrationStep, cellLength,
speed);
}
if ( this->MaximumIntegrationStep.Interval <= 0.0 )
{
maxStep = step;
}
else
{
maxStep = this->ConvertToTime(this->MaximumIntegrationStep,cellLength,
speed);
}
}
//-----------------------------------------------------------------------------
void vtkGenericStreamTracer::CalculateVorticity(vtkGenericAdaptorCell* cell,
double pcoords[3],
vtkGenericAttribute *attribute,
double vorticity[3])
{
assert("pre: attribute_exists" && attribute!=0);
assert("pre: point_centered_attribute" && attribute->GetCentering()==vtkPointCentered);
assert("pre: vector_attribute" && attribute->GetType()==vtkDataSetAttributes::VECTORS);
double derivs[9];
cell->Derivatives(0,pcoords,attribute,derivs);
vorticity[0] = derivs[7] - derivs[5];
vorticity[1] = derivs[2] - derivs[6];
vorticity[2] = derivs[3] - derivs[1];
}
//-----------------------------------------------------------------------------
void vtkGenericStreamTracer::InitializeSeeds(
vtkDataArray*& seeds,
vtkIdList*& seedIds,
vtkIntArray*& integrationDirections)
{
vtkDataSet* source = this->GetSource();
seedIds = vtkIdList::New();
integrationDirections = vtkIntArray::New();
seeds=0;
if (source)
{
int i;
vtkIdType numSeeds = source->GetNumberOfPoints();
if (numSeeds > 0)
{
// For now, one thread will do all
if (this->IntegrationDirection == BOTH)
{
seedIds->SetNumberOfIds(2*numSeeds);
for (i=0; i<numSeeds; i++)
{
seedIds->SetId(i, i);
seedIds->SetId(numSeeds + i, i);
}
}
else
{
seedIds->SetNumberOfIds(numSeeds);
for (i=0; i<numSeeds; i++)
{
seedIds->SetId(i, i);
}
}
// Check if the source is a PointSet
vtkPointSet* seedPts = vtkPointSet::SafeDownCast(source);
if (seedPts)
{
// If it is, use it's points as source
vtkDataArray* orgSeeds = seedPts->GetPoints()->GetData();
seeds = orgSeeds->NewInstance();
seeds->DeepCopy(orgSeeds);
}
else
{
// Else, create a seed source
seeds = vtkDoubleArray::New();
seeds->SetNumberOfComponents(3);
seeds->SetNumberOfTuples(numSeeds);
for (i=0; i<numSeeds; i++)
{
seeds->SetTuple(i, source->GetPoint(i));
}
}
}
}
else
{
seeds = vtkDoubleArray::New();
seeds->SetNumberOfComponents(3);
seeds->InsertNextTuple(this->StartPosition);
seedIds->InsertNextId(0);
if (this->IntegrationDirection == BOTH)
{
seedIds->InsertNextId(0);
}
}
if (seeds)
{
vtkIdType i;
vtkIdType numSeeds = seeds->GetNumberOfTuples();
if (this->IntegrationDirection == BOTH)
{
for(i=0; i<numSeeds; i++)
{
integrationDirections->InsertNextValue(FORWARD);
}
for(i=0; i<numSeeds; i++)
{
integrationDirections->InsertNextValue(BACKWARD);
}
}
else
{
for(i=0; i<numSeeds; i++)
{
integrationDirections->InsertNextValue(this->IntegrationDirection);
}
}
}
}
//-----------------------------------------------------------------------------
int vtkGenericStreamTracer::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()));
vtkDataArray* seeds = 0;
vtkIdList* seedIds = 0;
vtkIntArray* integrationDirections = 0;
this->InitializeSeeds(seeds, seedIds, integrationDirections);
if (seeds)
{
double lastPoint[3];
vtkGenericInterpolatedVelocityField* func;
if (this->CheckInputs(func, inputVector) != VTK_OK)
{
vtkDebugMacro("No appropriate inputs have been found. Can not execute.");
func->Delete();
seeds->Delete();
integrationDirections->Delete();
seedIds->Delete();
return 1;
}
this->Integrate(input,
output,
seeds,
seedIds,
integrationDirections,
lastPoint,
func);
func->Delete();
seeds->Delete();
}
integrationDirections->Delete();
seedIds->Delete();
return 1;
}
//-----------------------------------------------------------------------------
int vtkGenericStreamTracer::CheckInputs(
vtkGenericInterpolatedVelocityField*& func,
vtkInformationVector **inputVector
)
{
// Set the function set to be integrated
if (!this->InterpolatorPrototype)
{
func = vtkGenericInterpolatedVelocityField::New();
}
else
{
func = this->InterpolatorPrototype->NewInstance();
func->CopyParameters(this->InterpolatorPrototype);
}
func->SelectVectors(this->InputVectorsSelection);
// Add all the inputs ( except source, of course ) which
// have the appropriate vectors and compute the maximum
// cell size.
int numInputs = 0;
int numInputConnections = this->GetNumberOfInputConnections(0);
for (int i = 0; i < numInputConnections; i++)
{
vtkInformation *info = inputVector[0]->GetInformationObject(i);
vtkGenericDataSet* inp=0;
if(info!=0)
{
inp = vtkGenericDataSet::SafeDownCast(
info->Get(vtkDataObject::DATA_OBJECT()));
}
if(inp!=0)
{
int attrib;
int attributeFound;
if(this->InputVectorsSelection!=0)
{
attrib=inp->GetAttributes()->FindAttribute(this->InputVectorsSelection);
attributeFound=attrib>=0;
if(attributeFound)
{
attributeFound=(inp->GetAttributes()->GetAttribute(attrib)->GetType()==vtkDataSetAttributes::VECTORS)&&(inp->GetAttributes()->GetAttribute(attrib)->GetCentering()==vtkPointCentered);
}
}
else
{
// Find the first attribute, point centered and with vector type.
attrib=0;
attributeFound=0;
int c=inp->GetAttributes()->GetNumberOfAttributes();
while(attrib<c&&!attributeFound)
{
attributeFound=(inp->GetAttributes()->GetAttribute(attrib)->GetType()==vtkDataSetAttributes::VECTORS)&&(inp->GetAttributes()->GetAttribute(attrib)->GetCentering()==vtkPointCentered);
++attrib;
}
if(attributeFound)
{
--attrib;
this->SetInputVectorsSelection(inp->GetAttributes()->GetAttribute(attrib)->GetName());
}
}
if (!attributeFound)
{
vtkDebugMacro("Input " << i << "does not contain a velocity vector.");
continue;
}
func->AddDataSet(inp);
numInputs++;
}
}
if ( numInputs == 0 )
{
vtkDebugMacro("No appropriate inputs have been found. Can not execute.");
return VTK_ERROR;
}
return VTK_OK;
}
//-----------------------------------------------------------------------------
void vtkGenericStreamTracer::Integrate(
vtkGenericDataSet *input0,
vtkPolyData* output,
vtkDataArray* seedSource,
vtkIdList* seedIds,
vtkIntArray* integrationDirections,
double lastPoint[3],
vtkGenericInterpolatedVelocityField* func)
{
int i;
vtkIdType numLines = seedIds->GetNumberOfIds();
// Useful pointers
vtkDataSetAttributes* outputPD = output->GetPointData();
vtkDataSetAttributes* outputCD = output->GetCellData();
vtkGenericDataSet* input;
vtkGenericAttribute* inVectors;
int direction=1;
if (this->GetIntegrator() == 0)
{
vtkErrorMacro("No integrator is specified.");
return;
}
// Used in GetCell()
// vtkGenericCell* cell = vtkGenericCell::New();
vtkGenericAdaptorCell *cell=0;
// Create a new integrator, the type is the same as Integrator
vtkInitialValueProblemSolver* integrator =
this->GetIntegrator()->NewInstance();
integrator->SetFunctionSet(func);
// Since we do not know what the total number of points
// will be, we do not allocate any. This is important for
// cases where a lot of streamers are used at once. If we
// were to allocate any points here, potentially, we can
// waste a lot of memory if a lot of streamers are used.
// Always insert the first point
vtkPoints* outputPoints = vtkPoints::New();
vtkCellArray* outputLines = vtkCellArray::New();
// We will keep track of time in this array
vtkDoubleArray* time = vtkDoubleArray::New();
time->SetName("IntegrationTime");
// This array explains why the integration stopped
vtkIntArray* retVals = vtkIntArray::New();
retVals->SetName("ReasonForTermination");
vtkDoubleArray* vorticity = 0;
vtkDoubleArray* rotation = 0;
vtkDoubleArray* angularVel = 0;
if (this->ComputeVorticity)
{
vorticity = vtkDoubleArray::New();
vorticity->SetName("Vorticity");
vorticity->SetNumberOfComponents(3);
rotation = vtkDoubleArray::New();
rotation->SetName("Rotation");
angularVel = vtkDoubleArray::New();
angularVel->SetName("AngularVelocity");
}
// We will interpolate all point attributes of the input on
// each point of the output (unless they are turned off)
// Note that we are using only the first input, if there are more
// than one, the attributes have to match.
// prepare the output attributes
vtkGenericAttributeCollection *attributes=input0->GetAttributes();
vtkGenericAttribute *attribute;
vtkDataArray *attributeArray;
int c=attributes->GetNumberOfAttributes();
int attributeType;
// Only point centered attributes will be interpolated.
// Cell centered attributes are not ignored and not copied in output:
// is a missing part in vtkStreamTracer? Need to ask to the Berk.
i=0;
while(i<c)
{
attribute=attributes->GetAttribute(i);
attributeType=attribute->GetType();
if(attribute->GetCentering()==vtkPointCentered)
{
attributeArray=vtkDataArray::CreateDataArray(attribute->GetComponentType());
attributeArray->SetNumberOfComponents(attribute->GetNumberOfComponents());
attributeArray->SetName(attribute->GetName());
outputPD->AddArray(attributeArray);
attributeArray->Delete();
if(outputPD->GetAttribute(attributeType)==0)
{
outputPD->SetActiveAttribute(outputPD->GetNumberOfArrays()-1,
attributeType);
}
}
++i;
}
double *values=new double[outputPD->GetNumberOfComponents()]; // point centered attributes at some point.
// Note: It is an overestimation to have the estimate the same number of
// output points and input points. We sill have to squeeze at end.
vtkIdType numPtsTotal=0;
double velocity[3];
int shouldAbort = 0;
for(int currentLine = 0; currentLine < numLines; currentLine++)
{
double progress = static_cast<double>(currentLine)/numLines;
this->UpdateProgress(progress);
switch (integrationDirections->GetValue(currentLine))
{
case FORWARD:
direction = 1;
break;
case BACKWARD:
direction = -1;
break;
}
// temporary variables used in the integration
double point1[3], point2[3], pcoords[3], vort[3], omega;
vtkIdType index, numPts=0;
// Clear the last cell to avoid starting a search from
// the last point in the streamline
func->ClearLastCell();
// Initial point
seedSource->GetTuple(seedIds->GetId(currentLine), point1);
memcpy(point2, point1, 3*sizeof(double));
if (!func->FunctionValues(point1, velocity))
{
continue;
}
numPts++;
numPtsTotal++;
vtkIdType nextPoint = outputPoints->InsertNextPoint(point1);
time->InsertNextValue(0.0);
// We will always pass a time step to the integrator.
// If the user specifies a step size with another unit, we will
// have to convert it to time.
IntervalInformation delT;
delT.Unit = TIME_UNIT;
delT.Interval = 0;
IntervalInformation aStep;
aStep.Unit = this->MaximumPropagation.Unit;
double propagation = 0.0, step, minStep=0, maxStep=0;
double stepTaken, accumTime=0;
double speed;
double cellLength;
int retVal=OUT_OF_TIME, tmp;
// Make sure we use the dataset found
// by the vtkGenericInterpolatedVelocityField
input = func->GetLastDataSet();
inVectors=input->GetAttributes()->GetAttribute(input->GetAttributes()->FindAttribute(this->InputVectorsSelection));
// Convert intervals to time unit
cell=func->GetLastCell();
cellLength = sqrt(static_cast<double>(cell->GetLength2()));
speed = vtkMath::Norm(velocity);
// Never call conversion methods if speed == 0
if (speed != 0.0)
{
this->ConvertIntervals(delT.Interval, minStep, maxStep, direction,
cellLength, speed);
}
// Interpolate all point attributes on first point
func->GetLastLocalCoordinates(pcoords);
cell->InterpolateTuple(input->GetAttributes(),pcoords,
values);
double *p=values;
vtkDataArray *dataArray;
c=outputPD->GetNumberOfArrays();
int j=0;
while(j<c)
{
dataArray=outputPD->GetArray(j);
dataArray->InsertTuple(nextPoint,p);
++j;
p=p+dataArray->GetNumberOfComponents();
}
// Compute vorticity if required
// This can be used later for streamribbon generation.
if (this->ComputeVorticity)
{
// Here, we're assuming a linear cell by only taken values at
// corner points. there should be a subdivision step here instead.
// What is the criterium to stop the subdivision?
// Note: the original vtkStreamTracer is taking cell points, it means
// that for the quadratic cell, the standard stream tracer is more
// accurate than this one!
vtkGenericStreamTracer::CalculateVorticity(cell, pcoords, inVectors,
vort);
vorticity->InsertNextTuple(vort);
// rotation
// local rotation = vorticity . unit tangent ( i.e. velocity/speed )
if (speed != 0.0)
{
omega = vtkMath::Dot(vort, velocity);
omega /= speed;
omega *= this->RotationScale;
}
else
{
omega = 0.0;
}
angularVel->InsertNextValue(omega);
rotation->InsertNextValue(0.0);
}
vtkIdType numSteps = 0;
double error = 0;
// Integrate until the maximum propagation length is reached,
// maximum number of steps is reached or until a boundary is encountered.
// Begin Integration
while ( propagation < this->MaximumPropagation.Interval )
{
if (numSteps > this->MaximumNumberOfSteps)
{
retVal = OUT_OF_STEPS;
break;
}
if ( numSteps++ % 1000 == 1 )
{
progress =
(currentLine + propagation / this->MaximumPropagation.Interval) /
numLines ;
this->UpdateProgress(progress);
if (this->GetAbortExecute())
{
shouldAbort = 1;
break;
}
}
// Never call conversion methods if speed == 0
if ( (speed == 0) || (speed <= this->TerminalSpeed) )
{
retVal = STAGNATION;
break;
}
// If, with the next step, propagation will be larger than
// max, reduce it so that it is (approximately) equal to max.
aStep.Interval = fabs(this->ConvertToUnit(delT,
this->MaximumPropagation.Unit,
cellLength, speed));
if ( (propagation + aStep.Interval) >
this->MaximumPropagation.Interval )
{
aStep.Interval = this->MaximumPropagation.Interval - propagation;
if (delT.Interval >= 0)
{
delT.Interval = this->ConvertToTime(aStep, cellLength, speed);
}
else
{
delT.Interval = -1.0 * this->ConvertToTime(aStep, cellLength, speed);
}
maxStep = delT.Interval;
}
this->LastUsedTimeStep = delT.Interval;
// Calculate the next step using the integrator provided
// Break if the next point is out of bounds.
if ((tmp=
integrator->ComputeNextStep(point1, point2, 0, delT.Interval,
stepTaken, minStep, maxStep,
this->MaximumError, error)) != 0)
{
retVal = tmp;
memcpy(lastPoint, point2, 3*sizeof(double));
break;
}
accumTime += stepTaken;
// Calculate propagation (using the same units as MaximumPropagation
propagation += fabs(this->ConvertToUnit(delT,
this->MaximumPropagation.Unit,
cellLength, speed));
// This is the next starting point
for(i=0; i<3; i++)
{
point1[i] = point2[i];
}
// Interpolate the velocity at the next point
if ( !func->FunctionValues(point2, velocity) )
{
retVal = OUT_OF_DOMAIN;
memcpy(lastPoint, point2, 3*sizeof(double));
break;
}
// Make sure we use the dataset found by the vtkInterpolatedVelocityField
input = func->GetLastDataSet();
inVectors=input->GetAttributes()->GetAttribute(input->GetAttributes()->FindAttribute(this->InputVectorsSelection));
// Point is valid. Insert it.
numPts++;
numPtsTotal++;
nextPoint = outputPoints->InsertNextPoint(point1);
time->InsertNextValue(accumTime);
// Calculate cell length and speed to be used in unit conversions
cell=func->GetLastCell();
cellLength = sqrt(static_cast<double>(cell->GetLength2()));
speed = vtkMath::Norm(velocity);
// Interpolate all point attributes on current point
func->GetLastLocalCoordinates(pcoords);
cell->InterpolateTuple(input->GetAttributes(),pcoords,
values);
p=values;
c=outputPD->GetNumberOfArrays();
j=0;
while(j<c)
{
dataArray=outputPD->GetArray(j);
dataArray->InsertTuple(nextPoint,p);
++j;
p=p+dataArray->GetNumberOfComponents();
}
// Compute vorticity if required
// This can be used later for streamribbon generation.
if (this->ComputeVorticity)
{
vtkGenericStreamTracer::CalculateVorticity(cell, pcoords, inVectors,
vort);
vorticity->InsertNextTuple(vort);
// rotation
// angular velocity = vorticity . unit tangent ( i.e. velocity/speed )
// rotation = sum ( angular velocity * delT )
omega = vtkMath::Dot(vort, velocity);
omega /= speed;
omega *= this->RotationScale;
index = angularVel->InsertNextValue(omega);
rotation->InsertNextValue(rotation->GetValue(index-1) +
(angularVel->GetValue(index-1) + omega)/2 *
(accumTime - time->GetValue(index-1)));
}
// Never call conversion methods if speed == 0
if ( (speed == 0) || (speed <= this->TerminalSpeed) )
{
retVal = STAGNATION;
break;
}
// Convert all intervals to time
this->ConvertIntervals(step, minStep, maxStep, direction,
cellLength, speed);
// If the solver is adaptive and the next time step (delT.Interval)
// that the solver wants to use is smaller than minStep or larger
// than maxStep, re-adjust it. This has to be done every step
// because minStep and maxStep can change depending on the cell
// size (unless it is specified in time units)
if (integrator->IsAdaptive())
{
if (fabs(delT.Interval) < fabs(minStep))
{
delT.Interval = fabs(minStep) * delT.Interval/fabs(delT.Interval);
}
else if (fabs(delT.Interval) > fabs(maxStep))
{
delT.Interval = fabs(maxStep) * delT.Interval/fabs(delT.Interval);
}
}
else
{
delT.Interval = step;
}
// End Integration
}
if (shouldAbort)
{
break;
}
if (numPts > 1)
{
outputLines->InsertNextCell(numPts);
for (i=numPtsTotal-numPts; i<numPtsTotal; i++)
{
outputLines->InsertCellPoint(i);
}
retVals->InsertNextValue(retVal);
}
}
if (!shouldAbort)
{
// Create the output polyline
output->SetPoints(outputPoints);
outputPD->AddArray(time);
if (vorticity)
{
outputPD->AddArray(vorticity);
outputPD->AddArray(rotation);
outputPD->AddArray(angularVel);
}
vtkIdType numPts = outputPoints->GetNumberOfPoints();
if ( numPts > 1 )
{
// Assign geometry and attributes
output->SetLines(outputLines);
if (this->GenerateNormalsInIntegrate)
{
this->GenerateNormals(output, 0);
}
outputCD->AddArray(retVals);
}
}
if (vorticity)
{
vorticity->Delete();
rotation->Delete();
angularVel->Delete();
}
retVals->Delete();
outputPoints->Delete();
outputLines->Delete();
time->Delete();
integrator->Delete();
delete[] values;
output->Squeeze();
return;
}
//-----------------------------------------------------------------------------
void vtkGenericStreamTracer::GenerateNormals(vtkPolyData* output,
double* firstNormal)
{
// Useful pointers
vtkDataSetAttributes* outputPD = output->GetPointData();
vtkPoints* outputPoints = output->GetPoints();
vtkCellArray* outputLines = output->GetLines();
vtkDataArray* rotation = outputPD->GetArray("Rotation");
vtkIdType numPts = outputPoints->GetNumberOfPoints();
if ( numPts > 1 )
{
if (this->ComputeVorticity)
{
vtkPolyLine* lineNormalGenerator = vtkPolyLine::New();
vtkDoubleArray* normals = vtkDoubleArray::New();
normals->SetNumberOfComponents(3);
normals->SetNumberOfTuples(numPts);
lineNormalGenerator->GenerateSlidingNormals(outputPoints,
outputLines,
normals,
firstNormal);
lineNormalGenerator->Delete();
int i, j;
double normal[3], local1[3], local2[3], theta, costheta, sintheta, length;
double velocity[3];
normals->SetName("Normals");
vtkDataArray* newVectors =
outputPD->GetVectors(this->InputVectorsSelection);
for(i=0; i<numPts; i++)
{
normals->GetTuple(i, normal);
if (newVectors == NULL)
{ // This should never happen.
vtkErrorMacro("Could not find output array.");
return;
}
newVectors->GetTuple(i, velocity);
// obtain two unit orthogonal vectors on the plane perpendicular to
// the streamline
for(j=0; j<3; j++) { local1[j] = normal[j]; }
length = vtkMath::Normalize(local1);
vtkMath::Cross(local1, velocity, local2);
vtkMath::Normalize(local2);
// Rotate the normal with theta
rotation->GetTuple(i, &theta);
costheta = cos(theta);
sintheta = sin(theta);
for(j=0; j<3; j++)
{
normal[j] = length* (costheta*local1[j] + sintheta*local2[j]);
}
normals->SetTuple(i, normal);
}
outputPD->AddArray(normals);
outputPD->SetActiveAttribute("Normals", vtkDataSetAttributes::VECTORS);
normals->Delete();
}
}
}
//-----------------------------------------------------------------------------
// This is used by sub-classes in certain situations. It
// does a lot less (for example, does not compute attributes)
// than Integrate.
void vtkGenericStreamTracer::SimpleIntegrate(
double seed[3],
double lastPoint[3],
double delt,
vtkGenericInterpolatedVelocityField* func)
{
vtkIdType numSteps = 0;
vtkIdType maxSteps = 20;
double error = 0;
double stepTaken;
double point1[3], point2[3];
double velocity[3];
double speed;
(void)seed; // Seed is not used
memcpy(point1, lastPoint, 3*sizeof(double));
// Create a new integrator, the type is the same as Integrator
vtkInitialValueProblemSolver* integrator =
this->GetIntegrator()->NewInstance();
integrator->SetFunctionSet(func);
while ( 1 )
{
if (numSteps++ > maxSteps)
{
break;
}
// Calculate the next step using the integrator provided
// Break if the next point is out of bounds.
if (integrator->ComputeNextStep(point1, point2, 0, delt,
stepTaken, 0, 0, 0, error) != 0)
{
memcpy(lastPoint, point2, 3*sizeof(double));
break;
}
// This is the next starting point
for(int i=0; i<3; i++)
{
point1[i] = point2[i];
}
// Interpolate the velocity at the next point
if ( !func->FunctionValues(point2, velocity) )
{
memcpy(lastPoint, point2, 3*sizeof(double));
break;
}
speed = vtkMath::Norm(velocity);
// Never call conversion methods if speed == 0
if ( (speed == 0) || (speed <= this->TerminalSpeed) )
{
break;
}
memcpy(point1, point2, 3*sizeof(double));
// End Integration
}
integrator->Delete();
}
//-----------------------------------------------------------------------------
void vtkGenericStreamTracer::PrintSelf(ostream& os,
vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
os << indent << "Start position: "
<< this->StartPosition[0] << " "
<< this->StartPosition[1] << " "
<< this->StartPosition[2] << endl;
os << indent << "Terminal speed: " << this->TerminalSpeed << endl;
os << indent << "Maximum propagation: " << this->MaximumPropagation.Interval
<< " unit: ";
switch (this->MaximumPropagation.Unit)
{
case TIME_UNIT:
os << "time.";
break;
case LENGTH_UNIT:
os << "length.";
break;
case CELL_LENGTH_UNIT:
os << "cell length.";
break;
}
os << endl;
os << indent << "Min. integration step: "
<< this->MinimumIntegrationStep.Interval
<< " unit: ";
switch (this->MinimumIntegrationStep.Unit)
{
case TIME_UNIT:
os << "time.";
break;
case LENGTH_UNIT:
os << "length.";
break;
case CELL_LENGTH_UNIT:
os << "cell length.";
break;
}
os << endl;
os << indent << "Max. integration step: "
<< this->MaximumIntegrationStep.Interval
<< " unit: ";
switch (this->MaximumIntegrationStep.Unit)
{
case TIME_UNIT:
os << "time.";
break;
case LENGTH_UNIT:
os << "length.";
break;
case CELL_LENGTH_UNIT:
os << "cell length.";
break;
}
os << endl;
os << indent << "Initial integration step: "
<< this->InitialIntegrationStep.Interval
<< " unit: ";
switch (this->InitialIntegrationStep.Unit)
{
case TIME_UNIT:
os << "time.";
break;
case LENGTH_UNIT:
os << "length.";
break;
case CELL_LENGTH_UNIT:
os << "cell length.";
break;
}
os << endl;
os << indent << "Integration direction: ";
switch (this->IntegrationDirection)
{
case FORWARD:
os << "forward.";
break;
case BACKWARD:
os << "backward.";
break;
}
os << endl;
os << indent << "Integrator: " << this->Integrator << endl;
os << indent << "Maximum error: " << this->MaximumError << endl;
os << indent << "Max. number of steps: " << this->MaximumNumberOfSteps
<< endl;
os << indent << "Vorticity computation: "
<< (this->ComputeVorticity ? " On" : " Off") << endl;
os << indent << "Rotation scale: " << this->RotationScale << endl;
if (this->InputVectorsSelection)
{
os << indent << "InputVectorsSelection: " << this->InputVectorsSelection;
}
}