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 void vsol_conic_2d::parabola_parameters(double & ,
00363 double & ,
00364 double &cosphi,
00365 double &sinphi) const
00366 {
00367
00368 assert(is_parabola());
00369
00370
00371
00372
00373 const double norm=a()+c();
00374
00375 cosphi=-vcl_sqrt(c()/norm);
00376 sinphi=vcl_sqrt(a()/norm);
00377
00378
00379
00380 vcl_cerr << "vsol_conic_2d::parabola_parameters() not yet fully implemented\n";
00381 }
00382
00383
00384
00385
00386
00387
00388
00389
00390 double vsol_conic_2d::length() const
00391 {
00392 assert(is_real_ellipse());
00393
00394 vsol_point_2d_sptr p0 = this->p0();
00395 double start_angle = this->ellipse_angular_position(p0);
00396
00397
00398 vsol_point_2d_sptr p1 = this->p1();
00399 double end_angle = this->ellipse_angular_position(p1);
00400 if (end_angle<=start_angle)
00401 end_angle += 2.0*vnl_math::pi;
00402
00403 double xc, yc, angle, major_axis, minor_axis;
00404 this->ellipse_parameters(xc, yc, angle, major_axis, minor_axis);
00405 double dphi = 0.001;
00406 double sum = 0.0;
00407
00408 for (double phi = start_angle; phi<=end_angle; phi+=dphi)
00409 {
00410 double temp1 =
00411 minor_axis*vcl_cos(angle)*vcl_cos(phi)+ major_axis*vcl_sin(angle)*vcl_sin(phi);
00412 double temp2 = major_axis*vcl_sin(angle+phi);
00413
00414 double dl = vcl_sqrt(temp1*temp1 + temp2*temp2);
00415 sum += dl*dphi;
00416 }
00417 return sum;
00418 }
00419
00420
00421
00422
00423 vnl_double_3x3 vsol_conic_2d::matrix() const
00424 {
00425 vnl_double_3x3 result;
00426
00427
00428 result.put(0,0,a());
00429 result.put(0,1,b()/2);
00430 result.put(0,2,d()/2);
00431
00432 result.put(1,0,b()/2);
00433 result.put(1,1,c());
00434 result.put(1,2,e()/2);
00435
00436 result.put(2,0,d()/2);
00437 result.put(2,1,e()/2);
00438 result.put(2,2,f());
00439
00440 return result;
00441 }
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451 void vsol_conic_2d::set_p0(vsol_point_2d_sptr const& new_p0)
00452 {
00453
00454 assert(in(new_p0));
00455
00456 p0_=new_p0;
00457 }
00458
00459
00460
00461
00462
00463 void vsol_conic_2d::set_p1(vsol_point_2d_sptr const& new_p1)
00464 {
00465
00466 assert(in(new_p1));
00467
00468 p1_=new_p1;
00469 }
00470
00471
00472
00473
00474
00475
00476
00477
00478 vsol_point_2d_sptr vsol_conic_2d::midpoint() const
00479 {
00480 vgl_homg_point_2d<double> p = this->centre();
00481 return new vsol_point_2d(p.x()/p.w(), p.y()/p.w());
00482 }
00483
00484
00485
00486
00487 bool vsol_conic_2d::in(vsol_point_2d_sptr const& p) const
00488 {
00489 const double x=p->x();
00490 const double y=p->y();
00491 return is_zero(a()*x*x+b()*x*y+c()*y*y+d()*x+e()*y+f());
00492 }
00493
00494
00495
00496
00497
00498 vgl_homg_line_2d<double> *
00499 vsol_conic_2d::tangent_at_point(vsol_point_2d_sptr const& p) const
00500 {
00501 return new vgl_homg_line_2d<double>(
00502 vgl_conic<double>::tangent_at(vgl_homg_point_2d<double>(p->x(),p->y(),1.0)));
00503 }
00504
00505
00506
00507
00508 vcl_list<vsol_point_2d_sptr>
00509 vsol_conic_2d::intersection(vsol_line_2d const& l) const
00510 {
00511 vgl_homg_point_2d<double> p0(l.p0()->x(), l.p0()->y(), 1.0),
00512 p1(l.p1()->x(), l.p1()->y(), 1.0);
00513 vgl_homg_line_2d<double> line(p0,p1);
00514 vcl_list<vgl_homg_point_2d<double> > vv =
00515 vgl_homg_operators_2d<double>::intersection(*this,line);
00516 vcl_list<vsol_point_2d_sptr> v;
00517 vcl_list<vgl_homg_point_2d<double> >::iterator it = vv.begin();
00518 for (; !(it == vv.end()); ++it) {
00519 if ((*it).w() != 0) v.push_back(new vsol_point_2d((*it)));
00520 }
00521 return v;
00522 }
00523
00524
00525
00526
00527 vcl_list<vsol_point_2d_sptr>
00528 vsol_conic_2d::intersection(vsol_conic_2d const& c) const
00529 {
00530 vcl_list<vgl_homg_point_2d<double> > vv =
00531 vgl_homg_operators_2d<double>::intersection(*this,c);
00532 vcl_list<vsol_point_2d_sptr> v;
00533 vcl_list<vgl_homg_point_2d<double> >::iterator it = vv.begin();
00534 for (; !(it == vv.end()); ++it) {
00535 if ((*it).w() != 0) v.push_back(new vsol_point_2d((*it)));
00536 }
00537 return v;
00538 }
00539
00540
00541
00542
00543 vsol_point_2d_sptr
00544 vsol_conic_2d::closest_point_on_curve(vsol_point_2d_sptr const& pt) const
00545 {
00546
00547 if (this->in(pt))
00548 return pt;
00549
00550
00551
00552 vcl_list<vsol_point_2d_sptr> candidates;
00553 if (b()==0 && a()==c()) {
00554
00555 candidates = intersection(vsol_line_2d(midpoint(),pt));
00556 } else {
00557
00558 vsol_conic_2d conic(b()/2,
00559 c()-a(),
00560 -b()/2,
00561 a()*pt->y()-b()/2*pt->x()+e()/2,
00562 b()/2*pt->y()-c()*pt->x()-d()/2,
00563 d()/2*pt->y()-e()/2*pt->x());
00564
00565 candidates = conic.intersection(*this);
00566 }
00567
00568 vsol_point_2d_sptr p = 0;
00569 double dist = 1e31;
00570 vcl_list<vsol_point_2d_sptr>::iterator it = candidates.begin();
00571 for (; it != candidates.end(); ++it) {
00572 double d = (*it)->distance(pt);
00573 if (d < dist) { p = (*it); dist = d; }
00574 }
00575 return p;
00576 }
00577
00578
00579
00580
00581 double vsol_conic_2d::distance(vsol_point_2d_sptr const& pt) const
00582 {
00583 vsol_point_2d_sptr p = closest_point_on_curve(pt);
00584 return p->distance(pt);
00585 }
00586
00587
00588
00589
00590 vsol_line_2d_sptr vsol_conic_2d::axis() const
00591 {
00592 double cx, cy, phi, wd, ht;
00593 if (this->is_real_ellipse()) {
00594 this->ellipse_parameters(cx, cy, phi, wd, ht);
00595 vgl_vector_2d<double> v(vcl_cos(phi),vcl_sin(phi));
00596 return new vsol_line_2d(v,midpoint());
00597 }
00598 else if (this->is_hyperbola()) {
00599 this->hyperbola_parameters(cx, cy, phi, wd, ht);
00600 vgl_vector_2d<double> v(vcl_cos(phi),vcl_sin(phi));
00601 return new vsol_line_2d(v,midpoint());
00602 }
00603 else if (this->is_parabola()) {
00604 this->parabola_parameters(cx, cy, wd, ht);
00605 vgl_vector_2d<double> v(wd,ht);
00606 return new vsol_line_2d(v,new vsol_point_2d(cx,cy));
00607 }
00608 else return 0;
00609 }
00610
00611
00612
00613
00614
00615
00616 void vsol_conic_2d::b_write(vsl_b_ostream &os) const
00617 {
00618 vsl_b_write(os, version());
00619 vsl_b_write(os, static_cast<vgl_conic<double> >(*this));
00620 vsl_b_write(os, p0_);
00621 vsl_b_write(os, p1_);
00622 }
00623
00624
00625 void vsol_conic_2d::b_read(vsl_b_istream &is)
00626 {
00627 if (!is)
00628 return;
00629 short ver;
00630 vsl_b_read(is, ver);
00631 switch (ver)
00632 {
00633 default:
00634 assert(!"vsol_conic I/O version should be 1");
00635 case 1:
00636 vgl_conic<double> q;
00637 vsl_b_read(is, q);
00638 vsl_b_read(is, p0_);
00639 vsl_b_read(is, p1_);
00640 this->set(q.a(), q.b(), q.c(), q.d(), q.e(), q.f());
00641 }
00642 }
00643
00644
00645 short vsol_conic_2d::version() const
00646 {
00647 return 1;
00648 }
00649
00650
00651 void vsol_conic_2d::print_summary(vcl_ostream &os) const
00652 {
00653 os << *this;
00654 }
00655
00656
00657
00658
00659 void
00660 vsl_b_write(vsl_b_ostream &os, const vsol_conic_2d* c)
00661 {
00662 if (!c){
00663 vsl_b_write(os, false);
00664 }
00665 else{
00666 vsl_b_write(os,true);
00667 c->b_write(os);
00668 }
00669 }
00670
00671
00672 void
00673 vsl_b_read(vsl_b_istream &is, vsol_conic_2d* &c)
00674 {
00675 delete c;
00676 bool not_null_ptr;
00677 vsl_b_read(is, not_null_ptr);
00678 if (not_null_ptr) {
00679 c = new vsol_conic_2d();
00680 c->b_read(is);
00681 }
00682 else
00683 c = 0;
00684 }
00685