Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

point2.C

Go to the documentation of this file.
00001 /*!
00002  *  \file Point2.C
00003  *  \brief Contains the implementation of non-inline functions of the Point2 class
00004  *  and the Point2list class.
00005  *  \ingroup group_MLIB
00006  *
00007  */
00008 
00009 #include <climits>
00010 #include "point2.H"
00011 #include "vec2.H"
00012 
00013 namespace mlib {
00014 
00015 /*!
00016  *  \return Distance squared.
00017  *
00018  */
00019 template <class P, class V>
00020 MLIB_INLINE
00021 double
00022 ray_pt_dist2(const P  &p, const V  &v, const P  &q)
00023 {
00024    const V w = q-p;
00025    const double w2 = w*w;
00026    const double wv = w*v;
00027    return wv > 0 ?             // on positive side of ray?
00028           w2-(wv*wv)/(v*v) :   // ...perpendicular to ray
00029           w2;                  // ...distance to origin
00030 }
00031 
00032 /*!
00033  *  \brief Intersection of two infinite 2d lines (p1,v1) and (p2,v2). 
00034  *  \return succeeded==false if the two lines are are parallel
00035  *
00036  */
00037 template <class P, class V>
00038 inline P
00039 intersect2d(const Point2<P,V> &p1, const Vec2<V> &v1, 
00040             const Point2<P,V> &p2, const Vec2<V> &v2,
00041             bool  &succeeded)
00042 {
00043     succeeded = true;
00044 
00045     const double d = det(v1, v2); 
00046 
00047     if (fabs(d) <= epsAbsSqrdMath())
00048     {
00049         succeeded = false;
00050         return P(p1[0],p1[1]);
00051     }
00052     
00053     const double tmp1 = v1[0] * p1[1] - v1[1] * p1[0];
00054     const double tmp2 = v2[0] * p2[1] - v2[1] * p2[0];
00055     
00056     return P((v2[0]*tmp1 - v1[0]*tmp2) / d, 
00057              (v2[1]*tmp1 - v1[1]*tmp2) / d);
00058 }
00059 
00060 /*!
00061  *  \brief intersect ray starting at \p rayp w/ vector \p rayv with line segment
00062  *  between \p startpt and \p endpt.  \p inter is set to the intersection point.
00063  *
00064  */
00065 template <class P, class V>
00066 MLIB_INLINE
00067 bool
00068 ray_seg_intersect(const Point2<P,V> &rayp, const Vec2<V>     &rayv,
00069                   const Point2<P,V> &startpt, const Point2<P,V> &endpt, 
00070                   Point2<P,V> &inter)
00071 {
00072    bool succ;
00073    const V ray2v = endpt - (P &)startpt;
00074    P pt = intersect2d(rayp, rayv, startpt, ray2v, succ);
00075 
00076    if (!succ) 
00077       return false;
00078 
00079    if ( rayv  * (pt - (P &)rayp)    >= 0 &&
00080    ray2v * (pt - (P &)startpt) >= 0 &&
00081    ray2v * (pt - (P &)endpt)   <= 0) {
00082       inter = pt;
00083       return true;
00084    }
00085 
00086    return false;
00087 }
00088 
00089 } // namespace mlib
00090 
00091 template <class L, class P, class V, class S>
00092 MLIB_INLINE
00093 int
00094 mlib::Point2list<L,P,V,S>::contains(const P &p) const
00095 {
00096    if (num() < 3) return false; // must have at least 3 points
00097    
00098    int cnt(0);
00099    for (int i = 0;i < num(); i++) {
00100       P a((*this)[i]);
00101       P b((*this)[(i+1) % num()]);
00102       
00103       if (a[1] != b[1]) {
00104          if ((a[1] < p[1] && b[1] >= p[1]) ||
00105          (b[1] < p[1] && a[1] >= p[1])) {
00106             double mx((a[0] - b[0]) / (a[1] - b[1]));
00107             double bx(a[0] - mx * a[1]);
00108             double x_intercept((p[1] * mx) + bx);
00109             if (p[0] <= x_intercept) cnt++;
00110          }
00111       }
00112    }
00113    
00114    return (cnt % 2);
00115 }
00116 
00117 template <class L, class P, class V, class S>
00118 MLIB_INLINE
00119 int
00120 mlib::Point2list<L,P,V,S>::contains(const Point2list<L,P,V,S> &list) const
00121 {
00122    int inside = 1;
00123    for (int i = 0; i < list.num() && inside; i++)
00124       inside = inside && contains(list[i]);
00125 
00126    return inside;
00127 }
00128 
00129 template <class L, class P, class V, class S>
00130 MLIB_INLINE
00131 bool
00132 mlib::Point2list<L,P,V,S>::ray_intersect(
00133     const P &pt,
00134     const V &ray,
00135     P       &inter,
00136     int loop
00137     ) const
00138 {
00139     const int n = loop ? num() : num() -1;
00140     bool intersected = false, tmp;
00141     for (int i = 0; i < n ; i++) {
00142        tmp = ray_seg_intersect(pt,
00143                 ray,
00144                 (*this)[i],
00145                 (*this)[(i + 1) % num()],
00146                 inter);
00147        if(tmp)
00148      intersected=true;
00149     }
00150     return intersected;
00151 }
00152 
00153 template <class L, class P, class V, class S>
00154 MLIB_INLINE
00155 bool
00156 mlib::Point2list<L,P,V,S>::ray_intersect(
00157     const P &pt,
00158     const V &ray,
00159     L       &inter,
00160     int loop
00161     ) const
00162 {
00163     const int n = loop ? num() : num() -1;
00164     bool intersected = false;
00165     for (int i = 0; i < n ; i++) {
00166        P tmp;
00167        if(ray_seg_intersect(pt,
00168              ray,
00169              (*this)[i],
00170              (*this)[(i + 1) % num()],
00171              tmp)) {
00172         inter += tmp;
00173        }
00174     }
00175     return inter.num() > 1;
00176 }
00177 
00178 //! returns the intersection of the ray with a subpart (k0 through
00179 //! k1 inclusive) of the poly line.  if it doesn't intersect,
00180 //! returns the nearest point to the ray on the polyline part
00181 template <class L, class P, class V, class S>
00182 MLIB_INLINE
00183 P       
00184 mlib::Point2list<L,P,V,S>::ray_intersect(
00185    const P &p,
00186    const V &v,
00187    int      k0, 
00188    int      k1
00189    ) const
00190 {
00191    // best seen so far.  initialize w/sentinnel
00192    double d0 = DBL_MAX;
00193    P      p0 = p;
00194 
00195    for (int a=k0, b=a+1; b<=k1; a++, b++) {
00196       const P q = (*this)[a];
00197       const P r = (*this)[b];
00198       const V w = r - q;
00199       bool hit;
00200       P i = intersect2d(p, v, q, w, hit);
00201       if (!hit) {
00202          // lines are parallel.  didn't intersect.
00203          // use whichever of q or r is closer to p
00204          i =  p.dist(q) < p.dist(r) ? q : r;
00205       } else if ((i-q)*w < 0) {
00206          // intersected (q,r) before q.  use q
00207          hit = 0;
00208          i = q;
00209       } else if ((i-q).length() > w.length()) {
00210          // intersected (q,r) beyond r.  use r
00211          hit = 0;
00212          i = r;
00213       }
00214       // return immediately if there's a hit
00215       if (hit)
00216          return i;
00217 
00218       // keep closest point seen so far
00219       const double d = ray_pt_dist2(p, v, i);
00220       if (d<d0) {
00221          d0 = d;
00222          p0 = i;
00223       }
00224    }
00225    // no exact hit.  use the closest point
00226    return p0;
00227 }
00228 
00229 //! Pass input parameters by copying in case one is a current
00230 //! endpoint of the polyline.
00231 template<class L, class P, class V, class S>
00232 MLIB_INLINE
00233 void
00234 mlib::Point2list<L,P,V,S>::fix_endpoints(P a, P b)
00235 {
00236    if (num() < 2) {
00237       cerr << "Point2list<>::fix_endpoints(): not enough points "
00238            << "in list (num = " << num() << ")" << endl;
00239       return;
00240    }
00241 
00242    if (first().is_equal(a) && last().is_equal(b)) {
00243       // if new endpoints are the same as old endpoints, no-op
00244       return;
00245    }
00246 
00247    double old_len = first().dist(last());
00248    
00249    if (old_len < epsAbsMath()) {
00250       cerr << "Point2list<>::fix_endpoints(): distance between "
00251            << "first and last points is 0 (len = " << old_len << ")" << endl;
00252       return;
00253    }
00254    
00255    // adjustment needed to fix first point of list to a
00256    const V translation = a - first();
00257 
00258    // translate the entire curve so that now first() == a
00259    this->translate(translation); 
00260 
00261    const V old_vec  = last() - a;
00262    const V new_vec  = b - a;
00263    double angle,scale;
00264 
00265    scale = new_vec.length() / old_vec.length();
00266    angle = old_vec.signed_angle(new_vec);
00267 
00268    // Find the desired transform that take the span to
00269    // the desired span
00270    
00271    double cos_theta = cos(angle);
00272    double sin_theta = sin(angle);
00273    
00274    double aa = cos_theta * scale;
00275    double bb = sin_theta * scale;
00276    
00277    // It's actually the matrix [cos -sin; sin cos]*scale
00278    // that do the transform
00279    
00280    for (int k = 1; k < num() ;k++) {
00281       V v = (*this)[k] - first();
00282       V offset = V(aa*v[0]-bb*v[1], bb*v[0]+aa*v[1]);
00283       
00284       // reset to the transformed pt
00285       (*this)[k] = first()+offset;
00286    }
00287    
00288    this->update_length();
00289 }
00290 
00291 template <class L, class P, class V, class S>
00292 MLIB_INLINE
00293 bool
00294 mlib::Point2list<L,P,V,S>::intersects_line(const S& l) const
00295 {
00296 
00297    P o = l.point();
00298    V v = l.vector().perpend();
00299 
00300    for (int i=0; i<num()-1; i++)
00301       if (((pt(i) - o) * v) * ((pt(i+1) - o) * v) <= 0)
00302          return true;
00303    return false;
00304 }
00305 
00306 template <class L, class P, class V, class S>
00307 MLIB_INLINE
00308 bool
00309 mlib::Point2list<L,P,V,S>::intersects_seg(const S& s) const
00310 {
00311 
00312    for (int i=0; i<num()-1; i++)
00313       if (seg(i).intersect_segs(s))
00314          return true;
00315    return false;
00316 }
00317 
00318 template <class L, class P, class V, class S>
00319 MLIB_INLINE
00320 double
00321 mlib::Point2list<L,P,V,S>::winding_number(const P& p) const
00322 {
00323 
00324    double ret=0;
00325    for (int i=1; i<num(); i++)
00326       ret += signed_angle((pt(i-1) - p), (pt(i) - p));
00327    return ret / TWO_PI;
00328 }
00329 
00330 /* end of file Point2.C */

Generated on Mon Sep 18 11:39:33 2006 for jot by  doxygen 1.4.4