/*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkParametricSpline.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 "vtkParametricSpline.h" #include "vtkObjectFactory.h" #include "vtkCardinalSpline.h" #include "vtkPoints.h" #include "vtkMath.h" vtkCxxRevisionMacro(vtkParametricSpline, "$Revision: 1.6 $"); vtkStandardNewMacro(vtkParametricSpline); //---------------------------------------------------------------------------- vtkParametricSpline::vtkParametricSpline() { this->MinimumU = 0; this->MaximumU = 1.0; this->JoinU = 0; this->Points = NULL; this->XSpline = vtkCardinalSpline::New(); this->YSpline = vtkCardinalSpline::New(); this->ZSpline = vtkCardinalSpline::New(); this->Closed = 0; this->LeftConstraint = 1; this->LeftValue = 0.0; this->RightConstraint = 1; this->RightValue = 0.0; this->ParameterizeByLength = 1; this->InitializeTime = 0; } //---------------------------------------------------------------------------- vtkParametricSpline::~vtkParametricSpline() { if (this->Points) { this->Points->Delete(); } if (this->XSpline) { this->XSpline->Delete(); } if (this->YSpline) { this->YSpline->Delete(); } if (this->ZSpline) { this->ZSpline->Delete(); } } //---------------------------------------------------------------------------- void vtkParametricSpline::SetPoints(vtkPoints *pts) { if ( pts != this->Points ) { if ( this->Points != NULL ) { this->Points->Delete(); } this->Points = pts; if ( this->Points != NULL ) { this->Points->Register(this); } this->Modified(); } } //---------------------------------------------------------------------------- void vtkParametricSpline::SetXSpline(vtkSpline *s) { if ( s != this->XSpline ) { if ( this->XSpline != NULL ) { this->XSpline->Delete(); } this->XSpline = s; if ( this->XSpline != NULL ) { this->XSpline->Register(this); } this->Modified(); } } //---------------------------------------------------------------------------- void vtkParametricSpline::SetYSpline(vtkSpline *s) { if ( s != this->YSpline ) { if ( this->YSpline != NULL ) { this->YSpline->Delete(); } this->YSpline = s; if ( this->YSpline != NULL ) { this->YSpline->Register(this); } this->Modified(); } } //---------------------------------------------------------------------------- void vtkParametricSpline::SetZSpline(vtkSpline *s) { if ( s != this->ZSpline ) { if ( this->ZSpline != NULL ) { this->ZSpline->Delete(); } this->ZSpline = s; if ( this->ZSpline != NULL ) { this->ZSpline->Register(this); } this->Modified(); } } //---------------------------------------------------------------------------- void vtkParametricSpline::Evaluate(double U[3], double Pt[3], double*) { // make sure everything has been set up if ( this->InitializeTime < this->GetMTime () ) { if ( ! this->Initialize() ) { return; } } double t = (U[0] < 0.0 ? 0.0 : (U[0] > 1.0 ? 1.0 : U[0])); if ( this->Closed ) { t *= this->ClosedLength; } else { t *= this->Length; } // Evaluate the spline at the parameter t Pt[0] = this->XSpline->Evaluate(t); Pt[1] = this->YSpline->Evaluate(t); Pt[2] = this->ZSpline->Evaluate(t); } //---------------------------------------------------------------------------- double vtkParametricSpline::EvaluateScalar(double u[3], double*, double *) { // make sure everything has been set up if ( this->InitializeTime < this->GetMTime () ) { if ( ! this->Initialize() ) { return 0.0; } } return u[0]; //simply parametric value } //---------------------------------------------------------------------------- // Configure the splines for evaluation int vtkParametricSpline::Initialize() { // Check to make sure splines are available if ( !this->XSpline || !this->YSpline || !this->ZSpline ) { vtkErrorMacro("Please specify splines"); return 0; } if ( !this->Points ) { vtkErrorMacro("Please specify points"); return 0; } // Make sure that the splines are consistent with this instance this->XSpline->SetClosed(this->GetClosed()); this->XSpline->SetLeftConstraint(this->GetLeftConstraint()); this->XSpline->SetRightConstraint(this->GetRightConstraint()); this->XSpline->SetLeftValue(this->GetLeftValue()); this->XSpline->SetRightValue(this->GetRightValue()); this->YSpline->SetClosed(this->GetClosed()); this->YSpline->SetLeftConstraint(this->GetLeftConstraint()); this->YSpline->SetRightConstraint(this->GetRightConstraint()); this->YSpline->SetLeftValue(this->GetLeftValue()); this->YSpline->SetRightValue(this->GetRightValue()); this->ZSpline->SetClosed(this->GetClosed()); this->ZSpline->SetLeftConstraint(this->GetLeftConstraint()); this->ZSpline->SetRightConstraint(this->GetRightConstraint()); this->ZSpline->SetLeftValue(this->GetLeftValue()); this->ZSpline->SetRightValue(this->GetRightValue()); // Construct the splines, parameterized by length vtkIdType i; double xPrev[3], x[3], len; vtkIdType npts = this->Points->GetNumberOfPoints(); if ( npts < 2 ) { vtkErrorMacro("Please specify at least two points"); return 0; } if ( this->ParameterizeByLength ) { this->Points->GetPoint(0,xPrev); this->Length = 0.0; for ( i = 1; i < npts; ++i ) { this->Points->GetPoint(i,x); len = sqrt(vtkMath::Distance2BetweenPoints(x,xPrev)); if ( len <= 0.0 ) { vtkErrorMacro("Spline must have non-coincident points"); return 0; //failure } this->Length += len; xPrev[0]=x[0]; xPrev[1]=x[1]; xPrev[2]=x[2]; } if ( this->Length <= 0.0 ) { vtkErrorMacro("Spline must have non-zero length"); return 0; //failure } if ( this->Closed ) { this->Points->GetPoint(0,x); this->ClosedLength = this->Length + sqrt(vtkMath::Distance2BetweenPoints(x,xPrev)); } } else { this->Length = npts - 1; if ( this->Closed ) { this->ClosedLength = npts; } } this->XSpline->RemoveAllPoints(); this->YSpline->RemoveAllPoints(); this->ZSpline->RemoveAllPoints(); // Now we insert points into the splines with the parametric coordinate // based on (polyline) length. We keep track of the parametric coordinates // of the points for later point interpolation. if ( this->ParameterizeByLength ) { this->Points->GetPoint(0,xPrev); for ( len = 0.0, i = 0; i < npts; ++i ) { this->Points->GetPoint(i,x); len += sqrt(vtkMath::Distance2BetweenPoints(x,xPrev)); this->XSpline->AddPoint(len,x[0]); this->YSpline->AddPoint(len,x[1]); this->ZSpline->AddPoint(len,x[2]); xPrev[0]=x[0]; xPrev[1]=x[1]; xPrev[2]=x[2]; } } else { for ( i = 0; i < npts; ++i ) { this->Points->GetPoint(i,x); this->XSpline->AddPoint(i,x[0]); this->YSpline->AddPoint(i,x[1]); this->ZSpline->AddPoint(i,x[2]); } } // Specify the parametric range that the spline can take if ( ! this->Closed ) { this->XSpline->SetParametricRange(0.0,this->Length); this->YSpline->SetParametricRange(0.0,this->Length); this->ZSpline->SetParametricRange(0.0,this->Length); } else { this->XSpline->SetParametricRange(0.0,this->ClosedLength); this->YSpline->SetParametricRange(0.0,this->ClosedLength); this->ZSpline->SetParametricRange(0.0,this->ClosedLength); } this->InitializeTime = this->GetMTime(); return 1; } //---------------------------------------------------------------------------- void vtkParametricSpline::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); os << indent << "Points: "; if ( this->Points ) { os << this->Points << "\n"; } else { os << "(none)\n"; } os << indent << "X Spline: "; if ( this->XSpline ) { os << this->XSpline << "\n"; } else { os << "(none)\n"; } os << indent << "Y Spline: "; if ( this->YSpline ) { os << this->YSpline << "\n"; } else { os << "(none)\n"; } os << indent << "Z Spline: "; if ( this->ZSpline ) { os << this->ZSpline << "\n"; } else { os << "(none)\n"; } os << indent << "Closed: " << (this->Closed ? "On\n" : "Off\n"); os << indent << "Left Constraint: " << this->LeftConstraint << "\n"; os << indent << "Right Constraint: " << this->RightConstraint << "\n"; os << indent << "Left Value: " << this->LeftValue << "\n"; os << indent << "Right Value: " << this->RightValue << "\n"; os << indent << "Parameterize by length: " << (this->ParameterizeByLength ? "On\n" : "Off\n"); }