00001
00002 #ifndef vgl_homg_operators_2d_txx_
00003 #define vgl_homg_operators_2d_txx_
00004
00005
00006
00007 #include "vgl_homg_operators_2d.h"
00008
00009 #include <vcl_iostream.h>
00010 #include <vcl_limits.h>
00011 #include <vcl_cassert.h>
00012 #include <vcl_cmath.h>
00013 #include <vgl/vgl_homg_line_2d.h>
00014 #include <vgl/vgl_homg_point_2d.h>
00015 #include <vgl/vgl_point_2d.h>
00016 #include <vgl/vgl_conic.h>
00017 #include <vgl/vgl_box_2d.h>
00018 #include <vgl/vgl_homg.h>
00019
00020 #include <vnl/vnl_vector_fixed.h>
00021 #include <vnl/vnl_matrix.h>
00022 #include <vnl/vnl_matrix_fixed.h>
00023 #include <vnl/vnl_math.h>
00024 #include <vnl/algo/vnl_scatter_3x3.h>
00025 #include <vnl/algo/vnl_real_eigensystem.h>
00026 #include <vnl/vnl_diag_matrix.h>
00027
00028
00029
00030 template <class T>
00031 inline static vgl_homg_line_2d<T> cross(const vgl_homg_point_2d<T>& p1,
00032 const vgl_homg_point_2d<T>& p2)
00033 {
00034 return vgl_homg_line_2d<T> (p1.y() * p2.w() - p1.w() * p2.y(),
00035 p1.w() * p2.x() - p1.x() * p2.w(),
00036 p1.x() * p2.y() - p1.y() * p2.x());
00037 }
00038
00039 template <class T>
00040 inline static vgl_homg_point_2d<T> cross(const vgl_homg_line_2d<T>& l1,
00041 const vgl_homg_line_2d<T>& l2)
00042 {
00043 return vgl_homg_point_2d<T> (l1.b() * l2.c() - l1.c() * l2.b(),
00044 l1.c() * l2.a() - l1.a() * l2.c(),
00045 l1.a() * l2.b() - l1.b() * l2.a());
00046 }
00047
00048 template <class T>
00049 inline static T dot(vgl_homg_line_2d<T> const& l,
00050 vgl_homg_point_2d<T> const& p)
00051 {
00052 return l.a()*p.x() + l.b()*p.y() + l.c()*p.w();
00053 }
00054
00055
00056
00057 template <class T>
00058 vnl_vector_fixed<T,3> vgl_homg_operators_2d<T>::get_vector(vgl_homg_point_2d<T> const& p)
00059 {
00060 return vnl_vector_fixed<T,3>(p.x(),p.y(),p.w());
00061 }
00062
00063 template <class T>
00064 vnl_vector_fixed<T,3> vgl_homg_operators_2d<T>::get_vector(vgl_homg_line_2d<T> const& l)
00065 {
00066 return vnl_vector_fixed<T,3>(l.a(),l.b(),l.c());
00067 }
00068
00069 template <class T>
00070 vnl_vector_fixed<T,6> vgl_homg_operators_2d<T>::get_vector(vgl_conic<T> const& c)
00071 {
00072 vnl_vector_fixed<T,6> v;
00073 v.put(0,c.a());
00074 v.put(1,c.b());
00075 v.put(2,c.c());
00076 v.put(3,c.d());
00077 v.put(4,c.e());
00078 v.put(5,c.f());
00079
00080 return v;
00081 }
00082
00083
00084
00085 template <class T>
00086 void vgl_homg_operators_2d<T>::unitize(vgl_homg_point_2d<T>& a)
00087 {
00088 double norm = vcl_sqrt (a.x()*a.x() + a.y()*a.y() + a.w()*a.w());
00089
00090 if (norm == 0.0) {
00091 vcl_cerr << "vgl_homg_operators_2d<T>::unitize() -- Zero length vector\n";
00092 return;
00093 }
00094 norm = 1.0/norm;
00095 a.set(T(a.x()*norm), T(a.y()*norm), T(a.w()*norm));
00096 }
00097
00098
00099
00100 template <class T>
00101 T
00102 vgl_homg_operators_2d<T>::distance(const vgl_homg_point_2d<T>& point1,
00103 const vgl_homg_point_2d<T>& point2)
00104 {
00105 return vcl_sqrt(vgl_homg_operators_2d<T>::distance_squared(point1,point2));
00106 }
00107
00108 template <class T>
00109 T
00110 vgl_homg_operators_2d<T>::distance_squared(const vgl_homg_point_2d<T>& p1,
00111 const vgl_homg_point_2d<T>& p2)
00112 {
00113 if (p1 == p2) return T(0);
00114
00115 if (p1.w() == 0 || p2.w() == 0) {
00116 vcl_cerr << "vgl_homg_operators_2d<T>::distance_squared() -- point at infinity\n";
00117 return vcl_numeric_limits<T>::infinity();
00118 }
00119
00120 return vnl_math_sqr (p1.x() / p1.w() - p2.x() / p2.w()) +
00121 vnl_math_sqr (p1.y() / p1.w() - p2.y() / p2.w());
00122 }
00123
00124
00125
00126
00127
00128
00129
00130 template <class T>
00131 T
00132 vgl_homg_operators_2d<T>::perp_dist_squared(const vgl_homg_point_2d<T>& point,
00133 const vgl_homg_line_2d<T>& line)
00134 {
00135 if ((line.a()==0 && line.b()== 0) || point.w()==0) {
00136 vcl_cerr << "vgl_homg_operators_2d<T>::perp_dist_squared() -- line or point at infinity\n";
00137 return vgl_homg<T>::infinity;
00138 }
00139
00140 T numerator = vnl_math_sqr (dot(line,point) / point.w());
00141 if (numerator == 0) return T(0);
00142 T denominator = line.a()*line.a() + line.b()*line.b();
00143
00144 return numerator / denominator;
00145 }
00146
00147
00148
00149
00150
00151
00152 template <class T>
00153 double
00154 vgl_homg_operators_2d<T>::line_angle(const vgl_homg_line_2d<T>& line)
00155 {
00156 return vcl_atan2 (line.b(), line.a());
00157 }
00158
00159
00160
00161 template <class T>
00162 double
00163 vgl_homg_operators_2d<T>::abs_angle(const vgl_homg_line_2d<T>& line1,
00164 const vgl_homg_line_2d<T>& line2)
00165 {
00166 double angle1 = line_angle(line1);
00167 double angle2 = line_angle(line2);
00168
00169 double diff = angle2 - angle1;
00170 if (diff > vnl_math::pi_over_2) diff -= vnl_math::pi;
00171 if (diff < -vnl_math::pi_over_2) diff += vnl_math::pi;
00172
00173 return vcl_fabs(diff);
00174 }
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184 template <class T>
00185 double
00186 vgl_homg_operators_2d<T>::angle_between_oriented_lines(const vgl_homg_line_2d<T>& line1,
00187 const vgl_homg_line_2d<T>& line2)
00188 {
00189 return vcl_fmod(line_angle(line2)-line_angle(line1), 2*vnl_math::pi);
00190 }
00191
00192
00193
00194
00195
00196
00197
00198
00199 template <class T>
00200 vgl_homg_line_2d<T>
00201 vgl_homg_operators_2d<T>::join(const vgl_homg_point_2d<T>& p1,
00202 const vgl_homg_point_2d<T>& p2)
00203 {
00204 return cross(p1,p2);
00205 }
00206
00207
00208
00209
00210
00211
00212 template <class T>
00213 vgl_homg_line_2d<T>
00214 vgl_homg_operators_2d<T>::join_oriented(const vgl_homg_point_2d<T>&p1,
00215 const vgl_homg_point_2d<T>&p2)
00216 {
00217 int s1 = p1.w() < 0;
00218 int s2 = p2.w() < 0;
00219
00220 if (s1 ^ s2)
00221 return cross(p2,p1);
00222 else
00223 return cross(p1,p2);
00224 }
00225
00226
00227
00228
00229 template <class T>
00230 vgl_homg_point_2d<T>
00231 vgl_homg_operators_2d<T>::intersection(const vgl_homg_line_2d<T>& l1,
00232 const vgl_homg_line_2d<T>& l2)
00233 {
00234 return cross(l1,l2);
00235 }
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245 template <class T>
00246 vgl_homg_line_2d<T>
00247 vgl_homg_operators_2d<T>::perp_line_through_point(const vgl_homg_line_2d<T>& l,
00248 const vgl_homg_point_2d<T>& p)
00249 {
00250 vgl_homg_point_2d<T> d(l.a(), l.b(), 0);
00251 return cross(d, p);
00252 }
00253
00254
00255
00256
00257 template <class T>
00258 vgl_homg_point_2d<T>
00259 vgl_homg_operators_2d<T>::perp_projection(const vgl_homg_line_2d<T>& line,
00260 const vgl_homg_point_2d<T>& point)
00261 {
00262 vgl_homg_line_2d<T> perpline = perp_line_through_point (line, point);
00263 vgl_homg_point_2d<T> answer = cross(line, perpline);
00264 return answer;
00265 }
00266
00267
00268
00269
00270 template <class T>
00271 vgl_homg_point_2d<T>
00272 vgl_homg_operators_2d<T>::midpoint(const vgl_homg_point_2d<T>& p1,
00273 const vgl_homg_point_2d<T>& p2)
00274 {
00275 T x = p1.x() * p2.w() + p2.x() * p1.w();
00276 T y = p1.y() * p2.w() + p2.y() * p1.w();
00277 T w = p1.w() * p2.w() + p2.w() * p1.w();
00278
00279 return vgl_homg_point_2d<T>(x,y,w);
00280 }
00281
00282
00283
00284
00285 template <class T>
00286 vnl_vector_fixed<T,3>
00287 vgl_homg_operators_2d<T>::most_orthogonal_vector(const vcl_vector<vgl_homg_line_2d<T> >& inpoints)
00288 {
00289 vnl_scatter_3x3<T> scatter_matrix;
00290
00291 for (typename vcl_vector<vgl_homg_line_2d<T> >::const_iterator i = inpoints.begin();
00292 i != inpoints.end(); ++i)
00293 scatter_matrix.add_outer_product(get_vector(*i));
00294
00295 return scatter_matrix.minimum_eigenvector();
00296 }
00297
00298 #include <vnl/algo/vnl_svd.h>
00299
00300 template <class T>
00301 vnl_vector_fixed<T,3>
00302 vgl_homg_operators_2d<T>::most_orthogonal_vector_svd(const vcl_vector<vgl_homg_line_2d<T> >& lines)
00303 {
00304 vnl_matrix<T> D(lines.size(), 3);
00305
00306 typename vcl_vector<vgl_homg_line_2d<T> >::const_iterator i = lines.begin();
00307 for (unsigned j = 0; i != lines.end(); ++i,++j)
00308 D.set_row(j, get_vector(*i).as_ref());
00309
00310 vnl_svd<T> svd(D);
00311 #ifdef DEBUG
00312 vcl_cout << "[movrank " << svd.W() << ']';
00313 #endif
00314
00315 return svd.nullvector();
00316 }
00317
00318
00319
00320
00321
00322
00323
00324 template <class T>
00325 vgl_homg_point_2d<T>
00326 vgl_homg_operators_2d<T>::lines_to_point(const vcl_vector<vgl_homg_line_2d<T> >& lines)
00327 {
00328
00329 assert(lines.size() >= 2);
00330
00331 #ifdef VGL_HOMG_OPERATORS_2D_LINES_TO_POINT_USE_SVD
00332 vnl_vector_fixed<T,3> mov = most_orthogonal_vector_svd(lines);
00333 #else
00334 vnl_vector_fixed<T,3> mov = most_orthogonal_vector(lines);
00335 #endif
00336 return vgl_homg_point_2d<T>(mov[0], mov[1], mov[2]);
00337 }
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360 template <class T>
00361 double vgl_homg_operators_2d<T>::cross_ratio(const vgl_homg_point_2d<T>& a,
00362 const vgl_homg_point_2d<T>& b,
00363 const vgl_homg_point_2d<T>& c,
00364 const vgl_homg_point_2d<T>& d)
00365 {
00366 double x1 = a.x(), y1 = a.y(), w1 = a.w();
00367 double x2 = b.x(), y2 = b.y(), w2 = b.w();
00368 double x3 = c.x(), y3 = c.y(), w3 = c.w();
00369 double x4 = d.x(), y4 = d.y(), w4 = d.w();
00370 double x = x1 - x2; if (x<0) x = -x;
00371 double y = y1 - y2; if (y<0) y = -y;
00372 double n = (x>y) ? (x1*w3-x3*w1)*(x2*w4-x4*w2) : (y1*w3-y3*w1)*(y2*w4-y4*w2);
00373 double m = (x>y) ? (x1*w4-x4*w1)*(x2*w3-x3*w2) : (y1*w4-y4*w1)*(y2*w3-y3*w2);
00374 if (n == 0 && m == 0)
00375 vcl_cerr << "cross ratio not defined: three of the given points coincide\n";
00376 return n/m;
00377 }
00378
00379
00380
00381
00382 template <class T>
00383 vgl_homg_point_2d<T>
00384 vgl_homg_operators_2d<T>::conjugate(const vgl_homg_point_2d<T>& a,
00385 const vgl_homg_point_2d<T>& b,
00386 const vgl_homg_point_2d<T>& c,
00387 double cr)
00388
00389 {
00390 T x1 = a.x(), y1 = a.y(), w1 = a.w();
00391 T x2 = b.x(), y2 = b.y(), w2 = b.w();
00392 T x3 = c.x(), y3 = c.y(), w3 = c.w();
00393 T kx = x1*w3 - x3*w1, mx = x2*w3 - x3*w2, nx = T(kx*w2-cr*mx*w1);
00394 T ky = y1*w3 - y3*w1, my = y2*w3 - y3*w2, ny = T(ky*w2-cr*my*w1);
00395 return vgl_homg_point_2d<T>(T(x2*kx-cr*x1*mx)*ny,T(y2*ky-cr*y1*my)*nx,nx*ny);
00396 }
00397
00398
00399
00400
00401
00402
00403
00404 template <class T>
00405 vgl_conic<T>
00406 vgl_homg_operators_2d<T>::vgl_conic_from_matrix(vnl_matrix_fixed<T,3,3> const& mat)
00407 {
00408 return vgl_conic<T>(mat[0][0], mat[1][0]+mat[0][1], mat[1][1], mat[0][2]+mat[2][0], mat[1][2]+mat[2][1], mat[2][2]);
00409 }
00410
00411
00412
00413
00414
00415
00416
00417
00418 template <class T>
00419 vnl_matrix_fixed<T,3,3>
00420 vgl_homg_operators_2d<T>::matrix_from_conic(vgl_conic<T> const& c)
00421 {
00422 vnl_matrix_fixed<T,3,3> mat;
00423 T A = c.a(), B = c.b()/2, C = c.c(), D = c.d()/2, E = c.e()/2, F = c.f();
00424
00425 mat[0][0] = A; mat[0][1] = B; mat[0][2] = D;
00426 mat[1][0] = B; mat[1][1] = C; mat[1][2] = E;
00427 mat[2][0] = D; mat[2][1] = E; mat[2][2] = F;
00428
00429 return mat;
00430 }
00431
00432
00433
00434
00435
00436
00437 template <class T>
00438 vnl_matrix_fixed<T,3,3>
00439 vgl_homg_operators_2d<T>::matrix_from_dual_conic(vgl_conic<T> const& c)
00440 {
00441 vnl_matrix_fixed<T,3,3> mat;
00442 T A = c.a(), B = c.b()/2, C = c.c(), D = c.d()/2, E = c.e()/2, F = c.f();
00443
00444 mat[0][0] = C*F-E*E; mat[0][1] = E*D-B*F; mat[0][2] = B*E-C*D;
00445 mat[1][0] = E*D-B*F; mat[1][1] = A*F-D*D; mat[1][2] = B*D-A*E;
00446 mat[2][0] = B*E-C*D; mat[2][1] = B*D-A*E; mat[2][2] = A*C-B*B;
00447
00448 return mat;
00449 }
00450
00451
00452
00453 template <class T>
00454 vcl_list<vgl_homg_point_2d<T> >
00455 vgl_homg_operators_2d<T>::do_intersect(vgl_conic<T> const& c1,
00456 vgl_conic<T> const& c2)
00457 {
00458 if (c1==c2)
00459 {
00460 vcl_cerr << __FILE__
00461 << "Warning: the intersection of two identical conics is not a finite set of points.\n"
00462 << "Returning an empty list.\n";
00463 return vcl_list<vgl_homg_point_2d<T> >();
00464 }
00465 T A=c1.a(),B=c1.b(),C=c1.c(),D=c1.d(),E=c1.e(),F=c1.f();
00466 T a=c2.a(),b=c2.b(),c=c2.c(),d=c2.d(),e=c2.e(),f=c2.f();
00467
00468 T ab=a*B-A*b, ac=a*C-A*c, ad=a*D-A*d, ae=a*E-A*e, af=a*F-A*f, BD=b*D+B*d;
00469
00470
00471
00472
00473 if (ab==0 && ac==0)
00474 return intersection(c1,vgl_conic<T>(0,0,0,ad,ae,af));
00475
00476
00477
00478 if (ab==0 && ad==0)
00479 return intersection(c1,vgl_conic<T>(0,0,ac,0,ae,af));
00480
00481
00482 if (ab==0 && ae==0)
00483 return intersection(c1,vgl_conic<T>(0,0,ac,ad,0,af));
00484
00485 vnl_vector_fixed<T,5> coef;
00486 coef(0) = ac*ac-ab*(b*C-B*c);
00487 coef(1) = 2*ac*ae-ab*(b*E-B*e)-BD*(a*C+A*c)+2*A*b*C*d+2*a*B*c*D;
00488 coef(2) = ae*ae-ab*(b*F-B*f)+ad*(c*D-C*d)-BD*(a*E+A*e)+2*a*B*e*D+2*A*b*E*d+2*ac*af;
00489 coef(3) = 2*ae*af-ad*(d*E-D*e)-BD*(a*F+A*f)+2*A*b*d*F+2*a*B*D*f;
00490 coef(4) = af*af-ad*(d*F-D*f);
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501 if (coef(0) == 0 && coef(1) == 0) {
00502 if (coef(2) == 0 && coef(3) == 0) return vcl_list<vgl_homg_point_2d<T> >();
00503 T dis = coef(3)*coef(3)-4*coef(2)*coef(4);
00504 if (dis < 0) return vcl_list<vgl_homg_point_2d<T> >();
00505 T y;
00506 if (coef(2) == 0) dis=0, y = - coef(4) / coef(3);
00507 else y = - coef(3) / coef(2) / 2;
00508 T w = y*ab+ad;
00509 T x = -(y*y*ac+y*ae+af);
00510 if (x == 0 && w == 0) x = w = 1;
00511 if (dis == 0) {return vcl_list<vgl_homg_point_2d<T> >(2,vgl_homg_point_2d<T>(x,y*w,w));}
00512 dis = vcl_sqrt(dis) / coef(2) / 2;
00513 vcl_list<vgl_homg_point_2d<T> > solutions;
00514 y -= dis; w = y*ab+ad; x = -(y*y*ac+y*ae+af);
00515 if (x == 0 && w == 0) x = w = 1;
00516 solutions.push_back(vgl_homg_point_2d<T>(x,y*w,w));
00517 y += 2*dis; w = y*ab+ad; x = -(y*y*ac+y*ae+af);
00518 if (x == 0 && w == 0) x = w = 1;
00519 solutions.push_back(vgl_homg_point_2d<T>(x,y*w,w));
00520 return solutions;
00521 }
00522 if (coef(0) == 0) {
00523 coef /= -coef(1);
00524 double data[]={coef(2),coef(3),coef(4), 1,0,0, 0,1,0};
00525 vnl_matrix<double> M(data,3,3);
00526 vnl_real_eigensystem eig(M);
00527 vnl_diag_matrix<vcl_complex<double> > polysolutions = eig.D;
00528 vcl_list<vgl_homg_point_2d<T> > solutions;
00529 for (int i=0;i<3;i++)
00530 if (vcl_abs(vcl_imag(polysolutions(i))) < 1e-3) {
00531 T y = (T)vcl_real(polysolutions(i));
00532 T w = y*ab+ad;
00533 T x = -(y*y*ac+y*ae+af);
00534 if (x == 0 && w == 0) x = w = 1;
00535 solutions.push_back(vgl_homg_point_2d<T>(x,y*w,w));
00536 }
00537 return solutions;
00538 }
00539
00540 coef /= -coef(0);
00541 double data[]={coef(1),coef(2),coef(3),coef(4), 1,0,0,0, 0,1,0,0, 0,0,1,0};
00542 vnl_matrix<double> M(data,4,4);
00543 vnl_real_eigensystem eig(M);
00544
00545 vnl_diag_matrix<vcl_complex<double> > polysolutions = eig.D;
00546
00547
00548
00549
00550 vcl_list<vgl_homg_point_2d<T> > solutions;
00551
00552 for (int i=0;i<4;i++)
00553 if (vcl_abs(vcl_imag(polysolutions(i))) < 1e-7) {
00554 T y = (T)vcl_real(polysolutions(i));
00555 T w = y*ab+ad;
00556 T x = -(y*y*ac+y*ae+af);
00557 if (x == 0 && w == 0) x = w = 1;
00558 solutions.push_back(vgl_homg_point_2d<T>(x,y*w,w));
00559 }
00560 return solutions;
00561 }
00562
00563
00564
00565 template <class T>
00566 vcl_list<vgl_homg_point_2d<T> >
00567 vgl_homg_operators_2d<T>::do_intersect(vgl_conic<T> const& q,
00568 vgl_homg_line_2d<T> const& l)
00569 {
00570 T A=q.a(), B=q.b(), C=q.c(), D=q.d(), E=q.e(), F=q.f();
00571 T a=l.a(), b=l.b(), c=l.c();
00572
00573 if (a==0 && b==0) {
00574 if (A==0)
00575 return vcl_list<vgl_homg_point_2d<T> >(2,vgl_homg_point_2d<T>(1,0,0));
00576 T d = B*B-4*A*C;
00577 if (d < 0) return vcl_list<vgl_homg_point_2d<T> >();
00578 if (d == 0)
00579 return vcl_list<vgl_homg_point_2d<T> >(2,vgl_homg_point_2d<T>(-B,2*A,0));
00580 d = vcl_sqrt(d);
00581 vcl_list<vgl_homg_point_2d<T> > v(1, vgl_homg_point_2d<T>(-B+d, 2*A, 0));
00582 v.push_back(vgl_homg_point_2d<T>(-B-d, 2*A, 0));
00583 return v;
00584 }
00585 if (a==0) {
00586 T y = -c/b; B = B*y+D;
00587 T d = B*B-4*A*(C*y*y+E*y+F);
00588 if (d < 0) return vcl_list<vgl_homg_point_2d<T> >();
00589 if (d == 0 && A == 0)
00590 return vcl_list<vgl_homg_point_2d<T> >(2,vgl_homg_point_2d<T>(1,0,0));
00591 if (d == 0)
00592 return vcl_list<vgl_homg_point_2d<T> >(2,vgl_homg_point_2d<T>(-B,y*2*A,2*A));
00593 if (A == 0) {
00594 vcl_list<vgl_homg_point_2d<T> > v(1, vgl_homg_point_2d<T>(1,0,0));
00595 v.push_back(vgl_homg_point_2d<T>(C*y*y+E*y+F, -y*B, -B));
00596 return v;
00597 }
00598 d = vcl_sqrt(d);
00599 vcl_list<vgl_homg_point_2d<T> > v(1, vgl_homg_point_2d<T>(-B+d, y*2*A, 2*A));
00600 v.push_back(vgl_homg_point_2d<T>(-B-d, y*2*A, 2*A));
00601 return v;
00602 }
00603 b /= -a; c /= -a;
00604 T AA = A*b*b+B*b+C;
00605 B = 2*A*b*c+B*c+D*b+E;
00606 T d = B*B-4*AA*(A*c*c+D*c+F);
00607 if (d < 0) return vcl_list<vgl_homg_point_2d<T> >();
00608 if (d == 0 && AA == 0)
00609 return vcl_list<vgl_homg_point_2d<T> >(2,vgl_homg_point_2d<T>(b,1,0));
00610 if (d == 0)
00611 return vcl_list<vgl_homg_point_2d<T> >(2,vgl_homg_point_2d<T>(c*2*AA-b*B,-B,2*AA));
00612 if (AA == 0) {
00613 vcl_list<vgl_homg_point_2d<T> > v(1, vgl_homg_point_2d<T>(b,1,0));
00614 v.push_back(vgl_homg_point_2d<T>(b*A*c*c+b*D*c+b*F-c*B, A*c*c+D*c+F, -B));
00615 return v;
00616 }
00617 d = vcl_sqrt(d);
00618 vcl_list<vgl_homg_point_2d<T> > v(1, vgl_homg_point_2d<T>(c*2*AA-b*B+b*d, -B+d, 2*AA));
00619 v.push_back(vgl_homg_point_2d<T>(c*2*AA-b*B-b*d, -B-d, 2*AA));
00620 return v;
00621 }
00622
00623
00624 template <class T>
00625 vcl_list<vgl_homg_point_2d<T> >
00626 vgl_homg_operators_2d<T>::intersection(vgl_conic<T> const& c,
00627 vgl_homg_line_2d<T> const& l)
00628 {
00629 if (c.type()==vgl_conic<T>::no_type ||
00630 c.type()==vgl_conic<T>::complex_parallel_lines ||
00631 c.type()==vgl_conic<T>::complex_intersecting_lines ||
00632 c.type()==vgl_conic<T>::imaginary_ellipse ||
00633 c.type()==vgl_conic<T>::imaginary_circle)
00634 return vcl_list<vgl_homg_point_2d<T> >();
00635
00636
00637 if (c.type() == vgl_conic<T>::coincident_lines) {
00638 vgl_homg_point_2d<T> p = intersection(l, c.components().front());
00639 vcl_list<vgl_homg_point_2d<T> > list(2, p);
00640 return list;
00641 }
00642
00643 if (c.type() == vgl_conic<T>::real_intersecting_lines || c.type() == vgl_conic<T>::real_parallel_lines) {
00644 vcl_list<vgl_homg_point_2d<T> > list;
00645 list.push_back(intersection(l, c.components().front()));
00646 list.push_back(intersection(l, c.components().back()));
00647 return list;
00648 }
00649 return do_intersect(c, l);
00650 }
00651
00652
00653
00654 template <class T>
00655 vcl_list<vgl_homg_point_2d<T> >
00656 vgl_homg_operators_2d<T>::intersection(vgl_conic<T> const& c1, vgl_conic<T> const& c2)
00657 {
00658 if ((c1.type()==vgl_conic<T>::complex_parallel_lines ||
00659 c1.type()==vgl_conic<T>::complex_intersecting_lines)
00660 && c2.contains(c1.centre()))
00661 return vcl_list<vgl_homg_point_2d<T> >(2, c1.centre());
00662 if ((c2.type()==vgl_conic<T>::complex_parallel_lines ||
00663 c2.type()==vgl_conic<T>::complex_intersecting_lines)
00664 && c1.contains(c2.centre()))
00665 return vcl_list<vgl_homg_point_2d<T> >(2, c2.centre());
00666 if (c1.type() == vgl_conic<T>::no_type || c2.type() == vgl_conic<T>::no_type ||
00667 c1.type()==vgl_conic<T>::complex_parallel_lines||c2.type()==vgl_conic<T>::complex_parallel_lines ||
00668 c1.type()==vgl_conic<T>::complex_intersecting_lines||c2.type()==vgl_conic<T>::complex_intersecting_lines ||
00669 c1.type() == vgl_conic<T>::imaginary_ellipse|| c2.type() == vgl_conic<T>::imaginary_ellipse ||
00670 c1.type() == vgl_conic<T>::imaginary_circle || c2.type() == vgl_conic<T>::imaginary_circle)
00671 return vcl_list<vgl_homg_point_2d<T> >();
00672
00673 if (c1.type() == vgl_conic<T>::coincident_lines ||
00674 c1.type() == vgl_conic<T>::real_intersecting_lines ||
00675 c1.type() == vgl_conic<T>::real_parallel_lines) {
00676 vcl_list<vgl_homg_point_2d<T> > l1=intersection(c2,c1.components().front());
00677 vcl_list<vgl_homg_point_2d<T> > l2=intersection(c2,c1.components().back());
00678 l1.insert(l1.end(), l2.begin(), l2.end());
00679 return l1;
00680 }
00681
00682 if (c2.type() == vgl_conic<T>::coincident_lines ||
00683 c2.type() == vgl_conic<T>::real_intersecting_lines ||
00684 c2.type() == vgl_conic<T>::real_parallel_lines) {
00685 vcl_list<vgl_homg_point_2d<T> > l1=intersection(c1,c2.components().front());
00686 vcl_list<vgl_homg_point_2d<T> > l2=intersection(c1,c2.components().back());
00687 l1.insert(l1.end(), l2.begin(), l2.end());
00688 return l1;
00689 }
00690
00691 return do_intersect(c1, c2);
00692 }
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702 template <class T>
00703 vcl_list<vgl_homg_line_2d<T> >
00704 vgl_homg_operators_2d<T>::tangent_from(vgl_conic<T> const& c,
00705 vgl_homg_point_2d<T> const& p)
00706 {
00707 if (c.is_degenerate()) {
00708 if (!c.contains(p)) return vcl_list<vgl_homg_line_2d<T> >();
00709 vcl_list<vgl_homg_line_2d<T> > v = c.components();
00710 if (c.type() == vgl_conic<T>::coincident_lines || p == c.centre())
00711 return v;
00712 if (v.size() > 0 && dot(v.front(),p) == 0)
00713 return vcl_list<vgl_homg_line_2d<T> >(1,v.front());
00714 else if (v.size() > 1 && dot(v.back(),p) == 0)
00715 return vcl_list<vgl_homg_line_2d<T> >(1,v.back());
00716 else
00717 return vcl_list<vgl_homg_line_2d<T> >();
00718 }
00719
00720 vgl_conic<T> C = c.dual_conic();
00721 vgl_homg_line_2d<T> l(p.x(),p.y(),p.w());
00722 vcl_list<vgl_homg_point_2d<T> > dualpts = intersection(C,l);
00723 vcl_list<vgl_homg_line_2d<T> > v;
00724 typename vcl_list<vgl_homg_point_2d<T> >::iterator it = dualpts.begin();
00725 for (; !(it == dualpts.end()); ++it)
00726 v.push_back(vgl_homg_line_2d<T>((*it).x(), (*it).y(), (*it).w()));
00727 return v;
00728 }
00729
00730
00731
00732
00733
00734 template <class T>
00735 vcl_list<vgl_homg_line_2d<T> >
00736 vgl_homg_operators_2d<T>::common_tangents(vgl_conic<T> const& c1,
00737 vgl_conic<T> const& c2)
00738 {
00739 if ((c1.type() != vgl_conic<T>::parabola && ! c1.is_central()) ||
00740 (c2.type() != vgl_conic<T>::parabola && ! c2.is_central()))
00741 return vcl_list<vgl_homg_line_2d<T> >();
00742
00743 vgl_conic<T> C1 = c1.dual_conic();
00744 vgl_conic<T> C2 = c2.dual_conic();
00745 vcl_list<vgl_homg_point_2d<T> > dualpts = intersection(C1,C2);
00746 vcl_list<vgl_homg_line_2d<T> > v;
00747 typename vcl_list<vgl_homg_point_2d<T> >::iterator it = dualpts.begin();
00748 for (; !(it == dualpts.end()); ++it)
00749 v.push_back(vgl_homg_line_2d<T>((*it).x(), (*it).y(), (*it).w()));
00750 return v;
00751 }
00752
00753
00754 template <class T>
00755 vgl_homg_point_2d<T>
00756 vgl_homg_operators_2d<T>::closest_point(vgl_conic<T> const& c,
00757 vgl_homg_point_2d<T> const& pt)
00758 {
00759
00760 if (c.contains(pt)) return pt;
00761
00762
00763
00764
00765 vcl_list<vgl_homg_point_2d<T> > candidates;
00766 if (pt.w() == 0)
00767 {
00768
00769 vgl_homg_line_2d<T> l(c.a()*pt.y()*2-c.b()*pt.x(),
00770 -c.c()*pt.x()*2+c.b()*pt.y(),
00771 c.d()*pt.y() -c.e()*pt.x());
00772 candidates = intersection(c, l);
00773 if (candidates.size() == 0)
00774 return vgl_homg_point_2d<T>(0,0,0);
00775
00776 else return candidates.front();
00777 }
00778 else if (c.b()==0 && c.a()==c.c())
00779 {
00780
00781 vgl_homg_point_2d<T> centre = c.centre();
00782 if (centre == pt)
00783 centre = vgl_homg_point_2d<T>(1,0,0);
00784 candidates = intersection(c, vgl_homg_line_2d<T>(centre,pt));
00785 }
00786 else
00787 {
00788 vgl_conic<T> conic(pt.w()*c.b(),
00789 pt.w()*(c.c()-c.a())*2,
00790 -pt.w()*c.b(),
00791 pt.y()*c.a()*2-pt.x()*c.b()+pt.w()*c.e(),
00792 -pt.x()*c.c()*2+pt.y()*c.b()-pt.w()*c.d(),
00793 pt.y()*c.d() -pt.x()*c.e());
00794
00795 candidates = intersection(c, conic);
00796 }
00797 if (candidates.size() == 0)
00798 {
00799 vcl_cerr << "Warning: vgl_homg_operators_2d<T>::closest_point: no intersection\n";
00800 return vgl_homg_point_2d<T>(0,0,0);
00801 }
00802
00803
00804 typename vcl_list<vgl_homg_point_2d<T> >::iterator it = candidates.begin();
00805 vgl_homg_point_2d<T> p = (*it);
00806 T dist = vgl_homg_operators_2d<T>::distance_squared(*it,pt);
00807 for (++it; it != candidates.end(); ++it) {
00808 if ((*it).w() == 0) continue;
00809 T d = vgl_homg_operators_2d<T>::distance_squared(*it,pt);
00810 if (d < dist) { p = (*it); dist = d; }
00811 }
00812 return p;
00813 }
00814
00815
00816
00817 template <class T>
00818 vgl_homg_point_2d<T>
00819 vgl_homg_operators_2d<T>::closest_point(vgl_conic<T> const& c,
00820 vgl_point_2d<T> const& pt)
00821 {
00822 return closest_point(c,vgl_homg_point_2d<T>(pt));
00823 }
00824
00825
00826
00827
00828 template <class T>
00829 vgl_box_2d<T>
00830 vgl_homg_operators_2d<T>::compute_bounding_box(vgl_conic<T> const& c)
00831 {
00832
00833
00834 if (c.real_type() == "complex intersecting lines") {
00835 vgl_homg_point_2d<T> pt = c.centre();
00836 return vgl_box_2d<T>(vgl_point_2d<T>(pt), vgl_point_2d<T>(pt));
00837 }
00838
00839 if (c.real_type() == "invalid conic" ||
00840 c.real_type() == "imaginary ellipse" ||
00841 c.real_type() == "imaginary circle" ||
00842 c.real_type() == "complex parallel lines")
00843 return vgl_box_2d<T>();
00844
00845 if (c.real_type() == "real parallel lines" ||
00846 c.real_type() == "coincident lines")
00847 {
00848
00849 vcl_list<vgl_homg_line_2d<T> > l = c.components();
00850 if (l.front().a() == 0)
00851 return vgl_box_2d<T>(vgl_point_2d<T>(T(1e33),-l.front().c()/l.front().b()),
00852 vgl_point_2d<T>(T(-1e33),-l.back().c()/l.back().b()));
00853 if (l.front().b() == 0)
00854 return vgl_box_2d<T>(vgl_point_2d<T>(-l.front().c()/l.front().b(),T(1e33)),
00855 vgl_point_2d<T>(-l.back().c()/l.back().b(),T(-1e33)));
00856
00857 }
00858
00859 if (c.real_type() != "real ellipse" && c.real_type() != "real circle")
00860 return vgl_box_2d<T>(T(-1e33), T(1e33), T(-1e33), T(1e33));
00861
00862
00863
00864 vgl_homg_point_2d<T> px (1,0,0);
00865 vgl_homg_point_2d<T> py (0,1,0);
00866
00867 vcl_list<vgl_homg_line_2d<T> > lx = vgl_homg_operators_2d<T>::tangent_from(c, px);
00868 vcl_list<vgl_homg_line_2d<T> > ly = vgl_homg_operators_2d<T>::tangent_from(c, py);
00869
00870 T y1 = - lx.front().c() / lx.front().b();
00871 T y2 = - lx.back().c() / lx.back().b();
00872 if (y1 > y2) { T t = y1; y1 = y2; y2 = t; }
00873 T x1 = - ly.front().c() / ly.front().a();
00874 T x2 = - ly.back().c() / ly.back().a();
00875 if (x1 > x2) { T t = x1; x1 = x2; x2 = t; }
00876
00877 return vgl_box_2d<T>(x1, x2, y1, y2);
00878 }
00879
00880
00881
00882 template <class T>
00883 vgl_homg_point_2d<T> operator*(vnl_matrix_fixed<T,3,3> const& m,
00884 vgl_homg_point_2d<T> const& p)
00885 {
00886 return vgl_homg_point_2d<T>(m(0,0)*p.x()+m(0,1)*p.y()+m(0,2)*p.w(),
00887 m(1,0)*p.x()+m(1,1)*p.y()+m(1,2)*p.w(),
00888 m(2,0)*p.x()+m(2,1)*p.y()+m(2,2)*p.w());
00889 }
00890
00891
00892
00893 template <class T>
00894 vgl_homg_line_2d<T> operator*(vnl_matrix_fixed<T,3,3> const& m,
00895 vgl_homg_line_2d<T> const& l)
00896 {
00897 return vgl_homg_line_2d<T>(m(0,0)*l.a()+m(0,1)*l.b()+m(0,2)*l.c(),
00898 m(1,0)*l.a()+m(1,1)*l.b()+m(1,2)*l.c(),
00899 m(2,0)*l.a()+m(2,1)*l.b()+m(2,2)*l.c());
00900 }
00901
00902
00903 template <class T>
00904 vgl_homg_point_2d<T> vgl_homg_operators_2d<T>::closest_point(vgl_homg_line_2d<T> const& l,
00905 vgl_homg_point_2d<T> const& p)
00906 {
00907
00908 if (l.a()*p.x()+l.b()*p.y()+l.c()*p.w() == 0) return p;
00909
00910 assert(!l.ideal());
00911
00912 vgl_homg_line_2d<T> o(l.b()*p.w(), -l.a()*p.w(), l.a()*p.y()-l.b()*p.x());
00913
00914 return vgl_homg_operators_2d<T>::intersection(l,o);
00915 }
00916
00917 #undef VGL_HOMG_OPERATORS_2D_INSTANTIATE
00918 #define VGL_HOMG_OPERATORS_2D_INSTANTIATE(T) \
00919 template class vgl_homg_operators_2d<T >; \
00920 template vgl_homg_point_2d<T > operator*(vnl_matrix_fixed<T,3,3> const& m, vgl_homg_point_2d<T > const& p); \
00921 template vgl_homg_line_2d<T > operator*(vnl_matrix_fixed<T,3,3> const& m, vgl_homg_line_2d<T > const& p)
00922
00923 #endif // vgl_homg_operators_2d_txx_