00001
00002 #ifndef vgl_conic_txx_
00003 #define vgl_conic_txx_
00004
00005
00006
00007
00008 #include "vgl_conic.h"
00009
00010 #include <vcl_cmath.h>
00011 #include <vcl_iostream.h>
00012 #include <vcl_compiler.h>
00013
00014 static const char *vgl_conic_name[] =
00015 {
00016 "invalid conic",
00017 "real ellipse",
00018 "real circle",
00019 "imaginary ellipse",
00020 "imaginary circle",
00021 "hyperbola",
00022 "parabola",
00023 "real intersecting lines",
00024 "complex intersecting lines",
00025 "real parallel lines",
00026 "complex parallel lines",
00027 "coincident lines"
00028 };
00029
00030
00031
00032
00033
00034 template <class T>
00035 vcl_string vgl_conic<T>::real_type() const { return vgl_conic_name[(int)type_]; }
00036
00037 template <class T>
00038 typename vgl_conic<T>::vgl_conic_type vgl_conic<T>::type_by_name(vcl_string const& name)
00039 {
00040 for (int i = (int)no_type; i < num_conic_types; i++)
00041 if (name == vgl_conic_name[i])
00042 return (typename vgl_conic<T>::vgl_conic_type)i;
00043 return no_type;
00044 }
00045
00046 template <class T>
00047 vcl_string vgl_conic<T>::type_by_number(typename vgl_conic<T>::vgl_conic_type type)
00048 {
00049 if (type <= 0 || type >= num_conic_types) return vgl_conic_name[no_type];
00050 return vgl_conic_name[type];
00051 }
00052
00053
00054
00055 template <class T>
00056 bool vgl_conic<T>::operator==(vgl_conic<T> const& that) const
00057 {
00058 if ( type() != that.type() ) return false;
00059 return a()*that.b() == b()*that.a()
00060 && a()*that.c() == c()*that.a()
00061 && a()*that.d() == d()*that.a()
00062 && a()*that.e() == e()*that.a()
00063 && a()*that.f() == f()*that.a()
00064 && b()*that.c() == c()*that.b()
00065 && b()*that.d() == d()*that.b()
00066 && b()*that.e() == e()*that.b()
00067 && b()*that.f() == f()*that.b()
00068 && c()*that.d() == d()*that.c()
00069 && c()*that.e() == e()*that.c()
00070 && c()*that.f() == f()*that.c()
00071 && d()*that.e() == e()*that.d()
00072 && d()*that.f() == f()*that.d()
00073 && e()*that.f() == f()*that.e();
00074 }
00075
00076
00077
00078 template <class T>
00079 void vgl_conic<T>::set(T ta, T tb, T tc, T td, T te, T tf)
00080 {
00081 a_ = ta; b_ = tb; c_ = tc; d_ = td; e_ = te; f_ = tf;
00082 set_type_from_equation();
00083 }
00084
00085
00086
00087 template <class T>
00088 vgl_conic<T>::vgl_conic(T const co[])
00089 : type_(no_type), a_(co[0]), b_(co[1]), c_(co[2]), d_(co[3]), e_(co[4]), f_(co[5])
00090 {
00091 set_type_from_equation();
00092 }
00093
00094
00095
00096 template <class T>
00097 vgl_conic<T>::vgl_conic(T ta, T tb, T tc, T td, T te, T tf)
00098 : type_(no_type), a_(ta), b_(tb), c_(tc), d_(td), e_(te), f_(tf)
00099 {
00100 set_type_from_equation();
00101 }
00102
00103
00104 template <class T>
00105 vgl_conic<T>::vgl_conic(vgl_homg_point_2d<T> const& co, T rx, T ry, T theta)
00106 {
00107 if (co.w() == 0) {
00108 a_ = co.y()*co.y();
00109 b_ = -2*co.x()*co.y();
00110 c_ = co.x()*co.x();
00111
00112
00113 theta /= vcl_sqrt(co.x()*co.x()+co.y()*co.y());
00114 d_ = -2*a_*rx - b_*ry + 2*theta*co.x();
00115 e_ = -2*c_*ry - b_*rx + 2*theta*co.y();
00116
00117 f_ = -a_*rx*rx-b_*rx*ry-c_*ry*ry-d_*rx-e_*ry;
00118 }
00119 else {
00120 rx = (rx < 0) ? (-rx*rx) : rx*rx;
00121 ry = (ry < 0) ? (-ry*ry) : ry*ry;
00122
00123 double ct = vcl_cos(-theta);
00124 double st = vcl_sin(-theta);
00125 T u = co.x();
00126 T v = co.y();
00127 a_ = T(rx*st*st + ry*ct*ct);
00128 b_ = T(2*(rx-ry)*ct*st);
00129 c_ = T(rx*ct*ct + ry*st*st);
00130 d_ = T(-2*(rx*st*st + ry*ct*ct)*u - 2*(rx-ry)*ct*st*v);
00131 e_ = T(-2*(rx-ry)*ct*st*u - 2*(rx*ct*ct + ry*st*st)*v);
00132 f_ = T((rx*st*st +ry*ct*ct)*u*u + 2*(rx-ry)*ct*st*u*v + (rx*ct*ct + ry*st*st)*v*v - rx*ry);
00133 }
00134 set_type_from_equation();
00135 }
00136
00137
00138
00139
00140
00141
00142 template <class T>
00143 void vgl_conic<T>::set_type_from_equation()
00144 {
00145 T A = a_, B = b_/2, C = c_, D = d_/2, E = e_/2, F = f_;
00146
00147
00148 T det = A*(C*F - E*E) - B*(B*F - D*E) + D*(B*E - C*D);
00149 T J = A*C - B*B;
00150 T K = (C*F - E*E) + (A*F - D*D);
00151 T I = A + C;
00152
00153 if (det != 0) {
00154 if (J > 0) {
00155 if (det*I < 0) {
00156 if (A==C && B==0) type_ = real_circle;
00157 else type_ = real_ellipse;
00158 }
00159 else {
00160 if (A==C && B==0) type_ = imaginary_circle;
00161 else type_ = imaginary_ellipse;
00162 }
00163 }
00164 else if (J < 0) type_ = hyperbola;
00165 else type_ = parabola;
00166 }
00167 else {
00168 if (J < 0) type_ = real_intersecting_lines;
00169 else if (J > 0) type_ = complex_intersecting_lines;
00170 else {
00171 if ( A == 0 && B == 0 && C == 0 ) {
00172 if ( D !=0 || E != 0 ) type_ = real_intersecting_lines;
00173 else if (F != 0) type_ = coincident_lines;
00174 else type_ = no_type;
00175 }
00176 else if (K < 0) type_ = real_parallel_lines;
00177 else if (K > 0) type_ = complex_parallel_lines;
00178 else type_ = coincident_lines;
00179 }
00180 }
00181 }
00182
00183 template <class T>
00184 bool vgl_conic<T>::contains(vgl_homg_point_2d<T> const& p) const
00185 {
00186 return p.x()*p.x()*a_+p.x()*p.y()*b_+p.y()*p.y()*c_+p.x()*p.w()*d_+p.y()*p.w()*e_+p.w()*p.w()*f_ == 0;
00187 }
00188
00189 template <class T>
00190 bool vgl_conic<T>::is_degenerate() const
00191 {
00192 T A = a_, B = b_/2, C = c_, D = d_/2, E = e_/2, F = f_;
00193 T det = A*(C*F - E*E) - B*(B*F - D*E) + D*(B*E - C*D);
00194 return det==0;
00195 }
00196
00197
00198
00199 template <class T>
00200 bool vgl_conic<T>::
00201 ellipse_geometry(double& xc, double& yc, double& major_axis_length,
00202 double& minor_axis_length, double& angle_in_radians) const
00203 {
00204 if (type_!=real_ellipse && type_ != real_circle)
00205 return false;
00206
00207
00208 double A = static_cast<double>(a_), B = static_cast<double>(b_)*0.5,
00209 C = static_cast<double>(c_), D = static_cast<double>(d_)*0.5,
00210 F = static_cast<double>(f_), E = static_cast<double>(e_)*0.5;
00211 if (A < 0)
00212 A=-A, B=-B, C=-C, D=-D, E=-E, F=-F;
00213
00214 double det = A*(C*F - E*E) - B*(B*F- D*E) + D*(B*E-C*D);
00215 double D2 = A*C - B*B;
00216 xc = (E*B - C*D)/D2;
00217 yc = (D*B - A*E)/D2;
00218
00219 double trace = A + C;
00220 double disc = vcl_sqrt(trace*trace - 4.0*D2);
00221 double cmaj = (trace+disc)*D2/(2*det); if (cmaj < 0) cmaj = -cmaj;
00222 double cmin = (trace-disc)*D2/(2*det); if (cmin < 0) cmin = -cmin;
00223 minor_axis_length = 1.0/vcl_sqrt(cmaj>cmin?cmaj:cmin);
00224 major_axis_length = 1.0/vcl_sqrt(cmaj>cmin?cmin:cmaj);
00225
00226
00227 angle_in_radians = -0.5 * vcl_atan2(2*B, C-A);
00228
00229
00230 return true;
00231 }
00232
00233
00234
00235
00236 template <class T>
00237 vcl_list<vgl_homg_line_2d<T> > vgl_conic<T>::components() const
00238 {
00239 if (!is_degenerate() ||
00240 type() == complex_intersecting_lines ||
00241 type() == complex_parallel_lines)
00242 return vcl_list<vgl_homg_line_2d<T> >();
00243
00244 T A = a_, B = b_/2, C = c_, D = d_/2, E = e_/2, F = f_;
00245
00246 if (type() == coincident_lines) {
00247
00248 vgl_homg_line_2d<T> l;
00249 if (A!=0 || B!=0 || D!=0)
00250 l = vgl_homg_line_2d<T>(A,B,D);
00251 else if (C!=0 || E!=0)
00252 l = vgl_homg_line_2d<T>(B,C,E);
00253 else
00254 l = vgl_homg_line_2d<T>(D,E,F);
00255 return vcl_list<vgl_homg_line_2d<T> >(2,l);
00256 }
00257
00258
00259 vgl_homg_point_2d<T> cntr = centre();
00260
00261 if (type() == real_parallel_lines)
00262 {
00263
00264
00265 if (A!=0 || D!=0) {
00266 vgl_homg_line_2d<T> l1(cntr, vgl_homg_point_2d<T>(-D+vcl_sqrt(D*D-A*F),0,A)),
00267 l2(cntr, vgl_homg_point_2d<T>(-D-vcl_sqrt(D*D-A*F),0,A));
00268 vcl_list<vgl_homg_line_2d<T> > v(1,l1); v.push_back(l2);
00269 return v;
00270 }
00271 else {
00272 vgl_homg_line_2d<T> l1(cntr, vgl_homg_point_2d<T>(0,-E+vcl_sqrt(E*E-C*F),C)),
00273 l2(cntr, vgl_homg_point_2d<T>(0,-E-vcl_sqrt(E*E-C*F),C));
00274 vcl_list<vgl_homg_line_2d<T> > v(1,l1); v.push_back(l2);
00275 return v;
00276 }
00277 }
00278
00279
00280 if (A==0 && B==0 && C==0) {
00281 vcl_list<vgl_homg_line_2d<T> > v(1,vgl_homg_line_2d<T>(0,0,1));
00282 v.push_back(vgl_homg_line_2d<T>(d_,e_,f_));
00283 return v;
00284 }
00285
00286
00287 if (A==0 && C==0) {
00288 vgl_homg_line_2d<T> l1(cntr, vgl_homg_point_2d<T>(0,1,0)),
00289 l2(cntr, vgl_homg_point_2d<T>(1,0,0));
00290 vcl_list<vgl_homg_line_2d<T> > v(1,l1); v.push_back(l2);
00291 return v;
00292 }
00293 else {
00294 vgl_homg_line_2d<T> l1(cntr, vgl_homg_point_2d<T>(-B+vcl_sqrt(B*B-A*C),A,0)),
00295 l2(cntr, vgl_homg_point_2d<T>(-B-vcl_sqrt(B*B-A*C),A,0));
00296 vcl_list<vgl_homg_line_2d<T> > v(1,l1); v.push_back(l2);
00297 return v;
00298 }
00299 }
00300
00301
00302
00303
00304 template <class T>
00305 bool vgl_conic<T>::is_central() const
00306 {
00307 return type_ == real_ellipse|| type_ == imaginary_ellipse|| type_ == hyperbola
00308 || type_ == real_circle || type_ == imaginary_circle
00309 || type_ == real_intersecting_lines|| type_ == complex_intersecting_lines;
00310 }
00311
00312
00313 template <class T>
00314 void vgl_conic<T>::translate_by(T x, T y)
00315 {
00316 d_ += 2*a_*x + b_*y;
00317 f_ += c_ * y*y - a_ * x*x + d_ * x + e_ * y;
00318 e_ += 2*c_*y + b_*x;
00319
00320 }
00321
00322 template <class T>
00323 vgl_conic<T> vgl_conic<T>::dual_conic() const
00324 {
00325 T A = a_, B = b_/2, C = c_, D = d_/2, E = e_/2, F = f_;
00326 return vgl_conic<T>(E*E-C*F, 2*(B*F-D*E), D*D-A*F, 2*(C*D-B*E), 2*(A*E-B*D), B*B-A*C);
00327 }
00328
00329
00330 template <class T>
00331 vgl_homg_line_2d<T> vgl_conic<T>::polar_line(vgl_homg_point_2d<T> const& p) const
00332 {
00333 return vgl_homg_line_2d<T> (p.x()*a_ +p.y()*b_/2+p.w()*d_/2,
00334 p.x()*b_/2+p.y()*c_ +p.w()*e_/2,
00335 p.x()*d_/2+p.y()*e_/2+p.w()*f_ );
00336 }
00337
00338
00339 template <class T>
00340 vgl_homg_point_2d<T> vgl_conic<T>::polar_point(vgl_homg_line_2d<T> const& l) const
00341 {
00342 if (!is_degenerate()) {
00343 vgl_conic<T> co = this->dual_conic();
00344 return vgl_homg_point_2d<T> (l.a()*co.a() +l.b()*co.b()/2+l.c()*co.d()/2,
00345 l.a()*co.b()/2+l.b()*co.c() +l.c()*co.e()/2,
00346 l.a()*co.d()/2+l.b()*co.e()/2+l.c()*co.f() );
00347 }
00348 else
00349 if (a_==0 && b_==0 && d_==0)
00350 return vgl_homg_point_2d<T>(1,0,0);
00351 else if (a_*c_*4==b_*b_ && a_*e_*2==b_*d_)
00352 return vgl_homg_point_2d<T>(b_*f_*2-e_*d_, d_*d_-a_*f_*4, a_*e_*2-b_*d_);
00353 else
00354 return vgl_homg_point_2d<T>(b_*e_-c_*d_*2, b_*d_-a_*e_*2, a_*c_*4-b_*b_);
00355 }
00356
00357
00358 template <class T>
00359 double vgl_conic<T>::curvature_at(vgl_point_2d<T> const& p) const
00360 {
00361
00362 const T &a_xx = a_;
00363 const T &a_xy = b_;
00364 const T &a_yy = c_;
00365 const T &a_xw = d_;
00366 const T &a_yw = e_;
00367
00368 const T x = p.x();
00369 const T y = p.y();
00370
00371 double f_x = 2*a_xx*x + a_xy*y + a_xw;
00372 double f_y = 2*a_yy*y + a_xy*x + a_yw;
00373 double f_xy = a_xy;
00374 double f_xx = 2*a_xx;
00375 double f_yy = 2*a_yy;
00376
00377 double f_x_2 = f_x*f_x;
00378 double f_y_2 = f_y*f_y;
00379 double denom = f_x_2 + f_y_2;
00380 denom = vcl_sqrt(denom*denom*denom);
00381
00382
00383 return (f_xx*f_y_2 - 2*f_x*f_y*f_xy + f_yy*f_x_2) / denom;
00384 }
00385
00386
00387
00388 template <class T>
00389 vcl_ostream& operator<<(vcl_ostream& s, vgl_conic<T> const& co)
00390 {
00391 s << "<vgl_conic ";
00392 if (co.a() == 1) s << "X^2";
00393 else if (co.a() == -1) s << "-X^2";
00394 else if (co.a() != 0) s << co.a() << "X^2";
00395 if (co.b() > 0) s << '+';
00396 if (co.b() == 1) s << "XY";
00397 else if (co.b() == -1) s << "-XY";
00398 else if (co.b() != 0) s << co.b() << "XY";
00399 if (co.c() > 0) s << '+';
00400 if (co.c() == 1) s << "Y^2";
00401 else if (co.c() == -1) s << "-Y^2";
00402 else if (co.c() != 0) s << co.c() << "Y^2";
00403 if (co.d() > 0) s << '+';
00404 if (co.d() == 1) s << "XW";
00405 else if (co.d() == -1) s << "-XW";
00406 else if (co.d() != 0) s << co.d() << "XW";
00407 if (co.e() > 0) s << '+';
00408 if (co.e() == 1) s << "YW";
00409 else if (co.e() == -1) s << "-YW";
00410 else if (co.e() != 0) s << co.e() << "YW";
00411 if (co.f() > 0) s << '+';
00412 if (co.f() == 1) s << "W^2";
00413 else if (co.f() == -1) s << "-W^2";
00414 else if (co.f() != 0) s << co.f() << "W^2";
00415 return s << "=0 " << co.real_type() << "> ";
00416 }
00417
00418
00419 template <class T>
00420 vcl_istream& operator>>(vcl_istream& is, vgl_conic<T>& co)
00421 {
00422 T ta, tb, tc, td, te, tf; is >> ta >> tb >> tc >> td >> te >> tf;
00423 co.set(ta,tb,tc,td,te,tf); return is;
00424 }
00425
00426 #undef VGL_CONIC_INSTANTIATE
00427 #define VGL_CONIC_INSTANTIATE(T) \
00428 template class vgl_conic<T >; \
00429 template vcl_ostream& operator<<(vcl_ostream&, const vgl_conic<T >&); \
00430 template vcl_istream& operator>>(vcl_istream&, vgl_conic<T >&)
00431
00432 #endif // vgl_conic_txx_
00433