1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkSpline.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtkSpline.h"
16 
17 #include "vtkPiecewiseFunction.h"
18 
19 //------------------------------------------------------------------------------
20 // Construct a spline with the following defaults:
21 // ClampValueOff
vtkSpline()22 vtkSpline::vtkSpline()
23 {
24   this->ComputeTime = 0;
25   this->ClampValue = 0;
26   this->PiecewiseFunction = vtkPiecewiseFunction::New();
27   this->Intervals = nullptr;
28   this->Coefficients = nullptr;
29   this->LeftConstraint = 1;
30   this->LeftValue = 0.0;
31   this->RightConstraint = 1;
32   this->RightValue = 0.0;
33   this->Closed = 0;
34 
35   this->ParametricRange[0] = -1;
36   this->ParametricRange[1] = -1;
37 }
38 
39 //------------------------------------------------------------------------------
~vtkSpline()40 vtkSpline::~vtkSpline()
41 {
42   this->PiecewiseFunction->Delete();
43   delete[] this->Coefficients;
44   delete[] this->Intervals;
45 }
46 
47 //------------------------------------------------------------------------------
SetParametricRange(double tMin,double tMax)48 void vtkSpline::SetParametricRange(double tMin, double tMax)
49 {
50   if (tMin != this->ParametricRange[0] || tMax != this->ParametricRange[1])
51   {
52     if (tMin >= tMax)
53     {
54       tMax = tMin + 1;
55     }
56 
57     this->ParametricRange[0] = tMin;
58     this->ParametricRange[1] = tMax;
59 
60     this->Modified();
61   }
62 }
63 
64 //------------------------------------------------------------------------------
GetParametricRange(double tRange[2]) const65 void vtkSpline::GetParametricRange(double tRange[2]) const
66 {
67   if (this->ParametricRange[0] != this->ParametricRange[1])
68   {
69     tRange[0] = this->ParametricRange[0];
70     tRange[1] = this->ParametricRange[1];
71   }
72   else
73   {
74     tRange[0] = this->PiecewiseFunction->GetRange()[0];
75     tRange[1] = this->PiecewiseFunction->GetRange()[1];
76   }
77 }
78 
79 //------------------------------------------------------------------------------
ComputeLeftDerivative()80 double vtkSpline::ComputeLeftDerivative()
81 {
82   double* dptr = this->PiecewiseFunction->GetDataPointer();
83   int size = this->PiecewiseFunction->GetSize();
84   if (dptr == nullptr || size < 2)
85   {
86     return 0.0;
87   }
88   else
89   {
90     return (dptr[2] - dptr[0]);
91   }
92 }
93 
94 //------------------------------------------------------------------------------
ComputeRightDerivative()95 double vtkSpline::ComputeRightDerivative()
96 {
97   double* dptr = this->PiecewiseFunction->GetDataPointer();
98   int size = this->PiecewiseFunction->GetSize();
99   if (dptr == nullptr || size < 2)
100   {
101     return 0.0;
102   }
103   else
104   {
105     return (dptr[(size - 1) * 2] - dptr[(size - 2) * 2]);
106   }
107 }
108 
109 //------------------------------------------------------------------------------
GetNumberOfPoints()110 int vtkSpline::GetNumberOfPoints()
111 {
112   return this->PiecewiseFunction->GetSize();
113 }
114 
115 //------------------------------------------------------------------------------
116 // Add a point to the Piecewise Functions containing the data
AddPoint(double t,double x)117 void vtkSpline::AddPoint(double t, double x)
118 {
119   if (this->ParametricRange[0] != this->ParametricRange[1])
120   {
121     t = (t < this->ParametricRange[0]
122         ? this->ParametricRange[0]
123         : (t > this->ParametricRange[1] ? this->ParametricRange[1] : t));
124   }
125   this->PiecewiseFunction->AddPoint(t, x);
126 }
127 
128 //------------------------------------------------------------------------------
129 // Remove a point from the Piecewise Functions.
RemovePoint(double t)130 void vtkSpline::RemovePoint(double t)
131 {
132   if (this->ParametricRange[0] != this->ParametricRange[1])
133   {
134     t = (t < this->ParametricRange[0]
135         ? this->ParametricRange[0]
136         : (t > this->ParametricRange[1] ? this->ParametricRange[1] : t));
137   }
138   this->PiecewiseFunction->RemovePoint(t);
139 }
140 
141 //------------------------------------------------------------------------------
142 // Remove all points from the Piecewise Functions.
RemoveAllPoints()143 void vtkSpline::RemoveAllPoints()
144 {
145   this->PiecewiseFunction->RemoveAllPoints();
146 }
147 
148 //------------------------------------------------------------------------------
DeepCopy(vtkSpline * s)149 void vtkSpline::DeepCopy(vtkSpline* s)
150 {
151   vtkSpline* spline = vtkSpline::SafeDownCast(s);
152 
153   if (spline != nullptr)
154   {
155     this->ClampValue = s->ClampValue;
156     this->LeftConstraint = s->LeftConstraint;
157     this->LeftValue = s->LeftValue;
158     this->RightConstraint = s->RightConstraint;
159     this->RightValue = s->RightValue;
160     this->Closed = s->Closed;
161     this->PiecewiseFunction->DeepCopy(s->PiecewiseFunction);
162   }
163 }
164 
165 //------------------------------------------------------------------------------
166 // Overload standard modified time function. If data is modified,
167 // then this object is modified as well.
GetMTime()168 vtkMTimeType vtkSpline::GetMTime()
169 {
170   vtkMTimeType mTime = this->vtkObject::GetMTime();
171   vtkMTimeType DataMTime;
172 
173   if (this->PiecewiseFunction != nullptr)
174   {
175     DataMTime = this->PiecewiseFunction->GetMTime();
176     mTime = (DataMTime > mTime ? DataMTime : mTime);
177   }
178 
179   return mTime;
180 }
181 
182 //------------------------------------------------------------------------------
FindIndex(int size,double t)183 int vtkSpline::FindIndex(int size, double t)
184 {
185   int index = 0;
186   if (size > 2) // bisection method for speed
187   {
188     int rightIdx = size - 1;
189     int centerIdx = rightIdx - size / 2;
190     for (int converged = 0; !converged;)
191     {
192       if (this->Intervals[index] <= t && t <= this->Intervals[centerIdx])
193       {
194         rightIdx = centerIdx;
195       }
196       else // if ( this->Intervals[centerIdx] < t && t <= this->Intervals[rightIdx] )
197       {
198         index = centerIdx;
199       }
200       if ((index + 1) == rightIdx)
201       {
202         converged = 1;
203       }
204       else
205       {
206         centerIdx = index + (rightIdx - index) / 2;
207       }
208     } // while not converged
209   }
210   return index;
211 }
212 
213 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)214 void vtkSpline::PrintSelf(ostream& os, vtkIndent indent)
215 {
216   this->Superclass::PrintSelf(os, indent);
217 
218   os << indent << "Clamp Value: " << (this->ClampValue ? "On\n" : "Off\n");
219   os << indent << "Left Constraint: " << this->LeftConstraint << "\n";
220   os << indent << "Right Constraint: " << this->RightConstraint << "\n";
221   os << indent << "Left Value: " << this->LeftValue << "\n";
222   os << indent << "Right Value: " << this->RightValue << "\n";
223   os << indent << "Closed: " << (this->Closed ? "On\n" : "Off\n");
224 
225   os << indent << "Piecewise Function:\n";
226   this->PiecewiseFunction->PrintSelf(os, indent.GetNextIndent());
227 
228   os << indent << "Closed: " << (this->Closed ? "On\n" : "Off\n");
229 }
230