00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <climits>
00010 #include "point2.H"
00011 #include "vec2.H"
00012
00013 namespace mlib {
00014
00015
00016
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 ?
00028 w2-(wv*wv)/(v*v) :
00029 w2;
00030 }
00031
00032
00033
00034
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
00062
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 }
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;
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
00179
00180
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
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
00203
00204 i = p.dist(q) < p.dist(r) ? q : r;
00205 } else if ((i-q)*w < 0) {
00206
00207 hit = 0;
00208 i = q;
00209 } else if ((i-q).length() > w.length()) {
00210
00211 hit = 0;
00212 i = r;
00213 }
00214
00215 if (hit)
00216 return i;
00217
00218
00219 const double d = ray_pt_dist2(p, v, i);
00220 if (d<d0) {
00221 d0 = d;
00222 p0 = i;
00223 }
00224 }
00225
00226 return p0;
00227 }
00228
00229
00230
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
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
00256 const V translation = a - first();
00257
00258
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
00269
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
00278
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
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