SUMO - Simulation of Urban MObility
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-2016 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 "Helper_ConvexHull.h"
49 #include "Boundary.h"
50 
51 #ifdef CHECK_MEMORY_LEAKS
52 #include <foreign/nvwa/debug_new.h>
53 #endif // CHECK_MEMORY_LEAKS
54 
55 // ===========================================================================
56 // method definitions
57 // ===========================================================================
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 
67 PositionVector::PositionVector(const std::vector<Position>::const_iterator beg, const std::vector<Position>::const_iterator end) {
68  std::copy(beg, end, std::back_inserter(*this));
69 }
70 
71 
73  push_back(p1);
74  push_back(p2);
75 }
76 
77 
79 
80 
81 bool
82 PositionVector::around(const Position& p, SUMOReal offset) const {
83  if (offset != 0) {
84  PositionVector tmp(*this);
85  tmp.scaleAbsolute(offset);
86  return tmp.around(p);
87  }
88  SUMOReal angle = 0;
89  for (const_iterator i = begin(); i != end() - 1; i++) {
90  Position p1(
91  (*i).x() - p.x(),
92  (*i).y() - p.y());
93  Position p2(
94  (*(i + 1)).x() - p.x(),
95  (*(i + 1)).y() - p.y());
96  angle += GeomHelper::angle2D(p1, p2);
97  }
98  Position p1(
99  (*(end() - 1)).x() - p.x(),
100  (*(end() - 1)).y() - p.y());
101  Position p2(
102  (*(begin())).x() - p.x(),
103  (*(begin())).y() - p.y());
104  angle += GeomHelper::angle2D(p1, p2);
105  return (!(fabs(angle) < M_PI));
106 }
107 
108 
109 bool
111  for (const_iterator i = begin(); i != end() - 1; i++) {
112  if (poly.around(*i, offset)) {
113  return true;
114  }
115  }
116  return false;
117 }
118 
119 
120 bool
121 PositionVector::intersects(const Position& p1, const Position& p2) const {
122  if (size() < 2) {
123  return false;
124  }
125  for (const_iterator i = begin(); i != end() - 1; i++) {
126  if (intersects(*i, *(i + 1), p1, p2)) {
127  return true;
128  }
129  }
130  return false;
131 }
132 
133 
134 bool
136  if (size() < 2) {
137  return false;
138  }
139  for (const_iterator i = begin(); i != end() - 1; i++) {
140  if (v1.intersects(*i, *(i + 1))) {
141  return true;
142  }
143  }
144  return false;
145 }
146 
147 
148 Position
149 PositionVector::intersectionPosition2D(const Position& p1, const Position& p2, const SUMOReal withinDist) const {
150  for (const_iterator i = begin(); i != end() - 1; i++) {
151  SUMOReal x, y, m;
152  if (intersects(*i, *(i + 1), p1, p2, withinDist, &x, &y, &m)) {
153  return Position(x, y);
154  }
155  }
156  return Position::INVALID;
157 }
158 
159 
160 Position
162  for (const_iterator i = begin(); i != end() - 1; i++) {
163  if (v1.intersects(*i, *(i + 1))) {
164  return v1.intersectionPosition2D(*i, *(i + 1));
165  }
166  }
167  return Position::INVALID;
168 }
169 
170 
171 const Position&
172 PositionVector::operator[](int index) const {
173  if (index >= 0) {
174  return at(index);
175  } else {
176  return at((int)size() + index);
177  }
178 }
179 
180 
181 Position&
183  if (index >= 0) {
184  return at(index);
185  } else {
186  return at((int)size() + index);
187  }
188 }
189 
190 
191 Position
193  const_iterator i = begin();
194  SUMOReal seenLength = 0;
195  do {
196  const SUMOReal nextLength = (*i).distanceTo(*(i + 1));
197  if (seenLength + nextLength > pos) {
198  return positionAtOffset(*i, *(i + 1), pos - seenLength, lateralOffset);
199  }
200  seenLength += nextLength;
201  } while (++i != end() - 1);
202  return back();
203 }
204 
205 
206 Position
208  const_iterator i = begin();
209  SUMOReal seenLength = 0;
210  do {
211  const SUMOReal nextLength = (*i).distanceTo2D(*(i + 1));
212  if (seenLength + nextLength > pos) {
213  return positionAtOffset2D(*i, *(i + 1), pos - seenLength, lateralOffset);
214  }
215  seenLength += nextLength;
216  } while (++i != end() - 1);
217  return back();
218 }
219 
220 
221 SUMOReal
223  if (pos < 0) {
224  pos += length();
225  }
226  const_iterator i = begin();
227  SUMOReal seenLength = 0;
228  do {
229  const Position& p1 = *i;
230  const Position& p2 = *(i + 1);
231  const SUMOReal nextLength = p1.distanceTo(p2);
232  if (seenLength + nextLength > pos) {
233  return p1.angleTo2D(p2);
234  }
235  seenLength += nextLength;
236  } while (++i != end() - 1);
237  const Position& p1 = (*this)[-2];
238  const Position& p2 = back();
239  return p1.angleTo2D(p2);
240 }
241 
242 
243 SUMOReal
246 }
247 
248 
249 SUMOReal
251  const_iterator i = begin();
252  SUMOReal seenLength = 0;
253  do {
254  const Position& p1 = *i;
255  const Position& p2 = *(i + 1);
256  const SUMOReal nextLength = p1.distanceTo(p2);
257  if (seenLength + nextLength > pos) {
258  return RAD2DEG(atan2(p2.z() - p1.z(), p1.distanceTo2D(p2)));
259  }
260  seenLength += nextLength;
261  } while (++i != end() - 1);
262  const Position& p1 = (*this)[-2];
263  const Position& p2 = back();
264  return RAD2DEG(atan2(p2.z() - p1.z(), p1.distanceTo2D(p2)));
265 }
266 
267 
268 Position
269 PositionVector::positionAtOffset(const Position& p1, const Position& p2, SUMOReal pos, SUMOReal lateralOffset) {
270  const SUMOReal dist = p1.distanceTo(p2);
271  if (pos < 0 || dist < pos) {
272  return Position::INVALID;
273  }
274  if (lateralOffset != 0) {
275  const Position offset = sideOffset(p1, p2, -lateralOffset); // move in the same direction as Position::move2side
276  if (pos == 0.) {
277  return p1 + offset;
278  }
279  return p1 + (p2 - p1) * (pos / dist) + offset;
280  }
281  if (pos == 0.) {
282  return p1;
283  }
284  return p1 + (p2 - p1) * (pos / dist);
285 }
286 
287 
288 Position
289 PositionVector::positionAtOffset2D(const Position& p1, const Position& p2, SUMOReal pos, SUMOReal lateralOffset) {
290  const SUMOReal dist = p1.distanceTo2D(p2);
291  if (pos < 0 || dist < pos) {
292  return Position::INVALID;
293  }
294  if (lateralOffset != 0) {
295  const Position offset = sideOffset(p1, p2, -lateralOffset); // move in the same direction as Position::move2side
296  if (pos == 0.) {
297  return p1 + offset;
298  }
299  return p1 + (p2 - p1) * (pos / dist) + offset;
300  }
301  if (pos == 0.) {
302  return p1;
303  }
304  return p1 + (p2 - p1) * (pos / dist);
305 }
306 
307 
308 Boundary
310  Boundary ret;
311  for (const_iterator i = begin(); i != end(); i++) {
312  ret.add(*i);
313  }
314  return ret;
315 }
316 
317 
318 Position
320  SUMOReal x = 0;
321  SUMOReal y = 0;
322  SUMOReal z = 0;
323  for (const_iterator i = begin(); i != end(); i++) {
324  x += (*i).x();
325  y += (*i).y();
326  z += (*i).z();
327  }
328  return Position(x / (SUMOReal) size(), y / (SUMOReal) size(), z / (SUMOReal)size());
329 }
330 
331 
332 Position
334  PositionVector tmp = *this;
335  if (!isClosed()) { // make sure its closed
336  tmp.push_back(tmp[0]);
337  }
338  const int endIndex = (int)tmp.size() - 1;
339  SUMOReal div = 0; // 6 * area including sign
340  SUMOReal x = 0;
341  SUMOReal y = 0;
342  if (tmp.area() != 0) { // numerical instability ?
343  // http://en.wikipedia.org/wiki/Polygon
344  for (int i = 0; i < endIndex; i++) {
345  const SUMOReal z = tmp[i].x() * tmp[i + 1].y() - tmp[i + 1].x() * tmp[i].y();
346  div += z; // area formula
347  x += (tmp[i].x() + tmp[i + 1].x()) * z;
348  y += (tmp[i].y() + tmp[i + 1].y()) * z;
349  }
350  div *= 3; // 6 / 2, the 2 comes from the area formula
351  return Position(x / div, y / div);
352  } else {
353  // compute by decomposing into line segments
354  // http://en.wikipedia.org/wiki/Centroid#By_geometric_decomposition
355  SUMOReal lengthSum = 0;
356  for (int i = 0; i < endIndex; i++) {
357  SUMOReal length = tmp[i].distanceTo(tmp[i + 1]);
358  x += (tmp[i].x() + tmp[i + 1].x()) * length / 2;
359  y += (tmp[i].y() + tmp[i + 1].y()) * length / 2;
360  lengthSum += length;
361  }
362  if (lengthSum == 0) {
363  // it is probably only one point
364  return tmp[0];
365  }
366  return Position(x / lengthSum, y / lengthSum);
367  }
368 }
369 
370 
371 void
373  Position centroid = getCentroid();
374  for (int i = 0; i < static_cast<int>(size()); i++) {
375  (*this)[i] = centroid + (((*this)[i] - centroid) * factor);
376  }
377 }
378 
379 
380 void
382  Position centroid = getCentroid();
383  for (int i = 0; i < static_cast<int>(size()); i++) {
384  (*this)[i] = centroid + (((*this)[i] - centroid) + offset);
385  }
386 }
387 
388 
389 Position
391  if (size() == 1) {
392  return (*this)[0];
393  }
394  return positionAtOffset(SUMOReal((length() / 2.)));
395 }
396 
397 
398 SUMOReal
400  SUMOReal len = 0;
401  for (const_iterator i = begin(); i != end() - 1; i++) {
402  len += (*i).distanceTo(*(i + 1));
403  }
404  return len;
405 }
406 
407 
408 SUMOReal
410  SUMOReal len = 0;
411  for (const_iterator i = begin(); i != end() - 1; i++) {
412  len += (*i).distanceTo2D(*(i + 1));
413  }
414  return len;
415 }
416 
417 
418 SUMOReal
420  if (size() < 3) {
421  return 0;
422  }
423  SUMOReal area = 0;
424  PositionVector tmp = *this;
425  if (!isClosed()) { // make sure its closed
426  tmp.push_back(tmp[0]);
427  }
428  const int endIndex = (int)tmp.size() - 1;
429  // http://en.wikipedia.org/wiki/Polygon
430  for (int i = 0; i < endIndex; i++) {
431  area += tmp[i].x() * tmp[i + 1].y() - tmp[i + 1].x() * tmp[i].y();
432  }
433  if (area < 0) { // we whether we had cw or ccw order
434  area *= -1;
435  }
436  return area / 2;
437 }
438 
439 
440 bool
442  for (const_iterator i = begin(); i != end() - 1; i++) {
443  if (poly.around(*i, offset)) {
444  return true;
445  }
446  }
447  return false;
448 }
449 
450 
451 bool
452 PositionVector::crosses(const Position& p1, const Position& p2) const {
453  return intersects(p1, p2);
454 }
455 
456 
457 std::pair<PositionVector, PositionVector>
459  if (size() < 2) {
460  throw InvalidArgument("Vector to short for splitting");
461  }
462  if (where <= POSITION_EPS || where >= length() - POSITION_EPS) {
463  WRITE_WARNING("Splitting vector close to end (pos: " + toString(where) + ", length: " + toString(length()) + ")");
464  }
465  PositionVector first, second;
466  first.push_back((*this)[0]);
467  SUMOReal seen = 0;
468  const_iterator it = begin() + 1;
469  SUMOReal next = first.back().distanceTo(*it);
470  // see how many points we can add to first
471  while (where >= seen + next + POSITION_EPS) {
472  seen += next;
473  first.push_back(*it);
474  it++;
475  next = first.back().distanceTo(*it);
476  }
477  if (fabs(where - (seen + next)) > POSITION_EPS || it == end() - 1) {
478  // we need to insert a new point because 'where' is not close to an
479  // existing point or it is to close to the endpoint
480  const Position p = positionAtOffset(first.back(), *it, where - seen);
481  first.push_back(p);
482  second.push_back(p);
483  } else {
484  first.push_back(*it);
485  }
486  // add the remaining points to second
487  for (; it != end(); it++) {
488  second.push_back(*it);
489  }
490  assert(first.size() >= 2);
491  assert(second.size() >= 2);
492  assert(first.back() == second.front());
493  assert(fabs(first.length() + second.length() - length()) < 2 * POSITION_EPS);
494  return std::pair<PositionVector, PositionVector>(first, second);
495 }
496 
497 
498 std::ostream&
499 operator<<(std::ostream& os, const PositionVector& geom) {
500  for (PositionVector::const_iterator i = geom.begin(); i != geom.end(); i++) {
501  if (i != geom.begin()) {
502  os << " ";
503  }
504  os << (*i);
505  }
506  return os;
507 }
508 
509 
510 void
512  std::sort(begin(), end(), as_poly_cw_sorter());
513 }
514 
515 
516 void
518  for (int i = 0; i < static_cast<int>(size()); i++) {
519  (*this)[i].add(xoff, yoff, zoff);
520  }
521 }
522 
523 
524 void
526  for (int i = 0; i < static_cast<int>(size()); i++) {
527  (*this)[i].mul(1, -1);
528  }
529 }
530 
531 
533 
534 
535 int
537  return atan2(p1.x(), p1.y()) < atan2(p2.x(), p2.y());
538 }
539 
540 
541 void
543  std::sort(begin(), end(), increasing_x_y_sorter());
544 }
545 
546 
548 
549 
550 int
552  const Position& p2) const {
553  if (p1.x() != p2.x()) {
554  return p1.x() < p2.x();
555  }
556  return p1.y() < p2.y();
557 }
558 
559 
560 SUMOReal
561 PositionVector::isLeft(const Position& P0, const Position& P1, const Position& P2) const {
562  return (P1.x() - P0.x()) * (P2.y() - P0.y()) - (P2.x() - P0.x()) * (P1.y() - P0.y());
563 }
564 
565 
568  PositionVector ret = *this;
569  ret.sortAsPolyCWByAngle();
570  return simpleHull_2D(ret);
571 }
572 
573 
574 void
576  if (size() > 0 && v.size() > 0 && back().distanceTo(v[0]) < sameThreshold) {
577  copy(v.begin() + 1, v.end(), back_inserter(*this));
578  } else {
579  copy(v.begin(), v.end(), back_inserter(*this));
580  }
581 }
582 
583 
585 PositionVector::getSubpart(SUMOReal beginOffset, SUMOReal endOffset) const {
586  PositionVector ret;
587  Position begPos = front();
588  if (beginOffset > POSITION_EPS) {
589  begPos = positionAtOffset(beginOffset);
590  }
591  Position endPos = back();
592  if (endOffset < length() - POSITION_EPS) {
593  endPos = positionAtOffset(endOffset);
594  }
595  ret.push_back(begPos);
596 
597  SUMOReal seen = 0;
598  const_iterator i = begin();
599  // skip previous segments
600  while ((i + 1) != end()
601  &&
602  seen + (*i).distanceTo(*(i + 1)) < beginOffset) {
603  seen += (*i).distanceTo(*(i + 1));
604  i++;
605  }
606  // append segments in between
607  while ((i + 1) != end()
608  &&
609  seen + (*i).distanceTo(*(i + 1)) < endOffset) {
610 
611  ret.push_back_noDoublePos(*(i + 1));
612  seen += (*i).distanceTo(*(i + 1));
613  i++;
614  }
615  // append end
616  ret.push_back_noDoublePos(endPos);
617  return ret;
618 }
619 
620 
622 PositionVector::getSubpart2D(SUMOReal beginOffset, SUMOReal endOffset) const {
623  PositionVector ret;
624  Position begPos = front();
625  if (beginOffset > POSITION_EPS) {
626  begPos = positionAtOffset2D(beginOffset);
627  }
628  Position endPos = back();
629  if (endOffset < length2D() - POSITION_EPS) {
630  endPos = positionAtOffset2D(endOffset);
631  }
632  ret.push_back(begPos);
633 
634  SUMOReal seen = 0;
635  const_iterator i = begin();
636  // skip previous segments
637  while ((i + 1) != end()
638  &&
639  seen + (*i).distanceTo2D(*(i + 1)) < beginOffset) {
640  seen += (*i).distanceTo2D(*(i + 1));
641  i++;
642  }
643  // append segments in between
644  while ((i + 1) != end()
645  &&
646  seen + (*i).distanceTo2D(*(i + 1)) < endOffset) {
647 
648  ret.push_back_noDoublePos(*(i + 1));
649  seen += (*i).distanceTo2D(*(i + 1));
650  i++;
651  }
652  // append end
653  ret.push_back_noDoublePos(endPos);
654  return ret;
655 }
656 
657 
659 PositionVector::getSubpartByIndex(int beginIndex, int count) const {
660  if (beginIndex < 0) {
661  beginIndex += (int)size();
662  }
663  assert(count >= 0);
664  assert(beginIndex < (int)size());
665  assert(beginIndex + count <= (int)size());
666  PositionVector result;
667  for (int i = beginIndex; i < beginIndex + count; ++i) {
668  result.push_back((*this)[i]);
669  }
670  return result;
671 }
672 
673 
674 SUMOReal
676  return front().angleTo2D(back());
677 }
678 
679 
680 SUMOReal
681 PositionVector::nearest_offset_to_point2D(const Position& p, bool perpendicular) const {
684  SUMOReal seen = 0;
685  for (const_iterator i = begin(); i != end() - 1; i++) {
686  const SUMOReal pos =
687  GeomHelper::nearest_offset_on_line_to_point2D(*i, *(i + 1), p, perpendicular);
688  const SUMOReal dist = pos == GeomHelper::INVALID_OFFSET ? minDist : p.distanceTo2D(positionAtOffset2D(*i, *(i + 1), pos));
689  if (dist < minDist) {
690  nearestPos = pos + seen;
691  minDist = dist;
692  }
693  if (perpendicular && i != begin() && pos == GeomHelper::INVALID_OFFSET) {
694  // even if perpendicular is set we still need to check the distance to the inner points
695  const SUMOReal cornerDist = p.distanceTo2D(*i);
696  if (cornerDist < minDist) {
697  const SUMOReal pos1 =
698  GeomHelper::nearest_offset_on_line_to_point2D(*(i - 1), *i, p, false);
699  const SUMOReal pos2 =
700  GeomHelper::nearest_offset_on_line_to_point2D(*i, *(i + 1), p, false);
701  if (pos1 == (*(i - 1)).distanceTo2D(*i) && pos2 == 0.) {
702  nearestPos = seen;
703  minDist = cornerDist;
704  }
705  }
706  }
707  seen += (*i).distanceTo2D(*(i + 1));
708  }
709  return nearestPos;
710 }
711 
712 
713 Position
715  // @toDo this duplicates most of the code in nearest_offset_to_point2D. It should be refactored
716  if (extend) {
717  PositionVector extended = *this;
718  const SUMOReal dist = 2 * distance2D(p);
719  extended.extrapolate(dist);
720  return extended.transformToVectorCoordinates(p) - Position(dist, 0);
721  }
723  SUMOReal nearestPos = -1;
724  SUMOReal seen = 0;
725  int sign = 1;
726  for (const_iterator i = begin(); i != end() - 1; i++) {
727  const SUMOReal pos =
728  GeomHelper::nearest_offset_on_line_to_point2D(*i, *(i + 1), p, true);
729  const SUMOReal dist = pos < 0 ? minDist : p.distanceTo2D(positionAtOffset(*i, *(i + 1), pos));
730  if (dist < minDist) {
731  nearestPos = pos + seen;
732  minDist = dist;
733  sign = isLeft(*i, *(i + 1), p) >= 0 ? -1 : 1;
734  }
735  if (i != begin() && pos == GeomHelper::INVALID_OFFSET) {
736  // even if perpendicular is set we still need to check the distance to the inner points
737  const SUMOReal cornerDist = p.distanceTo2D(*i);
738  if (cornerDist < minDist) {
739  const SUMOReal pos1 =
740  GeomHelper::nearest_offset_on_line_to_point2D(*(i - 1), *i, p, false);
741  const SUMOReal pos2 =
742  GeomHelper::nearest_offset_on_line_to_point2D(*i, *(i + 1), p, false);
743  if (pos1 == (*(i - 1)).distanceTo2D(*i) && pos2 == 0.) {
744  nearestPos = seen;
745  minDist = cornerDist;
746  sign = isLeft(*(i - 1), *i, p) >= 0 ? -1 : 1;
747  }
748  }
749  }
750  seen += (*i).distanceTo2D(*(i + 1));
751  }
752  if (nearestPos != -1) {
753  return Position(nearestPos, sign * minDist);
754  } else {
755  return Position::INVALID;
756  }
757 }
758 
759 
760 int
762  assert(size() > 0);
764  SUMOReal dist;
765  int closest = 0;
766  for (int i = 0; i < (int)size(); i++) {
767  dist = p.distanceTo((*this)[i]);
768  if (dist < minDist) {
769  closest = i;
770  minDist = dist;
771  }
772  }
773  return closest;
774 }
775 
776 
777 int
780  int insertionIndex = 1;
781  for (int i = 0; i < (int)size() - 1; i++) {
782  const SUMOReal length = GeomHelper::nearest_offset_on_line_to_point2D((*this)[i], (*this)[i + 1], p, false);
783  const Position& outIntersection = PositionVector::positionAtOffset2D((*this)[i], (*this)[i + 1], length);
784  const SUMOReal dist = p.distanceTo2D(outIntersection);
785  if (dist < minDist) {
786  insertionIndex = i + 1;
787  minDist = dist;
788  }
789  }
790  insert(begin() + insertionIndex, p);
791  return insertionIndex;
792 }
793 
794 
795 std::vector<SUMOReal>
797  std::vector<SUMOReal> ret;
798  for (const_iterator i = other.begin(); i != other.end() - 1; i++) {
799  std::vector<SUMOReal> atSegment = intersectsAtLengths2D(*i, *(i + 1));
800  copy(atSegment.begin(), atSegment.end(), back_inserter(ret));
801  }
802  return ret;
803 }
804 
805 
806 std::vector<SUMOReal>
808  std::vector<SUMOReal> ret;
809  SUMOReal pos = 0;
810  for (const_iterator i = begin(); i != end() - 1; i++) {
811  const Position& p1 = *i;
812  const Position& p2 = *(i + 1);
813  SUMOReal x, y, m;
814  if (intersects(p1, p2, lp1, lp2, 0., &x, &y, &m)) {
815  ret.push_back(Position(x, y).distanceTo2D(p1) + pos);
816  }
817  pos += p1.distanceTo2D(p2);
818  }
819  return ret;
820 }
821 
822 
823 void
824 PositionVector::extrapolate(const SUMOReal val, const bool onlyFirst) {
825  assert(size() > 1);
826  Position& p1 = (*this)[0];
827  Position& p2 = (*this)[1];
828  const Position offset = (p2 - p1) * (val / p1.distanceTo(p2));
829  p1.sub(offset);
830  if (!onlyFirst) {
831  if (size() == 2) {
832  p2.add(offset);
833  } else {
834  const Position& e1 = (*this)[-2];
835  Position& e2 = (*this)[-1];
836  e2.sub((e1 - e2) * (val / e1.distanceTo(e2)));
837  }
838  }
839 }
840 
841 
842 void
843 PositionVector::extrapolate2D(const SUMOReal val, const bool onlyFirst) {
844  assert(size() > 1);
845  Position& p1 = (*this)[0];
846  Position& p2 = (*this)[1];
847  const Position offset = (p2 - p1) * (val / p1.distanceTo2D(p2));
848  p1.sub(offset);
849  if (!onlyFirst) {
850  if (size() == 2) {
851  p2.add(offset);
852  } else {
853  const Position& e1 = (*this)[-2];
854  Position& e2 = (*this)[-1];
855  e2.sub((e1 - e2) * (val / e1.distanceTo2D(e2)));
856  }
857  }
858 }
859 
860 
863  PositionVector ret;
864  for (const_reverse_iterator i = rbegin(); i != rend(); i++) {
865  ret.push_back(*i);
866  }
867  return ret;
868 }
869 
870 
871 Position
872 PositionVector::sideOffset(const Position& beg, const Position& end, const SUMOReal amount) {
873  const SUMOReal scale = amount / beg.distanceTo2D(end);
874  return Position((beg.y() - end.y()) * scale, (end.x() - beg.x()) * scale);
875 }
876 
877 
878 void
880  if (size() < 2) {
881  return;
882  }
883  PositionVector shape;
884  for (int i = 0; i < static_cast<int>(size()); i++) {
885  if (i == 0) {
886  const Position& from = (*this)[i];
887  const Position& to = (*this)[i + 1];
888  shape.push_back(from - sideOffset(from, to, amount));
889  } else if (i == static_cast<int>(size()) - 1) {
890  const Position& from = (*this)[i - 1];
891  const Position& to = (*this)[i];
892  shape.push_back(to - sideOffset(from, to, amount));
893  } else {
894  const Position& from = (*this)[i - 1];
895  const Position& me = (*this)[i];
896  const Position& to = (*this)[i + 1];
897  PositionVector fromMe(from, me);
898  fromMe.extrapolate2D(me.distanceTo2D(to));
899  const SUMOReal extrapolateDev = fromMe[1].distanceTo2D(to);
900  if (fabs(extrapolateDev) < POSITION_EPS) {
901  // parallel case, just shift the middle point
902  shape.push_back(me - sideOffset(from, to, amount));
903  } else if (fabs(extrapolateDev - 2 * me.distanceTo2D(to)) < POSITION_EPS) {
904  // counterparallel case, just shift the middle point
905  PositionVector fromMe(from, me);
906  fromMe.extrapolate2D(amount);
907  shape.push_back(fromMe[1]);
908  } else {
909  Position offsets = sideOffset(from, me, amount);
910  Position offsets2 = sideOffset(me, to, amount);
911  PositionVector l1(from - offsets, me - offsets);
912  PositionVector l2(me - offsets2, to - offsets2);
913  shape.push_back(l1.intersectionPosition2D(l2[0], l2[1], 100));
914  if (shape.back() == Position::INVALID) {
915  throw InvalidArgument("no line intersection");
916  }
917  }
918  // copy original z value
919  shape.back().set(shape.back().x(), shape.back().y(), me.z());
920  }
921  }
922  *this = shape;
923 }
924 
925 
926 SUMOReal
928  assert((int)size() > pos + 1);
929  return (*this)[pos].angleTo2D((*this)[pos + 1]);
930 }
931 
932 
933 void
935  if (size() == 0 || (*this)[0] == back()) {
936  return;
937  }
938  push_back((*this)[0]);
939 }
940 
941 
942 std::vector<SUMOReal>
943 PositionVector::distances(const PositionVector& s, bool perpendicular) const {
944  std::vector<SUMOReal> ret;
945  const_iterator i;
946  for (i = begin(); i != end(); i++) {
947  const SUMOReal dist = s.distance2D(*i, perpendicular);
948  if (dist != GeomHelper::INVALID_OFFSET) {
949  ret.push_back(dist);
950  }
951  }
952  for (i = s.begin(); i != s.end(); i++) {
953  const SUMOReal dist = distance2D(*i, perpendicular);
954  if (dist != GeomHelper::INVALID_OFFSET) {
955  ret.push_back(dist);
956  }
957  }
958  return ret;
959 }
960 
961 
962 SUMOReal
963 PositionVector::distance2D(const Position& p, bool perpendicular) const {
964  if (size() == 0) {
966  } else if (size() == 1) {
967  return front().distanceTo(p);
968  }
969  const SUMOReal nearestOffset = nearest_offset_to_point2D(p, perpendicular);
970  if (nearestOffset == GeomHelper::INVALID_OFFSET) {
972  } else {
973  return p.distanceTo2D(positionAtOffset2D(nearestOffset));
974  }
975 }
976 
977 
978 void
980  if (size() == 0 || !p.almostSame(back())) {
981  push_back(p);
982  }
983 }
984 
985 
986 void
988  if (size() == 0 || !p.almostSame(front())) {
989  insert(begin(), p);
990  }
991 }
992 
993 
994 bool
996  return size() >= 2 && (*this)[0] == back();
997 }
998 
999 
1000 void
1001 PositionVector::removeDoublePoints(SUMOReal minDist, bool assertLength) {
1002  if (size() > 1) {
1003  iterator last = begin();
1004  for (iterator i = begin() + 1; i != end() && (!assertLength || size() > 2);) {
1005  if (last->almostSame(*i, minDist)) {
1006  i = erase(i);
1007  } else {
1008  last = i;
1009  ++i;
1010  }
1011  }
1012  }
1013 }
1014 
1015 
1016 bool
1018  if (size() == v2.size()) {
1019  for (int i = 0; i < (int)size(); i++) {
1020  if ((*this)[i] != v2[i]) {
1021  return false;
1022  }
1023  }
1024  return true;
1025  } else {
1026  return false;
1027  }
1028 }
1029 
1030 
1031 bool
1033  if (size() > 2) {
1034  return false;
1035  }
1036  for (const_iterator i = begin(); i != end() - 1; i++) {
1037  if ((*i).z() != (*(i + 1)).z()) {
1038  return true;
1039  }
1040  }
1041  return false;
1042 }
1043 
1044 
1045 bool
1046 PositionVector::intersects(const Position& p11, const Position& p12, const Position& p21, const Position& p22, const SUMOReal withinDist, SUMOReal* x, SUMOReal* y, SUMOReal* mu) {
1047  const SUMOReal eps = std::numeric_limits<SUMOReal>::epsilon();
1048  const double denominator = (p22.y() - p21.y()) * (p12.x() - p11.x()) - (p22.x() - p21.x()) * (p12.y() - p11.y());
1049  const double numera = (p22.x() - p21.x()) * (p11.y() - p21.y()) - (p22.y() - p21.y()) * (p11.x() - p21.x());
1050  const double numerb = (p12.x() - p11.x()) * (p11.y() - p21.y()) - (p12.y() - p11.y()) * (p11.x() - p21.x());
1051  /* Are the lines coincident? */
1052  if (fabs(numera) < eps && fabs(numerb) < eps && fabs(denominator) < eps) {
1053  SUMOReal a1;
1054  SUMOReal a2;
1055  SUMOReal a3;
1056  SUMOReal a4;
1057  SUMOReal a = -1e12;
1058  if (p11.x() != p12.x()) {
1059  a1 = p11.x() < p12.x() ? p11.x() : p12.x();
1060  a2 = p11.x() < p12.x() ? p12.x() : p11.x();
1061  a3 = p21.x() < p22.x() ? p21.x() : p22.x();
1062  a4 = p21.x() < p22.x() ? p22.x() : p21.x();
1063  } else {
1064  a1 = p11.y() < p12.y() ? p11.y() : p12.y();
1065  a2 = p11.y() < p12.y() ? p12.y() : p11.y();
1066  a3 = p21.y() < p22.y() ? p21.y() : p22.y();
1067  a4 = p21.y() < p22.y() ? p22.y() : p21.y();
1068  }
1069  if (a1 <= a3 && a3 <= a2) {
1070  if (a4 < a2) {
1071  a = (a3 + a4) / 2;
1072  } else {
1073  a = (a2 + a3) / 2;
1074  }
1075  }
1076  if (a3 <= a1 && a1 <= a4) {
1077  if (a2 < a4) {
1078  a = (a1 + a2) / 2;
1079  } else {
1080  a = (a1 + a4) / 2;
1081  }
1082  }
1083  if (a != -1e12) {
1084  if (x != 0) {
1085  if (p11.x() != p12.x()) {
1086  *mu = (a - p11.x()) / (p12.x() - p11.x());
1087  *x = a;
1088  *y = p11.y() + (*mu) * (p12.y() - p11.y());
1089  } else {
1090  *x = p11.x();
1091  *y = a;
1092  if (p12.y() == p11.y()) {
1093  *mu = 0;
1094  } else {
1095  *mu = (a - p11.y()) / (p12.y() - p11.y());
1096  }
1097  }
1098  }
1099  return true;
1100  }
1101  return false;
1102  }
1103  /* Are the lines parallel */
1104  if (fabs(denominator) < eps) {
1105  return false;
1106  }
1107  /* Is the intersection along the segments */
1108  double mua = numera / denominator;
1109  /* reduce rounding errors for lines ending in the same point */
1110  if (fabs(p12.x() - p22.x()) < eps && fabs(p12.y() - p22.y()) < eps) {
1111  mua = 1.;
1112  } else {
1113  const double offseta = withinDist / p11.distanceTo2D(p12);
1114  const double offsetb = withinDist / p21.distanceTo2D(p22);
1115  const double mub = numerb / denominator;
1116  if (mua < -offseta || mua > 1 + offseta || mub < -offsetb || mub > 1 + offsetb) {
1117  return false;
1118  }
1119  }
1120  if (x != 0) {
1121  *x = p11.x() + mua * (p12.x() - p11.x());
1122  *y = p11.y() + mua * (p12.y() - p11.y());
1123  *mu = mua;
1124  }
1125  return true;
1126 }
1127 
1128 
1129 /****************************************************************************/
1130 
void sub(SUMOReal dx, SUMOReal dy)
Substracts the given position from this one.
Definition: Position.h:139
static SUMOReal angle2D(const Position &p1, const Position &p2)
Returns the angle between two vectors on a plane The angle is from vector 1 to vector 2...
Definition: GeomHelper.cpp:94
clase for increasing Sorter
static Position sideOffset(const Position &beg, const Position &end, const SUMOReal amount)
get a side position of position vector using a offset
bool hasElevation() const
return whether two positions differ in z-coordinate
SUMOReal rotationAtOffset(SUMOReal pos) const
Returns the rotation at the given length.
SUMOReal nearest_offset_to_point2D(const Position &p, bool perpendicular=true) const
return the nearest offest to point 2D
PositionVector getSubpart2D(SUMOReal beginOffset, SUMOReal endOffset) const
get subpart of a position vector in two dimensions (Z is ignored)
void sortAsPolyCWByAngle()
short as polygon CV by angle
void add(const Position &pos)
Adds the given position to this one.
Definition: Position.h:119
#define M_PI
Definition: angles.h:37
friend std::ostream & operator<<(std::ostream &os, const PositionVector &geom)
Position getCentroid() const
Returns the centroid (closes the polygon if unclosed)
bool intersects(const Position &p1, const Position &p2) const
Returns the information whether this list of points interesects the given line.
void scaleRelative(SUMOReal factor)
enlarges/shrinks the polygon by a factor based at the centroid
PositionVector getSubpartByIndex(int beginIndex, int count) const
get subpart of a position vector using index and a cout
bool partialWithin(const AbstractPoly &poly, SUMOReal offset=0) const
Returns the information whether this polygon lies partially within the given polygon.
#define RAD2DEG(x)
Definition: GeomHelper.h:46
SUMOReal distanceTo(const Position &p2) const
returns the euclidean distance in 3 dimension
Definition: Position.h:221
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:215
SUMOReal beginEndAngle() const
returns the angle in radians of the line connecting the first and the last position ...
bool isClosed() const
check if PositionVector is closed
const Position & operator[](int index) const
returns the constat 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
SUMOReal distance2D(const Position &p, bool perpendicular=false) const
closest 2D-distance to point p (or -1 if perpendicular is true and the point is beyond this vector) ...
PositionVector reverse() const
reverse position vector
SUMOReal slopeDegreeAtOffset(SUMOReal pos) const
Returns the slope at the given length.
PositionVector convexHull() const
~PositionVector()
Destructor.
void extrapolate2D(const SUMOReal val, const bool onlyFirst=false)
extrapolate position vector in two dimensions (Z is ignored)
SUMOReal length2D() const
Returns the length.
std::vector< SUMOReal > distances(const PositionVector &s, bool perpendicular=false) const
distances of all my points to s and all of s points to myself
void push_front_noDoublePos(const Position &p)
insert in front a non double position
#define max(a, b)
Definition: polyfonts.c:65
static SUMOReal legacyDegree(const SUMOReal angle, const bool positive=false)
Definition: GeomHelper.cpp:204
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:46
A list of positions.
void add(SUMOReal xoff, SUMOReal yoff, SUMOReal zoff)
int indexOfClosest(const Position &p) const
index of the closest position to p
int operator()(const Position &p1, const Position &p2) const
comparing operation for sort
SUMOReal z() const
Returns the z-position.
Definition: Position.h:73
Position positionAtOffset(SUMOReal pos, SUMOReal lateralOffset=0) const
Returns the position at the given length.
#define POSITION_EPS
Definition: config.h:188
int insertAtClosest(const Position &p)
inserts p between the two closest positions and returns the insertion index
std::string toString(const T &t, std::streamsize accuracy=OUTPUT_ACCURACY)
Definition: ToString.h:55
void sortByIncreasingXY()
shory by increasing X-Y Psitions
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.
PositionVector()
Constructor. Creates an empty position vector.
SUMOReal length() const
Returns the length.
SUMOReal rotationDegreeAtOffset(SUMOReal pos) const
Returns the rotation at the given length.
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.
SUMOReal angleAt2D(int pos) const
get angle in certain position of position vector
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.
static SUMOReal nearest_offset_on_line_to_point2D(const Position &lineStart, const Position &lineEnd, const Position &p, bool perpendicular=true)
Definition: GeomHelper.cpp:100
Position intersectionPosition2D(const Position &p1, const Position &p2, const SUMOReal withinDist=0.) const
Returns the position of the intersection.
Position getLineCenter() const
get line center
SUMOReal distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition: Position.h:232
void move2side(SUMOReal amount)
move position vector to side using certain ammount
#define SUMOReal
Definition: config.h:214
void push_back_noDoublePos(const Position &p)
insert in back a non double position
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)
virtual bool around(const Position &p, SUMOReal offset=0) const =0
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
PositionVector getSubpart(SUMOReal beginOffset, SUMOReal endOffset) const
get subpart of a position vector
SUMOReal angleTo2D(const Position &other) const
returns the angle in the plane of the vector pointing from here to the other position ...
Definition: Position.h:243
void append(const PositionVector &v, SUMOReal sameThreshold=2.0)
void extrapolate(const SUMOReal val, const bool onlyFirst=false)
extrapolate position vector
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
get left
static const Position INVALID
Definition: Position.h:261
Position transformToVectorCoordinates(const Position &p, bool extend=false) const
return position p within the length-wise coordinate system defined by this position vector...