00001 
00002 #include "vsol_conic_2d.h"
00003 
00004 
00005 
00006 #include <vnl/vnl_math.h>
00007 #include <vbl/io/vbl_io_smart_ptr.h>
00008 #include <vsol/vsol_point_2d.h>
00009 #include <vgl/vgl_vector_2d.h>
00010 #include <vgl/vgl_homg_point_2d.h>
00011 #include <vgl/vgl_homg_line_2d.h>
00012 #include <vgl/io/vgl_io_conic.h>
00013 #include <vgl/algo/vgl_homg_operators_2d.h>
00014 #include <vcl_cmath.h> 
00015 #include <vcl_cassert.h>
00016 
00017 
00018 
00019 
00020 
00021 inline static bool are_equal(double x, double y)
00022 {
00023   
00024   const double epsilon=1e-6*(vcl_abs(x)+vcl_abs(y));
00025   
00026   return vcl_abs(x-y)<=epsilon;
00027 }
00028 
00029 
00030 
00031 
00032 
00033 
00034 inline static bool is_zero(double x) { return vcl_abs(x)<=1e-6; }
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 
00045 
00046 
00047 
00048 
00049 
00050 vsol_conic_2d::vsol_conic_2d(vsol_point_2d const& c, double rx, double ry, double theta) :
00051   vsol_curve_2d(), vgl_conic<double>(vgl_homg_point_2d<double>(c.x(),c.y(),1.0), rx, ry, theta)
00052 {
00053 }
00054 
00055 
00056 
00057 
00058 
00059 
00060 
00061 
00062 
00063 
00064 
00065 void vsol_conic_2d::set_central_parameters(vsol_point_2d const& c, double rx, double ry, double theta)
00066 {
00067   vgl_conic<double> g(vgl_homg_point_2d<double>(c.x(),c.y(),1.0), rx, ry, theta);
00068   set(g.a(),g.b(),g.c(),g.d(),g.e(),g.f());
00069 }
00070 
00071 
00072 
00073 
00074 
00075 
00076 
00077 vsol_conic_2d::vsol_conic_2d(vgl_vector_2d<double> const& dir,
00078                              vsol_point_2d const& top, double theta) :
00079   vsol_curve_2d(), vgl_conic<double>(vgl_homg_point_2d<double>(dir.x(),dir.y(),0.0), top.x(), top.y(), theta)
00080 {
00081 }
00082 
00083 
00084 
00085 
00086 
00087 
00088 
00089 void vsol_conic_2d::set_parabola_parameters(vgl_vector_2d<double> const& dir,
00090                                             vsol_point_2d const& top, double theta)
00091 {
00092   vgl_conic<double> g(vgl_homg_point_2d<double>(dir.x(),dir.y(),0.0), top.x(), top.y(), theta);
00093   set(g.a(),g.b(),g.c(),g.d(),g.e(),g.f());
00094 }
00095 
00096 
00097 
00098 
00099 
00100 vsol_spatial_object_2d* vsol_conic_2d::clone() const
00101 {
00102   return new vsol_conic_2d(*this);
00103 }
00104 
00105 
00106 
00107 
00108 
00109 
00110 
00111 
00112 
00113 bool vsol_conic_2d::operator==(vsol_conic_2d const& other) const
00114 {
00115   if (this==&other)
00116     return true;
00117   
00118   bool conic_eq = vgl_conic<double>::operator==(other);
00119   
00120   bool epts_eq = vsol_curve_2d::endpoints_equal(other);
00121   return conic_eq&&epts_eq;
00122 }
00123 
00124 
00125 
00126 bool vsol_conic_2d::operator==(vsol_spatial_object_2d const& obj) const
00127 {
00128   return
00129     obj.cast_to_curve() && obj.cast_to_curve()->cast_to_conic() &&
00130     *this == *obj.cast_to_curve()->cast_to_conic();
00131 }
00132 
00133 
00134 
00135 
00136 
00137 
00138 
00139 
00140 vsol_conic_2d::vsol_conic_type vsol_conic_2d::real_type() const
00141 {
00142   if (type() == vgl_conic<double>::real_circle)
00143     return real_circle;
00144   else if (type() == vgl_conic<double>::real_ellipse)
00145     return real_ellipse;
00146   else if (type() == vgl_conic<double>::imaginary_circle)
00147     return complex_circle;
00148   else if (type() == vgl_conic<double>::imaginary_ellipse)
00149     return complex_ellipse;
00150   else if (type() == vgl_conic<double>::hyperbola)
00151     return hyperbola;
00152   else if (type() == vgl_conic<double>::parabola)
00153     return parabola;
00154   else if (type() == vgl_conic<double>::real_intersecting_lines)
00155     return real_intersecting_lines;
00156   else if (type() == vgl_conic<double>::complex_intersecting_lines)
00157     return complex_intersecting_lines;
00158   else if (type() == vgl_conic<double>::coincident_lines)
00159     return coincident_lines;
00160   else if (type() == vgl_conic<double>::real_parallel_lines)
00161     return real_parallel_lines;
00162   else if (type() == vgl_conic<double>::complex_parallel_lines)
00163     return complex_parallel_lines;
00164   else return invalid; 
00165 }
00166 
00167 
00168 
00169 
00170 bool vsol_conic_2d::is_real_ellipse() const
00171 {
00172   vsol_conic_type tmp=real_type();
00173   return (tmp==real_ellipse)||(tmp==real_circle);
00174 }
00175 
00176 
00177 
00178 
00179 bool vsol_conic_2d::is_real_circle() const
00180 {
00181   return real_type()==real_circle;
00182 }
00183 
00184 
00185 
00186 
00187 bool vsol_conic_2d::is_complex_ellipse() const
00188 {
00189   vsol_conic_type tmp=real_type();
00190   return (tmp==complex_ellipse)||(tmp==complex_circle);
00191 }
00192 
00193 
00194 
00195 
00196 bool vsol_conic_2d::is_complex_circle() const
00197 {
00198   return real_type()==complex_circle;
00199 }
00200 
00201 
00202 
00203 
00204 bool vsol_conic_2d::is_parabola() const
00205 {
00206   return real_type()==parabola;
00207 }
00208 
00209 
00210 
00211 
00212 bool vsol_conic_2d::is_hyperbola() const
00213 {
00214   return real_type()==hyperbola;
00215 }
00216 
00217 
00218 
00219 
00220 bool vsol_conic_2d::is_real_intersecting_lines() const
00221 {
00222   return real_type()==real_intersecting_lines;
00223 }
00224 
00225 
00226 
00227 
00228 bool vsol_conic_2d::is_complex_intersecting_lines() const
00229 {
00230   return real_type()==complex_intersecting_lines;
00231 }
00232 
00233 
00234 
00235 
00236 bool vsol_conic_2d::is_coincident_lines() const
00237 {
00238   return real_type()==coincident_lines;
00239 }
00240 
00241 
00242 
00243 
00244 
00245 void vsol_conic_2d::ellipse_parameters(double &cx,
00246                                        double &cy,
00247                                        double &phi,
00248                                        double &width,
00249                                        double &height) const
00250 {
00251   
00252   assert(is_real_ellipse());
00253 
00254   const double b2=b()/2;
00255   const double d2=d()/2;
00256   const double e2=e()/2;
00257   const double det=a()*c()-b2*b2;
00258   if (is_zero(b2*b2/det)) 
00259   {
00260     cx=-d2/a();
00261     cy=-e2/c();
00262   }
00263   else
00264   {
00265     cx=(b2*e2-c()*d2)/det;
00266     cy=(b2*d2-a()*e2)/det;
00267   }
00268 
00269   double f0=a()*cx*cx+b()*cx*cy+c()*cy*cy+d()*cx+e()*cy+f();
00270 
00271   if (is_zero(f0)) 
00272     f0=1;
00273   const double a0=-a()/f0;
00274   const double b0=-b2/f0;
00275   const double c0=-c()/f0;
00276 
00277   
00278   if (are_equal(a0,c0)&&is_zero(b0))
00279     phi=0; 
00280   else
00281     phi=vcl_atan2(-2*b0,c0-a0)/2; 
00282 
00283   const double cosphi=vcl_cos(phi);
00284   const double sinphi=vcl_sin(phi);
00285   width =vcl_sqrt(1.0/(a0*cosphi*cosphi+2*b0*cosphi*sinphi+c0*sinphi*sinphi));
00286   height=vcl_sqrt(1.0/(a0*sinphi*sinphi-2*b0*cosphi*sinphi+c0*cosphi*cosphi));
00287 }
00288 
00289 
00290 double vsol_conic_2d::ellipse_angular_position(vsol_point_2d_sptr const& pt) const
00291 {
00292   
00293   assert(is_real_ellipse());
00294 
00295   
00296   vsol_point_2d_sptr closest = this->closest_point_on_curve(pt);
00297   assert(closest);
00298   double x = closest->x(), y = closest->y();
00299 
00300   
00301   double cx, cy, major_axis, minor_axis, angle;
00302   this->ellipse_parameters(cx, cy, angle, major_axis, minor_axis);
00303 
00304   x -= cx; y -= cy;
00305 
00306   
00307   double phi =
00308     vcl_atan2(major_axis*(vcl_cos(angle)*y-vcl_sin(angle)*x),
00309               minor_axis*(vcl_cos(angle)*x + vcl_sin(angle)*y));
00310   if (phi<0.0)
00311     phi += 2.0*vnl_math::pi;
00312   return phi;
00313 }
00314 
00315 
00316 
00317 
00318 
00319 void vsol_conic_2d::hyperbola_parameters(double &cx,
00320                                          double &cy,
00321                                          double &phi,
00322                                          double &width,
00323                                          double &height) const
00324 {
00325   
00326   assert(is_hyperbola());
00327 
00328   const double b2=b()/2;
00329   const double d2=d()/2;
00330   const double e2=e()/2;
00331   const double det=a()*c()-b2*b2;
00332 
00333   cx=(b2*e2-c()*d2)/det;
00334   cy=(b2*d2-a()*e2)/det;
00335 
00336   double f0=a()*cx*cx+b()*cx*cy+c()*cy*cy+d()*cx+e()*cy+f();
00337 
00338   if (is_zero(f0)) 
00339     f0=1;
00340   const double a0=-a()/f0;
00341   const double b0=-b2/f0;
00342   const double c0=-c()/f0;
00343 
00344   
00345   if (is_zero(b0)) { 
00346     if (a0 > 0) phi = 0;
00347     else        phi = vcl_atan2(0.0,1.0); 
00348   }
00349   else
00350     phi=vcl_atan2(2*b0,a0-c0)/2;
00351 
00352   const double cosphi=vcl_cos(phi);
00353   const double sinphi=vcl_sin(phi);
00354   width = vcl_sqrt( 1.0/(a0*cosphi*cosphi+2*b0*cosphi*sinphi+c0*sinphi*sinphi));
00355   height=-vcl_sqrt(-1.0/(a0*sinphi*sinphi-2*b0*cosphi*sinphi+c0*cosphi*cosphi));
00356 }
00357 
00358 
00359 
00360 
00361 
00362 
00363 void vsol_conic_2d::parabola_parameters(double & ,
00364                                         double & ,
00365                                         double &cosphi,
00366                                         double &sinphi) const
00367 {
00368   
00369   assert(is_parabola());
00370 
00371   
00372   
00373   
00374   const double norm=a()+c();
00375   
00376   cosphi=-vcl_sqrt(c()/norm);
00377   sinphi=vcl_sqrt(a()/norm);
00378   
00379   
00380   
00381   vcl_cerr << "vsol_conic_2d::parabola_parameters() not yet fully implemented\n";
00382 }
00383 
00384 
00385 
00386 
00387 
00388 
00389 
00390 
00391 double vsol_conic_2d::length() const
00392 {
00393   assert(is_real_ellipse());
00394     
00395   vsol_point_2d_sptr p0 = this->p0();
00396  double start_angle = this->ellipse_angular_position(p0);
00397 
00398   
00399   vsol_point_2d_sptr p1 = this->p1();
00400   double end_angle = this->ellipse_angular_position(p1);
00401   if (end_angle<=start_angle)
00402     end_angle += 2.0*vnl_math::pi;
00403 
00404   double xc, yc, angle, major_axis, minor_axis;
00405   this->ellipse_parameters(xc, yc, angle, major_axis, minor_axis);
00406   double dphi = 0.001;
00407   double sum = 0.0;
00408   
00409   for (double phi = start_angle; phi<=end_angle; phi+=dphi)
00410   {
00411     double temp1 =
00412       minor_axis*vcl_cos(angle)*vcl_cos(phi)+ major_axis*vcl_sin(angle)*vcl_sin(phi);
00413     double temp2 = major_axis*vcl_sin(angle+phi);
00414     
00415     double dl = vcl_sqrt(temp1*temp1 + temp2*temp2);
00416     sum += dl*dphi;
00417   }
00418   return sum;
00419 }
00420 
00421 
00422 
00423 
00424 vnl_double_3x3 vsol_conic_2d::matrix() const
00425 {
00426   vnl_double_3x3 result;
00427 
00428   
00429   result.put(0,0,a());
00430   result.put(0,1,b()/2);
00431   result.put(0,2,d()/2);
00432   
00433   result.put(1,0,b()/2);
00434   result.put(1,1,c());
00435   result.put(1,2,e()/2);
00436   
00437   result.put(2,0,d()/2);
00438   result.put(2,1,e()/2);
00439   result.put(2,2,f());
00440 
00441   return result;
00442 }
00443 
00444 
00445 
00446 
00447 
00448 
00449 
00450 
00451 
00452 void vsol_conic_2d::set_p0(vsol_point_2d_sptr const& new_p0)
00453 {
00454   
00455   assert(in(new_p0));
00456 
00457   p0_=new_p0;
00458 }
00459 
00460 
00461 
00462 
00463 
00464 void vsol_conic_2d::set_p1(vsol_point_2d_sptr const& new_p1)
00465 {
00466   
00467   assert(in(new_p1));
00468 
00469   p1_=new_p1;
00470 }
00471 
00472 
00473 
00474 
00475 
00476 
00477 
00478 
00479 vsol_point_2d_sptr vsol_conic_2d::midpoint() const
00480 {
00481   vgl_homg_point_2d<double> p = this->centre();
00482   return new vsol_point_2d(p.x()/p.w(), p.y()/p.w());
00483 }
00484 
00485 
00486 
00487 
00488 bool vsol_conic_2d::in(vsol_point_2d_sptr const& p) const
00489 {
00490   const double x=p->x();
00491   const double y=p->y();
00492   return is_zero(a()*x*x+b()*x*y+c()*y*y+d()*x+e()*y+f());
00493 }
00494 
00495 
00496 
00497 
00498 
00499 vgl_homg_line_2d<double> *
00500 vsol_conic_2d::tangent_at_point(vsol_point_2d_sptr const& p) const
00501 {
00502   return new vgl_homg_line_2d<double>(
00503     vgl_conic<double>::tangent_at(vgl_homg_point_2d<double>(p->x(),p->y(),1.0)));
00504 }
00505 
00506 
00507 
00508 
00509 vcl_list<vsol_point_2d_sptr>
00510 vsol_conic_2d::intersection(vsol_line_2d const& l) const
00511 {
00512   vgl_homg_point_2d<double> p0(l.p0()->x(), l.p0()->y(), 1.0),
00513                             p1(l.p1()->x(), l.p1()->y(), 1.0);
00514   vgl_homg_line_2d<double> line(p0,p1);
00515   vcl_list<vgl_homg_point_2d<double> > vv =
00516     vgl_homg_operators_2d<double>::intersection(*this,line);
00517   vcl_list<vsol_point_2d_sptr> v;
00518   vcl_list<vgl_homg_point_2d<double> >::iterator it = vv.begin();
00519   for (; !(it == vv.end()); ++it) {
00520     if ((*it).w() != 0)  v.push_back(new vsol_point_2d((*it)));
00521   }
00522   return v;
00523 }
00524 
00525 
00526 
00527 
00528 vcl_list<vsol_point_2d_sptr>
00529 vsol_conic_2d::intersection(vsol_conic_2d const& c) const
00530 {
00531   vcl_list<vgl_homg_point_2d<double> > vv =
00532     vgl_homg_operators_2d<double>::intersection(*this,c);
00533   vcl_list<vsol_point_2d_sptr> v;
00534   vcl_list<vgl_homg_point_2d<double> >::iterator it = vv.begin();
00535   for (; !(it == vv.end()); ++it) {
00536     if ((*it).w() != 0)  v.push_back(new vsol_point_2d((*it)));
00537   }
00538   return v;
00539 }
00540 
00541 
00542 
00543 
00544 vsol_point_2d_sptr
00545 vsol_conic_2d::closest_point_on_curve(vsol_point_2d_sptr const& pt) const
00546 {
00547   
00548   if (this->in(pt))
00549     return pt;
00550   
00551   
00552   
00553   vcl_list<vsol_point_2d_sptr> candidates; 
00554   if (b()==0 && a()==c()) {
00555     
00556     candidates = intersection(vsol_line_2d(midpoint(),pt));
00557   }
00558   else {
00559     
00560     vsol_conic_2d conic(b()/2,
00561                         c()-a(),
00562                         -b()/2,
00563                         a()*pt->y()-b()/2*pt->x()+e()/2,
00564                         b()/2*pt->y()-c()*pt->x()-d()/2,
00565                         d()/2*pt->y()-e()/2*pt->x());
00566     
00567     candidates = conic.intersection(*this);
00568   }
00569   
00570   vsol_point_2d_sptr p = 0;
00571   double dist = 1e31; 
00572   vcl_list<vsol_point_2d_sptr>::iterator it = candidates.begin();
00573   for (; it != candidates.end(); ++it) {
00574     double d = (*it)->distance(pt);
00575     if (d < dist) { p = (*it); dist = d; }
00576   }
00577   return p;
00578 }
00579 
00580 
00581 
00582 
00583 double vsol_conic_2d::distance(vsol_point_2d_sptr const& pt) const
00584 {
00585   vsol_point_2d_sptr p = closest_point_on_curve(pt);
00586   return p->distance(pt);
00587 }
00588 
00589 
00590 
00591 
00592 vsol_line_2d_sptr vsol_conic_2d::axis() const
00593 {
00594   double cx, cy, phi, wd, ht;
00595   if (this->is_real_ellipse()) {
00596     this->ellipse_parameters(cx, cy, phi, wd, ht);
00597     vgl_vector_2d<double> v(vcl_cos(phi),vcl_sin(phi));
00598     return new vsol_line_2d(v,midpoint());
00599   }
00600   else if (this->is_hyperbola()) {
00601     this->hyperbola_parameters(cx, cy, phi, wd, ht);
00602     vgl_vector_2d<double> v(vcl_cos(phi),vcl_sin(phi));
00603     return new vsol_line_2d(v,midpoint());
00604   }
00605   else if (this->is_parabola()) {
00606     this->parabola_parameters(cx, cy, wd, ht);
00607     vgl_vector_2d<double> v(wd,ht);
00608     return new vsol_line_2d(v,new vsol_point_2d(cx,cy));
00609   }
00610   else return 0;
00611 }
00612 
00613 
00614 
00615 
00616 
00617 
00618 void vsol_conic_2d::b_write(vsl_b_ostream &os) const
00619 {
00620   vsl_b_write(os, version());
00621   vsl_b_write(os, static_cast<vgl_conic<double> >(*this));
00622   vsl_b_write(os, p0_);
00623   vsl_b_write(os, p1_);
00624 }
00625 
00626 
00627 void vsol_conic_2d::b_read(vsl_b_istream &is)
00628 {
00629   if (!is)
00630     return;
00631   short ver;
00632   vsl_b_read(is, ver);
00633   switch (ver)
00634   {
00635    default:
00636     assert(!"vsol_conic I/O version should be 1");
00637    case 1:
00638     vgl_conic<double> q;
00639     vsl_b_read(is, q);
00640     vsl_b_read(is, p0_);
00641     vsl_b_read(is, p1_);
00642     this->set(q.a(), q.b(), q.c(), q.d(), q.e(), q.f());
00643   }
00644 }
00645 
00646 
00647 short vsol_conic_2d::version() const
00648 {
00649   return 1;
00650 }
00651 
00652 
00653 void vsol_conic_2d::print_summary(vcl_ostream &os) const
00654 {
00655   os << *this;
00656 }
00657 
00658 
00659 
00660 
00661 void
00662 vsl_b_write(vsl_b_ostream &os, const vsol_conic_2d* c)
00663 {
00664   if (!c){
00665     vsl_b_write(os, false); 
00666   }
00667   else{
00668     vsl_b_write(os,true); 
00669     c->b_write(os);
00670   }
00671 }
00672 
00673 
00674 void
00675 vsl_b_read(vsl_b_istream &is, vsol_conic_2d* &c)
00676 {
00677   delete c;
00678   bool not_null_ptr;
00679   vsl_b_read(is, not_null_ptr);
00680   if (not_null_ptr) {
00681     c = new vsol_conic_2d();
00682     c->b_read(is);
00683   }
00684   else
00685     c = 0;
00686 }
00687