00001 // This is core/vgl/vgl_conic_segment_2d.h 00002 #ifndef vgl_conic_segment_2d_h_ 00003 #define vgl_conic_segment_2d_h_ 00004 #ifdef VCL_NEEDS_PRAGMA_INTERFACE 00005 #pragma interface 00006 #endif 00007 //: 00008 // \file 00009 // \author J.L. Mundy June 18, 2005 00010 // \brief A curve segment with the geometry of an conic 00011 // 00012 // A conic segment contains those points of a given conic which lie between the 00013 // given start point (inclusive) and the given end point, in a certain direction 00014 // (counter-clockwise by default). 00015 // No automatic validation checking is done for those two points effectively 00016 // lying on the conic; this is left to the user of the class. Operations on 00017 // vgl_conic_segment_2d<T> like intersection should actually take the "points 00018 // closest to the given end points" as the effective end points. 00019 // 00020 // The concept of counter-clockwise-ness is not projectively invariant, but is 00021 // invariant under most projective transformations that are useful in vision, 00022 // and most certainly is under affine and Euclidean transformations. Actually, 00023 // as long as the centre of the conic does not traverse the line at infinity, 00024 // orientation and thus counter-clockwise-ness of the conic is kept. There is 00025 // only one affine situation which is still ambiguous, viz. when the conic is 00026 // a hyperbola. In that case, the definition of "counter-clockwise" is based 00027 // --by definition-- on the view of the start point. Only when both end points 00028 // are at infinity, i.e. when, the segment is one of the two branches of the 00029 // hyperbola, this is still ambiguous and there is no way to distinguish which 00030 // of the two branches is meant by just giving the two end points. 00031 // 00032 // The only projectively "correct" way to define a segment would be to specify 00033 // a third point on the conic, or a direction vector from the start point. 00034 // This would be an overkill for most applications, though. 00035 // Those applications that require a fully projectively invariant segment should 00036 // consider storing an additional third point together with the conic segment, 00037 // and swap the two endpoints (by using the swap_endpoints() method) whenever 00038 // a transformation is applied that would invert the orientation of the conic. 00039 // 00040 // One more ambiguous situation left is a conic segment specified by two 00041 // identical end points. By definition, in this case, the segment only contains 00042 // of this single point. This is compatible with the use of conic segments in 00043 // conic fitting algorithms, where the shortest rather than the longest segment 00044 // should be selected. 00045 // 00046 // When the conic is an ellipse, the semantics of the conic segment are clear: 00047 // seen from the inside of the ellipse, and starting from the first end point, 00048 // one goes to the left to traverse the conic segment in a counter-clockwise way. 00049 // 00050 // If the conic is a parabola, the first endpoint should typically lie to the 00051 // right of the second one (as seen from the focal point of the parabola): in 00052 // that case, the conic segment has finite length when traversed in counter- 00053 // clockwise direction. Otherwise, we still have a valid conic segment but it 00054 // consists of two separate, infinite branches. 00055 // 00056 // If the conic is a hyperbola, there are even three cases to be considered: 00057 // if both end points lie on the same branch of the hyperbola, and the first 00058 // one lies to the right of the second one as seen from the "inside" of that 00059 // branch, the conic segment is a finite curve. This is the only finite case. 00060 // By swapping the end points, the segment will have three branches, not just 00061 // two: it will contain the two infinite fragments "outside" the end points on 00062 // the hyperbola branch of the end points, and also the complete other branch 00063 // of the hyperbola. 00064 // Finally, if the end points lie on different hyperbola branches, the segment 00065 // consists of all points to the left of the start point (as seen from the 00066 // "inside" of the start point's branch) and of all points to the left of the 00067 // end point (as seen from the "inside" of the end point's branch). 00068 // In this case, swapping the end points does not change the segment! As a 00069 // consequence, it will never be possible to specify the complement of this 00070 // segment as a single vgl_conic_segment_2d, only as the union of two. 00071 // 00072 // End points can of course happily be points at infinity (if the conic is 00073 // either a parabola or a hyperbola). A parabolic segment with the start point 00074 // at infinity contains all points to the left of the end point, as seen from 00075 // the focal point of the parabola. If the end point lies at infinity, it's the 00076 // points to the left of the start point which form the segment. 00077 // A hyperbolic segment for which the two endpoints are the two different points 00078 // at infinity of the hyperbola, contains all points of one of the two hyperbola 00079 // branches and none of the other branch. This is the only ambiguous situation 00080 // so it should be avoided unless a third point is used to define the segment. 00081 // If only one end point of a hyperbolic segment lies at infinity, the segment 00082 // either consists of just the points to the left on the branch of the other end 00083 // point, or of those points plus all points on the other branch. 00084 // 00085 // \verbatim 00086 // Modifications 00087 // 2009-06-06 Peter Vanroose - Added member "counterclockwise_" 00088 // 2009-06-06 Peter Vanroose - Added swap_endpoints(), swap_direction(), normalize() 00089 // 2009-06-06 Peter Vanroose - Added the is_finite() method (not yet implem.) 00090 // 2009-06-06 Peter Vanroose - Re-implemented to be fully homogeneous 00091 // 2009-06-06 Peter Vanroose - Added explicit "semantics" documentation 00092 // 2009-06-06 Peter Vanroose - Added the contains() method (not yet implem.) 00093 // \endverbatim 00094 00095 #include <vcl_iosfwd.h> 00096 #include <vgl/vgl_homg_point_2d.h> // data member of this class 00097 #include <vgl/vgl_conic.h> // data member of this class 00098 #include <vgl/vgl_point_2d.h> // return type of some methods 00099 00100 //: Represents a 2D conic segment using two points. 00101 template <class Type> 00102 class vgl_conic_segment_2d 00103 { 00104 //: One end of conic segment 00105 vgl_homg_point_2d<Type> p1_; 00106 00107 //: The other end of the conic segment 00108 vgl_homg_point_2d<Type> p2_; 00109 00110 //: The conic that represents the curve between point1 and point2 00111 vgl_conic<Type> conic_; 00112 00113 //: Whether traversal is in counter-clockwise direction (the default) or not 00114 bool counterclockwise_; 00115 00116 public: 00117 //: Default constructor - does not initialise! 00118 // Use the set() method to make this conic segment useful. 00119 inline vgl_conic_segment_2d() {} 00120 00121 //: Copy constructor 00122 inline vgl_conic_segment_2d(vgl_conic_segment_2d<Type> const& l) 00123 : p1_(l.p1_), p2_(l.p2_), conic_(l.conic_), 00124 counterclockwise_(l.counterclockwise_) {} 00125 00126 //: Construct from two end points (homogeneous) and a conic 00127 inline vgl_conic_segment_2d(vgl_homg_point_2d<Type> const& p1, 00128 vgl_homg_point_2d<Type> const& p2, 00129 vgl_conic<Type> const& co, 00130 bool counterclockwise = true) 00131 : p1_(p1), p2_(p2), conic_(co), 00132 counterclockwise_(counterclockwise) {} 00133 00134 //: Construct from two end points (Cartesian) and a conic 00135 inline vgl_conic_segment_2d(vgl_point_2d<Type> const& p1, 00136 vgl_point_2d<Type> const& p2, 00137 vgl_conic<Type> const& co, 00138 bool counterclockwise = true) 00139 : p1_(p1.x(), p1.y(), (Type)1), p2_(p2.x(), p2.y(), (Type)1), 00140 conic_(co), counterclockwise_(counterclockwise) {} 00141 00142 //: Construct from a conic and two end points (homogeneous) 00143 inline vgl_conic_segment_2d(vgl_conic<Type> const& co, 00144 vgl_homg_point_2d<Type> const& p1, 00145 vgl_homg_point_2d<Type> const& p2, 00146 bool counterclockwise = true) 00147 : p1_(p1), p2_(p2), conic_(co), 00148 counterclockwise_(counterclockwise) {} 00149 00150 //: Construct from a conic and two end points (Cartesian) 00151 inline vgl_conic_segment_2d(vgl_conic<Type> const& co, 00152 vgl_point_2d<Type> const& p1, 00153 vgl_point_2d<Type> const& p2, 00154 bool counterclockwise = true) 00155 : p1_(p1.x(), p1.y(), (Type)1), p2_(p2.x(), p2.y(), (Type)1), 00156 conic_(co), counterclockwise_(counterclockwise) {} 00157 00158 //: Destructor 00159 inline ~vgl_conic_segment_2d() {} 00160 00161 //: Normalise the direction of the segment to counterclockwise. 00162 // This will also swap the end points if the direction is to be swapped. 00163 void normalize() { if (!counterclockwise_) { counterclockwise_=true; swap_endpoints(); } } 00164 00165 //: Interchange the two endpoints but keep the direction. 00166 // This implies that now the conic segment contains those points of the conic 00167 // which before did not belong to the conic segment! (Except for the two end 00168 // points, of course.) 00169 void swap_endpoints() { vgl_homg_point_2d<Type> p=p1_; p1_=p2_; p2_=p; } 00170 00171 //: Change the direction of the conic section but keep the end points. 00172 // This implies that now the conic segment contains those points of the conic 00173 // which before did not belong to the conic segment! (Except for the two end 00174 // points, of course.) 00175 void swap_direction() { counterclockwise_ = !counterclockwise_; } 00176 00177 //: The first end-point of the conic segment. 00178 inline vgl_homg_point_2d<Type> point1() const { return p1_; } // return a copy 00179 00180 //: The second end-point of the conic segment. 00181 inline vgl_homg_point_2d<Type> point2() const { return p2_; } // return a copy 00182 00183 //: The conic underlying the segment 00184 inline vgl_conic<Type> conic() const { return conic_; } // return a copy 00185 00186 //: The direction of the segment (clockwise or counterclockwise) 00187 bool is_counterclockwise() const { return counterclockwise_; } 00188 00189 //: The direction of the segment (clockwise or counterclockwise) 00190 bool is_clockwise() const { return !counterclockwise_; } 00191 00192 //: The equality comparison operator 00193 // Two conic segments are only identical if the underlying conic is identical 00194 // and if direction and both endpoints are identical, in the same order! 00195 // Two conic segments with identical conic and identical end points but 00196 // in the opposite order are not identical but rather complementary: they 00197 // share no other points than the two end points. 00198 // Use the swap_direction or the swap_endpoints() method on one of the two 00199 // segments to turn complementary segments into identical ones. 00200 // Note that two conic segments *are* equal if both the direction and the 00201 // two end points are swapped. To normalize a conic segment such that its 00202 // direction becomes counterclockwise, use the normalize() method. 00203 inline bool operator==(vgl_conic_segment_2d<Type> const& l) const { 00204 return this==&l || 00205 (l.conic() == conic_ && 00206 l.is_counterclockwise() == counterclockwise_ && 00207 point1() == l.point1() && 00208 point2() == l.point2()) || 00209 (l.conic() == conic_ && 00210 l.is_counterclockwise() != counterclockwise_ && 00211 point2() == l.point1() && 00212 point1() == l.point2()); 00213 } 00214 00215 //: The inequality comparison operator. 00216 inline bool operator!=(vgl_conic_segment_2d<Type>const& other) const { return !operator==(other); } 00217 00218 //: (Re)initialise the conic segment by passing it its three "constructors" 00219 inline void set(vgl_homg_point_2d<Type> const& p1, vgl_homg_point_2d<Type> const& p2, 00220 vgl_conic<Type> co, bool counterclockwise = true) 00221 { p1_ = p1; p2_ = p2; conic_ = co; counterclockwise_ = counterclockwise; } 00222 00223 //: (Re)initialise the conic segment by passing it its three "constructors" 00224 inline void set(vgl_conic<Type> co, 00225 vgl_homg_point_2d<Type> const& p1, vgl_homg_point_2d<Type> const& p2, 00226 bool counterclockwise = true) 00227 { p1_ = p1; p2_ = p2; conic_ = co; counterclockwise_ = counterclockwise; } 00228 00229 //: (Re)initialise the conic segment by passing it its three "constructors" 00230 inline void set(vgl_point_2d<Type> const& p1, vgl_point_2d<Type> const& p2, 00231 vgl_conic<Type> co, bool counterclockwise = true) 00232 { p1_.set(p1.x(), p1.y()); p2_.set(p2.x(), p2.y()); conic_ = co; 00233 counterclockwise_ = counterclockwise; } 00234 00235 //: (Re)initialise the conic segment by passing it its three "constructors" 00236 inline void set(vgl_conic<Type> co, 00237 vgl_point_2d<Type> const& p1, vgl_point_2d<Type> const& p2, 00238 bool counterclockwise = true) 00239 { p1_.set(p1.x(), p1.y()); p2_.set(p2.x(), p2.y()); conic_ = co; 00240 counterclockwise_ = counterclockwise; } 00241 00242 //: Finds out whether this curve has a finite length. 00243 // If the conic segment has an underlying ellipse, the segment is of course 00244 // always finite. Otherwise, is_finite returns false whenever the segment 00245 // passes through one of the points at infinity of the hyperbola or parabola. 00246 // Note that the methods swap_endpoints() and swap_direction() always swaps 00247 // finiteness of a parabolic segment (unless the endpoints coincide). For 00248 // hyperbolic segments this is not necessarily the case: both can be infinite. 00249 bool is_finite() const { return true; } // TODO: NYI 00250 00251 //: Finds out whether the given point lies on the conic segment. 00252 // More specifically, lying on the segment implies lying on the conic. 00253 // Moreover, the two endpoints (if effectively on the conic) will always 00254 // lie on the segment. All other points of the conic lie either on this 00255 // segment, or on the "swapped" segment, but never on both. 00256 bool contains(vgl_homg_point_2d<Type> const& pt) const { return true; } // TODO: NYI 00257 }; 00258 00259 //: Write to stream 00260 // \relatesalso vgl_conic_segment_2d 00261 template <class Type> 00262 vcl_ostream& operator<<(vcl_ostream& s, const vgl_conic_segment_2d<Type>& c_s); 00263 00264 //: Read from stream 00265 // \relatesalso vgl_conic_segment_2d 00266 template <class Type> 00267 vcl_istream& operator>>(vcl_istream& is, vgl_conic_segment_2d<Type>& c_s); 00268 00269 #define VGL_CONIC_SEGMENT_2D_INSTANTIATE(T) extern "please include vgl/vgl_conic_segment_2d.txx first" 00270 00271 #endif // vgl_conic_segment_2d_h_
1.7.5.1