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 }