vgl_conic.hxx
Go to the documentation of this file.
1 // This is core/vgl/vgl_conic.hxx
2 #ifndef vgl_conic_hxx_
3 #define vgl_conic_hxx_
4 //:
5 // \file
6 // Written by Peter Vanroose, ESAT, K.U.Leuven, Belgium, 30 August 2001.
7 
8 #include <cmath>
9 #include <iostream>
10 #ifdef _MSC_VER
11 # include <vcl_msvc_warnings.h>
12 #endif
13 #include "vgl_conic.h"
14 
15 static const char *vgl_conic_name[] =
16 {
17  "invalid conic",
18  "real ellipse",
19  "real circle",
20  "imaginary ellipse",
21  "imaginary circle",
22  "hyperbola",
23  "parabola",
24  "real intersecting lines",
25  "complex intersecting lines",
26  "real parallel lines",
27  "complex parallel lines",
28  "coincident lines"
29 };
30 
31 
32 //--------------------------------------------------------------
33 //: Returns the type name of the conic.
34 
35 template <class T>
36 std::string vgl_conic<T>::real_type() const { return vgl_conic_name[(int)type_]; }
37 
38 template <class T>
40 {
41  for (int i = (int)no_type; i < num_conic_types; i++)
42  if (name == vgl_conic_name[i])
43  return (typename vgl_conic<T>::vgl_conic_type)i;
44  return no_type; // should never reach this point
45 }
46 
47 template <class T>
49 {
50  if (type <= 0 || type >= num_conic_types) return vgl_conic_name[no_type];
51  return vgl_conic_name[type];
52 }
53 
54 //-------------------------------------------------------------
55 //: equality test
56 template <class T>
57 bool vgl_conic<T>::operator==(vgl_conic<T> const& that) const
58 {
59  if ( type() != that.type() ) return false;
60  return a()*that.b() == b()*that.a()
61  && a()*that.c() == c()*that.a()
62  && a()*that.d() == d()*that.a()
63  && a()*that.e() == e()*that.a()
64  && a()*that.f() == f()*that.a()
65  && b()*that.c() == c()*that.b()
66  && b()*that.d() == d()*that.b()
67  && b()*that.e() == e()*that.b()
68  && b()*that.f() == f()*that.b()
69  && c()*that.d() == d()*that.c()
70  && c()*that.e() == e()*that.c()
71  && c()*that.f() == f()*that.c()
72  && d()*that.e() == e()*that.d()
73  && d()*that.f() == f()*that.d()
74  && e()*that.f() == f()*that.e();
75 }
76 
77 //-------------------------------------------------------------
78 //: set values
79 template <class T>
80 void vgl_conic<T>::set(T ta, T tb, T tc, T td, T te, T tf)
81 {
82  a_ = ta; b_ = tb; c_ = tc; d_ = td; e_ = te; f_ = tf;
83  set_type_from_equation();
84 }
85 
86 //-------------------------------------------------------------
87 //: constructor using polynomial coefficients.
88 template <class T>
90  : type_(no_type), a_(co[0]), b_(co[1]), c_(co[2]), d_(co[3]), e_(co[4]), f_(co[5])
91 {
93 }
94 
95 //-------------------------------------------------------------
96 //: constructor using polynomial coefficients.
97 template <class T>
98 vgl_conic<T>::vgl_conic(T ta, T tb, T tc, T td, T te, T tf)
99  : type_(no_type), a_(ta), b_(tb), c_(tc), d_(td), e_(te), f_(tf)
100 {
102 }
103 
104 //: ctor using centre, signed radii, and angle, or (for parabola) top + eccentricity
105 template <class T>
106 vgl_conic<T>::vgl_conic(vgl_homg_point_2d<T> const& co, T rx, T ry, T theta)
107 {
108  if (co.w() == 0) { // This is a parabola
109  a_ = co.y()*co.y();
110  b_ = -2*co.x()*co.y();
111  c_ = co.x()*co.x();
112  // polar line of (rx,ry) must have direction (co.y(),-co.x()), hence
113  // 2*a_*rx + b_*ry + d_ = 2*t*co.x() and b_*rx + 2*c_*ry +e_ = 2*t*co.y() :
114  theta /= std::sqrt(co.x()*co.x()+co.y()*co.y()); // cannot be 0
115  d_ = -2*a_*rx - b_*ry + 2*theta*co.x();
116  e_ = -2*c_*ry - b_*rx + 2*theta*co.y();
117  // conic must go through (rx,ry):
118  f_ = -a_*rx*rx-b_*rx*ry-c_*ry*ry-d_*rx-e_*ry;
119  }
120  else { // hyperbola or ellipse
121  rx = (rx < 0) ? (-rx*rx) : rx*rx; // abs of square
122  ry = (ry < 0) ? (-ry*ry) : ry*ry; // idem
123 
124  double ct = std::cos(-theta); // rotate counterclockwise over theta
125  double st = std::sin(-theta);
126  T u = co.x();
127  T v = co.y();
128  a_ = T(rx*st*st + ry*ct*ct);
129  b_ = T(2*(rx-ry)*ct*st);
130  c_ = T(rx*ct*ct + ry*st*st);
131  d_ = T(-2*(rx*st*st + ry*ct*ct)*u - 2*(rx-ry)*ct*st*v);
132  e_ = T(-2*(rx-ry)*ct*st*u - 2*(rx*ct*ct + ry*st*st)*v);
133  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);
134  }
135  set_type_from_equation();
136 }
137 
138 //--------------------------------------------------------------------------
139 //: set conic type from polynomial coefficients.
140 // This method must be called by all constructors (except the default
141 // constructor) and all methods that change the coefficients.
142 
143 template <class T>
145 {
146  T A = a_, B = b_/2, C = c_, D = d_/2, E = e_/2, F = f_;
147 
148  /* determinant, subdeterminants and trace values */
149  T det = A*(C*F - E*E) - B*(B*F - D*E) + D*(B*E - C*D); // determinant
150  T J = A*C - B*B; // upper 2x2 determinant
151  T K = (C*F - E*E) + (A*F - D*D); // sum of two other 2x2 determinants
152  T I = A + C; // trace of upper 2x2
153 
154  if (det != 0) {
155  if (J > 0) {
156  if (det*I < 0) {
157  if (A==C && B==0) type_ = real_circle;
158  else type_ = real_ellipse;
159  }
160  else {
161  if (A==C && B==0) type_ = imaginary_circle;
162  else type_ = imaginary_ellipse;
163  }
164  }
165  else if (J < 0) type_ = hyperbola;
166  else /* J == 0 */ type_ = parabola;
167  }
168  else { // limiting cases
169  if (J < 0) type_ = real_intersecting_lines;
170  else if (J > 0) type_ = complex_intersecting_lines;
171  else /* J == 0 */ {
172  if ( A == 0 && B == 0 && C == 0 ) { // line at infinity is component
173  if ( D !=0 || E != 0 ) type_ = real_intersecting_lines;
174  else if (F != 0) type_ = coincident_lines; // 2x w=0
175  else type_ = no_type; // all coefficients are 0
176  }
177  else if (K < 0) type_ = real_parallel_lines;
178  else if (K > 0) type_ = complex_parallel_lines;
179  else type_ = coincident_lines;
180  }
181  }
182 }
183 
184 template <class T>
186 {
187  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;
188 }
189 
190 template <class T>
192 {
193  T A = a_, B = b_/2, C = c_, D = d_/2, E = e_/2, F = f_;
194  T det = A*(C*F - E*E) - B*(B*F - D*E) + D*(B*E - C*D);
195  return det==0;
196 }
197 
198 //: return a geometric description of the conic if an ellipse
199 // The centre of the ellipse is (xc, yc)
200 template <class T>
201 bool vgl_conic<T>::
202 ellipse_geometry(double& xc, double& yc, double& major_axis_length,
203  double& minor_axis_length, double& angle_in_radians) const
204 {
205  if (type_!=real_ellipse && type_ != real_circle)
206  return false;
207 
208  // Cast to double and half the non-diagonal (non-quadratic) entries B, D, E.
209  double A = static_cast<double>(a_), B = static_cast<double>(b_)*0.5,
210  C = static_cast<double>(c_), D = static_cast<double>(d_)*0.5,
211  F = static_cast<double>(f_), E = static_cast<double>(e_)*0.5;
212  if (A < 0)
213  A=-A, B=-B, C=-C, D=-D, E=-E, F=-F;
214 
215  double det = A*(C*F - E*E) - B*(B*F- D*E) + D*(B*E-C*D);
216  double D2 = A*C - B*B;
217  xc = (E*B - C*D)/D2;
218  yc = (D*B - A*E)/D2;
219 
220  double trace = A + C;
221  double disc = std::sqrt(trace*trace - 4.0*D2);
222  double cmaj = (trace+disc)*D2/(2*det); if (cmaj < 0) cmaj = -cmaj;
223  double cmin = (trace-disc)*D2/(2*det); if (cmin < 0) cmin = -cmin;
224  minor_axis_length = 1.0/std::sqrt(cmaj>cmin?cmaj:cmin);
225  major_axis_length = 1.0/std::sqrt(cmaj>cmin?cmin:cmaj);
226 
227  // Find the angle that diagonalizes the upper 2x2 sub-matrix
228  angle_in_radians = -0.5 * std::atan2(2*B, C-A);
229  // ^
230  // and return the negative of this angle
231  return true;
232 }
233 
234 
235 //: Returns the list of component lines, when degenerate and real components.
236 // Otherwise returns an empty list.
237 template <class T>
238 std::list<vgl_homg_line_2d<T> > vgl_conic<T>::components() const
239 {
240  if (!is_degenerate() ||
241  type() == complex_intersecting_lines ||
242  type() == complex_parallel_lines)
243  return std::list<vgl_homg_line_2d<T> >(); // no real components
244 
245  T A = a_, B = b_/2, C = c_, D = d_/2, E = e_/2, F = f_;
246 
247  if (type() == coincident_lines) {
248  // coincident lines: rank of the matrix of this conic must be 1
250  if (A!=0 || B!=0 || D!=0)
251  l = vgl_homg_line_2d<T>(A,B,D);
252  else if (C!=0 || E!=0)
253  l = vgl_homg_line_2d<T>(B,C,E);
254  else // only F!=0 : 2x line at infinity w=0
255  l = vgl_homg_line_2d<T>(D,E,F);
256  return std::list<vgl_homg_line_2d<T> >(2,l); // two identical lines
257  }
258 
259  // Both component lines must pass through the centre of this conic
260  vgl_homg_point_2d<T> cntr = centre();
261 
262  if (type() == real_parallel_lines)
263  {
264  // In this case the centre lies at infinity.
265  // Either these lines both intersect the X axis, or both intersect the Y axis:
266  if (A!=0 || D!=0) { // X axis: intersections satisfy y=0 && Axx+2Dxw+Fww=0:
267  vgl_homg_line_2d<T> l1(cntr, vgl_homg_point_2d<T>(-D+std::sqrt(D*D-A*F),0,A)),
268  l2(cntr, vgl_homg_point_2d<T>(-D-std::sqrt(D*D-A*F),0,A));
269  std::list<vgl_homg_line_2d<T> > v(1,l1); v.push_back(l2);
270  return v;
271  }
272  else { // Y axis: x=0 && Cyy+2Eyw+Fww=0:
273  vgl_homg_line_2d<T> l1(cntr, vgl_homg_point_2d<T>(0,-E+std::sqrt(E*E-C*F),C)),
274  l2(cntr, vgl_homg_point_2d<T>(0,-E-std::sqrt(E*E-C*F),C));
275  std::list<vgl_homg_line_2d<T> > v(1,l1); v.push_back(l2);
276  return v;
277  }
278  }
279 
280  // Only remaining case: type() == real_intersecting_lines.
281  if (A==0 && B==0 && C==0) { // line at infinity (w=0) is a component
282  std::list<vgl_homg_line_2d<T> > v(1,vgl_homg_line_2d<T>(0,0,1));
283  v.push_back(vgl_homg_line_2d<T>(d_,e_,f_));
284  return v;
285  }
286  // If not, the two component lines are determined by cntr and their direction,
287  // i.e., they pass through one of the two pts satisfying w=0 && Axx+2Bxy+Cyy=0:
288  if (A==0 && C==0) { // components are vertical and horizontal, resp.
289  vgl_homg_line_2d<T> l1(cntr, vgl_homg_point_2d<T>(0,1,0)),
290  l2(cntr, vgl_homg_point_2d<T>(1,0,0));
291  std::list<vgl_homg_line_2d<T> > v(1,l1); v.push_back(l2);
292  return v;
293  }
294  else {
295  vgl_homg_line_2d<T> l1(cntr, vgl_homg_point_2d<T>(-B+std::sqrt(B*B-A*C),A,0)),
296  l2(cntr, vgl_homg_point_2d<T>(-B-std::sqrt(B*B-A*C),A,0));
297  std::list<vgl_homg_line_2d<T> > v(1,l1); v.push_back(l2);
298  return v;
299  }
300 }
301 
302 //: Return true if a central conic
303 // (This is an affine property, not a projective one.)
304 // Equivalent to saying that the line at infinity does not touch the conic.
305 template <class T>
307 {
308  return type_ == real_ellipse|| type_ == imaginary_ellipse|| type_ == hyperbola
309  || type_ == real_circle || type_ == imaginary_circle
310  || type_ == real_intersecting_lines|| type_ == complex_intersecting_lines;
311 }
312 
313 //--------------------------------------------------------------------------------
314 template <class T>
316 {
317  d_ += 2*a_*x + b_*y;
318  f_ += c_ * y*y - a_ * x*x + d_ * x + e_ * y;
319  e_ += 2*c_*y + b_*x;
320  // This does not change the type, so no need to run set_type_from_equation()
321 }
322 
323 template <class T>
325 {
326  T A = a_, B = b_/2, C = c_, D = d_/2, E = e_/2, F = f_;
327  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);
328 }
329 
330 //: return the polar line of the homogeneous 2-D point p.
331 template <class T>
333 {
334  return vgl_homg_line_2d<T> (p.x()*a_ +p.y()*b_/2+p.w()*d_/2,
335  p.x()*b_/2+p.y()*c_ +p.w()*e_/2,
336  p.x()*d_/2+p.y()*e_/2+p.w()*f_ );
337 }
338 
339 //: return the polar point of the homogeneous 2-D line l.
340 template <class T>
342 {
343  if (!is_degenerate()) {
344  vgl_conic<T> co = this->dual_conic();
345  return vgl_homg_point_2d<T> (l.a()*co.a() +l.b()*co.b()/2+l.c()*co.d()/2,
346  l.a()*co.b()/2+l.b()*co.c() +l.c()*co.e()/2,
347  l.a()*co.d()/2+l.b()*co.e()/2+l.c()*co.f() );
348  }
349  else // a degenerate conic has no dual; in this case, return the centre:
350  if (a_==0 && b_==0 && d_==0) // two horizontal lines
351  return vgl_homg_point_2d<T>(1,0,0);
352  else if (a_*c_*4==b_*b_ && a_*e_*2==b_*d_)
353  return vgl_homg_point_2d<T>(b_*f_*2-e_*d_, d_*d_-a_*f_*4, a_*e_*2-b_*d_);
354  else
355  return vgl_homg_point_2d<T>(b_*e_-c_*d_*2, b_*d_-a_*e_*2, a_*c_*4-b_*b_);
356 }
357 
358 //: Returns the curvature of the conic at point p, assuming p is on the conic.
359 template <class T>
361 {
362  // Shorthands
363  const T &a_xx = a_;
364  const T &a_xy = b_;
365  const T &a_yy = c_;
366  const T &a_xw = d_;
367  const T &a_yw = e_;
368 
369  const T x = p.x();
370  const T y = p.y();
371 
372  double f_x = 2*a_xx*x + a_xy*y + a_xw;
373  double f_y = 2*a_yy*y + a_xy*x + a_yw;
374  double f_xy = a_xy;
375  double f_xx = 2*a_xx;
376  double f_yy = 2*a_yy;
377 
378  double f_x_2 = f_x*f_x;
379  double f_y_2 = f_y*f_y;
380  double denom = f_x_2 + f_y_2;
381  denom = std::sqrt(denom*denom*denom);
382 
383  // Divergent of the unit normal grad f/|grad f|
384  return (f_xx*f_y_2 - 2*f_x*f_y*f_xy + f_yy*f_x_2) / denom;
385 }
386 
387 
388 //: Write "<vgl_conic aX^2+bXY+cY^2+dXW+eYW+fW^2=0>" to stream
389 template <class T>
390 std::ostream& operator<<(std::ostream& s, vgl_conic<T> const& co)
391 {
392  s << "<vgl_conic ";
393  if (co.a() == 1) s << "X^2";
394  else if (co.a() == -1) s << "-X^2";
395  else if (co.a() != 0) s << co.a() << "X^2";
396  if (co.b() > 0) s << '+';
397  if (co.b() == 1) s << "XY";
398  else if (co.b() == -1) s << "-XY";
399  else if (co.b() != 0) s << co.b() << "XY";
400  if (co.c() > 0) s << '+';
401  if (co.c() == 1) s << "Y^2";
402  else if (co.c() == -1) s << "-Y^2";
403  else if (co.c() != 0) s << co.c() << "Y^2";
404  if (co.d() > 0) s << '+';
405  if (co.d() == 1) s << "XW";
406  else if (co.d() == -1) s << "-XW";
407  else if (co.d() != 0) s << co.d() << "XW";
408  if (co.e() > 0) s << '+';
409  if (co.e() == 1) s << "YW";
410  else if (co.e() == -1) s << "-YW";
411  else if (co.e() != 0) s << co.e() << "YW";
412  if (co.f() > 0) s << '+';
413  if (co.f() == 1) s << "W^2";
414  else if (co.f() == -1) s << "-W^2";
415  else if (co.f() != 0) s << co.f() << "W^2";
416  return s << "=0 " << co.real_type() << "> ";
417 }
418 
419 //: Read a b c d e f from stream
420 template <class T>
421 std::istream& operator>>(std::istream& is, vgl_conic<T>& co)
422 {
423  T ta, tb, tc, td, te, tf; is >> ta >> tb >> tc >> td >> te >> tf;
424  co.set(ta,tb,tc,td,te,tf); return is;
425 }
426 
427 #undef VGL_CONIC_INSTANTIATE
428 #define VGL_CONIC_INSTANTIATE(T) \
429 template class vgl_conic<T >; \
430 template std::ostream& operator<<(std::ostream&, const vgl_conic<T >&); \
431 template std::istream& operator>>(std::istream&, vgl_conic<T >&)
432 
433 #endif // vgl_conic_hxx_
A quadratic plane curve.
vgl_conic_type type() const
Definition: vgl_conic.h:101
vgl_homg_point_1d< T > centre(vgl_homg_point_1d< T > const &p1, vgl_homg_point_1d< T > const &p2)
Return the point at the centre of gravity of two given points.
Represents a homogeneous 2D line.
Definition: vgl_fwd.h:14
double curvature_at(vgl_point_2d< T > const &p) const
Returns the curvature of the conic at point p, assuming p is on the conic.
Definition: vgl_conic.hxx:360
void translate_by(T x, T y)
Modify this conic by translating it over distance x in the X direction and distance y in the Y direct...
Definition: vgl_conic.hxx:315
bool contains(vgl_homg_point_2d< T > const &pt) const
Returns true if the point pt belongs to the conic.
Definition: vgl_conic.hxx:185
T f() const
Returns the coefficient of .
Definition: vgl_conic.h:135
std::ostream & operator<<(std::ostream &s, vgl_orient_box_3d< Type > const &p)
Write box to stream.
void set_type_from_equation()
set conic type from polynomial coefficients and store in member type_.
Definition: vgl_conic.hxx:144
T a() const
Returns the coefficient of .
Definition: vgl_conic.h:120
#define v
Definition: vgl_vector_2d.h:74
T c() const
Returns the coefficient of .
Definition: vgl_conic.h:126
#define trace(str)
Definition: vgl_rtree.hxx:16
static std::string type_by_number(vgl_conic_type type)
Converts the conic type from enum (internal representation) to string.
Definition: vgl_conic.hxx:48
std::string real_type() const
Returns the type of the conic as a string.
Definition: vgl_conic.hxx:36
bool is_central() const
Returns true if a central conic, i.e., an ellipse, circle, or hyperbola.
Definition: vgl_conic.hxx:306
vgl_conic_type
Definition: vgl_conic.h:73
T e() const
Returns the coefficient of .
Definition: vgl_conic.h:132
Type & y()
Definition: vgl_point_2d.h:72
vgl_conic dual_conic() const
Returns the dual or tangential representation of this conic.
Definition: vgl_conic.hxx:324
A quadratic plane curve.
Definition: vgl_conic.h:70
static vgl_conic_type type_by_name(std::string const &name)
Returns the internal enum value corresponding to the string argument.
Definition: vgl_conic.hxx:39
T b() const
Returns the coefficient of .
Definition: vgl_conic.h:123
bool ellipse_geometry(double &xc, double &yc, double &major_axis_length, double &minor_axis_length, double &angle_in_radians) const
Converts the coefficients to a geometric description of an ellipse.
Definition: vgl_conic.hxx:202
vgl_homg_point_2d< T > polar_point(vgl_homg_line_2d< T > const &l) const
Returns the polar point of the given line, w.r.t. this conic.
Definition: vgl_conic.hxx:341
std::istream & operator>>(std::istream &is, vgl_orient_box_3d< Type > &p)
Read box from stream.
T d() const
Returns the coefficient of .
Definition: vgl_conic.h:129
vgl_homg_line_2d< T > polar_line(vgl_homg_point_2d< T > const &p) const
Returns the polar line of the given point, w.r.t. this conic.
Definition: vgl_conic.hxx:332
void set(T a, T b, T c, T d, T e, T f)
set or reset the conic using polynomial coefficients.
Definition: vgl_conic.hxx:80
#define l
std::list< vgl_homg_line_2d< T > > components() const
Returns the list of component lines, when degenerate and real components.
Definition: vgl_conic.hxx:238
bool operator==(vgl_conic< T > const &c) const
comparison operator.
Definition: vgl_conic.hxx:57
Represents a homogeneous 2D point.
Definition: vgl_fwd.h:8
bool is_degenerate() const
Returns true if this conic is degenerate, i.e., if it consists of 2 lines.
Definition: vgl_conic.hxx:191
Type & x()
Definition: vgl_point_2d.h:71