SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PositionVector.cpp
Go to the documentation of this file.
1 /****************************************************************************/
10 // A list of positions
11 /****************************************************************************/
12 // SUMO, Simulation of Urban MObility; see http://sumo.dlr.de/
13 // Copyright (C) 2001-2015 DLR (http://www.dlr.de/) and contributors
14 /****************************************************************************/
15 //
16 // This file is part of SUMO.
17 // SUMO is free software: you can redistribute it and/or modify
18 // it under the terms of the GNU General Public License as published by
19 // the Free Software Foundation, either version 3 of the License, or
20 // (at your option) any later version.
21 //
22 /****************************************************************************/
23 
24 
25 // ===========================================================================
26 // included modules
27 // ===========================================================================
28 #ifdef _MSC_VER
29 #include <windows_config.h>
30 #else
31 #include <config.h>
32 #endif
33 
34 #include <queue>
35 #include <cmath>
36 #include <iostream>
37 #include <algorithm>
38 #include <cassert>
39 #include <iterator>
40 #include <limits>
41 #include <utils/common/StdDefs.h>
43 #include <utils/common/ToString.h>
44 #include "AbstractPoly.h"
45 #include "Position.h"
46 #include "PositionVector.h"
47 #include "GeomHelper.h"
48 #include "Line.h"
49 #include "Helper_ConvexHull.h"
50 #include "Boundary.h"
51 
52 #ifdef CHECK_MEMORY_LEAKS
53 #include <foreign/nvwa/debug_new.h>
54 #endif // CHECK_MEMORY_LEAKS
55 
56 // ===========================================================================
57 // method definitions
58 // ===========================================================================
60 
61 
62 PositionVector::PositionVector(const std::vector<Position>& v) {
63  std::copy(v.begin(), v.end(), std::back_inserter(*this));
64 }
65 
66 
68 
69 
70 // ------------ Adding items to the container
71 void
73  copy(p.begin(), p.end(), back_inserter(*this));
74 }
75 
76 
77 void
79  insert(begin(), p);
80 }
81 
82 
85  Position first = front();
86  erase(begin());
87  return first;
88 }
89 
90 
91 bool
92 PositionVector::around(const Position& p, SUMOReal offset) const {
93  if (offset != 0) {
94  PositionVector tmp(*this);
95  tmp.scaleAbsolute(offset);
96  return tmp.around(p);
97  }
98  SUMOReal angle = 0;
99  for (const_iterator i = begin(); i != end() - 1; i++) {
100  Position p1(
101  (*i).x() - p.x(),
102  (*i).y() - p.y());
103  Position p2(
104  (*(i + 1)).x() - p.x(),
105  (*(i + 1)).y() - p.y());
106  angle += GeomHelper::Angle2D(p1.x(), p1.y(), p2.x(), p2.y());
107  }
108  Position p1(
109  (*(end() - 1)).x() - p.x(),
110  (*(end() - 1)).y() - p.y());
111  Position p2(
112  (*(begin())).x() - p.x(),
113  (*(begin())).y() - p.y());
114  angle += GeomHelper::Angle2D(p1.x(), p1.y(), p2.x(), p2.y());
115  return (!(fabs(angle) < M_PI));
116 }
117 
118 
119 bool
121  for (const_iterator i = begin(); i != end() - 1; i++) {
122  if (poly.around(*i, offset)) {
123  return true;
124  }
125  }
126  return false;
127 }
128 
129 
130 bool
131 PositionVector::intersects(const Position& p1, const Position& p2) const {
132  if (size() < 2) {
133  return false;
134  }
135  for (const_iterator i = begin(); i != end() - 1; i++) {
136  if (GeomHelper::intersects(*i, *(i + 1), p1, p2)) {
137  return true;
138  }
139  }
140  //return GeomHelper::intersects(*(end()-1), *(begin()), p1, p2);
141  return false;
142 }
143 
144 
145 bool
147  if (size() < 2) {
148  return false;
149  }
150  for (const_iterator i = begin(); i != end() - 1; i++) {
151  if (v1.intersects(*i, *(i + 1))) {
152  return true;
153  }
154  }
155  //return v1.intersects(*(end()-1), *(begin()));
156  return false;
157 }
158 
159 
160 Position
162  const Position& p2) const {
163  for (const_iterator i = begin(); i != end() - 1; i++) {
164  if (GeomHelper::intersects(*i, *(i + 1), p1, p2)) {
165  return GeomHelper::intersection_position2D(*i, *(i + 1), p1, p2);
166  }
167  }
168  return Position::INVALID;
169 }
170 
171 
172 Position
174  for (const_iterator i = begin(); i != end() - 1; i++) {
175  if (v1.intersects(*i, *(i + 1))) {
176  return v1.intersectsAtPoint(*i, *(i + 1));
177  }
178  }
179  /*
180  if(v1.intersects(*(end()-1), *(begin()))) {
181  return v1.intersectsAtPoint(*(end()-1), *(begin()));
182  }
183  */
184  return Position::INVALID;
185 }
186 
187 
188 const Position&
189 PositionVector::operator[](int index) const {
190  if (index >= 0) {
191  return at(index);
192  } else {
193  return at((int)size() + index);
194  }
195 }
196 
197 
198 Position&
200  if (index >= 0) {
201  return at(index);
202  } else {
203  return at((int)size() + index);
204  }
205 }
206 
207 
208 Position
210  const_iterator i = begin();
211  SUMOReal seenLength = 0;
212  do {
213  const SUMOReal nextLength = (*i).distanceTo(*(i + 1));
214  if (seenLength + nextLength > pos) {
215  return positionAtOffset(*i, *(i + 1), pos - seenLength, lateralOffset);
216  }
217  seenLength += nextLength;
218  } while (++i != end() - 1);
219  return back();
220 }
221 
222 
223 Position
225  const_iterator i = begin();
226  SUMOReal seenLength = 0;
227  do {
228  const SUMOReal nextLength = (*i).distanceTo2D(*(i + 1));
229  if (seenLength + nextLength > pos) {
230  return positionAtOffset2D(*i, *(i + 1), pos - seenLength, lateralOffset);
231  }
232  seenLength += nextLength;
233  } while (++i != end() - 1);
234  return back();
235 }
236 
237 
238 SUMOReal
240  if (pos < 0) {
241  pos += length();
242  }
243  const_iterator i = begin();
244  SUMOReal seenLength = 0;
245  do {
246  SUMOReal nextLength = (*i).distanceTo(*(i + 1));
247  if (seenLength + nextLength > pos) {
248  Line l(*i, *(i + 1));
249  return l.atan2DegreeAngle();
250  }
251  seenLength += nextLength;
252  } while (++i != end() - 1);
253  Line l(*(end() - 2), *(end() - 1));
254  return l.atan2DegreeAngle();
255 }
256 
257 SUMOReal
259  const_iterator i = begin();
260  SUMOReal seenLength = 0;
261  do {
262  SUMOReal nextLength = (*i).distanceTo(*(i + 1));
263  if (seenLength + nextLength > pos) {
264  Line l(*i, *(i + 1));
265  return l.atan2DegreeSlope();
266  }
267  seenLength += nextLength;
268  } while (++i != end() - 1);
269  Line l(*(end() - 2), *(end() - 1));
270  return l.atan2DegreeSlope();
271 }
272 
273 Position
275  const Position& p2,
276  SUMOReal pos, SUMOReal lateralOffset) {
277  const SUMOReal dist = p1.distanceTo(p2);
278  if (dist < pos) {
279  return Position::INVALID;
280  }
281  if (lateralOffset != 0) {
282  Line l(p1, p2);
283  l.move2side(-lateralOffset); // move in the same direction as Position::move2side
284  return l.getPositionAtDistance(pos);
285  }
286  return p1 + (p2 - p1) * (pos / dist);
287 }
288 
289 
290 Position
292  const Position& p2,
293  SUMOReal pos, SUMOReal lateralOffset) {
294  const SUMOReal dist = p1.distanceTo2D(p2);
295  if (dist < pos) {
296  return Position::INVALID;
297  }
298  if (lateralOffset != 0) {
299  Line l(p1, p2);
300  l.move2side(-lateralOffset); // move in the same direction as Position::move2side
301  return l.getPositionAtDistance2D(pos);
302  }
303  return p1 + (p2 - p1) * (pos / dist);
304 }
305 
306 
307 Boundary
309  Boundary ret;
310  for (const_iterator i = begin(); i != end(); i++) {
311  ret.add(*i);
312  }
313  return ret;
314 }
315 
316 
317 Position
319  SUMOReal x = 0;
320  SUMOReal y = 0;
321  for (const_iterator i = begin(); i != end(); i++) {
322  x += (*i).x();
323  y += (*i).y();
324  }
325  return Position(x / (SUMOReal) size(), y / (SUMOReal) size());
326 }
327 
328 
329 Position
331  PositionVector tmp = *this;
332  if (!isClosed()) { // make sure its closed
333  tmp.push_back(tmp[0]);
334  }
335  const int endIndex = (int)tmp.size() - 1;
336  SUMOReal div = 0; // 6 * area including sign
337  SUMOReal x = 0;
338  SUMOReal y = 0;
339  if (tmp.area() != 0) { // numerical instability ?
340  // http://en.wikipedia.org/wiki/Polygon
341  for (int i = 0; i < endIndex; i++) {
342  const SUMOReal z = tmp[i].x() * tmp[i + 1].y() - tmp[i + 1].x() * tmp[i].y();
343  div += z; // area formula
344  x += (tmp[i].x() + tmp[i + 1].x()) * z;
345  y += (tmp[i].y() + tmp[i + 1].y()) * z;
346  }
347  div *= 3; // 6 / 2, the 2 comes from the area formula
348  return Position(x / div, y / div);
349  } else {
350  // compute by decomposing into line segments
351  // http://en.wikipedia.org/wiki/Centroid#By_geometric_decomposition
352  SUMOReal lengthSum = 0;
353  for (int i = 0; i < endIndex; i++) {
354  SUMOReal length = tmp[i].distanceTo(tmp[i + 1]);
355  x += (tmp[i].x() + tmp[i + 1].x()) * length / 2;
356  y += (tmp[i].y() + tmp[i + 1].y()) * length / 2;
357  lengthSum += length;
358  }
359  if (lengthSum == 0) {
360  // it is probably only one point
361  return tmp[0];
362  }
363  return Position(x / lengthSum, y / lengthSum);
364  }
365 }
366 
367 
368 void
370  Position centroid = getCentroid();
371  for (int i = 0; i < static_cast<int>(size()); i++) {
372  (*this)[i] = centroid + (((*this)[i] - centroid) * factor);
373  }
374 }
375 
376 
377 void
379  Position centroid = getCentroid();
380  for (int i = 0; i < static_cast<int>(size()); i++) {
381  (*this)[i] = centroid + (((*this)[i] - centroid) + offset);
382  }
383 }
384 
385 
386 Position
388  if (size() == 1) {
389  return (*this)[0];
390  }
391  return positionAtOffset(SUMOReal((length() / 2.)));
392 }
393 
394 
395 SUMOReal
397  SUMOReal len = 0;
398  for (const_iterator i = begin(); i != end() - 1; i++) {
399  len += (*i).distanceTo(*(i + 1));
400  }
401  return len;
402 }
403 
404 SUMOReal
406  SUMOReal len = 0;
407  for (const_iterator i = begin(); i != end() - 1; i++) {
408  len += (*i).distanceTo2D(*(i + 1));
409  }
410  return len;
411 }
412 
413 
414 SUMOReal
416  if (size() < 3) {
417  return 0;
418  }
419  SUMOReal area = 0;
420  PositionVector tmp = *this;
421  if (!isClosed()) { // make sure its closed
422  tmp.push_back(tmp[0]);
423  }
424  const int endIndex = (int)tmp.size() - 1;
425  // http://en.wikipedia.org/wiki/Polygon
426  for (int i = 0; i < endIndex; i++) {
427  area += tmp[i].x() * tmp[i + 1].y() - tmp[i + 1].x() * tmp[i].y();
428  }
429  if (area < 0) { // we whether we had cw or ccw order
430  area *= -1;
431  }
432  return area / 2;
433 }
434 
435 
436 bool
438  for (const_iterator i = begin(); i != end() - 1; i++) {
439  if (poly.around(*i, offset)) {
440  return true;
441  }
442  }
443  return false;
444 }
445 
446 
447 bool
448 PositionVector::crosses(const Position& p1, const Position& p2) const {
449  return intersects(p1, p2);
450 }
451 
452 
453 std::pair<PositionVector, PositionVector>
455  if (size() < 2) {
456  throw InvalidArgument("Vector to short for splitting");
457  }
458  if (where <= POSITION_EPS || where >= length() - POSITION_EPS) {
459  WRITE_WARNING("Splitting vector close to end (pos: " + toString(where) + ", length: " + toString(length()) + ")");
460  }
461  PositionVector first, second;
462  first.push_back((*this)[0]);
463  SUMOReal seen = 0;
464  const_iterator it = begin() + 1;
465  SUMOReal next = first.back().distanceTo(*it);
466  // see how many points we can add to first
467  while (where >= seen + next + POSITION_EPS) {
468  seen += next;
469  first.push_back(*it);
470  it++;
471  next = first.back().distanceTo(*it);
472  }
473  if (fabs(where - (seen + next)) > POSITION_EPS || it == end() - 1) {
474  // we need to insert a new point because 'where' is not close to an
475  // existing point or it is to close to the endpoint
476  Line tmpL(first.back(), *it);
477  Position p = tmpL.getPositionAtDistance(where - seen);
478  first.push_back(p);
479  second.push_back(p);
480  } else {
481  first.push_back(*it);
482  }
483  // add the remaining points to second
484  for (; it != end(); it++) {
485  second.push_back(*it);
486  }
487  assert(first.size() >= 2);
488  assert(second.size() >= 2);
489  assert(first.back() == second.front());
490  assert(fabs(first.length() + second.length() - length()) < 2 * POSITION_EPS);
491  return std::pair<PositionVector, PositionVector>(first, second);
492 }
493 
494 
495 std::ostream&
496 operator<<(std::ostream& os, const PositionVector& geom) {
497  for (PositionVector::const_iterator i = geom.begin(); i != geom.end(); i++) {
498  if (i != geom.begin()) {
499  os << " ";
500  }
501  os << (*i);
502  }
503  return os;
504 }
505 
506 
507 void
509  std::sort(begin(), end(), as_poly_cw_sorter());
510 }
511 
512 
513 void
515  for (int i = 0; i < static_cast<int>(size()); i++) {
516  (*this)[i].add(xoff, yoff, zoff);
517  }
518 }
519 
520 
521 void
523  for (int i = 0; i < static_cast<int>(size()); i++) {
524  (*this)[i].mul(1, -1);
525  }
526 }
527 
528 
529 void
531  for (int i = 0; i < static_cast<int>(size()); i++) {
532  (*this)[i].reshiftRotate(xoff, yoff, rot);
533  }
534 }
535 
536 
537 int
539  const Position& p2) const {
540  return atan2(p1.x(), p1.y()) < atan2(p2.x(), p2.y());
541 }
542 
543 
544 
545 void
547  std::sort(begin(), end(), increasing_x_y_sorter());
548 }
549 
550 
551 
553 
554 
555 
556 int
558  const Position& p2) const {
559  if (p1.x() != p2.x()) {
560  return p1.x() < p2.x();
561  }
562  return p1.y() < p2.y();
563 }
564 
565 
566 
567 SUMOReal
569  const Position& P2) const {
570  return (P1.x() - P0.x()) * (P2.y() - P0.y()) - (P2.x() - P0.x()) * (P1.y() - P0.y());
571 }
572 
573 
576  PositionVector ret = *this;
577  ret.sortAsPolyCWByAngle();
578  return simpleHull_2D(ret);
579 }
580 
581 
584  PositionVector ret;
585  for (const_iterator i = begin(); i != end() - 1; i++) {
586  if (GeomHelper::intersects(*i, *(i + 1), line.p1(), line.p2())) {
588  *i, *(i + 1), line.p1(), line.p2()));
589  }
590  }
591  return ret;
592 }
593 
594 
595 int
597  if (back().distanceTo(v[0]) < 2) { // !!! heuristic
598  copy(v.begin() + 1, v.end(), back_inserter(*this));
599  return 1;
600  }
601  //
602  Line l1((*this)[static_cast<int>(size()) - 2], back());
603  l1.extrapolateBy(100);
604  Line l2(v[0], v[1]);
605  l2.extrapolateBy(100);
606  if (l1.intersects(l2) && l1.intersectsAtLength2D(l2) < l1.length2D() - 100) { // !!! heuristic
607  Position p = l1.intersectsAt(l2);
608  (*this)[static_cast<int>(size()) - 1] = p;
609  copy(v.begin() + 1, v.end(), back_inserter(*this));
610  return 2;
611  } else {
612  copy(v.begin(), v.end(), back_inserter(*this));
613  return 3;
614  }
615 }
616 
617 
618 void
620  if (size() > 0 && v.size() > 0 && back().distanceTo(v[0]) < sameThreshold) {
621  copy(v.begin() + 1, v.end(), back_inserter(*this));
622  } else {
623  copy(v.begin(), v.end(), back_inserter(*this));
624  }
625 }
626 
627 
629 PositionVector::getSubpart(SUMOReal beginOffset, SUMOReal endOffset) const {
630  PositionVector ret;
631  Position begPos = front();
632  if (beginOffset > POSITION_EPS) {
633  begPos = positionAtOffset(beginOffset);
634  }
635  Position endPos = back();
636  if (endOffset < length() - POSITION_EPS) {
637  endPos = positionAtOffset(endOffset);
638  }
639  ret.push_back(begPos);
640 
641  SUMOReal seen = 0;
642  const_iterator i = begin();
643  // skip previous segments
644  while ((i + 1) != end()
645  &&
646  seen + (*i).distanceTo(*(i + 1)) < beginOffset) {
647  seen += (*i).distanceTo(*(i + 1));
648  i++;
649  }
650  // append segments in between
651  while ((i + 1) != end()
652  &&
653  seen + (*i).distanceTo(*(i + 1)) < endOffset) {
654 
655  ret.push_back_noDoublePos(*(i + 1));
656  /*
657  if(ret.at(-1)!=*(i+1)) {
658  ret.push_back(*(i+1));
659  }
660  */
661  seen += (*i).distanceTo(*(i + 1));
662  i++;
663  }
664  // append end
665  ret.push_back_noDoublePos(endPos);
666  return ret;
667 }
668 
669 
671 PositionVector::getSubpart2D(SUMOReal beginOffset, SUMOReal endOffset) const {
672  PositionVector ret;
673  Position begPos = front();
674  if (beginOffset > POSITION_EPS) {
675  begPos = positionAtOffset2D(beginOffset);
676  }
677  Position endPos = back();
678  if (endOffset < length() - POSITION_EPS) {
679  endPos = positionAtOffset2D(endOffset);
680  }
681  ret.push_back(begPos);
682 
683  SUMOReal seen = 0;
684  const_iterator i = begin();
685  // skip previous segments
686  while ((i + 1) != end()
687  &&
688  seen + (*i).distanceTo2D(*(i + 1)) < beginOffset) {
689  seen += (*i).distanceTo2D(*(i + 1));
690  i++;
691  }
692  // append segments in between
693  while ((i + 1) != end()
694  &&
695  seen + (*i).distanceTo2D(*(i + 1)) < endOffset) {
696 
697  ret.push_back_noDoublePos(*(i + 1));
698  /*
699  if(ret.at(-1)!=*(i+1)) {
700  ret.push_back(*(i+1));
701  }
702  */
703  seen += (*i).distanceTo2D(*(i + 1));
704  i++;
705  }
706  // append end
707  ret.push_back_noDoublePos(endPos);
708  return ret;
709 }
710 
711 
712 void
714  // find minimum distance (from the begin)
715  size_t pos = 0;
716  SUMOReal dist = 1000000;
717  size_t currPos = 0;
719  GeomHelper::extrapolate_first(*(begin()), *(begin() + 1), 100),
720  *(begin() + 1));
721 // assert(currDist>=0);
722  if (currDist >= 0 && currDist < dist) {
723  dist = currDist;
724  pos = currPos;
725  }
726 
727  for (iterator i = begin(); i != end() - 1; i++, currPos++) {
728  SUMOReal currDist = GeomHelper::distancePointLine(p, *i, *(i + 1));
729  if (currDist >= 0 && currDist < dist) {
730  dist = currDist;
731  pos = currPos;
732  }
733  }
734  // remove leading items
735  for (size_t j = 0; j < pos; j++) {
736  erase(begin());
737  }
738  // replace first item by the new position
740  (*this)[0], (*this)[1], p);
741  if (lpos == GeomHelper::INVALID_OFFSET) {
742  return;
743  }
744  Position np = positionAtOffset(lpos);
745  if (np != *(begin())) {
746  erase(begin());
747  if (np != *(begin())) {
748  insert(begin(), p);
749  assert(size() > 1);
750  assert(*(begin()) != *(end() - 1));
751  }
752  }
753 }
754 
755 
757 PositionVector::getSubpartByIndex(int beginIndex, int count) const {
758  if (beginIndex < 0) {
759  beginIndex += (int)size();
760  }
761  assert(count > 0);
762  assert(beginIndex < (int)size());
763  assert(beginIndex + count <= (int)size());
764  PositionVector result;
765  for (int i = beginIndex; i < beginIndex + count; ++i) {
766  result.push_back((*this)[i]);
767  }
768  return result;
769 }
770 
771 
772 void
774  // find minimum distance (from the end)
775  size_t pos = 0;
776  SUMOReal dist = 1000000;
777  size_t currPos = 0;
779  *(end() - 1),
780  GeomHelper::extrapolate_second(*(end() - 2), *(end() - 1), 100));
781 // assert(currDist>=0);
782  if (currDist >= 0 && currDist < dist) {
783  dist = currDist;
784  pos = currPos;
785  }
786 
787  for (reverse_iterator i = rbegin(); i != rend() - 1; i++, currPos++) {
788  SUMOReal currDist = GeomHelper::distancePointLine(p, *(i), *(i + 1));
789  if (currDist >= 0 && currDist < dist) {
790  dist = currDist;
791  pos = currPos;
792  }
793  }
794  // remove trailing items
795  for (size_t j = 0; j < pos; j++) {
796  erase(end() - 1);
797  }
798  // replace last item by the new position
799  SUMOReal lpos =
801  (*this)[static_cast<int>(size()) - 1], (*this)[static_cast<int>(size()) - 2], p);
802  if (lpos == GeomHelper::INVALID_OFFSET) {
803  return;
804  }
806  length() - lpos);
807  if (np != *(end() - 1)) {
808  erase(end() - 1);
809  if (np != *(end() - 1)) {
810  push_back(np);
811  assert(size() > 1);
812  assert(*(begin()) != *(end() - 1));
813  }
814  }
815 }
816 
817 
818 SUMOReal
820  Line tmp(front(), back());
821  return tmp.atan2Angle();
822 }
823 
824 
825 void
827  if (i >= 0) {
828  erase(begin() + i);
829  } else {
830  erase(end() + i);
831  }
832 }
833 
834 
835 SUMOReal
836 PositionVector::nearest_offset_to_point2D(const Position& p, bool perpendicular) const {
839  SUMOReal seen = 0;
840  for (const_iterator i = begin(); i != end() - 1; i++) {
841  const SUMOReal pos =
842  GeomHelper::nearest_offset_on_line_to_point2D(*i, *(i + 1), p, perpendicular);
843  const SUMOReal dist = pos == GeomHelper::INVALID_OFFSET ? minDist : p.distanceTo2D(Line(*i, *(i + 1)).getPositionAtDistance2D(pos));
844  if (dist < minDist) {
845  nearestPos = pos + seen;
846  minDist = dist;
847  }
848  if (perpendicular && i != begin() && pos == GeomHelper::INVALID_OFFSET) {
849  // even if perpendicular is set we still need to check the distance to the inner points
850  const SUMOReal cornerDist = p.distanceTo2D(*i);
851  if (cornerDist < minDist) {
852  const SUMOReal pos1 =
853  GeomHelper::nearest_offset_on_line_to_point2D(*(i - 1), *i, p, false);
854  const SUMOReal pos2 =
855  GeomHelper::nearest_offset_on_line_to_point2D(*i, *(i + 1), p, false);
856  if (pos1 == (*(i - 1)).distanceTo2D(*i) && pos2 == 0.) {
857  nearestPos = seen;
858  minDist = cornerDist;
859  }
860  }
861  }
862  seen += (*i).distanceTo2D(*(i + 1));
863  }
864  return nearestPos;
865 }
866 
867 
868 Position
870  // XXX this duplicates most of the code in nearest_offset_to_point2D. It should be refactored
871  if (extend) {
872  PositionVector extended = *this;
873  const SUMOReal dist = 2 * distance(p);
874  extended.extrapolate(dist);
875  return extended.transformToVectorCoordinates(p) - Position(dist, 0);
876  }
878  SUMOReal nearestPos = -1;
879  SUMOReal seen = 0;
880  int sign = 1;
881  for (const_iterator i = begin(); i != end() - 1; i++) {
882  const SUMOReal pos =
883  GeomHelper::nearest_offset_on_line_to_point2D(*i, *(i + 1), p, true);
884  const SUMOReal dist = pos < 0 ? minDist : p.distanceTo2D(Line(*i, *(i + 1)).getPositionAtDistance(pos));
885  if (dist < minDist) {
886  nearestPos = pos + seen;
887  minDist = dist;
888  sign = isLeft(*i, *(i + 1), p) >= 0 ? -1 : 1;
889  }
890  if (i != begin() && pos == GeomHelper::INVALID_OFFSET) {
891  // even if perpendicular is set we still need to check the distance to the inner points
892  const SUMOReal cornerDist = p.distanceTo2D(*i);
893  if (cornerDist < minDist) {
894  const SUMOReal pos1 =
895  GeomHelper::nearest_offset_on_line_to_point2D(*(i - 1), *i, p, false);
896  const SUMOReal pos2 =
897  GeomHelper::nearest_offset_on_line_to_point2D(*i, *(i + 1), p, false);
898  if (pos1 == (*(i - 1)).distanceTo2D(*i) && pos2 == 0.) {
899  nearestPos = seen;
900  minDist = cornerDist;
901  sign = isLeft(*(i - 1), *i, p) >= 0 ? -1 : 1;
902  }
903  }
904  }
905  seen += (*i).distanceTo2D(*(i + 1));
906  }
907  if (nearestPos != -1) {
908  return Position(nearestPos, sign * minDist);
909  } else {
910  return Position::INVALID;
911  }
912 }
913 
914 
915 int
917  assert(size() > 0);
919  SUMOReal dist;
920  int closest = 0;
921  for (int i = 0; i < (int)size(); i++) {
922  dist = p.distanceTo((*this)[i]);
923  if (dist < minDist) {
924  closest = i;
925  minDist = dist;
926  }
927  }
928  return closest;
929 }
930 
931 
932 int
934  Position outIntersection = Position();
936  SUMOReal dist;
937  int insertionIndex = 1;
938  for (int i = 0; i < (int)size() - 1; i++) {
939  dist = GeomHelper::closestDistancePointLine2D(p, (*this)[i], (*this)[i + 1], outIntersection);
940  if (dist < minDist) {
941  insertionIndex = i + 1;
942  minDist = dist;
943  }
944  }
945  insertAt(insertionIndex, p);
946  return insertionIndex;
947 }
948 
949 
950 std::vector<SUMOReal>
952  std::vector<SUMOReal> ret;
953  for (const_iterator i = other.begin(); i != other.end() - 1; i++) {
954  std::vector<SUMOReal> atSegment = intersectsAtLengths2D(Line(*i, *(i + 1)));
955  copy(atSegment.begin(), atSegment.end(), back_inserter(ret));
956  }
957  return ret;
958 }
959 
960 
961 std::vector<SUMOReal>
963  std::vector<SUMOReal> ret;
964  SUMOReal pos = 0;
965  for (const_iterator i = begin(); i != end() - 1; i++) {
966  Line l((*i), *(i + 1));
967  if (GeomHelper::intersects(l.p1(), l.p2(), line.p1(), line.p2())) {
968  Position p =
969  GeomHelper::intersection_position2D(l.p1(), l.p2(), line.p1(), line.p2());
970  SUMOReal atLength = p.distanceTo2D(l.p1());
971  ret.push_back(atLength + pos);
972  }
973  pos += l.length2D();
974  }
975  return ret;
976 }
977 
978 
979 void
981  assert(size() > 1);
982  Position nb =
983  GeomHelper::extrapolate_first((*this)[0], (*this)[1], val);
984  Position ne =
986  (*this)[static_cast<int>(size()) - 2], (*this)[static_cast<int>(size()) - 1], val);
987  erase(begin());
988  push_front(nb);
989  erase(end() - 1);
990  push_back(ne);
991 }
992 
993 
996  PositionVector ret;
997  for (const_reverse_iterator i = rbegin(); i != rend(); i++) {
998  ret.push_back(*i);
999  }
1000  return ret;
1001 }
1002 
1003 
1004 void
1006  if (size() < 2) {
1007  return;
1008  }
1009  PositionVector shape;
1010  for (int i = 0; i < static_cast<int>(size()); i++) {
1011  if (i == 0) {
1012  Position from = (*this)[i];
1013  Position to = (*this)[i + 1];
1014  std::pair<SUMOReal, SUMOReal> offsets =
1015  GeomHelper::getNormal90D_CW(from, to, amount);
1016  shape.push_back(Position(from.x() - offsets.first,
1017  from.y() - offsets.second, from.z()));
1018  } else if (i == static_cast<int>(size()) - 1) {
1019  Position from = (*this)[i - 1];
1020  Position to = (*this)[i];
1021  std::pair<SUMOReal, SUMOReal> offsets =
1022  GeomHelper::getNormal90D_CW(from, to, amount);
1023  shape.push_back(Position(to.x() - offsets.first,
1024  to.y() - offsets.second, to.z()));
1025  } else {
1026  Position from = (*this)[i - 1];
1027  Position me = (*this)[i];
1028  Position to = (*this)[i + 1];
1029  Line fromMe(from, me);
1030  fromMe.extrapolateBy2D(me.distanceTo2D(to));
1031  const double extrapolateDev = fromMe.p2().distanceTo2D(to);
1032  if (fabs(extrapolateDev) < POSITION_EPS) {
1033  // parallel case, just shift the middle point
1034  std::pair<SUMOReal, SUMOReal> off =
1035  GeomHelper::getNormal90D_CW(from, to, amount);
1036  shape.push_back(Position(me.x() - off.first, me.y() - off.second, me.z()));
1037  continue;
1038  }
1039  if (fabs(extrapolateDev - 2 * me.distanceTo2D(to)) < POSITION_EPS) {
1040  // counterparallel case, just shift the middle point
1041  Line fromMe(from, me);
1042  fromMe.extrapolateBy2D(amount);
1043  shape.push_back(fromMe.p2());
1044  continue;
1045  }
1046  std::pair<SUMOReal, SUMOReal> offsets =
1047  GeomHelper::getNormal90D_CW(from, me, amount);
1048  std::pair<SUMOReal, SUMOReal> offsets2 =
1049  GeomHelper::getNormal90D_CW(me, to, amount);
1050  Line l1(
1051  Position(from.x() - offsets.first, from.y() - offsets.second),
1052  Position(me.x() - offsets.first, me.y() - offsets.second));
1053  l1.extrapolateBy2D(100);
1054  Line l2(
1055  Position(me.x() - offsets2.first, me.y() - offsets2.second),
1056  Position(to.x() - offsets2.first, to.y() - offsets2.second));
1057  l2.extrapolateBy2D(100);
1058  if (l1.intersects(l2)) {
1059  shape.push_back(l1.intersectsAt(l2));
1060  } else {
1061  throw InvalidArgument("no line intersection");
1062  }
1063  }
1064  }
1065 
1066  /*
1067  ContType newCont;
1068  std::pair<SUMOReal, SUMOReal> p;
1069  Position newPos;
1070  // first point
1071  newPos = (*(begin()));
1072  p = GeomHelper::getNormal90D_CW(*(begin()), *(begin()+1), amount);
1073  newPos.add(p.first, p.second);
1074  newCont.push_back(newPos);
1075  // middle points
1076  for(const_iterator i=begin()+1; i!=end()-1; i++) {
1077  std::pair<SUMOReal, SUMOReal> oldp = p;
1078  newPos = *i;
1079  newPos.add(p.first, p.second);
1080  newCont.push_back(newPos);
1081  p = GeomHelper::getNormal90D_CW(*i, *(i+1), amount);
1082  // Position newPos(*i);
1083  // newPos.add((p.first+oldp.first)/2.0, (p.second+oldp.second)/2.0);
1084  // newCont.push_back(newPos);
1085  }
1086  // last point
1087  newPos = (*(end()-1));
1088  newPos.add(p.first, p.second);
1089  newCont.push_back(newPos);
1090  myCont = newCont;
1091  */
1092  *this = shape;
1093 }
1094 
1095 
1096 Line
1097 PositionVector::lineAt(int pos) const {
1098  assert((int)size() > pos + 1);
1099  return Line((*this)[pos], (*this)[pos + 1]);
1100 }
1101 
1102 
1103 Line
1105  return lineAt(0);
1106 }
1107 
1108 
1109 Line
1111  return lineAt((int)size() - 2);
1112 }
1113 
1114 
1115 void
1117  if (size() == 0 || (*this)[0] == back()) {
1118  return;
1119  }
1120  push_back((*this)[0]);
1121 }
1122 
1123 
1124 std::vector<SUMOReal>
1125 PositionVector::distances(const PositionVector& s, bool perpendicular) const {
1126  std::vector<SUMOReal> ret;
1127  const_iterator i;
1128  for (i = begin(); i != end(); i++) {
1129  const SUMOReal dist = s.distance(*i, perpendicular);
1130  if (dist != GeomHelper::INVALID_OFFSET) {
1131  ret.push_back(dist);
1132  }
1133  }
1134  for (i = s.begin(); i != s.end(); i++) {
1135  const SUMOReal dist = distance(*i, perpendicular);
1136  if (dist != GeomHelper::INVALID_OFFSET) {
1137  ret.push_back(dist);
1138  }
1139  }
1140  return ret;
1141 }
1142 
1143 
1144 SUMOReal
1145 PositionVector::distance(const Position& p, bool perpendicular) const {
1146  if (size() == 0) {
1148  } else if (size() == 1) {
1149  return front().distanceTo(p);
1150  }
1151  const SUMOReal nearestOffset = nearest_offset_to_point2D(p, perpendicular);
1152  if (nearestOffset == GeomHelper::INVALID_OFFSET) {
1154  } else {
1155  return p.distanceTo2D(positionAtOffset2D(nearestOffset));
1156  }
1157 }
1158 
1159 
1160 void
1161 PositionVector::insertAt(int index, const Position& p) {
1162  if (index >= 0) {
1163  insert(begin() + index, p);
1164  } else {
1165  insert(end() + index, p);
1166  }
1167 }
1168 
1169 
1170 void
1171 PositionVector::replaceAt(int index, const Position& p) {
1172  assert(index < static_cast<int>(size()));
1173  assert(index + static_cast<int>(size()) >= 0);
1174  if (index >= 0) {
1175  (*this)[index] = p;
1176  } else {
1177  (*this)[index + static_cast<int>(size())] = p;
1178  }
1179 }
1180 
1181 
1182 void
1184  if (size() == 0 || !p.almostSame(back())) {
1185  push_back(p);
1186  }
1187 }
1188 
1189 
1190 void
1192  if (size() == 0 || !p.almostSame(front())) {
1193  insert(begin(), p);
1194  }
1195 }
1196 
1197 
1198 bool
1200  return size() >= 2 && (*this)[0] == back();
1201 }
1202 
1203 
1204 void
1205 PositionVector::removeDoublePoints(SUMOReal minDist, bool assertLength) {
1206  if (size() > 1) {
1207  iterator last = begin();
1208  for (iterator i = begin() + 1; i != end() && (!assertLength || size() > 2);) {
1209  if (last->almostSame(*i, minDist)) {
1210  i = erase(i);
1211  } else {
1212  last = i;
1213  ++i;
1214  }
1215  }
1216  }
1217 }
1218 
1219 
1220 void
1222  if (size() > 2) {
1223  Position& last = front();
1224  for (iterator i = begin() + 1; i != end() - 1;) {
1225  if (GeomHelper::distancePointLine(*i, last, *(i + 1)) < 0.001) {
1226  i = erase(i);
1227  } else {
1228  last = *i;
1229  ++i;
1230  }
1231  }
1232  }
1233 }
1234 
1235 
1236 bool
1238  if (size() == v2.size()) {
1239  for (int i = 0; i < (int)size(); i++) {
1240  if ((*this)[i] != v2[i]) {
1241  return false;
1242  }
1243  }
1244  return true;
1245  } else {
1246  return false;
1247  }
1248 }
1249 
1250 
1251 bool
1253  if (size() > 2) {
1254  return false;
1255  }
1256  for (const_iterator i = begin(); i != end() - 1; i++) {
1257  if ((*i).z() != (*(i + 1)).z()) {
1258  return true;
1259  }
1260  }
1261  return false;
1262 }
1263 
1264 /****************************************************************************/
1265 
SUMOReal length2D() const
Definition: Line.cpp:186
SUMOReal atan2DegreeAngle() const
Definition: Line.cpp:152
static std::pair< SUMOReal, SUMOReal > getNormal90D_CW(const Position &beg, const Position &end, SUMOReal length, SUMOReal wanted_offset)
Definition: GeomHelper.cpp:373
const Position & p2() const
Definition: Line.cpp:95
static SUMOReal Angle2D(SUMOReal x1, SUMOReal y1, SUMOReal x2, SUMOReal y2)
Definition: GeomHelper.cpp:224
bool hasElevation() const
return whether two positions differ in z-coordinate
SUMOReal distance(const Position &p, bool perpendicular=false) const
void pruneFromBeginAt(const Position &p)
static Position intersection_position2D(const Position &p11, const Position &p12, const Position &p21, const Position &p22)
returns the intersection point of the (infinite) lines p11,p12 and p21,p22. If the given lines are pa...
Definition: GeomHelper.cpp:203
SUMOReal nearest_offset_to_point2D(const Position &p, bool perpendicular=true) const
PositionVector getSubpart2D(SUMOReal beginOffset, SUMOReal endOffset) const
void sortAsPolyCWByAngle()
void replaceAt(int index, const Position &by)
SUMOReal intersectsAtLength2D(const Line &v)
returns distance between myP1 and intersection or -1 if line segments do not intersect ...
Definition: Line.cpp:229
void insertAt(int index, const Position &p)
#define M_PI
Definition: angles.h:37
SUMOReal atan2DegreeSlope() const
Definition: Line.cpp:168
Position getPositionAtDistance2D(SUMOReal offset) const
Definition: Line.cpp:114
Line getEndLine() const
Position getCentroid() const
Returns the centroid (closes the polygon if unclosed)
bool intersects(const Position &p1, const Position &p2) const
void scaleRelative(SUMOReal factor)
enlarges/shrinks the polygon by a factor based at the centroid
PositionVector getSubpartByIndex(int beginIndex, int count) const
bool partialWithin(const AbstractPoly &poly, SUMOReal offset=0) const
Returns the information whether this polygon lies partially within the given polygon.
static Position extrapolate_second(const Position &p1, const Position &p2, SUMOReal length)
Definition: GeomHelper.cpp:253
SUMOReal distanceTo(const Position &p2) const
returns the euclidean distance in 3 dimension
Definition: Position.h:229
void eraseAt(int i)
bool around(const Position &p, SUMOReal offset=0) const
Returns the information whether the position vector describes a polygon lying around the given point ...
bool almostSame(const Position &p2, SUMOReal maxDiv=POSITION_EPS) const
Definition: Position.h:223
static Position extrapolate_first(const Position &p1, const Position &p2, SUMOReal length)
Definition: GeomHelper.cpp:245
SUMOReal beginEndAngle() const
bool isClosed() const
const Position & operator[](int index) const
returns the position at the given index !!! exceptions?
SUMOReal x() const
Returns the x-position.
Definition: Position.h:63
Position positionAtOffset2D(SUMOReal pos, SUMOReal lateralOffset=0) const
Returns the position at the given length.
A class that stores a 2D geometrical boundary.
Definition: Boundary.h:48
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:200
PositionVector reverse() const
SUMOReal slopeDegreeAtOffset(SUMOReal pos) const
Returns the slope at the given length.
PositionVector convexHull() const
~PositionVector()
Destructor.
SUMOReal length2D() const
Returns the length.
std::vector< SUMOReal > distances(const PositionVector &s, bool perpendicular=false) const
Position getPositionAtDistance(SUMOReal offset) const
Definition: Line.cpp:101
static SUMOReal nearest_offset_on_line_to_point2D(const Position &l1, const Position &l2, const Position &p, bool perpendicular=true)
Definition: GeomHelper.cpp:261
Line lineAt(int pos) const
static bool intersects(const Position &p11, const Position &p12, const Position &p21, const Position &p22)
return whether given lines intersect
Definition: GeomHelper.cpp:145
void push_front_noDoublePos(const Position &p)
const Position & p1() const
Definition: Line.cpp:89
#define max(a, b)
Definition: polyfonts.c:65
void reshiftRotate(SUMOReal xoff, SUMOReal yoff, SUMOReal rot)
void mirrorX()
mirror coordinates along the x-axis
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:46
Position pop_front()
Removes and returns the position at the fron of the list.
A list of positions.
void add(SUMOReal xoff, SUMOReal yoff, SUMOReal zoff)
int indexOfClosest(const Position &p) const
int operator()(const Position &p1, const Position &p2) const
comparing operation
void push_front(const Position &p)
Puts the given position at the front of the list.
static SUMOReal distancePointLine(const Position &point, const Position &lineStart, const Position &lineEnd)
Definition: GeomHelper.cpp:288
void move2side(SUMOReal amount)
Definition: Line.cpp:127
SUMOReal z() const
Returns the z-position.
Definition: Position.h:73
static SUMOReal closestDistancePointLine2D(const Position &point, const Position &lineStart, const Position &lineEnd, Position &outIntersection)
Definition: GeomHelper.cpp:312
Position positionAtOffset(SUMOReal pos, SUMOReal lateralOffset=0) const
Returns the position at the given length.
Definition: Line.h:51
#define POSITION_EPS
Definition: config.h:189
int insertAtClosest(const Position &p)
std::string toString(const T &t, std::streamsize accuracy=OUTPUT_ACCURACY)
Definition: ToString.h:53
Position intersectsAtPoint(const Position &p1, const Position &p2) const
SUMOReal atan2Angle() const
Definition: Line.cpp:146
bool intersects(const Line &l) const
Definition: Line.cpp:180
bool operator==(const PositionVector &v2) const
comparing operation
std::pair< PositionVector, PositionVector > splitAt(SUMOReal where) const
Returns the two lists made when this list vector is splitted at the given point.
virtual bool around(const Position &p, SUMOReal offset=0) const =0
void extrapolate(SUMOReal val)
PositionVector()
Constructor.
void extrapolateBy(SUMOReal length)
Definition: Line.cpp:60
SUMOReal length() const
Returns the length.
SUMOReal rotationDegreeAtOffset(SUMOReal pos) const
Returns the rotation at the given length.
void push_back(const PositionVector &p)
Appends all positions from the given vector.
void add(SUMOReal x, SUMOReal y)
Makes the boundary include the given coordinate.
Definition: Boundary.cpp:76
PositionVector simpleHull_2D(const PositionVector &V)
#define sign(a)
Definition: polyfonts.c:68
void removeDoublePoints(SUMOReal minDist=POSITION_EPS, bool assertLength=false)
Removes positions if too near.
PositionVector intersectionPoints2D(const Line &line) const
int appendWithCrossingPoint(const PositionVector &v)
void scaleAbsolute(SUMOReal offset)
enlarges/shrinks the polygon by an absolute offset based at the centroid
SUMOReal y() const
Returns the y-position.
Definition: Position.h:68
bool overlapsWith(const AbstractPoly &poly, SUMOReal offset=0) const
Returns the information whether the given polygon overlaps with this Again a boundary may be specifie...
Line getBegLine() const
void pruneFromEndAt(const Position &p)
Position getLineCenter() const
void extrapolateBy2D(SUMOReal length)
Definition: Line.cpp:69
SUMOReal distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition: Position.h:240
void move2side(SUMOReal amount)
#define SUMOReal
Definition: config.h:215
void push_back_noDoublePos(const Position &p)
int operator()(const Position &p1, const Position &p2) const
comparing operation
Position getPolygonCenter() const
Returns the arithmetic of all corner points.
SUMOReal area() const
Returns the area (0 for non-closed)
std::ostream & operator<<(std::ostream &os, const MTRand &mtrand)
std::vector< SUMOReal > intersectsAtLengths2D(const PositionVector &other) const
For all intersections between this vector and other, return the 2D-length of the subvector from this ...
void closePolygon()
ensures that the last position equals the first
Boundary getBoxBoundary() const
Returns a boundary enclosing this list of lines.
bool crosses(const Position &p1, const Position &p2) const
Position intersectsAt(const Line &l) const
Definition: Line.cpp:174
PositionVector getSubpart(SUMOReal beginOffset, SUMOReal endOffset) const
void append(const PositionVector &v, SUMOReal sameThreshold=2.0)
static const SUMOReal INVALID_OFFSET
a value to signify offsets outside the range of [0, Line.length()]
Definition: GeomHelper.h:59
SUMOReal isLeft(const Position &P0, const Position &P1, const Position &P2) const
static const Position INVALID
Definition: Position.h:262
Position transformToVectorCoordinates(const Position &p, bool extend=false) const
return position p within the length-wise coordinate system defined by this position vector...