contrib/gel/vdgl/vdgl_edgel_chain.cxx
Go to the documentation of this file.
00001 // This is gel/vdgl/vdgl_edgel_chain.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 
00008 #include "vdgl_edgel_chain.h"
00009 #include <vgl/vgl_distance.h>
00010 #include <vcl_cassert.h>
00011 #include <vcl_cmath.h>   // for vcl_sqrt(float)
00012 #include <vcl_cstdlib.h> // for vcl_abs(int)
00013 #include <vcl_iostream.h>
00014 
00015 vdgl_edgel_chain::vdgl_edgel_chain( const double x0, const double y0,
00016                                     const double x1, const double y1)
00017 {
00018   bool init = true, done = false;//should be internal statics but seems not to work
00019   double x, y; // the intermediate pixels
00020   while (this->line_gen(x0, y0, x1, y1, init, done, x, y))
00021       es_.push_back(vdgl_edgel( x, y));
00022 }
00023 
00024 bool vdgl_edgel_chain::add_edgel( const vdgl_edgel &e)
00025 {
00026   es_.push_back( e);
00027 
00028   // let friends know that chain has changed
00029   notify_change();
00030 
00031   return true;
00032 }
00033 
00034 bool vdgl_edgel_chain::set_edgel( int index, const vdgl_edgel &e)
00035 {
00036   assert(index>=0);
00037   if ( (unsigned int)index >= es_.size())
00038     return false;
00039 
00040   es_[index]= e;
00041 
00042   return true;
00043 }
00044 
00045 void vdgl_edgel_chain::notify_change()
00046 {
00047   // let friends know that chain has changed
00048   vul_timestamp::touch();
00049 }
00050 
00051 bool vdgl_edgel_chain::add_edgels( const vcl_vector<vdgl_edgel> &es, int index)
00052 {
00053   assert(index>=0);
00054   if ( (unsigned int)index> es_.size())
00055     return false;
00056   else if (es_.size()== 0)
00057     es_= es;
00058   else
00059   {
00060     vcl_vector<vdgl_edgel> temp;
00061     for (int i=0; i< index; i++)
00062       temp.push_back( es_[i]);
00063 
00064     for (unsigned int i=0; i< es.size(); i++)
00065       temp.push_back( es[i]);
00066 
00067     for (unsigned int i=index; i< es_.size(); i++)
00068       temp.push_back( es_[i]);
00069 
00070     es_= temp;
00071   }
00072 
00073   // let friends know that chain has changed
00074   notify_change();
00075 
00076   return true;
00077 }
00078 
00079 vcl_ostream& operator<<(vcl_ostream& s, const vdgl_edgel_chain& p)
00080 {
00081   s << "<vdgl_edgel_chain (";
00082   if ( p.es_.size() > 0)
00083     s << p.es_[0];
00084   for (unsigned int i=1; i< p.es_.size(); ++i)
00085     s << ", " << p.es_[i];
00086 
00087   return s << ')';
00088 }
00089 
00090 inline static double sq_dist(vdgl_edgel const& e, double x, double y)
00091 {
00092   double dx = e.get_x() - x, dy = e.get_y() - y;
00093   return dx*dx+dy+dy;
00094 }
00095 
00096 vdgl_edgel_chain_sptr vdgl_edgel_chain::extract_subchain(int start, int end)
00097 {
00098   vcl_vector<vdgl_edgel> e;
00099   ++end;
00100   if (end > (int)size()) end = size();
00101   if (start < 0) start = 0;
00102   for (int i=start; i<end; ++i)
00103     e.push_back(edgel(i));
00104   return new vdgl_edgel_chain(e); // could be empty
00105 }
00106 
00107 bool vdgl_edgel_chain::split( double x, double y,
00108                               vdgl_edgel_chain_sptr &ec1,
00109                               vdgl_edgel_chain_sptr &ec2)
00110 {
00111   int split_index = -1;
00112   const int n = size();
00113   double d = 1e10;
00114   for (int i=0;i+1<n;i++) {
00115     double x1=edgel(i  ).get_x(), y1=edgel(i  ).get_y(),
00116            x2=edgel(i+1).get_x(), y2=edgel(i+1).get_y();
00117     double e = vgl_distance2_to_linesegment(x1,y1,x2,y2,x,y);
00118     if (e < d) { d=e; split_index = i+1;}
00119   }
00120 
00121   if (split_index < 0) return false; // only happens with empty edgel_chain
00122 
00123   if (split_index == 1 && d == sq_dist(edgel(0),x,y)) split_index = 0;
00124   if (split_index == n-1 && d == sq_dist(edgel(n-1),x,y)) split_index = n;
00125 
00126   if (split_index > 0) ec1 = this->extract_subchain(0, split_index-1);
00127   if (split_index < n) ec2 = this->extract_subchain(split_index, n-1);
00128   return split_index > 0 && split_index < n;
00129 }
00130 
00131 //: Advance along a line and generate contiguous pixels on the line.
00132 //
00133 bool vdgl_edgel_chain::line_gen(double xs, double ys, double xe, double ye,
00134                                 bool& init, bool& done,
00135                                 double& x, double& y)
00136 {
00137   assert(xs >= 0.0); assert(ys >= 0.0);
00138   const double pix_edge = 1.0; //We are working at scale = 1.0
00139   static double xi=0.0, yi=0.0;
00140   if (init)
00141   {
00142     xi = xs;
00143     yi = ys;
00144     x = (double)(unsigned int)(xi/pix_edge);
00145     y = (double)(unsigned int)(yi/pix_edge);
00146     init = false;
00147     return true;
00148   }
00149   if (done) return false;
00150   double dx = xe-xs;
00151   double dy = ye-ys;
00152   double mag = vcl_sqrt(dx*dx + dy*dy);
00153   if (mag<pix_edge)//Can't reach the next pixel under any circumstances
00154   {                //so just output the target, xe, ye.
00155     x = (double)(unsigned int)xe;
00156     y = (double)(unsigned int)ye;
00157     done = true;
00158     return true;
00159   }
00160   double delta = (0.5*pix_edge)/mag; //move in 1/2 pixel increments
00161   //Previous pixel location
00162   int xp = int(xi/pix_edge);
00163   int yp = int(yi/pix_edge);
00164   //Increment along the line until the motion is greater than one pixel
00165   for (int i = 0; i<3; i++)
00166   {
00167     xi += dx*delta;
00168     yi += dy*delta;
00169     //Check for end of segment, make sure we emit the end of the segment
00170     if ((xe>=xs&&xi>xe)||(xe<=xs&&xi<xe)||(ye>=ys&&yi>ye)||(ye<=ys&&yi<ye))
00171     {
00172       x = xe; y = ye;
00173       done = true;
00174       return true;
00175     }
00176     //Check if we have advanced by more than .5 pixels
00177     x = (xi/pix_edge);
00178     y = (yi/pix_edge);
00179     double dx1 = (double)(int(x)-xp), dy1 = (double)(int(y)-yp);
00180     if (vcl_abs(dx1)>(.5*pix_edge)||vcl_abs(dy1)>(.5*pix_edge))
00181       return true;
00182   }
00183   vcl_cout << "in vdgl_edgel_chain::line_gen(..) - shouldn't happen\n";
00184   return false;
00185 }
00186 
00187 bool operator==( const vdgl_edgel_chain &ec1, const vdgl_edgel_chain &ec2)
00188 {
00189   int size1 = ec1.size(), size2 = ec2.size();
00190   if (size1 != size2)
00191     return false;
00192   for (int i = 0; i<size1; i++)
00193     if (!(ec1[i] == ec2[i]))
00194       return false;
00195   return true;
00196 }
00197 
00198 bool operator!=( const vdgl_edgel_chain &ec1, const vdgl_edgel_chain &ec2)
00199 {
00200   return !(ec1==ec2);
00201 }
00202 
00203 //----------------------------------------------------------------
00204 // ================   Binary I/O Methods ========================
00205 //----------------------------------------------------------------
00206 
00207 //: Binary save self to stream.
00208 void vdgl_edgel_chain::b_write(vsl_b_ostream &os) const
00209 {
00210   vsl_b_write(os, version());
00211   vsl_b_write(os, es_.size());
00212   for (unsigned int i = 0; i<es_.size(); i++)
00213   {
00214     vsl_b_write(os, es_[i].get_x());
00215     vsl_b_write(os, es_[i].get_y());
00216     vsl_b_write(os, es_[i].get_grad());
00217     vsl_b_write(os, es_[i].get_theta());
00218   }
00219 }
00220 //: Binary load self from stream (not typically used)
00221 void vdgl_edgel_chain::b_read(vsl_b_istream &is)
00222 {
00223   if (!is)
00224     return;
00225   short ver;
00226   vsl_b_read(is, ver);
00227   switch (ver)
00228   {
00229    case 1:
00230    {
00231     int size =0; vsl_b_read(is, size);
00232     for (int i = 0; i<size; i++)
00233     {
00234       double x=0, y=0, grad=-1, theta=0;
00235       vsl_b_read(is, x);
00236       vsl_b_read(is, y);
00237       vsl_b_read(is, grad);
00238       vsl_b_read(is, theta);
00239       vdgl_edgel e(x, y, grad, theta);
00240       this->add_edgel(e);
00241     }
00242     return;
00243    }
00244    default:
00245     assert(!"Invalid version");
00246     return;
00247   }
00248 }
00249 //: Return IO version number;
00250 short vdgl_edgel_chain::version() const
00251 {
00252   return 1;
00253 }
00254 
00255 //: Print an ascii summary to the stream
00256 void vdgl_edgel_chain::print_summary(vcl_ostream &os) const
00257 {
00258   os << *this;
00259 }
00260 
00261 //: Binary save vdgl_edgel_chain* to stream.
00262 void
00263 vsl_b_write(vsl_b_ostream &os, const vdgl_edgel_chain* e)
00264 {
00265   if (!e){
00266     vsl_b_write(os, false); // Indicate null pointer stored
00267   }
00268   else{
00269     vsl_b_write(os,true); // Indicate non-null pointer stored
00270     e->b_write(os);
00271   }
00272 }
00273 
00274 //: Binary load vdgl_edgel_chain* from stream.
00275 void
00276 vsl_b_read(vsl_b_istream &is, vdgl_edgel_chain* &ec)
00277 {
00278   delete ec;
00279   bool not_null_ptr;
00280   vsl_b_read(is, not_null_ptr);
00281   if (not_null_ptr) {
00282     ec = new vdgl_edgel_chain();
00283     ec->b_read(is);
00284   }
00285   else
00286     ec = 0;
00287 }
00288 
00289 //: Print human readable summary of vdgl_edgel_chain* to a stream.
00290 void
00291 vsl_print_summary(vcl_ostream &os, const vdgl_edgel_chain* e)
00292 {
00293   os << *e;
00294 }
00295