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