/*========================================================================= Program: Visualization Toolkit Module: vtkSCurveSpline.cxx 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. =========================================================================*/ /*------------------------------------------------------------------------- Copyright 2009 Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. -------------------------------------------------------------------------*/ #include "vtkSCurveSpline.h" #include "vtkObjectFactory.h" #include "vtkPiecewiseFunction.h" #include // for std::min()/std::max() #include vtkStandardNewMacro(vtkSCurveSpline); //------------------------------------------------------------------------------ // Construct a SCurve Spline. vtkSCurveSpline::vtkSCurveSpline() { this->NodeWeight = 0.0; } //------------------------------------------------------------------------------ // Evaluate a 1D Spline double vtkSCurveSpline::Evaluate(double t) { int index; 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 using bisection method index = this->FindIndex(size, t); // calculate offset within interval t = (t - intervals[index]); // normalize to unit width t /= intervals[index + 1] - intervals[index]; // apply weighting function if (this->NodeWeight > 0.0) { double shift = t * (t * (t * (-4 * this->NodeWeight) + (6 * this->NodeWeight))) - this->NodeWeight; // clamp t t = std::max(std::min(t + shift, 1.0), 0.0); } // evaluate intervals value y return (t * (t * (t * *(coefficients + index * 3 + 2) // a + *(coefficients + index * 3 + 1))) // b + *(coefficients + index * 3)); // d } //------------------------------------------------------------------------------ // Compute SCurve Splines for each dependent variable void vtkSCurveSpline::Compute() { double *ts, *xs; // double *work; 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("Cannot compute a spline with less than 2 points. # of points is: " << size); return; } // copy the independent variables. Note that if the spline // is closed the first and last point are assumed repeated - // so we add and extra point delete[] this->Intervals; if (!this->Closed) { this->Intervals = new double[size]; ts = this->PiecewiseFunction->GetDataPointer(); for (i = 0; i < size; i++) { this->Intervals[i] = *(ts + 2 * i); } // allocate memory for work arrays // work = new double[size]; // allocate memory for coefficients delete[] this->Coefficients; this->Coefficients = new double[3 * 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); } for (int k = 0; k < size - 1; k++) { *(coefficients + 3 * k) = dependent[k]; // d *(coefficients + 3 * k + 1) = 3 * (dependent[k + 1] - dependent[k]); // b *(coefficients + 3 * k + 2) = -2 * (dependent[k + 1] - dependent[k]); // a } *(coefficients + 3 * (size - 1)) = dependent[size - 1]; *(coefficients + 3 * (size - 1) + 1) = dependent[size - 1]; *(coefficients + 3 * (size - 1) + 2) = dependent[size - 1]; } else // add extra "fictitious" point to close loop { size = size + 1; 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 work arrays // work = new double[size]; // allocate memory for coefficients delete[] this->Coefficients; // this->Coefficients = new double [4*size]; this->Coefficients = new double[3 * 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; for (int k = 0; k < size - 1; k++) { *(coefficients + 3 * k) = dependent[k]; // d *(coefficients + 3 * k + 1) = 3 * (dependent[k + 1] - dependent[k]); // b *(coefficients + 3 * k + 2) = -2 * (dependent[k + 1] - dependent[k]); // a } *(coefficients + 3 * (size - 1)) = dependent[size - 1]; *(coefficients + 3 * (size - 1) + 1) = dependent[size - 1]; *(coefficients + 3 * (size - 1) + 2) = dependent[size - 1]; } // free the work array and dependent variable storage // delete [] work; delete[] dependent; // update compute time this->ComputeTime = this->GetMTime(); } //------------------------------------------------------------------------------ void vtkSCurveSpline::DeepCopy(vtkSpline* s) { vtkSCurveSpline* spline = vtkSCurveSpline::SafeDownCast(s); if (spline != nullptr) { // nothing to do } // Now do superclass this->vtkSpline::DeepCopy(s); } //------------------------------------------------------------------------------ void vtkSCurveSpline::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << "NodeWeight: " << this->NodeWeight << endl; }