You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
468 lines
16 KiB
C++
468 lines
16 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkStreamTracer.h
|
|
|
|
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.
|
|
|
|
=========================================================================*/
|
|
/**
|
|
* @class vtkStreamTracer
|
|
* @brief Streamline generator
|
|
*
|
|
* vtkStreamTracer is a filter that integrates a vector field to generate
|
|
* streamlines. The integration is performed using a specified integrator,
|
|
* by default Runge-Kutta2.
|
|
*
|
|
* vtkStreamTracer produces polylines as the output, with each cell (i.e.,
|
|
* polyline) representing a streamline. The attribute values associated
|
|
* with each streamline are stored in the cell data, whereas those
|
|
* associated with streamline-points are stored in the point data.
|
|
*
|
|
* vtkStreamTracer supports forward (the default), backward, and combined
|
|
* (i.e., BOTH) integration. The length of a streamline is governed by
|
|
* specifying a maximum value either in physical arc length or in (local)
|
|
* cell length. Otherwise, the integration terminates upon exiting the
|
|
* flow field domain, or if the particle speed is reduced to a value less
|
|
* than a specified terminal speed, or when a maximum number of steps is
|
|
* completed. The specific reason for the termination is stored in a cell
|
|
* array named ReasonForTermination.
|
|
*
|
|
* Note that normalized vectors are adopted in streamline integration,
|
|
* which achieves high numerical accuracy/smoothness of flow lines that is
|
|
* particularly guaranteed for Runge-Kutta45 with adaptive step size and
|
|
* error control). In support of this feature, the underlying step size is
|
|
* ALWAYS in arc length unit (LENGTH_UNIT) while the 'real' time interval
|
|
* (virtual for steady flows) that a particle actually takes to trave in a
|
|
* single step is obtained by dividing the arc length by the LOCAL speed.
|
|
* The overall elapsed time (i.e., the life span) of the particle is the
|
|
* sum of those individual step-wise time intervals.
|
|
*
|
|
* The quality of streamline integration can be controlled by setting the
|
|
* initial integration step (InitialIntegrationStep), particularly for
|
|
* Runge-Kutta2 and Runge-Kutta4 (with a fixed step size), and in the case
|
|
* of Runge-Kutta45 (with an adaptive step size and error control) the
|
|
* minimum integration step, the maximum integration step, and the maximum
|
|
* error. These steps are in either LENGTH_UNIT or CELL_LENGTH_UNIT while
|
|
* the error is in physical arc length. For the former two integrators,
|
|
* there is a trade-off between integration speed and streamline quality.
|
|
*
|
|
* The integration time, vorticity, rotation and angular velocity are stored
|
|
* in point data arrays named "IntegrationTime", "Vorticity", "Rotation" and
|
|
* "AngularVelocity", respectively (vorticity, rotation and angular velocity
|
|
* are computed only when ComputeVorticity is on). All point data attributes
|
|
* in the source dataset are interpolated on the new streamline points.
|
|
*
|
|
* vtkStreamTracer supports integration through any type of dataset. Thus if
|
|
* the dataset contains 2D cells like polygons or triangles, the integration
|
|
* is constrained to lie on the surface defined by 2D cells.
|
|
*
|
|
* The starting point, or the so-called 'seed', of a streamline may be set
|
|
* in two different ways. Starting from global x-y-z "position" allows you
|
|
* to start a single trace at a specified x-y-z coordinate. If you specify
|
|
* a source object, traces will be generated from each point in the source
|
|
* that is inside the dataset.
|
|
*
|
|
* @sa
|
|
* vtkRibbonFilter vtkRuledSurfaceFilter vtkInitialValueProblemSolver
|
|
* vtkRungeKutta2 vtkRungeKutta4 vtkRungeKutta45 vtkParticleTracerBase
|
|
* vtkParticleTracer vtkParticlePathFilter vtkStreaklineFilter
|
|
* vtkAbstractInterpolatedVelocityField vtkInterpolatedVelocityField
|
|
* vtkCellLocatorInterpolatedVelocityField
|
|
*
|
|
*/
|
|
|
|
#ifndef vtkStreamTracer_h
|
|
#define vtkStreamTracer_h
|
|
|
|
#include "vtkFiltersFlowPathsModule.h" // For export macro
|
|
#include "vtkPolyDataAlgorithm.h"
|
|
|
|
#include "vtkInitialValueProblemSolver.h" // Needed for constants
|
|
|
|
class vtkAbstractInterpolatedVelocityField;
|
|
class vtkCompositeDataSet;
|
|
class vtkDataArray;
|
|
class vtkDataSetAttributes;
|
|
class vtkDoubleArray;
|
|
class vtkExecutive;
|
|
class vtkGenericCell;
|
|
class vtkIdList;
|
|
class vtkIntArray;
|
|
class vtkPoints;
|
|
|
|
#include <vector>
|
|
|
|
class VTKFILTERSFLOWPATHS_EXPORT vtkStreamTracer : public vtkPolyDataAlgorithm
|
|
{
|
|
public:
|
|
vtkTypeMacro(vtkStreamTracer, vtkPolyDataAlgorithm);
|
|
void PrintSelf(ostream& os, vtkIndent indent) override;
|
|
|
|
/**
|
|
* Construct object to start from position (0,0,0), with forward
|
|
* integration, terminal speed 1.0E-12, vorticity computation on,
|
|
* integration step size 0.5 (in cell length unit), maximum number
|
|
* of steps 2000, using Runge-Kutta2, and maximum propagation 1.0
|
|
* (in arc length unit).
|
|
*/
|
|
static vtkStreamTracer* New();
|
|
|
|
//@{
|
|
/**
|
|
* Specify the starting point (seed) of a streamline in the global
|
|
* coordinate system. Search must be performed to find the initial cell
|
|
* from which to start integration.
|
|
*/
|
|
vtkSetVector3Macro(StartPosition, double);
|
|
vtkGetVector3Macro(StartPosition, double);
|
|
//@}
|
|
|
|
//@{
|
|
/**
|
|
* Specify the source object used to generate starting points (seeds).
|
|
* Note that this method does not connect the pipeline. The algorithm will
|
|
* work on the input data as it is without updating the producer of the data.
|
|
* See SetSourceConnection for connecting the pipeline.
|
|
*/
|
|
void SetSourceData(vtkDataSet* source);
|
|
vtkDataSet* GetSource();
|
|
//@}
|
|
|
|
/**
|
|
* Specify the source object used to generate starting points (seeds).
|
|
* New style.
|
|
*/
|
|
void SetSourceConnection(vtkAlgorithmOutput* algOutput);
|
|
|
|
// The previously-supported TIME_UNIT is excluded in this current
|
|
// enumeration definition because the underlying step size is ALWAYS in
|
|
// arc length unit (LENGTH_UNIT) while the 'real' time interval (virtual
|
|
// for steady flows) that a particle actually takes to trave in a single
|
|
// step is obtained by dividing the arc length by the LOCAL speed. The
|
|
// overall elapsed time (i.e., the life span) of the particle is the sum
|
|
// of those individual step-wise time intervals. The arc-length-to-time
|
|
// conversion only occurs for vorticity computation and for generating a
|
|
// point data array named 'IntegrationTime'.
|
|
enum Units
|
|
{
|
|
LENGTH_UNIT = 1,
|
|
CELL_LENGTH_UNIT = 2
|
|
};
|
|
|
|
enum Solvers
|
|
{
|
|
RUNGE_KUTTA2,
|
|
RUNGE_KUTTA4,
|
|
RUNGE_KUTTA45,
|
|
NONE,
|
|
UNKNOWN
|
|
};
|
|
|
|
enum ReasonForTermination
|
|
{
|
|
OUT_OF_DOMAIN = vtkInitialValueProblemSolver::OUT_OF_DOMAIN,
|
|
NOT_INITIALIZED = vtkInitialValueProblemSolver::NOT_INITIALIZED,
|
|
UNEXPECTED_VALUE = vtkInitialValueProblemSolver::UNEXPECTED_VALUE,
|
|
OUT_OF_LENGTH = 4,
|
|
OUT_OF_STEPS = 5,
|
|
STAGNATION = 6,
|
|
FIXED_REASONS_FOR_TERMINATION_COUNT
|
|
};
|
|
|
|
//@{
|
|
/**
|
|
* Set/get the integrator type to be used for streamline generation.
|
|
* The object passed is not actually used but is cloned with
|
|
* NewInstance in the process of integration (prototype pattern).
|
|
* The default is Runge-Kutta2. The integrator can also be changed
|
|
* using SetIntegratorType. The recognized solvers are:
|
|
* RUNGE_KUTTA2 = 0
|
|
* RUNGE_KUTTA4 = 1
|
|
* RUNGE_KUTTA45 = 2
|
|
*/
|
|
void SetIntegrator(vtkInitialValueProblemSolver*);
|
|
vtkGetObjectMacro(Integrator, vtkInitialValueProblemSolver);
|
|
void SetIntegratorType(int type);
|
|
int GetIntegratorType();
|
|
void SetIntegratorTypeToRungeKutta2() { this->SetIntegratorType(RUNGE_KUTTA2); }
|
|
void SetIntegratorTypeToRungeKutta4() { this->SetIntegratorType(RUNGE_KUTTA4); }
|
|
void SetIntegratorTypeToRungeKutta45() { this->SetIntegratorType(RUNGE_KUTTA45); }
|
|
//@}
|
|
|
|
/**
|
|
* Set the velocity field interpolator type to the one involving
|
|
* a dataset point locator.
|
|
*/
|
|
void SetInterpolatorTypeToDataSetPointLocator();
|
|
|
|
/**
|
|
* Set the velocity field interpolator type to the one involving
|
|
* a cell locator.
|
|
*/
|
|
void SetInterpolatorTypeToCellLocator();
|
|
|
|
//@{
|
|
/**
|
|
* Specify the maximum length of a streamline expressed in LENGTH_UNIT.
|
|
*/
|
|
vtkSetMacro(MaximumPropagation, double);
|
|
vtkGetMacro(MaximumPropagation, double);
|
|
//@}
|
|
|
|
/**
|
|
* Specify a uniform integration step unit for MinimumIntegrationStep,
|
|
* InitialIntegrationStep, and MaximumIntegrationStep. NOTE: The valid
|
|
* unit is now limited to only LENGTH_UNIT (1) and CELL_LENGTH_UNIT (2),
|
|
* EXCLUDING the previously-supported TIME_UNIT.
|
|
*/
|
|
void SetIntegrationStepUnit(int unit);
|
|
int GetIntegrationStepUnit() { return this->IntegrationStepUnit; }
|
|
|
|
//@{
|
|
/**
|
|
* Specify the Initial step size used for line integration, expressed in:
|
|
* LENGTH_UNIT = 1
|
|
* CELL_LENGTH_UNIT = 2
|
|
* (either the starting size for an adaptive integrator, e.g., RK45,
|
|
* or the constant / fixed size for non-adaptive ones, i.e., RK2 and RK4)
|
|
*/
|
|
vtkSetMacro(InitialIntegrationStep, double);
|
|
vtkGetMacro(InitialIntegrationStep, double);
|
|
//@}
|
|
|
|
//@{
|
|
/**
|
|
* Specify the Minimum step size used for line integration, expressed in:
|
|
* LENGTH_UNIT = 1
|
|
* CELL_LENGTH_UNIT = 2
|
|
* (Only valid for an adaptive integrator, e.g., RK45)
|
|
*/
|
|
vtkSetMacro(MinimumIntegrationStep, double);
|
|
vtkGetMacro(MinimumIntegrationStep, double);
|
|
//@}
|
|
|
|
//@{
|
|
/**
|
|
* Specify the Maximum step size used for line integration, expressed in:
|
|
* LENGTH_UNIT = 1
|
|
* CELL_LENGTH_UNIT = 2
|
|
* (Only valid for an adaptive integrator, e.g., RK45)
|
|
*/
|
|
vtkSetMacro(MaximumIntegrationStep, double);
|
|
vtkGetMacro(MaximumIntegrationStep, double);
|
|
//@}
|
|
|
|
//@{
|
|
/**
|
|
* Specify the maximum error tolerated throughout streamline integration.
|
|
*/
|
|
vtkSetMacro(MaximumError, double);
|
|
vtkGetMacro(MaximumError, double);
|
|
//@}
|
|
|
|
//@{
|
|
/**
|
|
* Specify the maximum number of steps for integrating a streamline.
|
|
*/
|
|
vtkSetMacro(MaximumNumberOfSteps, vtkIdType);
|
|
vtkGetMacro(MaximumNumberOfSteps, vtkIdType);
|
|
//@}
|
|
|
|
//@{
|
|
/**
|
|
* Specify the terminal speed value, below which integration is terminated.
|
|
*/
|
|
vtkSetMacro(TerminalSpeed, double);
|
|
vtkGetMacro(TerminalSpeed, double);
|
|
//@}
|
|
|
|
//@{
|
|
/**
|
|
* Set/Unset the streamlines to be computed on a surface
|
|
*/
|
|
vtkGetMacro(SurfaceStreamlines, bool);
|
|
vtkSetMacro(SurfaceStreamlines, bool);
|
|
vtkBooleanMacro(SurfaceStreamlines, bool);
|
|
//@}
|
|
|
|
enum
|
|
{
|
|
FORWARD,
|
|
BACKWARD,
|
|
BOTH
|
|
};
|
|
|
|
enum
|
|
{
|
|
INTERPOLATOR_WITH_DATASET_POINT_LOCATOR,
|
|
INTERPOLATOR_WITH_CELL_LOCATOR
|
|
};
|
|
|
|
//@{
|
|
/**
|
|
* Specify whether the streamline is integrated in the upstream or
|
|
* downstream direction.
|
|
*/
|
|
vtkSetClampMacro(IntegrationDirection, int, FORWARD, BOTH);
|
|
vtkGetMacro(IntegrationDirection, int);
|
|
void SetIntegrationDirectionToForward() { this->SetIntegrationDirection(FORWARD); }
|
|
void SetIntegrationDirectionToBackward() { this->SetIntegrationDirection(BACKWARD); }
|
|
void SetIntegrationDirectionToBoth() { this->SetIntegrationDirection(BOTH); }
|
|
//@}
|
|
|
|
//@{
|
|
/**
|
|
* Turn on/off vorticity computation at streamline points
|
|
* (necessary for generating proper stream-ribbons using the
|
|
* vtkRibbonFilter.
|
|
*/
|
|
vtkSetMacro(ComputeVorticity, bool);
|
|
vtkGetMacro(ComputeVorticity, bool);
|
|
//@}
|
|
|
|
//@{
|
|
/**
|
|
* This can be used to scale the rate with which the streamribbons
|
|
* twist. The default is 1.
|
|
*/
|
|
vtkSetMacro(RotationScale, double);
|
|
vtkGetMacro(RotationScale, double);
|
|
//@}
|
|
|
|
/**
|
|
* The object used to interpolate the velocity field during
|
|
* integration is of the same class as this prototype.
|
|
*/
|
|
void SetInterpolatorPrototype(vtkAbstractInterpolatedVelocityField* ivf);
|
|
|
|
/**
|
|
* Set the type of the velocity field interpolator to determine whether
|
|
* vtkInterpolatedVelocityField (INTERPOLATOR_WITH_DATASET_POINT_LOCATOR) or
|
|
* vtkCellLocatorInterpolatedVelocityField (INTERPOLATOR_WITH_CELL_LOCATOR)
|
|
* is employed for locating cells during streamline integration. The latter
|
|
* (adopting vtkAbstractCellLocator sub-classes such as vtkCellLocator and
|
|
* vtkModifiedBSPTree) is more robust then the former (through vtkDataSet /
|
|
* vtkPointSet::FindCell() coupled with vtkPointLocator).
|
|
*/
|
|
void SetInterpolatorType(int interpType);
|
|
|
|
/**
|
|
* Asks the user if the current streamline should be terminated.
|
|
* clientdata is set by the client when setting up the callback.
|
|
* points is the array of points integrated so far
|
|
* velocity velocity vector integrated to produce the streamline
|
|
* integrationDirection FORWARD of BACKWARD
|
|
* The function returns true if the streamline should be terminated
|
|
* and false otherwise.
|
|
*/
|
|
typedef bool (*CustomTerminationCallbackType)(
|
|
void* clientdata, vtkPoints* points, vtkDataArray* velocity, int integrationDirection);
|
|
/**
|
|
* Adds a custom termination callback.
|
|
* callback is a function provided by the user that says if the streamline
|
|
* should be terminated.
|
|
* clientdata user specific data passed to the callback
|
|
* reasonForTermination this value will be set in the ReasonForTermination cell
|
|
* array if the streamline is terminated by this callback.
|
|
*/
|
|
void AddCustomTerminationCallback(
|
|
CustomTerminationCallbackType callback, void* clientdata, int reasonForTermination);
|
|
|
|
protected:
|
|
vtkStreamTracer();
|
|
~vtkStreamTracer() override;
|
|
|
|
// Create a default executive.
|
|
vtkExecutive* CreateDefaultExecutive() override;
|
|
|
|
// hide the superclass' AddInput() from the user and the compiler
|
|
void AddInput(vtkDataObject*)
|
|
{
|
|
vtkErrorMacro(<< "AddInput() must be called with a vtkDataSet not a vtkDataObject.");
|
|
}
|
|
|
|
int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override;
|
|
int FillInputPortInformation(int, vtkInformation*) override;
|
|
|
|
void CalculateVorticity(
|
|
vtkGenericCell* cell, double pcoords[3], vtkDoubleArray* cellVectors, double vorticity[3]);
|
|
void Integrate(vtkPointData* inputData, vtkPolyData* output, vtkDataArray* seedSource,
|
|
vtkIdList* seedIds, vtkIntArray* integrationDirections, double lastPoint[3],
|
|
vtkAbstractInterpolatedVelocityField* func, int maxCellSize, int vecType,
|
|
const char* vecFieldName, double& propagation, vtkIdType& numSteps, double& integrationTime);
|
|
double SimpleIntegrate(double seed[3], double lastPoint[3], double stepSize,
|
|
vtkAbstractInterpolatedVelocityField* func);
|
|
int CheckInputs(vtkAbstractInterpolatedVelocityField*& func, int* maxCellSize);
|
|
void GenerateNormals(vtkPolyData* output, double* firstNormal, const char* vecName);
|
|
|
|
bool GenerateNormalsInIntegrate;
|
|
|
|
// starting from global x-y-z position
|
|
double StartPosition[3];
|
|
|
|
static const double EPSILON;
|
|
double TerminalSpeed;
|
|
|
|
double LastUsedStepSize;
|
|
|
|
struct IntervalInformation
|
|
{
|
|
double Interval;
|
|
int Unit;
|
|
};
|
|
|
|
double MaximumPropagation;
|
|
double MinimumIntegrationStep;
|
|
double MaximumIntegrationStep;
|
|
double InitialIntegrationStep;
|
|
|
|
void ConvertIntervals(
|
|
double& step, double& minStep, double& maxStep, int direction, double cellLength);
|
|
static double ConvertToLength(double interval, int unit, double cellLength);
|
|
static double ConvertToLength(IntervalInformation& interval, double cellLength);
|
|
|
|
int SetupOutput(vtkInformation* inInfo, vtkInformation* outInfo);
|
|
void InitializeSeeds(vtkDataArray*& seeds, vtkIdList*& seedIds,
|
|
vtkIntArray*& integrationDirections, vtkDataSet* source);
|
|
|
|
int IntegrationStepUnit;
|
|
int IntegrationDirection;
|
|
|
|
// Prototype showing the integrator type to be set by the user.
|
|
vtkInitialValueProblemSolver* Integrator;
|
|
|
|
double MaximumError;
|
|
vtkIdType MaximumNumberOfSteps;
|
|
|
|
bool ComputeVorticity;
|
|
double RotationScale;
|
|
|
|
// Compute streamlines only on surface.
|
|
bool SurfaceStreamlines;
|
|
|
|
vtkAbstractInterpolatedVelocityField* InterpolatorPrototype;
|
|
|
|
vtkCompositeDataSet* InputData;
|
|
bool
|
|
HasMatchingPointAttributes; // does the point data in the multiblocks have the same attributes?
|
|
std::vector<CustomTerminationCallbackType> CustomTerminationCallback;
|
|
std::vector<void*> CustomTerminationClientData;
|
|
std::vector<int> CustomReasonForTermination;
|
|
|
|
friend class PStreamTracerUtils;
|
|
|
|
private:
|
|
vtkStreamTracer(const vtkStreamTracer&) = delete;
|
|
void operator=(const vtkStreamTracer&) = delete;
|
|
};
|
|
|
|
#endif
|
|
// VTK-HeaderTest-Exclude: vtkStreamTracer.h
|