vgl_conic_segment_2d.h
Go to the documentation of this file.
1 // This is core/vgl/vgl_conic_segment_2d.h
2 #ifndef vgl_conic_segment_2d_h_
3 #define vgl_conic_segment_2d_h_
4 //:
5 // \file
6 // \author J.L. Mundy June 18, 2005
7 // \brief A curve segment with the geometry of a conic
8 //
9 // A conic segment contains those points of a given conic which lie between the
10 // given start point (inclusive) and the given end point, in a certain direction
11 // (counter-clockwise by default).
12 // No automatic validation checking is done for those two points effectively
13 // lying on the conic; this is left to the user of the class. Operations on
14 // vgl_conic_segment_2d<T> like intersection should actually take the "points
15 // closest to the given end points" as the effective end points.
16 //
17 // The concept of counter-clockwise-ness is not projectively invariant, but is
18 // invariant under most projective transformations that are useful in vision,
19 // and most certainly is under affine and Euclidean transformations. Actually,
20 // as long as the centre of the conic does not traverse the line at infinity,
21 // orientation and thus counter-clockwise-ness of the conic is kept. There is
22 // only one affine situation which is still ambiguous, viz. when the conic is
23 // a hyperbola. In that case, the definition of "counter-clockwise" is based
24 // --by definition-- on the view of the start point. Only when both end points
25 // are at infinity, i.e. when, the segment is one of the two branches of the
26 // hyperbola, this is still ambiguous and there is no way to distinguish which
27 // of the two branches is meant by just giving the two end points.
28 //
29 // The only projectively "correct" way to define a segment would be to specify
30 // a third point on the conic, or a direction vector from the start point.
31 // This would be an overkill for most applications, though.
32 // Those applications that require a fully projectively invariant segment should
33 // consider storing an additional third point together with the conic segment,
34 // and swap the two endpoints (by using the swap_endpoints() method) whenever
35 // a transformation is applied that would invert the orientation of the conic.
36 //
37 // One more ambiguous situation left is a conic segment specified by two
38 // identical end points. By definition, in this case, the segment only contains
39 // of this single point. This is compatible with the use of conic segments in
40 // conic fitting algorithms, where the shortest rather than the longest segment
41 // should be selected.
42 //
43 // When the conic is an ellipse, the semantics of the conic segment are clear:
44 // seen from the inside of the ellipse, and starting from the first end point,
45 // one goes to the left to traverse the conic segment in a counter-clockwise way.
46 //
47 // If the conic is a parabola, the first endpoint should typically lie to the
48 // right of the second one (as seen from the focal point of the parabola): in
49 // that case, the conic segment has finite length when traversed in counter-
50 // clockwise direction. Otherwise, we still have a valid conic segment but it
51 // consists of two separate, infinite branches.
52 //
53 // If the conic is a hyperbola, there are even three cases to be considered:
54 // if both end points lie on the same branch of the hyperbola, and the first
55 // one lies to the right of the second one as seen from the "inside" of that
56 // branch, the conic segment is a finite curve. This is the only finite case.
57 // By swapping the end points, the segment will have three branches, not just
58 // two: it will contain the two infinite fragments "outside" the end points on
59 // the hyperbola branch of the end points, and also the complete other branch
60 // of the hyperbola.
61 // Finally, if the end points lie on different hyperbola branches, the segment
62 // consists of all points to the left of the start point (as seen from the
63 // "inside" of the start point's branch) and of all points to the left of the
64 // end point (as seen from the "inside" of the end point's branch).
65 // In this case, swapping the end points does not change the segment! As a
66 // consequence, it will never be possible to specify the complement of this
67 // segment as a single vgl_conic_segment_2d, only as the union of two.
68 //
69 // End points can of course happily be points at infinity (if the conic is
70 // either a parabola or a hyperbola). A parabolic segment with the start point
71 // at infinity contains all points to the left of the end point, as seen from
72 // the focal point of the parabola. If the end point lies at infinity, it's the
73 // points to the left of the start point which form the segment.
74 // A hyperbolic segment for which the two endpoints are the two different points
75 // at infinity of the hyperbola, contains all points of one of the two hyperbola
76 // branches and none of the other branch. This is the only ambiguous situation
77 // so it should be avoided unless a third point is used to define the segment.
78 // If only one end point of a hyperbolic segment lies at infinity, the segment
79 // either consists of just the points to the left on the branch of the other end
80 // point, or of those points plus all points on the other branch.
81 //
82 // \verbatim
83 // Modifications
84 // 2009-06-06 Peter Vanroose - Added member "counterclockwise_"
85 // 2009-06-06 Peter Vanroose - Added swap_endpoints(), swap_direction(), normalize()
86 // 2009-06-06 Peter Vanroose - Added the is_finite() method (not yet implem.)
87 // 2009-06-06 Peter Vanroose - Re-implemented to be fully homogeneous
88 // 2009-06-06 Peter Vanroose - Added explicit "semantics" documentation
89 // 2009-06-06 Peter Vanroose - Added the contains() method (not yet implem.)
90 // \endverbatim
91 
92 #include <iosfwd>
93 #include <vgl/vgl_homg_point_2d.h> // data member of this class
94 #include <vgl/vgl_conic.h> // data member of this class
95 #include <vgl/vgl_point_2d.h> // return type of some methods
96 #ifdef _MSC_VER
97 # include <vcl_msvc_warnings.h>
98 #endif
99 #include <cassert>
100 
101 //: Represents a 2D conic segment using two points.
102 template <class Type>
104 {
105  //: One end of conic segment
107 
108  //: The other end of the conic segment
110 
111  //: The conic that represents the curve between point1 and point2
113 
114  //: Whether traversal is in counter-clockwise direction (the default) or not
116 
117  public:
118  //: Default constructor - does not initialise!
119  // Use the set() method to make this conic segment useful.
120  inline vgl_conic_segment_2d() = default;
121 
122  //: Copy constructor
124  : p1_(l.p1_), p2_(l.p2_), conic_(l.conic_),
126 
127  //: Construct from two end points (homogeneous) and a conic
129  vgl_homg_point_2d<Type> const& p2,
130  vgl_conic<Type> const& co,
131  bool counterclockwise = true)
132  : p1_(p1), p2_(p2), conic_(co),
133  counterclockwise_(counterclockwise) {}
134 
135  //: Construct from two end points (Cartesian) and a conic
137  vgl_point_2d<Type> const& p2,
138  vgl_conic<Type> const& co,
139  bool counterclockwise = true)
140  : p1_(p1.x(), p1.y(), (Type)1), p2_(p2.x(), p2.y(), (Type)1),
141  conic_(co), counterclockwise_(counterclockwise) {}
142 
143  //: Construct from a conic and two end points (homogeneous)
145  vgl_homg_point_2d<Type> const& p1,
146  vgl_homg_point_2d<Type> const& p2,
147  bool counterclockwise = true)
148  : p1_(p1), p2_(p2), conic_(co),
149  counterclockwise_(counterclockwise) {}
150 
151  //: Construct from a conic and two end points (Cartesian)
153  vgl_point_2d<Type> const& p1,
154  vgl_point_2d<Type> const& p2,
155  bool counterclockwise = true)
156  : p1_(p1.x(), p1.y(), (Type)1), p2_(p2.x(), p2.y(), (Type)1),
157  conic_(co), counterclockwise_(counterclockwise) {}
158 
159  //: Destructor
160  inline ~vgl_conic_segment_2d() = default;
161 
162  //: Normalise the direction of the segment to counterclockwise.
163  // This will also swap the end points if the direction is to be swapped.
165 
166  //: Interchange the two endpoints but keep the direction.
167  // This implies that now the conic segment contains those points of the conic
168  // which before did not belong to the conic segment! (Except for the two end
169  // points, of course.)
171 
172  //: Change the direction of the conic section but keep the end points.
173  // This implies that now the conic segment contains those points of the conic
174  // which before did not belong to the conic segment! (Except for the two end
175  // points, of course.)
177 
178  //: The first end-point of the conic segment.
179  inline vgl_homg_point_2d<Type> point1() const { return p1_; } // return a copy
180 
181  //: The second end-point of the conic segment.
182  inline vgl_homg_point_2d<Type> point2() const { return p2_; } // return a copy
183 
184  //: The conic underlying the segment
185  inline vgl_conic<Type> conic() const { return conic_; } // return a copy
186 
187  //: The direction of the segment (clockwise or counterclockwise)
188  bool is_counterclockwise() const { return counterclockwise_; }
189 
190  //: The direction of the segment (clockwise or counterclockwise)
191  bool is_clockwise() const { return !counterclockwise_; }
192 
193  //: The equality comparison operator
194  // Two conic segments are only identical if the underlying conic is identical
195  // and if direction and both endpoints are identical, in the same order!
196  // Two conic segments with identical conic and identical end points but
197  // in the opposite order are not identical but rather complementary: they
198  // share no other points than the two end points.
199  // Use the swap_direction or the swap_endpoints() method on one of the two
200  // segments to turn complementary segments into identical ones.
201  // Note that two conic segments \e are equal if both the direction and the
202  // two end points are swapped. To normalize a conic segment such that its
203  // direction becomes counterclockwise, use the normalize() method.
204  inline bool operator==(vgl_conic_segment_2d<Type> const& l) const {
205  return this==&l ||
206  (l.conic() == conic_ &&
207  l.is_counterclockwise() == counterclockwise_ &&
208  point1() == l.point1() &&
209  point2() == l.point2()) ||
210  (l.conic() == conic_ &&
211  l.is_counterclockwise() != counterclockwise_ &&
212  point2() == l.point1() &&
213  point1() == l.point2());
214  }
215 
216  //: The inequality comparison operator.
217  inline bool operator!=(vgl_conic_segment_2d<Type>const& other) const { return !operator==(other); }
218 
219  //: (Re)initialise the conic segment by passing it its three "constructors"
220  inline void set(vgl_homg_point_2d<Type> const& p1, vgl_homg_point_2d<Type> const& p2,
221  vgl_conic<Type> co, bool counterclockwise = true)
222  { p1_ = p1; p2_ = p2; conic_ = co; counterclockwise_ = counterclockwise; }
223 
224  //: (Re)initialise the conic segment by passing it its three "constructors"
225  inline void set(vgl_conic<Type> co,
227  bool counterclockwise = true)
228  { p1_ = p1; p2_ = p2; conic_ = co; counterclockwise_ = counterclockwise; }
229 
230  //: (Re)initialise the conic segment by passing it its three "constructors"
231  inline void set(vgl_point_2d<Type> const& p1, vgl_point_2d<Type> const& p2,
232  vgl_conic<Type> co, bool counterclockwise = true)
233  { p1_.set(p1.x(), p1.y()); p2_.set(p2.x(), p2.y()); conic_ = co;
234  counterclockwise_ = counterclockwise; }
235 
236  //: (Re)initialise the conic segment by passing it its three "constructors"
237  inline void set(vgl_conic<Type> co,
238  vgl_point_2d<Type> const& p1, vgl_point_2d<Type> const& p2,
239  bool counterclockwise = true)
240  { p1_.set(p1.x(), p1.y()); p2_.set(p2.x(), p2.y()); conic_ = co;
241  counterclockwise_ = counterclockwise; }
242 
243  //: Finds out whether this curve has a finite length.
244  // If the conic segment has an underlying ellipse, the segment is of course
245  // always finite. Otherwise, is_finite returns false whenever the segment
246  // passes through one of the points at infinity of the hyperbola or parabola.
247  // Note that the methods swap_endpoints() and swap_direction() always swaps
248  // finiteness of a parabolic segment (unless the endpoints coincide). For
249  // hyperbolic segments this is not necessarily the case: both can be infinite.
250  // \todo not yet implemented
251  bool is_finite() const { assert(!"Not yet implemented"); return true; }
252 
253  //: Finds out whether the given point lies on the conic segment.
254  // More specifically, lying on the segment implies lying on the conic.
255  // Moreover, the two endpoints (if effectively on the conic) will always
256  // lie on the segment. All other points of the conic lie either on this
257  // segment, or on the "swapped" segment, but never on both.
258  // \todo not yet implemented
259  bool contains(vgl_homg_point_2d<Type> const& /*pt*/) const { assert(!"Not yet implemented"); return false; }
260 };
261 
262 //: Write to stream
263 // \relatesalso vgl_conic_segment_2d
264 template <class Type>
265 std::ostream& operator<<(std::ostream& s, const vgl_conic_segment_2d<Type>& c_s);
266 
267 //: Read from stream
268 // \relatesalso vgl_conic_segment_2d
269 template <class Type>
270 std::istream& operator>>(std::istream& is, vgl_conic_segment_2d<Type>& c_s);
271 
272 #define VGL_CONIC_SEGMENT_2D_INSTANTIATE(T) extern "please include vgl/vgl_conic_segment_2d.hxx first"
273 
274 #endif // vgl_conic_segment_2d_h_
A quadratic plane curve.
vgl_conic_segment_2d(vgl_conic< Type > const &co, vgl_point_2d< Type > const &p1, vgl_point_2d< Type > const &p2, bool counterclockwise=true)
Construct from a conic and two end points (Cartesian).
vgl_homg_point_2d< Type > point2() const
The second end-point of the conic segment.
vgl_homg_point_2d< Type > p1_
One end of conic segment.
a point in 2D nonhomogeneous space
void set(vgl_conic< Type > co, vgl_homg_point_2d< Type > const &p1, vgl_homg_point_2d< Type > const &p2, bool counterclockwise=true)
(Re)initialise the conic segment by passing it its three "constructors".
vgl_homg_point_2d< Type > point1() const
The first end-point of the conic segment.
vgl_conic< Type > conic() const
The conic underlying the segment.
void swap_direction()
Change the direction of the conic section but keep the end points.
bool contains(vgl_homg_point_2d< Type > const &) const
Finds out whether the given point lies on the conic segment.
vgl_conic< Type > conic_
The conic that represents the curve between point1 and point2.
bool is_counterclockwise() const
The direction of the segment (clockwise or counterclockwise).
void swap_endpoints()
Interchange the two endpoints but keep the direction.
bool is_clockwise() const
The direction of the segment (clockwise or counterclockwise).
std::ostream & operator<<(std::ostream &s, vgl_orient_box_3d< Type > const &p)
Write box to stream.
bool counterclockwise_
Whether traversal is in counter-clockwise direction (the default) or not.
~vgl_conic_segment_2d()=default
Destructor.
vgl_conic_segment_2d()=default
Default constructor - does not initialise!.
bool operator==(vgl_conic_segment_2d< Type > const &l) const
The equality comparison operator.
Represents a 2D conic segment using two points.
bool is_finite() const
Finds out whether this curve has a finite length.
void set(vgl_homg_point_2d< Type > const &p1, vgl_homg_point_2d< Type > const &p2, vgl_conic< Type > co, bool counterclockwise=true)
(Re)initialise the conic segment by passing it its three "constructors".
Type & y()
Definition: vgl_point_2d.h:72
point in projective 2D space
void set(T px, T py, T pw=(T) 1)
Set x,y,w.
bool operator!=(vgl_conic_segment_2d< Type >const &other) const
The inequality comparison operator.
std::istream & operator>>(std::istream &is, vgl_orient_box_3d< Type > &p)
Read box from stream.
#define l
void set(vgl_point_2d< Type > const &p1, vgl_point_2d< Type > const &p2, vgl_conic< Type > co, bool counterclockwise=true)
(Re)initialise the conic segment by passing it its three "constructors".
vgl_homg_point_2d< Type > p2_
The other end of the conic segment.
Represents a cartesian 2D point.
Definition: vgl_area.h:7
void normalize()
Normalise the direction of the segment to counterclockwise.
void set(vgl_conic< Type > co, vgl_point_2d< Type > const &p1, vgl_point_2d< Type > const &p2, bool counterclockwise=true)
(Re)initialise the conic segment by passing it its three "constructors".
vgl_conic_segment_2d(vgl_point_2d< Type > const &p1, vgl_point_2d< Type > const &p2, vgl_conic< Type > const &co, bool counterclockwise=true)
Construct from two end points (Cartesian) and a conic.
vgl_conic_segment_2d(vgl_homg_point_2d< Type > const &p1, vgl_homg_point_2d< Type > const &p2, vgl_conic< Type > const &co, bool counterclockwise=true)
Construct from two end points (homogeneous) and a conic.
Type & x()
Definition: vgl_point_2d.h:71
vgl_conic_segment_2d(vgl_conic_segment_2d< Type > const &l)
Copy constructor.
vgl_conic_segment_2d(vgl_conic< Type > const &co, vgl_homg_point_2d< Type > const &p1, vgl_homg_point_2d< Type > const &p2, bool counterclockwise=true)
Construct from a conic and two end points (homogeneous).