00001
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005
00006
00007
00008 #include "vdgl_interpolator_cubic.h"
00009 #include <vcl_cassert.h>
00010 #include <vcl_cmath.h>
00011 #include <vnl/vnl_matrix_fixed.h>
00012 #include <vnl/vnl_vector_fixed.h>
00013 #include <vnl/vnl_math.h>
00014 #include <vnl/vnl_numeric_traits.h>
00015 #include <vnl/vnl_inverse.h>
00016 #include <vgl/vgl_point_2d.h>
00017 #include <vsol/vsol_point_2d.h>
00018 #include <vdgl/vdgl_edgel.h>
00019 #include <vdgl/vdgl_edgel_chain.h>
00020
00021
00022 vdgl_interpolator_cubic::vdgl_interpolator_cubic(vdgl_edgel_chain_sptr chain)
00023 : vdgl_interpolator(chain)
00024 {
00025 recompute_all();
00026 }
00027
00028 vdgl_interpolator_cubic::~vdgl_interpolator_cubic()
00029 {
00030 }
00031
00032
00033 double vdgl_interpolator_cubic::get_x(double index)
00034 {
00035 const int N = chain_->size();
00036 int a= int(index)-1;
00037 if (index == N-2) --a;
00038 int b= a+1;
00039 int c= b+1;
00040 int d= c+1;
00041 assert(a >= 0 && d < N);
00042
00043 vdgl_edgel ae(chain_->edgel(a));
00044 vdgl_edgel be(chain_->edgel(b));
00045 vdgl_edgel ce(chain_->edgel(c));
00046 vdgl_edgel de(chain_->edgel(d));
00047
00048 vnl_vector_fixed<double,4> A;
00049 vnl_matrix_fixed<double,4,4> M;
00050
00051 A(0) = ae.get_x(); A(1) = be.get_x();
00052 A(2) = ce.get_x(); A(3) = de.get_x();
00053
00054 M(0,0)= a*a*a; M(0,1)= a*a; M(0,2)= a; M(0,3)= 1;
00055 M(1,0)= b*b*b; M(1,1)= b*b; M(1,2)= b; M(1,3)= 1;
00056 M(2,0)= c*c*c; M(2,1)= c*c; M(2,2)= c; M(2,3)= 1;
00057 M(3,0)= d*d*d; M(3,1)= d*d; M(3,2)= d; M(3,3)= 1;
00058
00059
00060 vnl_vector_fixed<double,4> P = vnl_inverse(M) * A;
00061
00062 return P(0) * index * index * index + P(1) * index * index + P(2) * index + P(3);
00063 }
00064
00065
00066 double vdgl_interpolator_cubic::get_y(double index)
00067 {
00068 const int N = chain_->size();
00069 int a= int(index)-1;
00070 if (index == N-2) --a;
00071 int b= a+1;
00072 int c= b+1;
00073 int d= c+1;
00074 assert(a >= 0 && d < N);
00075
00076 vdgl_edgel ae(chain_->edgel(a));
00077 vdgl_edgel be(chain_->edgel(b));
00078 vdgl_edgel ce(chain_->edgel(c));
00079 vdgl_edgel de(chain_->edgel(d));
00080
00081 vnl_vector_fixed<double,4> A;
00082 vnl_matrix_fixed<double,4,4> M;
00083
00084 A(0) = ae.get_y(); A(1) = be.get_y();
00085 A(2) = ce.get_y(); A(3) = de.get_y();
00086
00087 M(0,0)= a*a*a; M(0,1)= b*b; M(0,2)= a; M(0,3)= 1;
00088 M(1,0)= b*b*b; M(1,1)= b*b; M(1,2)= b; M(1,3)= 1;
00089 M(2,0)= c*c*c; M(2,1)= c*c; M(2,2)= c; M(2,3)= 1;
00090 M(3,0)= d*d*d; M(3,1)= d*d; M(3,2)= d; M(3,3)= 1;
00091
00092
00093 vnl_vector_fixed<double,4> P = vnl_inverse(M) * A;
00094
00095 return P(0) * index * index * index + P(1) * index * index + P(2) * index + P(3);
00096 }
00097
00098 double vdgl_interpolator_cubic::get_grad(double index)
00099 {
00100 const int N = chain_->size();
00101 int a= int(index)-1;
00102 if (index == N-2) --a;
00103 int b= a+1;
00104 int c= b+1;
00105 int d= c+1;
00106 assert(a >= 0 && d < N);
00107
00108 vdgl_edgel ae(chain_->edgel(a));
00109 vdgl_edgel be(chain_->edgel(b));
00110 vdgl_edgel ce(chain_->edgel(c));
00111 vdgl_edgel de(chain_->edgel(d));
00112
00113 vnl_vector_fixed<double,4> A;
00114 vnl_matrix_fixed<double,4,4> M;
00115
00116 A(0) = ae.get_grad(); A(1) = be.get_grad();
00117 A(2) = ce.get_grad(); A(3) = de.get_grad();
00118
00119 M(0,0)= a*a*a; M(0,1)= a*a; M(0,2)= a; M(0,3)= 1;
00120 M(1,0)= b*b*b; M(1,1)= b*b; M(1,2)= b; M(1,3)= 1;
00121 M(2,0)= c*c*c; M(2,1)= c*c; M(2,2)= c; M(2,3)= 1;
00122 M(3,0)= d*d*d; M(3,1)= d*d; M(3,2)= d; M(3,3)= 1;
00123
00124
00125 vnl_vector_fixed<double,4> P = vnl_inverse(M) * A;
00126
00127 return P(0) * index * index * index + P(1) * index * index + P(2) * index + P(3);
00128 }
00129
00130 double vdgl_interpolator_cubic::get_theta(double index)
00131 {
00132 const int N = chain_->size();
00133 int a= int(index)-1;
00134 if (index == N-2) --a;
00135 int b= a+1;
00136 int c= b+1;
00137 int d= c+1;
00138 assert(a >= 0 && d < N);
00139
00140 vdgl_edgel ae(chain_->edgel(a));
00141 vdgl_edgel be(chain_->edgel(b));
00142 vdgl_edgel ce(chain_->edgel(c));
00143 vdgl_edgel de(chain_->edgel(d));
00144
00145 vnl_vector_fixed<double,4> A;
00146 vnl_matrix_fixed<double,4,4> M;
00147
00148 A(0) = ae.get_theta(); A(1) = be.get_theta();
00149 A(2) = ce.get_theta(); A(3) = de.get_theta();
00150
00151 M(0,0)= a*a*a; M(0,1)= a*a; M(0,2)= a; M(0,3)= 1;
00152 M(1,0)= b*b*b; M(1,1)= b*b; M(1,2)= b; M(1,3)= 1;
00153 M(2,0)= c*c*c; M(2,1)= c*c; M(2,2)= c; M(2,3)= 1;
00154 M(3,0)= d*d*d; M(3,1)= d*d; M(3,2)= d; M(3,3)= 1;
00155
00156
00157 vnl_vector_fixed<double,4> P = vnl_inverse(M) * A;
00158
00159 return P(0) * index * index * index + P(1) * index * index + P(2) * index + P(3);
00160 }
00161
00162
00163
00164
00165 double vdgl_interpolator_cubic::get_tangent_angle(double index)
00166 {
00167 const int N = chain_->size();
00168 int a= int(index)-1;
00169 if (index == N-2) --a;
00170 int b= a+1;
00171 int c= b+1;
00172 int d= c+1;
00173 assert(a >= 0 && d < N);
00174
00175 vdgl_edgel ae = chain_->edgel(a),
00176 be = chain_->edgel(b),
00177 ce = chain_->edgel(c),
00178 de = chain_->edgel(d);
00179
00180 double xa = ae.x(), ya = ae.y(),
00181 xb = be.x(), yb = be.y(),
00182 xc = ce.x(), yc = ce.y(),
00183 xd = de.x(), yd = de.y(),
00184
00185 x2 = xd-4.5*xc+9*xb-5.5*xa,
00186 y2 = yd-4.5*yc+9*yb-5.5*ya,
00187 x1 = -x2-0.5*xc+4*xb-3.5*xa,
00188 y1 = -y2-0.5*yc+4*yb-3.5*ya,
00189 x0 = x2/2+0.75*xc-3*xb+2.25*xa,
00190 y0 = y2/2+0.75*yc-3*yb+2.25*ya,
00191
00192 xp = x0*index*index + x1*index + x2/3,
00193 yp = y0*index*index + y1*index + y2/3;
00194
00195 return vnl_math::deg_per_rad*vcl_atan2(yp, xp);
00196 }
00197
00198
00199 double vdgl_interpolator_cubic::get_curvature(double index)
00200 {
00201 const int N = chain_->size();
00202 int a= int(index)-1;
00203 if (index == N-2) --a;
00204 int b= a+1;
00205 int c= b+1;
00206 int d= c+1;
00207 assert(a >= 0 && d < N);
00208
00209 vdgl_edgel ae(chain_->edgel(a));
00210 vdgl_edgel be(chain_->edgel(b));
00211 vdgl_edgel ce(chain_->edgel(c));
00212 vdgl_edgel de(chain_->edgel(d));
00213
00214 vnl_vector_fixed<double,4> A;
00215 vnl_matrix_fixed<double,4,4> M;
00216
00217 A(0) = ae.get_x(); A(1) = be.get_x();
00218 A(2) = ce.get_x(); A(3) = de.get_x();
00219
00220 M(0,0)= a*a*a; M(0,1)= a*a; M(0,2)= a; M(0,3)= 1;
00221 M(1,0)= b*b*b; M(1,1)= b*b; M(1,2)= b; M(1,3)= 1;
00222 M(2,0)= c*c*c; M(2,1)= c*c; M(2,2)= c; M(2,3)= 1;
00223 M(3,0)= d*d*d; M(3,1)= d*d; M(3,2)= d; M(3,3)= 1;
00224
00225
00226 vnl_vector_fixed<double,4> P = vnl_inverse(M) * A;
00227
00228 double x_new= P(0) * index * index * index + P(1) * index * index + P(2) * index + P(3);
00229
00230 double t2 = 3 * P(0) * x_new * x_new + 2 * P(1) * x_new + P(2);
00231 double t3 = 1 + t2 * t2;
00232 return t2/t3/vcl_sqrt(t3);
00233 }
00234
00235
00236 double vdgl_interpolator_cubic::get_length()
00237 {
00238
00239 if ( older(chain_.ptr()) )
00240 recompute_all();
00241
00242 return lengthcache_;
00243 }
00244
00245
00246 double vdgl_interpolator_cubic::get_min_x()
00247 {
00248 if ( older(chain_.ptr()) )
00249 recompute_all();
00250
00251 return minxcache_;
00252 }
00253
00254
00255 double vdgl_interpolator_cubic::get_max_x()
00256 {
00257 if ( older(chain_.ptr()) )
00258 recompute_all();
00259
00260 return maxxcache_;
00261 }
00262
00263
00264 double vdgl_interpolator_cubic::get_min_y()
00265 {
00266 if ( older(chain_.ptr()) )
00267 recompute_all();
00268
00269 return minycache_;
00270 }
00271
00272
00273 double vdgl_interpolator_cubic::get_max_y()
00274 {
00275 if ( older(chain_.ptr()) )
00276 recompute_all();
00277
00278 return maxycache_;
00279 }
00280
00281
00282
00283 void vdgl_interpolator_cubic::recompute_all()
00284 {
00285 recompute_length();
00286 recompute_bbox();
00287
00288 touch();
00289 }
00290
00291 void vdgl_interpolator_cubic::recompute_length()
00292 {
00293 const int N = chain_->size();
00294 lengthcache_= 0;
00295 if (N <= 1) return;
00296
00297 for (int i=N-1, j=i-1; j>=0; --i,--j)
00298 {
00299 vgl_point_2d<double> p1= chain_->edgel(j).get_pt();
00300 vgl_point_2d<double> p2= chain_->edgel(i).get_pt();
00301
00302 lengthcache_ += length(p2-p1);
00303 }
00304 }
00305
00306 void vdgl_interpolator_cubic::recompute_bbox()
00307 {
00308 const int N = chain_->size();
00309 if (N == 0) return;
00310 minxcache_= chain_->edgel(0).get_x();
00311 maxxcache_= chain_->edgel(0).get_x();
00312 minycache_= chain_->edgel(0).get_y();
00313 maxycache_= chain_->edgel(0).get_y();
00314
00315 for (int i=1; i< N; i++)
00316 {
00317 if (chain_->edgel(i).get_x()< minxcache_) minxcache_= chain_->edgel(i).get_x();
00318 if (chain_->edgel(i).get_x()> maxxcache_) maxxcache_= chain_->edgel(i).get_x();
00319 if (chain_->edgel(i).get_y()< minycache_) minycache_= chain_->edgel(i).get_y();
00320 if (chain_->edgel(i).get_y()> maxycache_) maxycache_= chain_->edgel(i).get_y();
00321 }
00322 }
00323
00324 vsol_point_2d_sptr vdgl_interpolator_cubic::
00325 closest_point_on_curve ( vsol_point_2d_sptr p )
00326 {
00327 unsigned int n = chain_->size();
00328 if (n==0)
00329 return 0;
00330 double px = p->x(), py = p->y(), dmin = vnl_numeric_traits<double>::maxval;
00331 int imin = 0;
00332 for (unsigned int i = 0; i<n; i++)
00333 {
00334 double x = (*chain_)[i].x(), y = (*chain_)[i].y();
00335 double d = vcl_sqrt((x-px)*(x-px) + (y-py)*(y-py));
00336 if (d<dmin)
00337 {
00338 dmin = d;
00339 imin = i;
00340 }
00341 }
00342
00343
00344 px = this->get_x(imin);
00345 py = this->get_y(imin);
00346 return new vsol_point_2d(px, py);
00347 }