contrib/gel/vsol/vsol_conic_2d.cxx
Go to the documentation of this file.
00001 // This is gel/vsol/vsol_conic_2d.cxx
00002 #include "vsol_conic_2d.h"
00003 //:
00004 // \file
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> // for vcl_abs(double)
00015 #include <vcl_cassert.h>
00016 
00017 //---------------------------------------------------------------------------
00018 //: Are `x' and `y' almost equal ?
00019 //  The comparison uses an adaptive epsilon
00020 //---------------------------------------------------------------------------
00021 inline static bool are_equal(double x, double y)
00022 {
00023   // epsilon is a fixed fraction of the absolute average of x and y
00024   const double epsilon=1e-6*(vcl_abs(x)+vcl_abs(y));
00025   // <=epsilon but not <epsilon, to compare to null values
00026   return vcl_abs(x-y)<=epsilon;
00027 }
00028 
00029 //---------------------------------------------------------------------------
00030 //: Is `x' almost zero ?
00031 //  The comparison uses a fixed epsilon, as the adaptive one from
00032 //  are_equal() makes no sense here.
00033 //---------------------------------------------------------------------------
00034 inline static bool is_zero(double x) { return vcl_abs(x)<=1e-6; }
00035 
00036 //***************************************************************************
00037 // Initialization
00038 //***************************************************************************
00039 
00040 //---------------------------------------------------------------------------
00041 //: Ellipse/hyperbola constructor from centre, size and orientation.
00042 //  This constructor can only be used for non-degenerate, real ellipses and
00043 //  hyperbolas: if rx and ry have the same sign, an ellipse is defined
00044 //  (and any ellipse can uniquely be specified this way);
00045 //  rx is the length of one main axis, ry of the other axis.
00046 //  Hyperbolas are obtained if rx and ry have opposite sign; the positive
00047 //  one determines the distance from bots tops to the centre, and the other
00048 //  one specified the 'minor' axis length.
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 //: Set ellipse/hyperbola from centre, size and orientation.
00057 //  Can only be used for non-degenerate, real ellipses and
00058 //  hyperbolas: if rx and ry have the same sign, an ellipse is defined
00059 //  (and any ellipse can uniquely be specified this way);
00060 //  rx is the length of one main axis, ry of the other axis.
00061 //  Hyperbolas are obtained if rx and ry have opposite sign; the positive
00062 //  one determines the distance from bots tops to the centre, and the other
00063 //  one specified the 'minor' axis length.
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 //: Parabola constructor from direction, top and eccentricity parameter.
00073 //  This constructor can only be used for non-degenerate parabolas:
00074 //  specify the direction of the symmetry axis, the top, and an eccentricity
00075 //  parameter theta.
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 //: Set parabola from direction, top and eccentricity parameter.
00085 //  This can only be used for non-degenerate parabolas:
00086 //  specify the direction of the symmetry axis, the top, and an eccentricity
00087 //  parameter theta.
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 //: Clone `this': creation of a new object and initialization
00098 // See Prototype pattern
00099 //---------------------------------------------------------------------------
00100 vsol_spatial_object_2d* vsol_conic_2d::clone() const
00101 {
00102   return new vsol_conic_2d(*this);
00103 }
00104 
00105 //***************************************************************************
00106 // Comparison
00107 //***************************************************************************
00108 
00109 //---------------------------------------------------------------------------
00110 //: Has `this' the same coefficients and (geometrical) end points than `other'?
00111 //  The test anticipates that the conic may have null endpoints
00112 //---------------------------------------------------------------------------
00113 bool vsol_conic_2d::operator==(vsol_conic_2d const& other) const
00114 {
00115   if (this==&other)
00116     return true;
00117   // Delegate to both parent classes:
00118   bool conic_eq = vgl_conic<double>::operator==(other);
00119   // Check endpoints
00120   bool epts_eq = vsol_curve_2d::endpoints_equal(other);
00121   return conic_eq&&epts_eq;
00122 }
00123 
00124 //: spatial object equality
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 // Status report
00135 //***************************************************************************
00136 
00137 //---------------------------------------------------------------------------
00138 //: Find the real type of the conic from its coefficients
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; // 'degenerate' was is not a good name: some of the above are already degenerate!
00165 }
00166 
00167 //---------------------------------------------------------------------------
00168 //: Is `this' a real ellipse ?
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 //: Is `this' a real circle ?
00178 //---------------------------------------------------------------------------
00179 bool vsol_conic_2d::is_real_circle() const
00180 {
00181   return real_type()==real_circle;
00182 }
00183 
00184 //---------------------------------------------------------------------------
00185 //: Is `this' a complex ellipse ?
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 //: Is `this' a complex circle ?
00195 //---------------------------------------------------------------------------
00196 bool vsol_conic_2d::is_complex_circle() const
00197 {
00198   return real_type()==complex_circle;
00199 }
00200 
00201 //---------------------------------------------------------------------------
00202 //: Is `this' a parabola ?
00203 //---------------------------------------------------------------------------
00204 bool vsol_conic_2d::is_parabola() const
00205 {
00206   return real_type()==parabola;
00207 }
00208 
00209 //---------------------------------------------------------------------------
00210 //: Is `this' a hyperbola ?
00211 //---------------------------------------------------------------------------
00212 bool vsol_conic_2d::is_hyperbola() const
00213 {
00214   return real_type()==hyperbola;
00215 }
00216 
00217 //---------------------------------------------------------------------------
00218 //: Is `this' a pair of real intersecting lines ?
00219 //---------------------------------------------------------------------------
00220 bool vsol_conic_2d::is_real_intersecting_lines() const
00221 {
00222   return real_type()==real_intersecting_lines;
00223 }
00224 
00225 //---------------------------------------------------------------------------
00226 //: Is `this' a pair of complex intersecting lines ?
00227 //---------------------------------------------------------------------------
00228 bool vsol_conic_2d::is_complex_intersecting_lines() const
00229 {
00230   return real_type()==complex_intersecting_lines;
00231 }
00232 
00233 //---------------------------------------------------------------------------
00234 //: Is `this' a pair of coincident lines ?
00235 //---------------------------------------------------------------------------
00236 bool vsol_conic_2d::is_coincident_lines() const
00237 {
00238   return real_type()==coincident_lines;
00239 }
00240 
00241 //---------------------------------------------------------------------------
00242 //: Return 3 ellipse parameters: centre (`cx',`cy'), orientation `phi', size (`width',`height')
00243 // Require: is_real_ellipse()
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   // require
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)) // only for accuracy
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)) // avoid dividing by zero
00272     f0=1;
00273   const double a0=-a()/f0;
00274   const double b0=-b2/f0;
00275   const double c0=-c()/f0;
00276 
00277   // Now rotate the ellipse such that the main axis is horizontal.
00278   if (are_equal(a0,c0)&&is_zero(b0))
00279     phi=0; // circle
00280   else
00281     phi=vcl_atan2(-2*b0,c0-a0)/2; //ellipse
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 // Return the angular position given a point on the ellipse
00290 double vsol_conic_2d::ellipse_angular_position(vsol_point_2d_sptr const& pt) const
00291 {
00292   // require
00293   assert(is_real_ellipse());
00294 
00295   // Find the closest point to pt on the ellipse
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   // Extract the ellipse parameters
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   //In this shifted frame:
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 //: Return 3 hyperbola parameters: centre (`cx',`cy'), orientation `phi', size (`half-axis',`half-secondary-axis')
00317 // Require: is_hyperbola()
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   // require
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)) // this should not happen
00339     f0=1;
00340   const double a0=-a()/f0;
00341   const double b0=-b2/f0;
00342   const double c0=-c()/f0;
00343 
00344   // Now rotate the hyperbola such that the main axis is horizontal.
00345   if (is_zero(b0)) { // axis already horizontal or vertical
00346     if (a0 > 0) phi = 0;
00347     else        phi = vcl_atan2(0.0,1.0); // 90 degrees
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 //: Return 2 parabola parameters: top (`cx',`cy'), orientation (`cosphi',`sinphi')
00360 // Require: is_parabola()
00361 // \todo not yet fully implemented
00362 //---------------------------------------------------------------------------
00363 void vsol_conic_2d::parabola_parameters(double & /* cx */,
00364                                         double & /* cy */,
00365                                         double &cosphi,
00366                                         double &sinphi) const
00367 {
00368   // require
00369   assert(is_parabola());
00370 
00371   // Note that for a parabola B*B == 4*A*C, hence the quadratic part
00372   // of the equation is a square: (nX+mY)^2, with n=sqrt(A), m=sqrt(C)
00373   // Hence norm cannot be zero since the parabola is not degenerate:
00374   const double norm=a()+c();
00375   // The parabola direction is then (-m,n):
00376   cosphi=-vcl_sqrt(c()/norm);
00377   sinphi=vcl_sqrt(a()/norm);
00378   // Finally, the top can be found as the point with tangent direction
00379   // orthogonal to the direction of the axis:
00380   // TODO
00381   vcl_cerr << "vsol_conic_2d::parabola_parameters() not yet fully implemented\n";
00382 }
00383 
00384 //---------------------------------------------------------------------------
00385 //: Return the length of `this'.
00386 // Currently only implemented for ellipse segment
00387 // and accurate to 0.001 of the major axis length.  Alternatively provide
00388 // code for the incomplete elliptic integral of the second kind. However,
00389 // that would be numerical integration anyway.
00390 //---------------------------------------------------------------------------
00391 double vsol_conic_2d::length() const
00392 {
00393   assert(is_real_ellipse());
00394     // compute the angle at p0
00395   vsol_point_2d_sptr p0 = this->p0();
00396  double start_angle = this->ellipse_angular_position(p0);
00397 
00398   // compute the angle at p1
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   //sum the arc length on the ellipse boundary
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     //the incremental arc length
00415     double dl = vcl_sqrt(temp1*temp1 + temp2*temp2);
00416     sum += dl*dphi;
00417   }
00418   return sum;
00419 }
00420 
00421 //---------------------------------------------------------------------------
00422 //: Return the matrix associated with the coefficients.
00423 //---------------------------------------------------------------------------
00424 vnl_double_3x3 vsol_conic_2d::matrix() const
00425 {
00426   vnl_double_3x3 result;
00427 
00428   // row 0
00429   result.put(0,0,a());
00430   result.put(0,1,b()/2);
00431   result.put(0,2,d()/2);
00432   // row 1
00433   result.put(1,0,b()/2);
00434   result.put(1,1,c());
00435   result.put(1,2,e()/2);
00436   // row 2
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 // Status setting
00446 //***************************************************************************
00447 
00448 //---------------------------------------------------------------------------
00449 //: Set the first point of the curve
00450 // Require: in(new_p0)
00451 //---------------------------------------------------------------------------
00452 void vsol_conic_2d::set_p0(vsol_point_2d_sptr const& new_p0)
00453 {
00454   // require
00455   assert(in(new_p0));
00456 
00457   p0_=new_p0;
00458 }
00459 
00460 //---------------------------------------------------------------------------
00461 //: Set the last point of the curve
00462 // Require: in(new_p1)
00463 //---------------------------------------------------------------------------
00464 void vsol_conic_2d::set_p1(vsol_point_2d_sptr const& new_p1)
00465 {
00466   // require
00467   assert(in(new_p1));
00468 
00469   p1_=new_p1;
00470 }
00471 
00472 //***************************************************************************
00473 // Basic operations
00474 //***************************************************************************
00475 
00476 //---------------------------------------------------------------------------
00477 //: Return the centre or symmetry point of a central conic.
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 //: Is `p' in `this' ? (ie `p' verifies the equation, within some margin)
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 //: Return the tangent to the conic in the point p, if p is on the conic.
00497 //  In general, returns the polar line of the point w.r.t. the conic.
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 //: Return the set of (real) intersection points of this conic with a line
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 //: Return the set of (real) intersection points of two conics
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 //: Return the point on the conic boundary which is closest to the given point
00543 //---------------------------------------------------------------------------
00544 vsol_point_2d_sptr
00545 vsol_conic_2d::closest_point_on_curve(vsol_point_2d_sptr const& pt) const
00546 {
00547   //First check to see if the point is already on the conic boundary
00548   if (this->in(pt))
00549     return pt;
00550   // The nearest point must have a polar line which is orthogonal to its
00551   // connection line with the given point; all points with this property form
00552   // a certain conic  (actually a hyperbola) :
00553   vcl_list<vsol_point_2d_sptr> candidates; // all intersection points
00554   if (b()==0 && a()==c()) {
00555     // this ellipse is a circle ==> degenerate hyperbola (line + line at infinity)
00556     candidates = intersection(vsol_line_2d(midpoint(),pt));
00557   }
00558   else {
00559     // Non-degenerate hyperbola:
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     // Now it suffices to intersect the hyperbola with "this" ellipse:
00567     candidates = conic.intersection(*this);
00568   }
00569   // And find the intersection point closest to the given location:
00570   vsol_point_2d_sptr p = 0;
00571   double dist = 1e31; // infinity
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 //: Return the shortest distance of the point to the conic boundary
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 //: Return the main symmetry axis, if not degenerate.
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 // ================   Binary I/O Methods ========================
00615 //----------------------------------------------------------------
00616 
00617 //: Binary save self to stream.
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 //: Binary load self from stream (not typically used)
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 //: Return IO version number;
00647 short vsol_conic_2d::version() const
00648 {
00649   return 1;
00650 }
00651 
00652 //: Print an ascii summary to the stream
00653 void vsol_conic_2d::print_summary(vcl_ostream &os) const
00654 {
00655   os << *this;
00656 }
00657 
00658 //external functions
00659 
00660 //: Binary save vsol_conic_2d* to stream.
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); // Indicate null conic stored
00666   }
00667   else{
00668     vsl_b_write(os,true); // Indicate non-null conic stored
00669     c->b_write(os);
00670   }
00671 }
00672 
00673 //: Binary load vsol_conic_2d* from stream.
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