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.

903 lines
20 KiB

2 years ago
/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkPiecewiseFunction.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 "vtkPiecewiseFunction.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
vtkCxxRevisionMacro(vtkPiecewiseFunction, "$Revision: 1.41.8.1 $");
vtkStandardNewMacro(vtkPiecewiseFunction);
// Construct a new vtkPiecewiseFunction with default values
vtkPiecewiseFunction::vtkPiecewiseFunction()
{
this->ArraySize = 64;
this->Clamping = 1;
this->Function = new double[this->ArraySize*2];
this->FunctionSize = 0;
this->FunctionRange[0] = 0;
this->FunctionRange[1] = 0;
for (int i=0; i < this->ArraySize*2; i++)
{
this->Function[i] = 0.0;
}
}
// Destruct a vtkPiecewiseFunction
vtkPiecewiseFunction::~vtkPiecewiseFunction()
{
if( this->Function )
{
delete [] this->Function;
}
}
void vtkPiecewiseFunction::DeepCopy( vtkDataObject *o )
{
vtkPiecewiseFunction *f = vtkPiecewiseFunction::SafeDownCast(o);
if (f != NULL)
{
this->ArraySize = f->ArraySize;
this->Clamping = f->Clamping;
this->FunctionSize = f->FunctionSize;
memcpy( this->FunctionRange, f->FunctionRange, 2*sizeof(double) );
if ( this->ArraySize > 0 )
{
delete [] this->Function;
this->Function = new double[this->ArraySize*2];
memcpy( this->Function, f->Function, this->ArraySize*2*sizeof(double) );
}
this->Modified();
}
// Do the superclass
this->vtkDataObject::DeepCopy(o);
}
void vtkPiecewiseFunction::ShallowCopy( vtkDataObject *o )
{
vtkPiecewiseFunction *f = vtkPiecewiseFunction::SafeDownCast(o);
if (f != NULL)
{
this->ArraySize = f->ArraySize;
this->Clamping = f->Clamping;
this->Function = new double[this->ArraySize*2];
this->FunctionSize = f->FunctionSize;
memcpy( this->FunctionRange, f->FunctionRange, 2*sizeof(double) );
memcpy( this->Function, f->Function, this->ArraySize*2*sizeof(double) );
}
// Do the superclass
this->vtkDataObject::ShallowCopy(o);
}
void vtkPiecewiseFunction::Initialize()
{
if ( this->Function)
{
delete [] this->Function;
}
this->ArraySize = 64;
this->Clamping = 1;
this->Function = new double[this->ArraySize*2];
this->FunctionSize = 0;
this->FunctionRange[0] = 0;
this->FunctionRange[1] = 0;
for (int i=0; i < this->ArraySize*2; i++)
{
this->Function[i] = 0.0;
}
}
// Return the number of points which specify this function
int vtkPiecewiseFunction::GetSize()
{
return this->FunctionSize;
}
// Return the type of function stored in object:
// Function Types:
// 0 : Constant (No change in slope between end points)
// 1 : NonDecreasing (Always increasing or zero slope)
// 2 : NonIncreasing (Always decreasing or zero slope)
// 3 : Varied (Contains both decreasing and increasing slopes)
// 4 : Unknown (Error condition)
//
const char *vtkPiecewiseFunction::GetType()
{
int i;
double value;
double prev_value = 0.0;
int function_type;
function_type = 0;
if( this->FunctionSize )
{
prev_value = this->Function[1];
}
for( i=1; i < this->FunctionSize; i++ )
{
value = this->Function[(2*i+1)];
// Do not change the function type if equal
if( value != prev_value )
{
if( value > prev_value )
{
switch( function_type )
{
case 0:
case 1:
function_type = 1; // NonDecreasing
break;
case 2:
function_type = 3; // Varied
break;
}
}
else // value < prev_value
{
switch( function_type )
{
case 0:
case 2:
function_type = 2; // NonIncreasing
break;
case 1:
function_type = 3; // Varied
break;
}
}
}
prev_value = value;
// Exit loop if we find a Varied function
if( function_type == 3 )
{
break;
}
}
switch( function_type )
{
case 0:
return "Constant";
case 1:
return "NonDecreasing";
case 2:
return "NonIncreasing";
case 3:
return "Varied";
}
return "Unknown";
}
// Returns the first point location which starts a non-zero segment of the
// function. Note that the value at this point may be zero.
double vtkPiecewiseFunction::GetFirstNonZeroValue()
{
int i;
int all_zero = 1;
double x = 0.0;
// Check if no points specified
if( this->FunctionSize == 0 )
{
return 0;
}
for( i=0; i < this->FunctionSize; i++ )
{
if( this->Function[(2*i+1)] != 0.0 )
{
x = this->Function[(2*i)];
all_zero = 0;
break;
}
}
// If every specified point has a zero value then return the first points
// position
if( all_zero )
{
x = this->Function[0];
}
else // A point was found with a non-zero value
{
if( i > 0 )
// Return the value of the point that precedes this one
{
x = this->Function[2*(i-1)];
}
else
// If this is the first point in the function, return its value
{
x = this->Function[0];
}
}
return x;
}
// Adds a point to the function. If a duplicate point is inserted
// then the function value at that location is set to the new value.
int vtkPiecewiseFunction::AddPoint( double x, double val )
{
return this->InsertPoint( x, val );
}
// Adds a point to the function and returns the array index of the point.
int vtkPiecewiseFunction::InsertPoint( double x, double val )
{
int point_index;
int i;
// Increase function size if we exceed array bound
if( (this->FunctionSize*2) >= this->ArraySize )
{
this->IncreaseArraySize();
}
// Insert the first point
if( this->FunctionSize == 0 )
{
// Set the point in the function
this->Function[0] = x;
this->Function[1] = val;
this->FunctionSize = 1;
// Update function range
this->FunctionRange[0] = x;
this->FunctionRange[1] = x;
point_index = 0;
}
else // Insert a point inside list
{
i = 0;
// Find insertion index
while( (i < this->FunctionSize) && (this->Function[(i*2)] <= x) )
{
// Check for duplicate entries
// Overwrite value if found
if( x == this->Function[(i*2)] )
{
if (this->Function[(i*2 + 1)] != val)
{
this->Function[(i*2 + 1)] = val;
this->Modified();
}
return i;
}
// Move to next point
i++;
}
this->FunctionSize++;
// Move points down one element
this->MovePoints( i, 1 );
// Insert new point at index
this->Function[(2*i)] = x;
this->Function[(2*i+1)] = val;
point_index = i;
// Update function range
if( x < this->FunctionRange[0] )
{
this->FunctionRange[0] = x;
}
if( x > this->FunctionRange[1] )
{
this->FunctionRange[1] = x;
}
}
this->Modified();
return point_index;
}
// Moves all points to the right of index down or up by one index value
// depending on the down flag. Assumes that memory for move is already
// allocated.
void vtkPiecewiseFunction::MovePoints( int index, int down )
{
int i;
double swap1_x, swap1_y;
double swap2_x, swap2_y;
i = index;
// Moving down
if( down )
{
// If it is the last point we don't need to move anything
if ( (i+1) < this->FunctionSize )
{
// Move points down (i+1) = i
swap1_x = this->Function[(2*i)];
swap1_y = this->Function[(2*i+1)];
i = i + 1;
// Move following points down
while( i < this->FunctionSize )
{
swap2_x = this->Function[(2*i)];
swap2_y = this->Function[(2*i+1)];
this->Function[(2*i)] = swap1_x;
this->Function[(2*i+1)] = swap1_y;
swap1_x = swap2_x;
swap1_y = swap2_y;
i++;
}
}
}
// Moving up
else
{
// Move points up (i = i+1)
// This destroys values at index i
while( i < (this->FunctionSize-1) )
{
this->Function[(2*i)] = this->Function[(2*(i+1))];
this->Function[(2*i+1)] = this->Function[(2*(i+1)+1)];
i++;
}
}
}
// Removes a point from the function. If no point is found then function
// remains the same.
int vtkPiecewiseFunction::RemovePoint( double x )
{
int i;
double x1;
if( this->FunctionSize )
{
i = 0;
x1 = this->Function[0];
// Locate the point in the array
while( (x1 != x) && (i < this->FunctionSize) )
{
// Move to next point
i++;
x1 = this->Function[(i*2)];
}
// Remove the point
if( i < this->FunctionSize )
{
this->MovePoints( i, 0 );
this->FunctionSize--;
if (this->FunctionSize > 0)
{
this->FunctionRange[0] = this->Function[0];
this->FunctionRange[1] = this->Function[2*(this->FunctionSize-1)];
}
else
{
this->FunctionRange[0] = this->FunctionRange[1] = 0.0;
}
this->Modified();
return i;
}
}
return -1;
}
// Removes all points from the function.
void vtkPiecewiseFunction::RemoveAllPoints()
{
if (!this->FunctionSize)
{
return;
}
this->FunctionSize = 0;
this->FunctionRange[0] = 0;
this->FunctionRange[1] = 0;
this->Modified();
}
// Add in end points of line and remove any points between them
void vtkPiecewiseFunction::AddSegment( double x1, double val1,
double x2, double val2 )
{
int index1, index2;
int swap;
int distance;
int i;
// Insert the two endpoints
index1 = this->InsertPoint( x1, val1 );
index2 = this->InsertPoint( x2, val2 );
if( index1 == index2 )
{
return;
}
if( index1 > index2 )
{
swap = index1;
index1 = index2;
index2 = swap;
}
distance = index2 - index1 - 1;
// Loop between index2 and last point and remove points
for( i=index2; i < this->FunctionSize; i++ )
{
this->Function[(2*(i-distance))] = this->Function[(2*i)];
this->Function[(2*(i-distance)+1)] = this->Function[(2*i+1)];
}
this->FunctionSize = this->FunctionSize - distance;
}
// Return the value of the function at a position
double vtkPiecewiseFunction::GetValue( double x )
{
int i1, i2;
double x1, y1; // Point before x
double x2, y2; // Point after x
double slope;
double value;
if( this->FunctionSize == 0 )
{
return 0.0;
}
if( this->Clamping == 1 ) // Clamped to lowest value below range and highest above range
{
// Check to see if point is out of range
if( x < this->FunctionRange[0] )
{
x = this->Function[0];
}
else if( x > this->FunctionRange[1] )
{
x = this->Function[(this->FunctionSize-1)*2];
}
}
else if( this->Clamping == 0 ) // Always zero outside of range
{
if( (x < this->FunctionRange[0]) || (x > this->FunctionRange[1]) )
{
return 0.0;
}
}
else
{
vtkErrorMacro( << "Error: vtkPiecewiseFunction has an unknown clamp type: " << this->Clamping << "\n" );
return 0.0;
}
i2 = 0;
x2 = this->Function[0];
y2 = this->Function[1];
while( (x2 < x) && (i2 < this->FunctionSize) )
{
i2 += 1;
x2 = this->Function[(i2*2)];
y2 = this->Function[(i2*2+1)];
}
// Check if we have found the exact point
if( x2 == x )
{
return this->Function[(i2*2 + 1)];
}
else
{
i1 = i2 - 1;
x1 = this->Function[(i1*2)];
y1 = this->Function[(i1*2 +1)];
}
// Now that we have the two points, use linear interpolation
slope = (y2-y1)/(x2-x1);
value = y1 + slope*(x-x1);
return value;
}
// Return the smallest and largest position stored in function
double *vtkPiecewiseFunction::GetRange()
{
return this->FunctionRange;
}
int vtkPiecewiseFunction::AdjustRange(double range[2])
{
if (!range)
{
return 0;
}
double *function_range = this->GetRange();
// Make sure we have points at each end of the range
if (function_range[0] < range[0])
{
this->AddPoint(range[0], this->GetValue(range[0]));
}
else
{
this->AddPoint(range[0], this->GetValue(function_range[0]));
}
if (function_range[1] > range[1])
{
this->AddPoint(range[1], this->GetValue(range[1]));
}
else
{
this->AddPoint(range[1], this->GetValue(function_range[1]));
}
// Remove all points out-of-range
int func_size = this->GetSize();
double *func_ptr = this->GetDataPointer();
int i;
for (i = func_size - 1; i >= 0; i--)
{
double x = func_ptr[i * 2];
if (x < range[0] || x > range[1])
{
this->RemovePoint(x);
}
}
return 1;
}
// Returns a table of function values evaluated at regular intervals
void vtkPiecewiseFunction::GetTable( double x1, double x2, int size,
double* table, int stride )
{
double x, xi1, xi2, yi1, yi2, tx;
double inc, value, slope, *tbl;
int i, i1, i2;
if( x1 == x2 )
{
return;
}
if( size > 1 )
{
inc = (x2-x1)/(double)(size-1);
}
else
{
inc = 0;
}
tbl = table;
x = x1;
i2 = 0;
xi2 = this->Function[0];
yi2 = this->Function[1];
for (i=0; i < size; i++)
{
tx = x;
// Clamped to lowest value below range and highest above range
if( this->Clamping == 1 )
{
if( x < this->FunctionRange[0] )
{
tx = this->Function[0];
}
else if( x > this->FunctionRange[1] )
{
tx = this->Function[(this->FunctionSize-1)*2];
}
}
else if( this->Clamping == 0 ) // Always zero outside of range
{
if( (x < this->FunctionRange[0]) || (x > this->FunctionRange[1]) )
{
*tbl = 0.0;
tbl += stride;
x += inc;
continue;
}
}
else
{
vtkErrorMacro( << "Error: vtkPiecewiseFunction has an unknown clamp type: " << this->Clamping << "\n" );
*tbl = 0.0;
tbl += stride;
x += inc;
continue;
}
// search for the end of the interval containing x
while( (xi2 < tx) && (i2 < this->FunctionSize) )
{
i2 += 1;
xi2 = this->Function[(i2*2)];
yi2 = this->Function[(i2*2+1)];
}
// Check if we have found the exact point
if( xi2 == tx )
{
value = this->Function[(i2*2 + 1)];
}
else
{
i1 = i2 - 1;
xi1 = this->Function[(i1*2)];
yi1 = this->Function[(i1*2 +1)];
// Now that we have the two points, use linear interpolation
slope = (yi2-yi1)/(xi2-xi1);
value = yi1 + slope*(tx-xi1);
}
*tbl = value;
tbl += stride;
x += inc;
}
}
void vtkPiecewiseFunction::GetTable( double x1, double x2, int size,
float* table, int stride )
{
double x, xi1, xi2, yi1, yi2, tx;
double inc, value, slope;
float *tbl;
int i, i1, i2;
if( x1 == x2 )
{
return;
}
if( size > 1 )
{
inc = (x2-x1)/(double)(size-1);
}
else
{
inc = 0;
}
tbl = table;
x = x1;
i2 = 0;
xi2 = this->Function[0];
yi2 = this->Function[1];
for (i=0; i < size; i++)
{
tx = x;
// Clamped to lowest value below range and highest above range
if( this->Clamping == 1 )
{
if( x < this->FunctionRange[0] )
{
tx = this->Function[0];
}
else if( x > this->FunctionRange[1] )
{
tx = this->Function[(this->FunctionSize-1)*2];
}
}
else if( this->Clamping == 0 ) // Always zero outside of range
{
if( (x < this->FunctionRange[0]) || (x > this->FunctionRange[1]) )
{
*tbl = 0.0f;
tbl += stride;
x += inc;
continue;
}
}
else
{
vtkErrorMacro( << "Error: vtkPiecewiseFunction has an unknown clamp type: " << this->Clamping << "\n" );
*tbl = 0.0f;
tbl += stride;
x += inc;
continue;
}
// search for the end of the interval containing x
while( (xi2 < tx) && (i2 < this->FunctionSize) )
{
i2 += 1;
xi2 = this->Function[(i2*2)];
yi2 = this->Function[(i2*2+1)];
}
// Check if we have found the exact point
if( xi2 == tx )
{
value = this->Function[(i2*2 + 1)];
}
else
{
i1 = i2 - 1;
xi1 = this->Function[(i1*2)];
yi1 = this->Function[(i1*2 +1)];
// Now that we have the two points, use linear interpolation
slope = (yi2-yi1)/(xi2-xi1);
value = yi1 + slope*(tx-xi1);
}
*tbl = static_cast<float>(value);
tbl += stride;
x += inc;
}
}
void vtkPiecewiseFunction::BuildFunctionFromTable( double x1, double x2,
int size,
double* table, int stride )
{
int i;
double inc = 0.0;
double *tptr = table;
if (size > this->ArraySize)
{
delete [] this->Function;
this->ArraySize = size;
this->FunctionSize = size;
this->Function = new double[this->ArraySize*2];
}
else
{
// no need to reallocate memory, just adjust the function size
this->FunctionSize = size;
}
this->FunctionRange[0] = x1;
this->FunctionRange[1] = x2;
if( size > 1 )
{
inc = (x2-x1)/(double)(size-1);
}
for (i=0; i < size; i++)
{
this->Function[2*i] = x1 + inc*i;
this->Function[2*i+1] = *tptr;
tptr += stride;
}
this->Modified();
}
// Increase the size of the array used to store the function
void vtkPiecewiseFunction::IncreaseArraySize()
{
double *old_function;
int old_size;
int i;
old_function = this->Function;
old_size = this->ArraySize;
// Create larger array to store points
this->ArraySize = old_size * 2;
this->Function = new double[(this->ArraySize*2)];
// Copy points from old array to new array
for( i=0; i<old_size; i++ )
{
this->Function[(2*i)] = old_function[(2*i)];
this->Function[(2*i)+1] = old_function[(2*i)+1];
}
// Initialize the rest of the memory to avoid purify problems
for ( ; i < this->ArraySize; i++ )
{
this->Function[(2*i)] = 0;
this->Function[(2*i)+1] = 0;
}
delete [] old_function;
}
void vtkPiecewiseFunction::FillFromDataPointer(int nb, double *ptr)
{
if (nb <= 0 || !ptr)
{
return;
}
this->RemoveAllPoints();
while (nb)
{
this->AddPoint(ptr[0], ptr[1]);
ptr += 2;
nb--;
}
}
//----------------------------------------------------------------------------
vtkPiecewiseFunction* vtkPiecewiseFunction::GetData(vtkInformation* info)
{
return
info? vtkPiecewiseFunction::SafeDownCast(info->Get(DATA_OBJECT())) : 0;
}
//----------------------------------------------------------------------------
vtkPiecewiseFunction* vtkPiecewiseFunction::GetData(vtkInformationVector* v,
int i)
{
return vtkPiecewiseFunction::GetData(v->GetInformationObject(i));
}
// Print method for tkPiecewiseFunction
void vtkPiecewiseFunction::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
int i;
os << indent << "Clamping: " << this->Clamping << "\n";
os << indent << "Function Points: " << this->GetSize() << "\n";
for( i = 0; i < this->FunctionSize; i++ )
{
os << indent << indent << i << ": "
<< this->Function[(2*i)] << ", " << this->Function[(2*i+1)] << "\n";
}
}