00001 #include "CardinalSpline.h"
00002
00003
00004 #include <vsl/vsl_vector_io.txx>
00005 #include <vcl_cassert.h>
00006
00007
00008
00009
00010
00011 vcl_vector<CardinalSpline::Vector3D> CardinalSpline::getPoints(int num_points) const
00012 {
00013 assert(num_points!=0);
00014 vcl_vector<Vector3D> points;
00015 Vector3D current_point;
00016 for (int i=0; i<num_points; i++)
00017 {
00018 current_point = getPoint((double)i/(double)num_points);
00019 points.push_back(current_point);
00020 }
00021 return points;
00022 }
00023
00024
00025
00026 CardinalSpline::Vector3D CardinalSpline::getVal(
00027 const vnl_matrix_fixed<double, 1, 4> &uvec, int pk) const
00028 {
00029
00030 int n = controlPoints.size();
00031 int pkn1 = (pk+n-1)%n;
00032 int pk1 = (pk+1)%n;
00033 int pk2 = (pk+2)%n;
00034
00035 vnl_matrix_fixed<double, 1, 4> weightMatrix;
00036 weightMatrix = uvec*Mc;
00037
00038
00039 Vector3D res = controlPoints[pkn1]*weightMatrix(0,0)+
00040 controlPoints[pk ]*weightMatrix(0,1)+
00041 controlPoints[pk1 ]*weightMatrix(0,2)+
00042 controlPoints[pk2 ]*weightMatrix(0,3);
00043 return res;
00044 }
00045
00046
00047
00048
00049
00050
00051
00052
00053 CardinalSpline::Vector3D CardinalSpline::getPoint(double t) const
00054 {
00055 assert(t>=0.0);
00056 assert(t<=1.0);
00057
00058 int n = controlPoints.size();
00059 assert(n!=0);
00060 int pk = ((int)(t*n))%n;
00061
00062
00063 double u = t*n-(int)(t*n);
00064 vnl_matrix<double> uvec(1, 4);
00065 uvec(0,3) = 1;
00066 for (int i=2; i>=0; i--) uvec(0,i) = uvec(0,i+1)*u;
00067 return getVal(uvec, pk);
00068 }
00069
00070
00071 CardinalSpline::Vector3D CardinalSpline::firstDerivative(double t) const
00072 {
00073 assert(t>=0.0);
00074 assert(t<=1.0);
00075
00076 int n = controlPoints.size();
00077 int pk = ((int)(t*n))%n;
00078
00079
00080 double u = t*n-(int)(t*n);
00081
00082 vnl_matrix<double> uvec(1, 4);
00083 uvec(0,3) = 0;
00084 uvec(0,2) = 1;
00085 uvec(0,1) = 2*u;
00086 uvec(0,0) = 3*u*u;
00087
00088 return ((double)n)*getVal(uvec, pk);
00089 }
00090
00091
00092 CardinalSpline::Vector3D CardinalSpline::secondDerivative(double t) const
00093 {
00094 assert(t>=0.0);
00095 assert(t<=1.0);
00096
00097 int n = controlPoints.size();
00098 int pk = ((int)(t*n))%n;
00099
00100
00101 double u = t*n-(int)(t*n);
00102
00103 vnl_matrix<double> uvec(1, 4);
00104 uvec(0,3) = 0;
00105 uvec(0,2) = 0;
00106 uvec(0,1) = 2;
00107 uvec(0,0) = 6*u;
00108 return ((double)(n*n))*getVal(uvec, pk);
00109 }
00110
00111
00112
00113 double CardinalSpline::distanceFunctionFirstDerivative(double t,
00114 const Vector3D &point) const
00115 {
00116 Vector3D curvePt = getPoint(t);
00117 Vector3D firstDeriv = firstDerivative(t);
00118 Vector3D diff = curvePt-point;
00119 return 2*dot_product(firstDeriv, diff);
00120 }
00121
00122 double CardinalSpline::distanceFunctionSecondDerivative(double t,
00123 const Vector3D &point) const
00124 {
00125 Vector3D curvePt = getPoint(t);
00126 Vector3D diff = curvePt-point;
00127 Vector3D firstDeriv = firstDerivative(t);
00128 Vector3D secondDeriv = secondDerivative(t);
00129 return 2*dot_product(secondDeriv, diff)
00130 + 2*dot_product(firstDeriv, firstDeriv);
00131 }
00132
00133
00134
00135
00136 double CardinalSpline::closest_point_t(const Vector3D &point) const
00137 {
00138
00139
00140 int n = controlPoints.size()*10;
00141 double delta = 1.0/(double)n;
00142 double t1=0.0;
00143 double d1 = (point-getPoint(t1)).magnitude();
00144 for (double t=delta; t<1.0; t+=delta)
00145 {
00146 double dist = (point-getPoint(t)).magnitude();
00147
00148 if (dist<d1)
00149 {
00150 d1 = dist; t1 = t;
00151 }
00152 }
00153
00154
00155 double t2 = t1+delta;
00156 if (t2>1.0) t2 = 0.0;
00157 double t3 = t1-delta;
00158 if (t3<0.0) t3 = 1.0-delta;
00159
00160
00161 double d2 = (point-getPoint(t2)).magnitude();
00162 double d3 = (point-getPoint(t3)).magnitude();
00163 if (d3<d2)
00164 {
00165 t2 = t3;
00166 }
00167
00168
00169
00170
00171 if (vcl_fabs(t2-t1)>2.0*delta)
00172 {
00173 if (t2>t1) t1 = 1.0;
00174 }
00175
00176
00177 int numloops=0;
00178 delta = distanceFunctionFirstDerivative(t1, point)/
00179 distanceFunctionSecondDerivative(t1, point);
00180 for (double t = t1 ;
00181
00182 vcl_fabs(delta)>1e-8;
00183 delta = distanceFunctionFirstDerivative(t, point)/
00184 distanceFunctionSecondDerivative(t, point)
00185 )
00186 {
00187 t -= delta;
00188 if (t<0.0) t += 1.0;
00189 if (t>1.0) t -= 1.0;
00190 double dist = (point-getPoint(t)).magnitude();
00191
00192
00193
00194 if (dist>d1)
00195 {
00196 vcl_cerr << "Closest point not converging:\n"
00197 << " t = " << t1
00198 << ", dist = " << dist << ", d1 = " << d1
00199 << ", delta = " << delta << vcl_endl;
00200 break;
00201 }
00202 else if (dist<d1)
00203 {
00204 t1 = t; d1 = dist;
00205 }
00206 if (++numloops>50)
00207 assert(false);
00208 }
00209
00210 return t1;
00211 }
00212
00213
00214
00215
00216
00217 VSL_VECTOR_IO_INSTANTIATE(CardinalSpline::Vector3D);
00218
00219 void CardinalSpline::b_write(vsl_b_ostream &os) const
00220 {
00221 vsl_b_write(os, controlPoints);
00222 vsl_b_write(os, Mc);
00223 vsl_b_write(os, s);
00224 }
00225
00226 void CardinalSpline::b_read(vsl_b_istream &is)
00227 {
00228 vsl_b_read(is, controlPoints);
00229 vsl_b_read(is, Mc);
00230 vsl_b_read(is, s);
00231 }
00232
00233 void vsl_b_write(vsl_b_ostream &os, const CardinalSpline &e)
00234 {
00235 e.b_write(os);
00236 }
00237
00238 void vsl_b_read(vsl_b_istream &is, CardinalSpline &e)
00239 {
00240 e.b_read(is);
00241 }
00242
00243 void vsl_print_summary(vcl_ostream &os, const CardinalSpline &e)
00244 {
00245 e.print_summary(os);
00246 }