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.
 
 
 
 
 
 

406 lines
12 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkKochanekSpline.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 "vtkKochanekSpline.h"
#include "vtkObjectFactory.h"
#include "vtkPiecewiseFunction.h"
vtkCxxRevisionMacro(vtkKochanekSpline, "$Revision: 1.28 $");
vtkStandardNewMacro(vtkKochanekSpline);
//----------------------------------------------------------------------------
// Construct a KochanekSpline wth the following defaults:
// DefaultBias = 0,
// DefaultTension = 0,
// DefaultContinuity = 0.
vtkKochanekSpline::vtkKochanekSpline ()
{
this->DefaultBias = 0.0;
this->DefaultTension = 0.0;
this->DefaultContinuity = 0.0;
}
//----------------------------------------------------------------------------
// Evaluate a 1D Spline
double vtkKochanekSpline::Evaluate (double t)
{
int index = 0;
double *intervals;
double *coefficients;
// check to see if we need to recompute the spline
if (this->ComputeTime < this->GetMTime ())
{
this->Compute ();
}
// make sure we have at least 2 points
int size = this->PiecewiseFunction->GetSize ();
if (size < 2)
{
return 0.0;
}
intervals = this->Intervals;
coefficients = this->Coefficients;
if ( this->Closed )
{
size = size + 1;
}
// clamp the function at both ends
if (t < intervals[0])
{
t = intervals[0];
}
if (t > intervals[size - 1])
{
t = intervals[size - 1];
}
// find pointer to cubic spline coefficient
index = this->FindIndex(size,t);
// calculate offset within interval
t = (t - intervals[index]) / (intervals[index+1] - intervals[index]);
// evaluate y
return (t * (t * (t * *(coefficients + index * 4 + 3)
+ *(coefficients + index * 4 + 2))
+ *(coefficients + index * 4 + 1))
+ *(coefficients + index * 4));
}
//----------------------------------------------------------------------------
// Compute Kochanek Spline coefficients.
void vtkKochanekSpline::Compute ()
{
double *ts, *xs;
double *coefficients;
double *dependent;
int size;
int i;
// Make sure the function is up to date.
this->PiecewiseFunction->Update();
// get the size of the independent variables
size = this->PiecewiseFunction->GetSize ();
if(size < 2)
{
vtkErrorMacro("Spline requires at least 2 points. # of points is: " <<size);
return;
}
if ( !this->Closed )
{
// copy the independent variables
if (this->Intervals)
{
delete [] this->Intervals;
}
this->Intervals = new double[size];
ts = this->PiecewiseFunction->GetDataPointer ();
for (i = 0; i < size; i++)
{
this->Intervals[i] = *(ts + 2*i);
}
// allocate memory for coefficients
if (this->Coefficients)
{
delete [] this->Coefficients;
}
this->Coefficients = new double [4*size];
// allocate memory for dependent variables
dependent = new double [size];
// get start of coefficients for this dependent variable
coefficients = this->Coefficients;
// get the dependent variable values
xs = this->PiecewiseFunction->GetDataPointer () + 1;
for (int j = 0; j < size; j++)
{
*(dependent + j) = *(xs + 2*j);
}
}
else //spline is closed, create extra "fictitious" point
{
size = size + 1;
// copy the independent variables
if (this->Intervals)
{
delete [] this->Intervals;
}
this->Intervals = new double[size];
ts = this->PiecewiseFunction->GetDataPointer ();
for (i = 0; i < size-1; i++)
{
this->Intervals[i] = *(ts + 2 * i);
}
if ( this->ParametricRange[0] != this->ParametricRange[1] )
{
this->Intervals[size-1] = this->ParametricRange[1];
}
else
{
this->Intervals[size-1] = this->Intervals[size-2] + 1.0;
}
// allocate memory for coefficients
if (this->Coefficients)
{
delete [] this->Coefficients;
}
this->Coefficients = new double [4 * size];
// allocate memory for dependent variables
dependent = new double [size];
// get start of coefficients for this dependent variable
coefficients = this->Coefficients;
// get the dependent variable values
xs = this->PiecewiseFunction->GetDataPointer () + 1;
for (int j = 0; j < size-1; j++)
{
*(dependent + j) = *(xs + 2*j);
}
dependent[size-1] = *xs;
}
this->Fit1D (size, this->Intervals, dependent,
this->DefaultTension,
this->DefaultBias,
this->DefaultContinuity,
(double (*)[4])coefficients,
this->LeftConstraint, this->LeftValue,
this->RightConstraint, this->RightValue);
// free the dependent variable storage
delete [] dependent;
// update compute time
this->ComputeTime = this->GetMTime();
}
#define VTK_EPSILON .0001
//----------------------------------------------------------------------------
// Compute the coefficients for a 1D spline
void vtkKochanekSpline::Fit1D (int size, double *x, double *y,
double tension, double bias, double continuity,
double coefficients[][4],
int leftConstraint, double leftValue,
int rightConstraint, double rightValue)
{
double cs; /* source chord */
double cd; /* destination chord */
double ds; /* source deriviative */
double dd; /* destination deriviative */
double n0, n1; /* number of frames btwn nodes */
int N; /* top point number */
int i;
if (size == 2)
{
// two points, set coefficients for a straight line
coefficients[0][3] = 0.0;
coefficients[1][3] = 0.0;
coefficients[0][2] = 0.0;
coefficients[1][2] = 0.0;
coefficients[0][1] = (y[1] - y[0]) / (x[1] - x[0]);
coefficients[1][1] = coefficients[0][1];
coefficients[0][0] = y[0];
coefficients[1][0] = y[1];
return;
}
N = size - 1;
for (i=1; i < N; i++)
{
cs = y[i] - y[i-1];
cd = y[i+1] - y[i];
ds = cs*((1 - tension)*(1 - continuity)*(1 + bias)) / 2.0
+ cd*((1 - tension)*(1 + continuity)*(1 - bias)) / 2.0;
dd = cs*((1 - tension)*(1 + continuity)*(1 + bias)) / 2.0
+ cd*((1 - tension)*(1 - continuity)*(1 - bias)) / 2.0;
// adjust deriviatives for non uniform spacing between nodes
n1 = x[i+1] - x[i];
n0 = x[i] - x[i-1];
ds *= (2 * n0 / (n0 + n1));
dd *= (2 * n1 / (n0 + n1));
coefficients[i][0] = y[i];
coefficients[i][1] = dd;
coefficients[i][2] = ds;
}
// Calculate the deriviatives at the end points
coefficients[0][0] = y[0];
coefficients[N][0] = y[N];
if ( this->Closed ) //the curve is continuous and closed at P0=Pn
{
cs = y[N] - y[N-1];
cd = y[1] - y[0];
ds = cs*((1 - tension)*(1 - continuity)*(1 + bias)) / 2.0
+ cd*((1 - tension)*(1 + continuity)*(1 - bias)) / 2.0;
dd = cs*((1 - tension)*(1 + continuity)*(1 + bias)) / 2.0
+ cd*((1 - tension)*(1 - continuity)*(1 - bias)) / 2.0;
// adjust deriviatives for non uniform spacing between nodes
n1 = x[1] - x[0];
n0 = x[N] - x[N-1];
ds *= (2 * n1 / (n0 + n1));
dd *= (2 * n0 / (n0 + n1));
coefficients[0][1] = dd;
coefficients[0][2] = ds;
coefficients[N][1] = dd;
coefficients[N][2] = ds;
}
else //curve is open
{
switch (leftConstraint)
{
case 0:
// desired slope at leftmost point is leftValue
coefficients[0][1] = this->ComputeLeftDerivative();
break;
case 1:
// desired slope at leftmost point is leftValue
coefficients[0][1] = leftValue;
break;
case 2:
// desired second derivative at leftmost point is leftValue
coefficients[0][1] = (6*(y[1] - y[0]) - 2*coefficients[1][2] - leftValue)
/ 4.0;
break;
case 3:
// desired secord derivative at leftmost point is leftValue
// times secod derivative at first interior point
if ((leftValue > (-2.0 + VTK_EPSILON)) ||
(leftValue < (-2.0 - VTK_EPSILON)))
{
coefficients[0][1] = (3*(1 + leftValue)*(y[1] - y[0]) -
(1 + 2*leftValue)*coefficients[1][2])
/ (2 + leftValue);
}
else
{
coefficients[0][1] = 0.0;
}
break;
}
switch (rightConstraint)
{
case 0:
// desired slope at rightmost point is rightValue
coefficients[N][2] = this->ComputeRightDerivative();
break;
case 1:
// desired slope at rightmost point is rightValue
coefficients[N][2] = rightValue;
break;
case 2:
// desired second derivative at rightmost point is rightValue
coefficients[N][2] = (6*(y[N] - y[N-1]) - 2*coefficients[N-1][1] +
rightValue) / 4.0;
break;
case 3:
// desired secord derivative at rightmost point is rightValue
// times secord derivative at last interior point
if ((rightValue > (-2.0 + VTK_EPSILON)) ||
(rightValue < (-2.0 - VTK_EPSILON)))
{
coefficients[N][2] = (3*(1 + rightValue)*(y[N] - y[N-1]) -
(1 + 2*rightValue)*coefficients[N-1][1])
/ (2 + rightValue);
}
else
{
coefficients[N][2] = 0.0;
}
break;
}
}//curve is open
// Compute the Coefficients
for (i=0; i < N; i++)
{
//
// c0 = P ; c1 = DD ;
// i i i i
//
// c1 = P ; c2 = DS ;
// i+1 i+1 i+1 i+1
//
// c2 = -3P + 3P - 2DD - DS ;
// i i i+1 i i+1
//
// c3 = 2P - 2P + DD + DS ;
// i i i+1 i i+1
//
coefficients[i][2] = (-3 * y[i]) + ( 3 * y[i+1])
+ (-2 * coefficients[i][1]) + (-1 * coefficients[i+1][2]);
coefficients[i][3] = ( 2 * y[i]) + (-2 * y[i+1])
+ ( 1 * coefficients[i][1]) + ( 1 * coefficients[i+1][2]);
}
}
//----------------------------------------------------------------------------
void vtkKochanekSpline::DeepCopy(vtkSpline *s)
{
vtkKochanekSpline *spline = vtkKochanekSpline::SafeDownCast(s);
if ( spline != NULL )
{
this->DefaultBias = spline->DefaultBias;
this->DefaultTension = spline->DefaultTension;
this->DefaultContinuity = spline->DefaultContinuity;
}
// Now do superclass
this->vtkSpline::DeepCopy(s);
}
//----------------------------------------------------------------------------
void vtkKochanekSpline::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
os << indent << "DefaultBias: " << this->DefaultBias << "\n";
os << indent << "DefaultTension: " << this->DefaultTension << "\n";
os << indent << "DefaultContinuity: " << this->DefaultContinuity << "\n";
}