00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <vamos/geometry/Spline.h>
00021
00022 #include <cmath>
00023 #include <cassert>
00024
00025
00026 Vamos_Geometry::
00027 Spline::Spline (double first_slope, double last_slope) :
00028 m_first_slope (first_slope),
00029 m_last_slope (last_slope),
00030 m_calculated (false),
00031 m_slope (0.0)
00032 {
00033 }
00034
00035
00036 Vamos_Geometry::
00037 Spline::Spline (const std::vector <Two_Point>& points,
00038 double first_slope, double last_slope) :
00039 m_first_slope (first_slope),
00040 m_last_slope (last_slope),
00041 m_calculated (false),
00042 m_slope (0.0)
00043 {
00044 clear ();
00045 load (points);
00046 }
00047
00048
00049 void Vamos_Geometry::
00050 Spline::load (const Two_Point& point)
00051 {
00052 m_points.push_back (point);
00053 m_calculated = false;
00054 }
00055
00056
00057 void Vamos_Geometry::
00058 Spline::load (const std::vector <Two_Point>& points)
00059 {
00060 for (std::vector <Two_Point>::const_iterator it = points.begin ();
00061 it != points.end ();
00062 it++)
00063 {
00064 m_points.push_back (*it);
00065 }
00066 m_calculated = false;
00067 }
00068
00069
00070 void Vamos_Geometry::
00071 Spline::clear ()
00072 {
00073 m_points.clear ();
00074 m_calculated = false;
00075 }
00076
00077
00078 void Vamos_Geometry::
00079 Spline::remove_greater (double limit)
00080 {
00081 size_t size = 0;
00082 for (std::vector <Two_Point>::const_iterator it = m_points.begin ();
00083 it != m_points.end ();
00084 it++)
00085 {
00086 if (it->x > limit)
00087 {
00088 m_points.resize (size);
00089 break;
00090 }
00091 size++;
00092 }
00093 m_calculated = false;
00094 }
00095
00096
00097 void Vamos_Geometry::
00098 Spline::scale (double factor)
00099 {
00100 for (std::vector <Two_Point>::iterator it = m_points.begin ();
00101 it != m_points.end ();
00102 it++)
00103 {
00104 it->x *= factor;
00105 }
00106
00107 m_calculated = false;
00108 }
00109
00110
00111
00112
00113
00114
00115 double Vamos_Geometry::
00116 Spline::interpolate (double distance) const
00117 {
00118 if (m_points.size () == 1)
00119 {
00120 m_slope = 0.0;
00121 return m_points [0].y;
00122 }
00123
00124
00125
00126 if (!m_calculated)
00127 calculate ();
00128
00129
00130 size_t low = 0;
00131 size_t high = m_points.size () - 1;
00132 size_t index;
00133
00134
00135 while ((high - low) > 1)
00136 {
00137 index = size_t ((high + low) / 2.0);
00138 if (m_points [index].x > distance)
00139 high = index;
00140 else
00141 low = index;
00142 }
00143
00144
00145 const double diff = m_points [high].x - m_points [low].x;
00146 assert (diff >= 0.0);
00147
00148
00149 const double a = (m_points [high].x - distance) / diff;
00150 const double b = 1.0 - a;
00151 const double sq = diff*diff / 6.0;
00152 const double a2 = a*a;
00153 const double b2 = b*b;
00154
00155
00156 m_slope =
00157 (m_points [high].y - m_points [low].y)/diff
00158 - (3.0 * a2- 1.0) / 6.0 * diff * m_second_deriv [low]
00159 + (3.0 * b2 - 1.0) / 6.0 * diff * m_second_deriv [high];
00160
00161
00162 return a * m_points [low].y
00163 + b * m_points [high].y
00164 + a * (a2 - 1.0) * sq * m_second_deriv [low]
00165 + b * (b2 - 1.0) * sq * m_second_deriv [high];
00166 }
00167
00168
00169
00170 void Vamos_Geometry::
00171 Spline::calculate () const
00172 {
00173 size_t n = m_points.size ();
00174 double* a = new double [n];
00175 double* b = new double [n];
00176 double* c = new double [n];
00177 double* r = new double [n];
00178
00179
00180
00181 double diff = m_points [1].x - m_points [0].x;
00182 b [0] = diff / 3.0;
00183 c [0] = diff / 6.0;
00184 r [0] = (m_points [1].y - m_points [0].y) / diff - m_first_slope;
00185
00186 for (size_t i = 1; i < n - 1; i++)
00187 {
00188 double diff1 = m_points [i+1].x - m_points [i].x;
00189 double diff2 = m_points [i].x - m_points [i-1].x;
00190
00191 a [i] = diff2 / 6.0;
00192 b [i] = (m_points [i+1].x - m_points [i-1].x) / 3.0;
00193 c [i] = diff1 / 6.0;
00194 r [i] = (m_points [i+1].y - m_points [i].y) / diff1
00195 - (m_points [i].y - m_points [i-1].y) / diff2;
00196 }
00197
00198 diff = m_points [n-1].x - m_points [n-2].x;
00199 a [n-1] = diff / 6.0;
00200 b [n-1] = diff / 3.0;
00201
00202 r [n-1] = m_last_slope - (m_points [n-1].y - m_points [n-2]).y / diff;
00203
00204
00205 for (size_t i = 1; i < n; i++)
00206 {
00207
00208 double factor = a [i] / b [i-1];
00209
00210 b [i] -= factor * c [i-1];
00211
00212 r [i] -= factor * r [i-1];
00213 }
00214
00215
00216
00217
00218 m_second_deriv.resize (n);
00219 m_second_deriv [n-1] = r [n-1] / b [n-1];
00220 for (int i = n - 2; i >= 0; i--)
00221 {
00222
00223 m_second_deriv [i] = (r [i] - c [i] * m_second_deriv [i+1]) / b [i];
00224 }
00225
00226 delete [] r;
00227 delete [] c;
00228 delete [] b;
00229 delete [] a;
00230
00231 m_calculated = true;
00232 }
00233
00234
00235 Vamos_Geometry::Two_Point Vamos_Geometry::
00236 Spline::normal (double distance) const
00237 {
00238 interpolate (distance);
00239 double theta = std::atan (m_slope);
00240 return Two_Point (-std::sin (theta), std::cos (theta));
00241 }