00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <climits>
00010
00011 #include "mlib/global.H"
00012
00013 #include "mlib/pointlist.H"
00014
00015
00016
00017 template <class L, class P, class V, class S>
00018 MLIB_INLINE
00019 bool
00020 mlib::Pointlist<L,P,V,S>::is_straight(double len_scale) const
00021 {
00022
00023
00024 if (num() < 2)
00025 return 0;
00026
00027
00028 if (num() == 2)
00029 return 1;
00030
00031
00032
00033 int k;
00034 V v;
00035 for (k=1; k<num() && v.is_null(); k++)
00036 v = ((*this)[k] - (*this)[0]).normalized();
00037
00038 if (v.is_null())
00039 return 0;
00040
00041
00042
00043
00044
00045
00046 if (num() != _partial_length.num()) {
00047 cerr << "Pointlist::is_straight: Error: lengths are not updated"
00048 << endl;
00049 return 0;
00050 }
00051 double thresh = length()*len_scale;
00052 for (k=1; k<num(); k++)
00053 if ((pt(k) - pt(0)).orthogonalized(v).length() > thresh)
00054 return 0;
00055
00056
00057 return 1;
00058 }
00059
00060 template <class L, class P, class V, class S>
00061 MLIB_INLINE
00062 bool
00063 mlib::Pointlist<L,P,V,S>::self_intersects() const
00064 {
00065
00066 int n = num();
00067 for (int i = 0; i < n-3; i++) {
00068 S seg_i = seg(i);
00069
00070
00071
00072 int max_j = (is_closed() && (i == 0)) ? (n-3) : (n-2);
00073 for (int j = i+2; j <= max_j; j++)
00074 if (seg_i.intersect_segs(seg(j)))
00075 return true;
00076 }
00077 return false;
00078 }
00079
00080
00081
00082 template <class L, class P, class V, class S>
00083 MLIB_INLINE
00084 int
00085 mlib::Pointlist<L,P,V,S>::nearest_point(
00086 const P &p
00087 ) const
00088 {
00089 int nearest = 0;
00090 double min_dist = DBL_MAX;
00091
00092 for ( int i = 0; i < num(); i++ ) {
00093 double dist = (p - (*this)[i]).length_sqrd();
00094 if ( dist < min_dist ) {
00095 min_dist = dist;
00096 nearest = i;
00097 }
00098 }
00099 return nearest;
00100 }
00101
00102
00103
00104
00105
00106
00107
00108
00109 template <class L, class P, class V, class S>
00110 MLIB_INLINE
00111 void
00112 mlib::Pointlist<L,P,V,S>::closest(
00113 const P &p,
00114 P &nearpt,
00115 double &neardist,
00116 int &seg_index
00117 ) const
00118 {
00119 if (num()>1) {
00120 neardist = DBL_MAX;
00121
00122 for (int i = 0; i < num()-1; i++) {
00123 const P a((*this)[i]);
00124 const P b((*this)[i+1]);
00125 const P npt = nearest_pt_to_line_seg(p,a,b);
00126 const double d = (npt-p).length();
00127 if (d < neardist) {
00128 neardist = d;
00129 nearpt = npt;
00130 seg_index = i;
00131 }
00132 }
00133 }
00134 else {
00135 if (empty()) {
00136 err_msg("Pointlist::closest() called on empty list");
00137 neardist = DBL_MAX;
00138 seg_index = 0;
00139 }
00140 else {
00141 nearpt = (*this)[0];
00142 seg_index = 0;
00143 neardist = p.dist(nearpt);
00144 }
00145 }
00146 }
00147
00148 template <class L, class P, class V, class S>
00149 MLIB_INLINE
00150 double
00151 mlib::Pointlist<L,P,V,S>::closest(
00152 const P &p,
00153 P &nearpt,
00154 int &pt_ind
00155 ) const
00156 {
00157 if (num() == 0)
00158 return DBL_MAX;
00159
00160 double d;
00161 int i;
00162 closest(p, nearpt, d, i);
00163
00164 P a((*this)[i]);
00165 P b((*this)[i+1]);
00166 if ((p-a).length() < (p-b).length())
00167 pt_ind = i;
00168 else pt_ind = i+1;
00169 return d;
00170 }
00171
00172 template <class L, class P, class V, class S>
00173 MLIB_INLINE
00174 P
00175 mlib::Pointlist<L,P,V,S>::closest(
00176 const P &p
00177 ) const
00178 {
00179 P nearpt(DBL_MAX);
00180 double dist;
00181 int index;
00182 closest(p, nearpt, dist, index);
00183 return nearpt;
00184 }
00185
00186
00187
00188 template <class L, class P, class V, class S>
00189 MLIB_INLINE
00190 P
00191 mlib::Pointlist<L,P,V,S>::sum() const {
00192
00193 P ret;
00194 for (int i=0; i<num(); i++)
00195 ret += (*this)[i];
00196 return ret;
00197
00198 }
00199
00200 template <class L, class P, class V, class S>
00201 MLIB_INLINE
00202 double
00203 mlib::Pointlist<L,P,V,S>::dist_to_seg(
00204 const P &p,
00205 int k
00206 ) const
00207 {
00208 return (p -
00209 nearest_pt_to_line_seg(p, (*this)[k], (*this)[(k+1)%num()])).length();
00210 }
00211
00212
00213 template <class L, class P, class V, class S>
00214 MLIB_INLINE
00215 double
00216 mlib::Pointlist<L,P,V,S>::avg_dist_to_seg(
00217 const P &p,
00218 int k
00219 ) const
00220 {
00221 return ((p - (*this)[k]).length() + (p - (*this)[(k+1)%num()]).length() ) / 2.0;
00222 }
00223
00224 template <class L, class P, class V, class S>
00225 MLIB_INLINE
00226 double
00227 mlib::Pointlist<L,P,V,S>::spread() const
00228 {
00229
00230
00231 if (empty())
00232 return 0;
00233
00234 P avg = average();
00235
00236 double ret = avg.dist((*this)[0]);
00237 for (int k=1; k<num(); k++)
00238 ret = max(avg.dist((*this)[k]), ret);
00239
00240 return ret;
00241 }
00242
00243
00244
00245
00246
00247
00248
00249 template <class L, class P, class V, class S>
00250 typename P::value_type
00251 mlib::Pointlist<L,P,V,S>::min_val(int i) const {
00252 if (empty()) {
00253 err_msg("Point3list::min_val: Error: polyline is empty");
00254 return 0;
00255 }
00256 assert(i >= 0 && i<P::dim());
00257 typename P::value_type ret = pt(0)[i];
00258 for (int k=1; k<num(); k++)
00259 ret = min(ret, pt(k)[i]);
00260 return ret;
00261 }
00262
00263
00264
00265
00266
00267
00268
00269 template <class L, class P, class V, class S>
00270 typename P::value_type
00271 mlib::Pointlist<L,P,V,S>::max_val(int i) const {
00272 if (empty()) {
00273 err_msg("Point3list::max_val: Error: polyline is empty");
00274 return 0;
00275 }
00276 assert(i >= 0 && i<P::dim());
00277 typename P::value_type ret = pt(0)[i];
00278 for (int k=1; k<num(); k++)
00279 ret = max(ret, pt(k)[i]);
00280 return ret;
00281 }
00282
00283
00284
00285 template<class L, class P, class V, class S>
00286 MLIB_INLINE
00287 void
00288 mlib::Pointlist<L,P,V,S>::update_length()
00289 {
00290 _partial_length.clear();
00291 if (num())
00292 _partial_length.realloc(num());
00293 _partial_length += 0;
00294 double cur_length = 0;
00295 for ( int i=1; i< num(); i++ ) {
00296 cur_length += segment_length(i-1);
00297 _partial_length += cur_length;
00298 }
00299 err_mesg(ERR_LEV_SPAM,
00300 "Pointlist<L,P,V,S>::update_length(): # of Segments = %i Total Length = %f",
00301 num(), (float)_partial_length.last());
00302 }
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319 template<class L, class P, class V, class S>
00320 MLIB_INLINE
00321 P
00322 mlib::Pointlist<L,P,V,S>::interpolate(
00323 double s,
00324 V *tan,
00325 int *segp,
00326 double *tp
00327 ) const
00328 {
00329
00330
00331
00332 if (empty()) {
00333 cerr << "Pointlist::interpolate: Error: list is empty"
00334 << endl;
00335 return P();
00336 }
00337
00338 int seg;
00339 double t;
00340 interpolate_length(s, seg, t);
00341 const V v = (*this)[seg+1] - (*this)[seg];
00342
00343 if (tan) *tan = v.normalized();
00344 if (segp) *segp = seg;
00345 if (tp) *tp = t;
00346
00347 return (*this)[seg]+v*t;
00348 }
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360 template<class L, class P, class V, class S>
00361 MLIB_INLINE
00362 void
00363 mlib::Pointlist<L,P,V,S>::interpolate_length(
00364 double s,
00365 int &seg,
00366 double &t
00367 ) const
00368 {
00369
00370 if (empty()) {
00371 cerr << "Pointlist::interpolate_length: Error: list is empty"
00372 << endl;
00373 return;
00374 }
00375
00376
00377
00378
00379
00380
00381
00382
00383 if (_partial_length.num() != num()) {
00384 cerr << "Pointlist::interpolate_length: "
00385 << "Warning: partial lengths not updated"
00386 << endl;
00387
00388 ((L*)this)->update_length();
00389 }
00390
00391
00392
00393
00394
00395
00396
00397 const double val = s*_partial_length.last();
00398 if (val <= 0) { seg = 0; t = 0; return; }
00399 if (val >= _partial_length.last()) { seg = num()-2; t = 1; return; }
00400
00401 int l=0, r=num()-1, m;
00402 while ((m = (l+r) >> 1) != l) {
00403 if (val < _partial_length[m]) { r = m; }
00404 else { l = m; }
00405 }
00406 seg = m;
00407 t = (val-_partial_length[m])/(_partial_length[m+1]-_partial_length[m]);
00408 }
00409
00410 template<class L, class P, class V, class S>
00411 MLIB_INLINE
00412 V
00413 mlib::Pointlist<L,P,V,S>::get_tangent(double s) const
00414 {
00415
00416 if (s == (int)s) {
00417 int i = s;
00418 const int n=num()-1;
00419 if (i<0 || i>n || n<1) return V();
00420 if (i==0) return ((*this)[1]-(*this)[ 0]).normalized();
00421 if (i==n) return ((*this)[n]-(*this)[n-1]).normalized();
00422 return (((*this)[i+1]-(*this)[i]).normalized() +
00423 ((*this)[i]-(*this)[i-1]).normalized()).
00424 normalize();
00425 }
00426 else {
00427 int seg;
00428 double t;
00429 V tan0;
00430 V tan1;
00431
00432 interpolate_length(s, seg, t);
00433
00434
00435 if ( t < .5 ) {
00436 tan0 = get_tangent(seg);
00437 tan1 = ((*this)[seg+1] - (*this)[seg]).normalized();
00438 t *= 2.0;
00439 }
00440 else {
00441 tan0 = ((*this)[seg+1] - (*this)[seg]).normalized();
00442 tan1 = get_tangent(seg+1);
00443 t = ( t - .5 ) * 2.0;
00444 }
00445
00446 return (((1-t) * tan0) + (t * tan1)).normalized();
00447 }
00448 }
00449
00450
00451
00452 template<class L, class P, class V, class S>
00453 MLIB_INLINE
00454 double
00455 mlib::Pointlist<L,P,V,S>::invert(
00456 const P &p) const
00457 {
00458 P nearpt;
00459 double neardist;
00460 int seg_index;
00461
00462 closest(p, nearpt, neardist, seg_index);
00463 return invert(p, seg_index);
00464 }
00465
00466 template<class L, class P, class V, class S>
00467 MLIB_INLINE
00468 double
00469 mlib::Pointlist<L,P,V,S>::invert(
00470 const P &p,
00471 int seg) const
00472 {
00473 const V v = (*this)[seg + 1] - (*this)[seg];
00474 const V vnorm = v.normalized();
00475 const P pp = (*this)[seg] + ( (p-(*this)[seg]) * vnorm ) * vnorm;
00476
00477 double len = _partial_length[seg] + (pp-(*this)[seg]).length();
00478 return len/length();
00479 }
00480
00481
00482
00483 template <class L, class P, class V, class S>
00484 MLIB_INLINE
00485 void
00486 mlib::Pointlist<L,P,V,S>::resample(
00487 int num_segs
00488 )
00489 {
00490 update_length();
00491
00492 Pointlist<L,P,V,S> result;
00493 double dt = 1.0 / num_segs;
00494 for (int k=0; k<num_segs; k++)
00495 result += interpolate(k*dt);
00496 result += last();
00497
00498 *this = result;
00499 }
00500
00501
00502
00503
00504
00505
00506
00507
00508 template<class L, class P, class V, class S>
00509 MLIB_INLINE
00510 L
00511 mlib::Pointlist<L,P,V,S>::clone_piece(
00512 int k1,
00513 int k2) const
00514 {
00515 if (!(valid_index(k1) && valid_index(k2)))
00516 return L();
00517
00518 L ret(num());
00519
00520 bool loop = (k2 < k1);
00521 if (loop) {
00522 int n = num();
00523 int end = (k2+1)%n;
00524 if (k1 == end) {
00525 ret = *this;
00526 } else {
00527 for (int k=k1; k != end; k = (k+1)%n) {
00528 ret.add((*this)[k]);
00529 }
00530 }
00531 } else {
00532 for (int k=k1; k<=k2; k++) {
00533 ret.add((*this)[k]);
00534 }
00535 }
00536 return ret;
00537 }
00538
00539 template<class L, class P, class V, class S>
00540 MLIB_INLINE
00541 void
00542 mlib::Pointlist<L,P,V,S>::append(
00543 Pointlist<L,P,V,S> * poly
00544 )
00545 {
00546 this->operator+=(*poly);
00547 }
00548
00549 template<class L, class P, class V, class S>
00550 MLIB_INLINE
00551 void
00552 mlib::Pointlist<L,P,V,S>::prepend(
00553 Pointlist<L,P,V,S> * poly
00554 )
00555 {
00556 Pointlist<L,P,V,S> pts(*poly);
00557 for ( int i = 0; i < num(); i++ ) {
00558 pts += (*this)[i];
00559 }
00560 clear();
00561 (*this) = pts;
00562 }
00563
00564