contrib/brl/bbas/bdgl/bdgl_curve_algs.cxx
Go to the documentation of this file.
00001 #include "bdgl_curve_algs.h"
00002 //:
00003 // \file
00004 #include <vcl_cmath.h>
00005 #include <vcl_cstdlib.h> // for std::abs(int)
00006 #include <vcl_cassert.h>
00007 #include <vcl_iostream.h>
00008 #include <vnl/vnl_numeric_traits.h>
00009 #include <vnl/vnl_double_2.h>
00010 #include <vnl/vnl_double_3.h>
00011 #include <vnl/vnl_math.h> // for pi
00012 #include <vgl/vgl_line_2d.h>
00013 #include <vgl/vgl_point_2d.h>
00014 #include <vgl/vgl_homg_point_2d.h>
00015 #include <vgl/vgl_box_2d.h>
00016 #include <vgl/vgl_intersection.h>
00017 #include <vgl/algo/vgl_homg_operators_2d.h>
00018 #include <vsol/vsol_box_2d.h>
00019 #include <vdgl/vdgl_edgel_chain.h>
00020 #include <vdgl/vdgl_interpolator.h>
00021 #include <vdgl/vdgl_interpolator_linear.h>
00022 #include <vdgl/vdgl_digital_curve.h>
00023 #include <vnl/algo/vnl_gaussian_kernel_1d.h>
00024 
00025 const double bdgl_curve_algs::tol = 1e-16;
00026 const double bdgl_curve_algs::max_edgel_sep = 2.0; // the maximum separation
00027                                                    // of edgels (in pixels)
00028 const double bdgl_curve_algs::synthetic = 0;//Indicates synthetic edgel
00029                                             //default constructor is -1
00030 
00031 //: Destructor
00032 bdgl_curve_algs::~bdgl_curve_algs()
00033 {
00034 }
00035 
00036 //:
00037 //--------------------------------------------------------------------------
00038 // Finds the index (on the interval [0.0 1.0]) on a digital curve closest
00039 // to the given point (x, y).
00040 //--------------------------------------------------------------------------
00041 
00042 double bdgl_curve_algs::closest_point(vdgl_digital_curve_sptr const& dc,
00043                                       const double x, const double y)
00044 {
00045   if (!dc)
00046   {
00047     vcl_cout<<"In bdgl_curve_algs::closest_point(..) -"
00048             << " warning, null digital curve\n";
00049     return 0;
00050   }
00051   vdgl_interpolator_sptr interp = dc->get_interpolator();
00052   vdgl_edgel_chain_sptr  ec = interp->get_edgel_chain();
00053   int index = closest_point(ec, x, y);
00054   double parm = index/ec->size();
00055   return parm;
00056 }
00057 
00058 //:
00059 //-----------------------------------------------------------------------------
00060 // Finds the index on an edgel_chain closest to the given
00061 // point (x, y). Later this routine can become a method on
00062 // vdgl_edgel_chain.
00063 //-----------------------------------------------------------------------------
00064 int bdgl_curve_algs::closest_point(vdgl_edgel_chain_sptr const& ec,
00065                                    const double x, const double y)
00066 {
00067   if (!ec)
00068   {
00069     vcl_cout<<"In bdgl_curve_algs::closest_point(..) - warning, null chain\n";
00070     return 0;
00071   }
00072   //for now just scan the curve and save the closest point
00073   double mind = vnl_numeric_traits<double>::maxval;
00074   int N =ec->size(), imin = 0;
00075 
00076   for (int i = 0; i<N; i++)
00077   {
00078     vdgl_edgel ed = ec->edgel(i);
00079     double d = vcl_sqrt((ed.x()-x)*(ed.x()-x) + (ed.y()-y)*(ed.y()-y));
00080     if (d<mind)
00081     {
00082       mind = d;
00083       imin = i;
00084     }
00085   }
00086   return imin;
00087 }
00088 
00089 //:
00090 //-----------------------------------------------------------------------------
00091 // Finds the closest point, (xc, yc) on a digital curve to a given
00092 // location (x,y).
00093 // Current implementation is not the best since it is discrete with
00094 // the edgel_chain index.  Ultimately it should use the interpolator
00095 // to refine the location on the digital_curve.
00096 //-----------------------------------------------------------------------------
00097 bool bdgl_curve_algs::closest_point(vdgl_digital_curve_sptr const& dc,
00098                                     const double x, const double y,
00099                                     double& xc, double& yc)
00100 {
00101   if (!dc)
00102   {
00103     vcl_cout<<"In bdgl_curve_algs::closest_point(..) - warning, null curve\n";
00104     return false;
00105   }
00106   vdgl_interpolator_sptr interp = dc->get_interpolator();
00107   vdgl_edgel_chain_sptr ec = interp->get_edgel_chain();
00108   int index = bdgl_curve_algs::closest_point(ec, x, y);
00109   xc = (*ec)[index].x();
00110   yc = (*ec)[index].y();
00111   return true;
00112 }
00113 
00114 //: Interpolates between p0 and p1 finding the closest point to p.
00115 //  Returns the parameter t on [0, 1] -> [p0, p1].
00116 static double interpolate_segment(vnl_double_2& p0,
00117                                   vnl_double_2& p1,
00118                                   vnl_double_2& p,
00119                                   vnl_double_2& pc)
00120 {
00121   double Dx = p1[0]-p0[0], Dy = p1[1]-p0[1];
00122   double dx = p[0]-p0[0], dy = p[1]-p0[1];
00123   double den = Dx*Dx + Dy*Dy;
00124   if (den<bdgl_curve_algs::tol)
00125   {
00126     pc = p0;
00127     return 0;
00128   }
00129   double t = (dx*Dx + Dy*dy)/den;
00130   //clip t to lie within the interval
00131   if (t<0)
00132     t=0.0;
00133   if (t>1.0)
00134     t=1.0;
00135   pc[0] = t*Dx + p0[0];   pc[1] = t*Dy + p0[1];
00136   return t;
00137 }
00138 
00139 //:
00140 //-----------------------------------------------------------------------------
00141 // Finds the closest point on an edgel chain near a given point (x, y)
00142 // in the neighborhood of an index.  We assume that the nearest
00143 // point is on the interval [index, index+1].
00144 //-----------------------------------------------------------------------------
00145 bool bdgl_curve_algs::closest_point_near(vdgl_edgel_chain_sptr const& ec,
00146                                          const int index,
00147                                          const double x,
00148                                          const double y,
00149                                          double & xc,
00150                                          double & yc)
00151 {
00152   int last = ec->size()-1;//last edgel
00153   vnl_double_2 p(x, y);
00154   vnl_double_2 p0, p1, pc;
00155 
00156   if (index<0)
00157     return false;
00158   else if (index<last)
00159   {
00160     p0[0]=(*ec)[index].x();
00161     p0[1]=(*ec)[index].y();
00162     p1[0]=(*ec)[index+1].x();
00163     p1[1]=(*ec)[index+1].y();
00164   }
00165   else if (index==last)
00166   {
00167     p0[0]=(*ec)[index-1].x();
00168     p0[1]=(*ec)[index-1].y();
00169     p1[0]=(*ec)[index].x();
00170     p1[1]=(*ec)[index].y();
00171   }
00172   else // index > last
00173     return false;
00174 
00175   double t = interpolate_segment(p0, p1, p, pc);
00176   vcl_cout << "At " << p << " t = " << t << '\n';
00177   xc = pc[0];   yc = pc[1];
00178   return true;
00179 }
00180 
00181 //:
00182 // It is sometimes necessary to reverse the order of the digital curve
00183 // so that the initial point corresponds to v1 of a topology edge
00184 vdgl_digital_curve_sptr bdgl_curve_algs::reverse(vdgl_digital_curve_sptr const& dc)
00185 {
00186   if (!dc)
00187     return 0;
00188   vdgl_interpolator_sptr intrp = dc->get_interpolator();
00189   vdgl_edgel_chain_sptr ec = intrp->get_edgel_chain();
00190   int N = ec->size();
00191   vdgl_edgel_chain_sptr rev_ec = new vdgl_edgel_chain();
00192   for (int i = 0; i<N; i++)
00193     rev_ec->add_edgel((*ec)[N-1-i]);
00194   vdgl_interpolator_sptr rev_intrp = new vdgl_interpolator_linear(rev_ec);
00195   vdgl_digital_curve_sptr rev_dc = new vdgl_digital_curve(rev_intrp);
00196   return rev_dc;
00197 }
00198 //: preliminary test to see if an infinite line intersects the bounding box of the digital curve.
00199 bool bdgl_curve_algs::intersect_bounding_box(vdgl_digital_curve_sptr const& dc,
00200                                              vgl_line_2d<double> & line)
00201 {
00202   vsol_box_2d_sptr bb = dc->get_bounding_box();
00203   if (!bb)
00204     return false;
00205   vgl_box_2d<double> box(bb->get_min_x(), bb->get_max_x(),
00206                          bb->get_min_y(), bb->get_max_y());
00207   vgl_point_2d<double> p0, p1;
00208   if (vgl_intersection(box, line, p0, p1))
00209     return true;
00210   return false;
00211 }
00212 //: Intersect an infinite line with a line formed by the two input points , p0 and p1.
00213 // It is assumed that the two lines do intersect.
00214 // If they are parallel, "false" is returned.
00215 static bool intersect_crossing(vnl_double_3& line_coefs,
00216                                vnl_double_3& p0,
00217                                vnl_double_3& p1,
00218                                vnl_double_3& inter)
00219 {
00220   //Form the line from p0 and p1
00221   vnl_double_3 lv01 = vnl_cross_3d(p0, p1);
00222 
00223   //Find the intersection point
00224   inter = vnl_cross_3d(lv01, line_coefs);
00225   //Check sanity of the intersection
00226   return vcl_fabs(inter[2]) >= bdgl_curve_algs::tol;
00227 }
00228 
00229 
00230 //: Recursive helper function for intersect_line_fast
00231 static bool intersect_line_helper(vdgl_edgel_chain const& ec,
00232                                   vnl_double_3& lv,
00233                                   double dist1, double dist2,
00234                                   int index1, int index2,
00235                                   vcl_vector<vgl_point_2d<double> >& pts)
00236 {
00237   int di = (index2 - index1);
00238   if (di<1) {
00239     vcl_cout << "In bdgl_curve_algs::intersect_line_helper -"
00240              << " invalid curve segment\n";
00241     return false;
00242   }
00243 
00244   if (vcl_fabs(dist2)<bdgl_curve_algs::tol || dist1*dist2<0.0) {
00245     // base case: compute the intersection
00246     if (di==1) {
00247       // the first and last edgels
00248       vdgl_edgel const& e1 = ec[index1];
00249       vdgl_edgel const& e2 = ec[index2];
00250       vnl_double_3 p1(e1.get_x(), e1.get_y(), 1.0);
00251       vnl_double_3 p2(e2.get_x(), e2.get_y(), 1.0);
00252 
00253       vnl_double_3 inter;
00254       if (intersect_crossing(lv, p1, p2, inter)) {
00255         vgl_point_2d<double> p(inter[0]/inter[2], inter[1]/inter[2]);
00256         pts.push_back(p);
00257         return true;
00258       }
00259       return false;
00260     }
00261   }
00262   else{
00263     if (di==1) return false;
00264     if ((di*bdgl_curve_algs::max_edgel_sep)<vcl_fabs(dist1+dist2)) return false;
00265   }
00266 
00267   int mid_index = index1 + di/2;
00268   vnl_double_3 mid_point(ec[mid_index].get_x(), ec[mid_index].get_y(), 1.0);
00269   double mid_dist = dot_product(mid_point, lv);
00270   bool i1 = intersect_line_helper(ec, lv, dist1, mid_dist, index1, mid_index, pts);
00271   bool i2 = intersect_line_helper(ec, lv, mid_dist, dist2, mid_index, index2, pts);
00272   return i1 || i2;
00273 }
00274 
00275 //-------------------------------------------------------------
00276 //: intersect an infinite line with the digital curve.
00277 //  If there is no intersection return false. Note that the line
00278 //  can intersect multiple times. All the intersections are returned.
00279 //
00280 //  This implementation uses a recursive helper function
00281 bool bdgl_curve_algs::intersect_line_fast(vdgl_digital_curve_sptr const& dc,
00282                                           vgl_line_2d<double> & line,
00283                                           vcl_vector<vgl_point_2d<double> >& pts)
00284 {
00285   if (!dc)
00286   {
00287     vcl_cout << "In bdgl_curve_algs::intersect_line_fast - null curve\n";
00288     return false;
00289   }
00290   vdgl_interpolator_sptr interp = dc->get_interpolator();
00291   vdgl_edgel_chain_sptr  ec = interp->get_edgel_chain();
00292 
00293   // normalized the line so that the algebraic distance between
00294   // lv and (x,y,1) is the geometric distance
00295   line.normalize();
00296   vnl_double_3 lv(line.a(), line.b(), line.c());
00297 
00298   // the first and last edgels
00299   vdgl_edgel const& e1 = (*ec)[0];
00300   vdgl_edgel const& e2 = (*ec)[ec->size()-1];
00301 
00302   vnl_double_3 p1(e1.get_x(), e1.get_y(), 1.0);
00303   vnl_double_3 p2(e2.get_x(), e2.get_y(), 1.0);
00304 
00305   double dist1 = dot_product(p1, lv);
00306   double dist2 = dot_product(p2, lv);
00307 
00308   bool intersection = false;
00309   // This case (the first edgel is on the line)
00310   // is not covered by the recursion
00311   if (vcl_fabs(dist1)<bdgl_curve_algs::tol) {
00312     vdgl_edgel const& e = (*ec)[1];
00313     vnl_double_3 p(e.get_x(), e.get_y(), 1.0);
00314     vnl_double_3 inter;
00315     if (intersect_crossing(lv, p1, p, inter)) {
00316       vgl_point_2d<double> p(inter[0]/inter[2], inter[1]/inter[2]);
00317       pts.push_back(p);
00318       intersection = true;
00319     }
00320   }
00321 
00322   return intersect_line_helper(*ec, lv, dist1, dist2, 0, ec->size()-1, pts) ||
00323          intersection;
00324 }
00325 
00326 
00327 //-------------------------------------------------------------
00328 //: intersect an infinite line with the digital curve.
00329 //  If there is no intersection return false. Note that the line
00330 //  can intersect multiple times. All the intersections are returned.
00331 bool bdgl_curve_algs::intersect_line(vdgl_digital_curve_sptr const& dc,
00332                                      vgl_line_2d<double>& line,
00333                                      vcl_vector<vgl_point_2d<double> >& pts)
00334 {
00335   if (!dc)
00336   {
00337     vcl_cout << "In bdgl_curve_algs::intersect_line - null curve\n";
00338     return false;
00339   }
00340   //compute the resolution of the intersection. The digital curve is
00341   //typically embedded in image coordinates so we would want to compute the
00342   //intersection to 0.1 pixels.  The parametrization of the curve is [0,1]
00343   //so the search interval on the parmeter should be dt = 1/(10*dc->length())
00344   //That is, this change of dt corresponds to 0.1 pixel on the curve.
00345 
00346   bool intersection = false;
00347   vnl_double_3 lv(line.a(), line.b(), line.c());
00348 
00349   //We take advantage of the fact that the algebraic distance to
00350   //a line changes sign if we cross it.
00351   double t=0, dt = 1/(10*dc->length());
00352   vnl_double_3 p0(dc->get_x(t), dc->get_y(t), 1.0), p1;
00353   for (double t=dt; t<=1.0; t+=dt)
00354   {
00355     p1[0]=dc->get_x(t); p1[1]=dc->get_y(t); p1[2]= 1.0;
00356     double sign0 = dot_product(p0, lv);
00357     double sign1 = dot_product(p1, lv);
00358     if (vcl_fabs(sign0)<bdgl_curve_algs::tol||              //we have crossed or
00359         vcl_fabs(sign1)<bdgl_curve_algs::tol||sign0*sign1<=0) // are on the line
00360     {
00361       vnl_double_3 inter;
00362       if (intersect_crossing(lv, p0, p1, inter))
00363       {
00364         vgl_point_2d<double> p(inter[0]/inter[2], inter[1]/inter[2]);
00365         pts.push_back(p);
00366         intersection = true;
00367       }
00368     }
00369     p0=p1;
00370   }
00371   return intersection;
00372 }
00373 
00374 //------------------------------------------------------------------
00375 //:
00376 // Given a line segment and a point interior to the line segment
00377 // find the intermediate line parameter value for the point. t0 and t1
00378 // are the line parameter values for p0 and p1 respectively.
00379 static double interpolate_parameter(const double t0, const double t1,
00380                                     vnl_double_3& p0,
00381                                     vnl_double_3& p1,
00382                                     vnl_double_3& pt)
00383 {
00384   if (vcl_fabs(p0[2])<bdgl_curve_algs::tol)
00385     return t0;
00386   if (vcl_fabs(p1[2])<bdgl_curve_algs::tol)
00387     return t0;
00388   if (vcl_fabs(pt[2])<bdgl_curve_algs::tol)
00389     return t0;
00390   double x0 = p0[0]/p0[2], y0 = p0[1]/p0[2];
00391   double x1 = p1[0]/p1[2], y1 = p1[1]/p1[2];
00392   double xt = pt[0]/pt[2], yt = pt[1]/pt[2];
00393   double d01 = vcl_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0));
00394   double d0t = vcl_sqrt((xt-x0)*(xt-x0) + (yt-y0)*(yt-y0));
00395   double r = d0t/d01;//relative length from p0 to pt
00396   double dt = t1-t0;
00397   return t0 + r*dt;
00398 }
00399 
00400 
00401 //: Recursive helper function for intersect_line_fast
00402 static bool intersect_line_helper(vdgl_edgel_chain const& ec,
00403                                   vnl_double_3& lv,
00404                                   double dist1, double dist2,
00405                                   int index1, int index2,
00406                                   vcl_vector<double>& indices)
00407 {
00408   int di = (index2 - index1);
00409   if (di<1) {
00410     vcl_cout << "In bdgl_curve_algs::intersect_line_helper -"
00411              << " invalid curve segment\n";
00412     return false;
00413   }
00414 
00415   if (vcl_fabs(dist2)<bdgl_curve_algs::tol || dist1*dist2<0.0) {
00416     // base case: compute the intersection
00417     if (di==1) {
00418       // the first and last edgels
00419       vdgl_edgel const& e1 = ec[index1];
00420       vdgl_edgel const& e2 = ec[index2];
00421       vnl_double_3 p1(e1.get_x(), e1.get_y(), 1.0);
00422       vnl_double_3 p2(e2.get_x(), e2.get_y(), 1.0);
00423 
00424       vnl_double_3 inter;
00425       if (intersect_crossing(lv, p1, p2, inter)) {
00426         double param_step = 1.0/(ec.size()-1);
00427         double ti = interpolate_parameter(index1*param_step, index2*param_step,
00428                                           p1, p2, inter);
00429         indices.push_back(ti);
00430         return true;
00431       }
00432       return false;
00433     }
00434   }
00435   else{
00436     if (di==1) return false;
00437     if ((di*bdgl_curve_algs::max_edgel_sep)<vcl_fabs(dist1+dist2)) return false;
00438   }
00439 
00440   int mid_index = index1 + di/2;
00441   vnl_double_3 mid_point(ec[mid_index].get_x(), ec[mid_index].get_y(), 1.0);
00442   double mid_dist = dot_product(mid_point, lv);
00443 
00444   bool i1 = intersect_line_helper(ec, lv, dist1, mid_dist, index1, mid_index, indices);
00445   bool i2 = intersect_line_helper(ec, lv, mid_dist, dist2, mid_index, index2, indices);
00446   return i1 || i2;
00447 }
00448 
00449 //-------------------------------------------------------------
00450 //: intersect an infinite line with the digital curve.
00451 //  If there is no intersection return false. Note that the line
00452 //  can intersect multiple times. The curve parameter indices at
00453 //  the intersection points are returned
00454 //
00455 //  This implementation uses a recursive helper function
00456 bool bdgl_curve_algs::intersect_line_fast(vdgl_digital_curve_sptr const& dc,
00457                                           vgl_line_2d<double> & line,
00458                                           vcl_vector<double>& indices)
00459 {
00460   if (!dc)
00461   {
00462     vcl_cout << "In bdgl_curve_algs::intersect_line_fast - null curve\n";
00463     return false;
00464   }
00465   vdgl_interpolator_sptr interp = dc->get_interpolator();
00466   vdgl_edgel_chain_sptr  ec = interp->get_edgel_chain();
00467 
00468   // normalized the line so that the algebraic distance between
00469   // lv and (x,y,1) is the geometric distance
00470   line.normalize();
00471   vnl_double_3 lv(line.a(), line.b(), line.c());
00472 
00473   // the first and last edgels
00474   vdgl_edgel const& e1 = (*ec)[0];
00475   vdgl_edgel const& e2 = (*ec)[ec->size()-1];
00476 
00477   vnl_double_3 p1(e1.get_x(), e1.get_y(), 1.0);
00478   vnl_double_3 p2(e2.get_x(), e2.get_y(), 1.0);
00479 
00480   double dist1 = dot_product(p1, lv);
00481   double dist2 = dot_product(p2, lv);
00482 
00483   bool intersection = false;
00484   // This case (the first edgel is on the line)
00485   // is not covered by the recursion
00486   if (vcl_fabs(dist1)<bdgl_curve_algs::tol) {
00487     vdgl_edgel const& e = (*ec)[1];
00488     vnl_double_3 p(e.get_x(), e.get_y(), 1.0);
00489     vnl_double_3 inter;
00490     if (intersect_crossing(lv, p1, p, inter)) {
00491       double param_step = 1.0/(ec->size()-1);
00492       double ti = interpolate_parameter(0.0, param_step, p1, p, inter);
00493       indices.push_back(ti);
00494       intersection = true;
00495     }
00496   }
00497 
00498   return intersect_line_helper(*ec, lv, dist1, dist2, 0, ec->size()-1, indices) ||
00499          intersection;
00500 }
00501 
00502 
00503 //-------------------------------------------------------------
00504 //: intersect an infinite line with the digital curve.
00505 //  If there is no intersection return false. Note that the line
00506 //  can intersect multiple times. The curve parameter indices at
00507 //  the intersection points are returned
00508 bool bdgl_curve_algs::intersect_line(vdgl_digital_curve_sptr const& dc,
00509                                      vgl_line_2d<double>& line,
00510                                      vcl_vector<double>& indices)
00511 {
00512   if (!dc)
00513   {
00514     vcl_cout << "In bdgl_curve_algs::intersect_line - null curve\n";
00515     return false;
00516   }
00517   //compute the resolution of the intersection. The digital curve is
00518   //typically embedded in image coordinates so we would want to compute the
00519   //intersection to 0.1 pixels.  The parametrization of the curve is [0,1]
00520   //so the search interval on the parmeter should be dt = 1/(10*dc->length())
00521   //That is, this change of dt corresponds to 0.1 pixel on the curve.
00522 
00523   bool intersection = false;
00524   vnl_double_3 lv(line.a(), line.b(), line.c());
00525 
00526   //We take advantage of the fact that the algebraic distance to
00527   //a line changes sign if we cross it.
00528   double t=0, dt = 1/(10*dc->length());
00529   vnl_double_3 p0(dc->get_x(t), dc->get_y(t), 1.0), p1;
00530   for (double t=dt; t<=1.0; t+=dt)
00531   {
00532     p1[0]=dc->get_x(t); p1[1]=dc->get_y(t); p1[2]= 1.0;
00533     double sign0 = dot_product(p0, lv);
00534     double sign1 = dot_product(p1, lv);
00535     if (vcl_fabs(sign0)<bdgl_curve_algs::tol||              //we have crossed or
00536         vcl_fabs(sign1)<bdgl_curve_algs::tol||sign0*sign1<=0) // are on the line
00537     {
00538       vnl_double_3 inter;
00539       if (intersect_crossing(lv, p0, p1, inter))
00540       {
00541         double ti = interpolate_parameter(t, t+dt, p0, p1, inter);
00542         indices.push_back(ti);
00543         intersection = true;
00544       }
00545     }
00546     p0=p1;
00547   }
00548   return intersection;
00549 }
00550 
00551 
00552 //:Intersect a curve and find the closest point to \a ref_point with a compatible gradient angle
00553 bool
00554 bdgl_curve_algs::match_intersection(vdgl_digital_curve_sptr const& dc,
00555                                     vgl_line_2d<double>& line,
00556                                     vgl_point_2d<double> const& ref_point,
00557                                     double ref_gradient_angle,
00558                                     vgl_point_2d<double>& point)
00559 {
00560   double angle_thresh = 7.0;//epipolar angle threshold
00561   double angle_tol = 12.5;//gradient angle threshold
00562   if (!dc)
00563     return false;
00564   double la = line.slope_degrees();
00565   if (la<0)
00566     la+=180;
00567   vcl_vector<double> indices;
00568   if (!bdgl_curve_algs::intersect_line(dc, line, indices))
00569     return false;
00570   vgl_homg_point_2d<double> rph(ref_point.x(), ref_point.y());
00571   double dist = 1e10;
00572   bool found_valid_intersection = false;
00573   for (vcl_vector<double>::iterator iit = indices.begin();
00574        iit != indices.end(); iit++)
00575   {
00576     double grad_angle = dc->get_theta(*iit);
00577     if (vcl_fabs(ref_gradient_angle-grad_angle)>angle_tol)
00578       continue;
00579     double ca = dc->get_tangent_angle(*iit);
00580     if (ca<0)
00581       ca+=180;
00582     double delt = vcl_fabs(vcl_sin(vcl_fabs(vnl_math::pi_over_180*(ca-la)))*vnl_math::deg_per_rad);
00583     if (delt<angle_thresh)
00584       continue;
00585     vgl_homg_point_2d<double> ph(dc->get_x(*iit), dc->get_y(*iit));
00586     double d = vgl_homg_operators_2d<double>::distance_squared(rph, ph);
00587     d = vcl_sqrt(d);
00588     found_valid_intersection = true;
00589     if (d<dist)
00590     {
00591       //double best_delt = delt;
00592       //double best_ind = *iit;
00593       dist = d;
00594       point = vgl_point_2d<double>(dc->get_x(*iit), dc->get_y(*iit));
00595     }
00596   }
00597   return found_valid_intersection;
00598 }
00599 
00600 //: generate contiguous pixels on a straight line.
00601 // Advance along a line and generate contiguous pixels on a straight
00602 // line defined by (xs, ys) : (xe, ye).  The samples are generated
00603 // as values of (x, y).
00604 // The routine is called in a loop that generates the points, e.g.,
00605 // \code
00606 //   while (line_gen(xs, ys, xe, ye, init, done, x, y))
00607 //   { ...
00608 // \endcode
00609 // The routine needs two internal state variables, init and done.
00610 // init should be set to true
00611 // done should be set to false
00612 // when the routine is first called.
00613 //
00614 bool bdgl_curve_algs::line_gen(const float xs, const float ys,
00615                                const float xe, const float ye,
00616                                bool& init, bool& done,
00617                                float& x, float& y)
00618 {
00619   assert(xs >= 0.0f); assert(ys >= 0.0f);
00620   const float pix_edge = 1.0f; //We are working at scale = 1.0
00621   static float xi=0, yi=0;
00622   if (init)
00623   {
00624     xi = xs;
00625     yi = ys;
00626     x = (float)(xi/pix_edge);
00627     y = (float)(yi/pix_edge);
00628     init = false;
00629     return true;
00630   }
00631   if (done) return false;
00632   float dx = xe-xs;
00633   float dy = ye-ys;
00634   float mag = vcl_sqrt(dx*dx + dy*dy);
00635   if (mag<pix_edge)//Can't reach the next pixel under any circumstances
00636   {                //so just output the target, xe, ye.
00637     x = (float)xe; y = (float)ye;
00638     done = true;
00639     return true;
00640   }
00641   float delta = (0.5f*pix_edge)/mag; //move in 1/2 pixel increments
00642   //Previous pixel location
00643   int xp = int(xi/pix_edge);
00644   int yp = int(yi/pix_edge);
00645   //Increment along the line until the motion is greater than one pixel
00646   for (int i = 0; i<3; i++)
00647   {
00648     xi += dx*delta;
00649     yi += dy*delta;
00650     //Check for end of segment, make sure we emit the end of the segment
00651     if ((xe>=xs&&xi>xe)||(xe<=xs&&xi<xe)||(ye>=ys&&yi>ye)||(ye<=ys&&yi<ye))
00652     {
00653       x = (float)xe; y = (float)ye;
00654       done = true;
00655       return true;
00656     }
00657     //Check if we have advanced by more than .5 pixels
00658     x = (float)(xi/pix_edge);
00659     y = (float)(yi/pix_edge);
00660     if (2*vcl_abs(int(x)-xp)>pix_edge || 2*vcl_abs(int(y)-yp)>pix_edge)
00661       return true;
00662   }
00663   vcl_cout << "in bdgl_curve_algs::line_gen - shouldn't happen\n";
00664   return false;
00665 }
00666 
00667 //:
00668 // Given an existing edgel_chain, add new edgels from the end
00669 // along a straight digital line to reach (x, y). The number of
00670 // edgels added is returned
00671 int bdgl_curve_algs::add_straight_edgels(vdgl_edgel_chain_sptr const& ec,
00672                                          const double xe, const double ye,
00673                                          bool debug)
00674 {
00675   assert (ec);
00676   assert (ec->size() > 0);
00677   int Npix = 0, last = ec->size()-1;
00678 
00679   float xs = float((*ec)[last].x()), ys = float((*ec)[last].y());
00680   bool first = true, init = true, done = false;
00681   float x, y;
00682   while (bdgl_curve_algs::line_gen(xs, ys, float(xe), float(ye), init, done, x, y))
00683     if (!first)
00684     {
00685       vdgl_edgel ed(x, y, bdgl_curve_algs::synthetic);
00686       ec->add_edgel(ed);
00687       Npix++;
00688       if (debug)
00689         vcl_cout << "Adding edgel " << ed << '\n';
00690     }
00691     else
00692       first = false;//skip first point since it is already last element of ec
00693   return Npix;
00694 }
00695 
00696 //:
00697 // returns either 0 or N depending on which end of the chain is
00698 // closer to the given point
00699 int bdgl_curve_algs::closest_end(vdgl_edgel_chain_sptr const & ec,
00700                                  const double x, const double y)
00701 {
00702   if (!ec)
00703   {
00704     vcl_cout << "In bdgl_curve_algs::closest_end - null edgel chain\n";
00705     return 0;
00706   }
00707   int N = ec->size();
00708   if (!N)
00709   {
00710     vcl_cout << "In bdgl_curve_algs::closest_end - no edgels in chain\n";
00711     return 0;
00712   }
00713   double x0 = (*ec)[0].x(), y0=(*ec)[0].y();
00714   double xn = (*ec)[N-1].x(), yn=(*ec)[N-1].y();
00715   double d0 = vcl_sqrt((x0-x)*(x0-x)+ (y0-y)*(y0-y));
00716   double dn = vcl_sqrt((xn-x)*(xn-x)+ (yn-y)*(yn-y));
00717   if (d0<dn)
00718     return 0;
00719   return N;
00720 }
00721 
00722 
00723 // smooth a curve by convolving x(s),y(s) with a gaussian filter
00724 void bdgl_curve_algs::
00725 smooth_curve(vcl_vector<vgl_point_2d<double> > &curve,double sigma)
00726 {
00727   vnl_gaussian_kernel_1d gauss_1d(sigma);
00728   curve.insert(curve.begin(),curve[0]);
00729   curve.insert(curve.begin(),curve[0]);
00730   curve.insert(curve.begin(),curve[0]);
00731 
00732   curve.insert(curve.end(),curve[curve.size()-1]);
00733   curve.insert(curve.end(),curve[curve.size()-1]);
00734   curve.insert(curve.end(),curve[curve.size()-1]);
00735   double sum=gauss_1d[0];
00736   for (int i=1;i<gauss_1d.width();i++)
00737     sum+=2*gauss_1d[i];
00738 
00739   for (unsigned int i=3; i+3<curve.size(); ++i)
00740   {
00741     double x=curve[i-3].x()*gauss_1d[3] + curve[i-2].x()*gauss_1d[2]+
00742              curve[i-1].x()*gauss_1d[1] + curve[i  ].x()*gauss_1d[0]+
00743              curve[i+1].x()*gauss_1d[1] + curve[i+2].x()*gauss_1d[2]+
00744              curve[i+3].x()*gauss_1d[3];
00745     double y=curve[i-3].y()*gauss_1d[3] + curve[i-2].y()*gauss_1d[2]+
00746              curve[i-1].y()*gauss_1d[1] + curve[i  ].y()*gauss_1d[0]+
00747              curve[i+1].y()*gauss_1d[1] + curve[i+2].y()*gauss_1d[2]+
00748              curve[i+3].y()*gauss_1d[3];
00749     x/=sum;
00750     y/=sum;
00751     curve[i].set(x,y);
00752   }
00753 }
00754 
00755 vdgl_digital_curve_sptr  bdgl_curve_algs::
00756 create_digital_curves(vcl_vector<vgl_point_2d<double> > & curve)
00757 {
00758   vdgl_edgel_chain_sptr vec;
00759   vec= new vdgl_edgel_chain;
00760   for (unsigned int j=0; j<curve.size(); ++j)
00761   {
00762     vdgl_edgel el(curve[j].x(),curve[j].y(), 0,0 );
00763     vec->add_edgel(el);
00764   }
00765   vdgl_interpolator_sptr interp= new vdgl_interpolator_linear(vec);
00766   vdgl_digital_curve_sptr dc = new vdgl_digital_curve(interp);
00767   return dc;
00768 }
00769