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-2017 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 "Boundary.h"
49 
50 // ===========================================================================
51 // method definitions
52 // ===========================================================================
53 
55 
56 
57 PositionVector::PositionVector(const std::vector<Position>& v) {
58  std::copy(v.begin(), v.end(), std::back_inserter(*this));
59 }
60 
61 
62 PositionVector::PositionVector(const std::vector<Position>::const_iterator beg, const std::vector<Position>::const_iterator end) {
63  std::copy(beg, end, std::back_inserter(*this));
64 }
65 
66 
68  push_back(p1);
69  push_back(p2);
70 }
71 
72 
74 
75 
76 bool
77 PositionVector::around(const Position& p, double offset) const {
78  if (size() < 2) {
79  return false;
80  }
81  if (offset != 0) {
82  PositionVector tmp(*this);
83  tmp.scaleAbsolute(offset);
84  return tmp.around(p);
85  }
86  double angle = 0;
87  for (const_iterator i = begin(); i != end() - 1; i++) {
88  Position p1(
89  (*i).x() - p.x(),
90  (*i).y() - p.y());
91  Position p2(
92  (*(i + 1)).x() - p.x(),
93  (*(i + 1)).y() - p.y());
94  angle += GeomHelper::angle2D(p1, p2);
95  }
96  Position p1(
97  (*(end() - 1)).x() - p.x(),
98  (*(end() - 1)).y() - p.y());
99  Position p2(
100  (*(begin())).x() - p.x(),
101  (*(begin())).y() - p.y());
102  angle += GeomHelper::angle2D(p1, p2);
103  return (!(fabs(angle) < M_PI));
104 }
105 
106 
107 bool
108 PositionVector::overlapsWith(const AbstractPoly& poly, double offset) const {
109  if (
110  // check whether one of my points lies within the given poly
111  partialWithin(poly, offset) ||
112  // check whether the polygon lies within me
113  poly.partialWithin(*this, offset)) {
114  return true;
115  }
116  if (size() >= 2) {
117  for (const_iterator i = begin(); i != end() - 1; i++) {
118  if (poly.crosses(*i, *(i + 1))) {
119  return true;
120  }
121  }
122  if (size() > 2 && poly.crosses(back(), front())) {
123  return true;
124  }
125  }
126  return false;
127 }
128 
129 
130 double
131 PositionVector::getOverlapWith(const PositionVector& poly, double zThreshold) const {
132  double result = 0;
133  // this points within poly
134  for (const_iterator i = begin(); i != end() - 1; i++) {
135  if (poly.around(*i)) {
136  Position closest = poly.positionAtOffset2D(poly.nearest_offset_to_point2D(*i));
137  if (fabs(closest.z() - (*i).z()) < zThreshold) {
138  result = MAX2(result, poly.distance2D(*i));
139  }
140  }
141  }
142  // polys points within this
143  for (const_iterator i = poly.begin(); i != poly.end() - 1; i++) {
144  if (around(*i)) {
146  if (fabs(closest.z() - (*i).z()) < zThreshold) {
147  result = MAX2(result, distance2D(*i));
148  }
149  }
150  }
151  return result;
152 }
153 
154 
155 bool
156 PositionVector::intersects(const Position& p1, const Position& p2) const {
157  if (size() < 2) {
158  return false;
159  }
160  for (const_iterator i = begin(); i != end() - 1; i++) {
161  if (intersects(*i, *(i + 1), p1, p2)) {
162  return true;
163  }
164  }
165  return false;
166 }
167 
168 
169 bool
171  if (size() < 2) {
172  return false;
173  }
174  for (const_iterator i = begin(); i != end() - 1; i++) {
175  if (v1.intersects(*i, *(i + 1))) {
176  return true;
177  }
178  }
179  return false;
180 }
181 
182 
183 Position
184 PositionVector::intersectionPosition2D(const Position& p1, const Position& p2, const double withinDist) const {
185  for (const_iterator i = begin(); i != end() - 1; i++) {
186  double x, y, m;
187  if (intersects(*i, *(i + 1), p1, p2, withinDist, &x, &y, &m)) {
188  return Position(x, y);
189  }
190  }
191  return Position::INVALID;
192 }
193 
194 
195 Position
197  for (const_iterator i = begin(); i != end() - 1; i++) {
198  if (v1.intersects(*i, *(i + 1))) {
199  return v1.intersectionPosition2D(*i, *(i + 1));
200  }
201  }
202  return Position::INVALID;
203 }
204 
205 
206 const Position&
207 PositionVector::operator[](int index) const {
208  if (index >= 0) {
209  return at(index);
210  } else {
211  return at((int)size() + index);
212  }
213 }
214 
215 
216 Position&
218  if (index >= 0) {
219  return at(index);
220  } else {
221  return at((int)size() + index);
222  }
223 }
224 
225 
226 Position
227 PositionVector::positionAtOffset(double pos, double lateralOffset) const {
228  assert(size() != 0);
229  const_iterator i = begin();
230  double seenLength = 0;
231  do {
232  const double nextLength = (*i).distanceTo(*(i + 1));
233  if (seenLength + nextLength > pos) {
234  return positionAtOffset(*i, *(i + 1), pos - seenLength, lateralOffset);
235  }
236  seenLength += nextLength;
237  } while (++i != end() - 1);
238  if (lateralOffset == 0 || size() < 2) {
239  return back();
240  } else {
241  return positionAtOffset(*(end() - 2), *(end() - 1), (*(end() - 2)).distanceTo(*(end() - 1)), lateralOffset);
242  }
243 }
244 
245 
246 Position
247 PositionVector::positionAtOffset2D(double pos, double lateralOffset) const {
248  const_iterator i = begin();
249  double seenLength = 0;
250  do {
251  const double nextLength = (*i).distanceTo2D(*(i + 1));
252  if (seenLength + nextLength > pos) {
253  return positionAtOffset2D(*i, *(i + 1), pos - seenLength, lateralOffset);
254  }
255  seenLength += nextLength;
256  } while (++i != end() - 1);
257  return back();
258 }
259 
260 
261 double
263  if (pos < 0) {
264  pos += length();
265  }
266  const_iterator i = begin();
267  double seenLength = 0;
268  do {
269  const Position& p1 = *i;
270  const Position& p2 = *(i + 1);
271  const double nextLength = p1.distanceTo(p2);
272  if (seenLength + nextLength > pos) {
273  return p1.angleTo2D(p2);
274  }
275  seenLength += nextLength;
276  } while (++i != end() - 1);
277  const Position& p1 = (*this)[-2];
278  const Position& p2 = back();
279  return p1.angleTo2D(p2);
280 }
281 
282 
283 double
286 }
287 
288 
289 double
291  const_iterator i = begin();
292  double seenLength = 0;
293  do {
294  const Position& p1 = *i;
295  const Position& p2 = *(i + 1);
296  const double nextLength = p1.distanceTo(p2);
297  if (seenLength + nextLength > pos) {
298  return RAD2DEG(atan2(p2.z() - p1.z(), p1.distanceTo2D(p2)));
299  }
300  seenLength += nextLength;
301  } while (++i != end() - 1);
302  const Position& p1 = (*this)[-2];
303  const Position& p2 = back();
304  return RAD2DEG(atan2(p2.z() - p1.z(), p1.distanceTo2D(p2)));
305 }
306 
307 
308 Position
309 PositionVector::positionAtOffset(const Position& p1, const Position& p2, double pos, double lateralOffset) {
310  const double dist = p1.distanceTo(p2);
311  if (pos < 0. || dist < pos) {
312  return Position::INVALID;
313  }
314  if (lateralOffset != 0) {
315  if (dist == 0.) {
316  return Position::INVALID;
317  }
318  const Position offset = sideOffset(p1, p2, -lateralOffset); // move in the same direction as Position::move2side
319  if (pos == 0.) {
320  return p1 + offset;
321  }
322  return p1 + (p2 - p1) * (pos / dist) + offset;
323  }
324  if (pos == 0.) {
325  return p1;
326  }
327  return p1 + (p2 - p1) * (pos / dist);
328 }
329 
330 
331 Position
332 PositionVector::positionAtOffset2D(const Position& p1, const Position& p2, double pos, double lateralOffset) {
333  const double dist = p1.distanceTo2D(p2);
334  if (pos < 0 || dist < pos) {
335  return Position::INVALID;
336  }
337  if (lateralOffset != 0) {
338  const Position offset = sideOffset(p1, p2, -lateralOffset); // move in the same direction as Position::move2side
339  if (pos == 0.) {
340  return p1 + offset;
341  }
342  return p1 + (p2 - p1) * (pos / dist) + offset;
343  }
344  if (pos == 0.) {
345  return p1;
346  }
347  return p1 + (p2 - p1) * (pos / dist);
348 }
349 
350 
351 Boundary
353  Boundary ret;
354  for (const_iterator i = begin(); i != end(); i++) {
355  ret.add(*i);
356  }
357  return ret;
358 }
359 
360 
361 Position
363  double x = 0;
364  double y = 0;
365  double z = 0;
366  for (const_iterator i = begin(); i != end(); i++) {
367  x += (*i).x();
368  y += (*i).y();
369  z += (*i).z();
370  }
371  return Position(x / (double) size(), y / (double) size(), z / (double)size());
372 }
373 
374 
375 Position
377  PositionVector tmp = *this;
378  if (!isClosed()) { // make sure its closed
379  tmp.push_back(tmp[0]);
380  }
381  const int endIndex = (int)tmp.size() - 1;
382  double div = 0; // 6 * area including sign
383  double x = 0;
384  double y = 0;
385  if (tmp.area() != 0) { // numerical instability ?
386  // http://en.wikipedia.org/wiki/Polygon
387  for (int i = 0; i < endIndex; i++) {
388  const double z = tmp[i].x() * tmp[i + 1].y() - tmp[i + 1].x() * tmp[i].y();
389  div += z; // area formula
390  x += (tmp[i].x() + tmp[i + 1].x()) * z;
391  y += (tmp[i].y() + tmp[i + 1].y()) * z;
392  }
393  div *= 3; // 6 / 2, the 2 comes from the area formula
394  return Position(x / div, y / div);
395  } else {
396  // compute by decomposing into line segments
397  // http://en.wikipedia.org/wiki/Centroid#By_geometric_decomposition
398  double lengthSum = 0;
399  for (int i = 0; i < endIndex; i++) {
400  double length = tmp[i].distanceTo(tmp[i + 1]);
401  x += (tmp[i].x() + tmp[i + 1].x()) * length / 2;
402  y += (tmp[i].y() + tmp[i + 1].y()) * length / 2;
403  lengthSum += length;
404  }
405  if (lengthSum == 0) {
406  // it is probably only one point
407  return tmp[0];
408  }
409  return Position(x / lengthSum, y / lengthSum);
410  }
411 }
412 
413 
414 void
416  Position centroid = getCentroid();
417  for (int i = 0; i < static_cast<int>(size()); i++) {
418  (*this)[i] = centroid + (((*this)[i] - centroid) * factor);
419  }
420 }
421 
422 
423 void
425  Position centroid = getCentroid();
426  for (int i = 0; i < static_cast<int>(size()); i++) {
427  (*this)[i] = centroid + (((*this)[i] - centroid) + offset);
428  }
429 }
430 
431 
432 Position
434  if (size() == 1) {
435  return (*this)[0];
436  }
437  return positionAtOffset(double((length() / 2.)));
438 }
439 
440 
441 double
443  double len = 0;
444  for (const_iterator i = begin(); i != end() - 1; i++) {
445  len += (*i).distanceTo(*(i + 1));
446  }
447  return len;
448 }
449 
450 
451 double
453  double len = 0;
454  for (const_iterator i = begin(); i != end() - 1; i++) {
455  len += (*i).distanceTo2D(*(i + 1));
456  }
457  return len;
458 }
459 
460 
461 double
463  if (size() < 3) {
464  return 0;
465  }
466  double area = 0;
467  PositionVector tmp = *this;
468  if (!isClosed()) { // make sure its closed
469  tmp.push_back(tmp[0]);
470  }
471  const int endIndex = (int)tmp.size() - 1;
472  // http://en.wikipedia.org/wiki/Polygon
473  for (int i = 0; i < endIndex; i++) {
474  area += tmp[i].x() * tmp[i + 1].y() - tmp[i + 1].x() * tmp[i].y();
475  }
476  if (area < 0) { // we whether we had cw or ccw order
477  area *= -1;
478  }
479  return area / 2;
480 }
481 
482 
483 bool
484 PositionVector::partialWithin(const AbstractPoly& poly, double offset) const {
485  if (size() < 2) {
486  return false;
487  }
488  for (const_iterator i = begin(); i != end() - 1; i++) {
489  if (poly.around(*i, offset)) {
490  return true;
491  }
492  }
493  return false;
494 }
495 
496 
497 bool
498 PositionVector::crosses(const Position& p1, const Position& p2) const {
499  return intersects(p1, p2);
500 }
501 
502 
503 std::pair<PositionVector, PositionVector>
504 PositionVector::splitAt(double where) const {
505  if (size() < 2) {
506  throw InvalidArgument("Vector to short for splitting");
507  }
508  if (where <= POSITION_EPS || where >= length() - POSITION_EPS) {
509  WRITE_WARNING("Splitting vector close to end (pos: " + toString(where) + ", length: " + toString(length()) + ")");
510  }
511  PositionVector first, second;
512  first.push_back((*this)[0]);
513  double seen = 0;
514  const_iterator it = begin() + 1;
515  double next = first.back().distanceTo(*it);
516  // see how many points we can add to first
517  while (where >= seen + next + POSITION_EPS) {
518  seen += next;
519  first.push_back(*it);
520  it++;
521  next = first.back().distanceTo(*it);
522  }
523  if (fabs(where - (seen + next)) > POSITION_EPS || it == end() - 1) {
524  // we need to insert a new point because 'where' is not close to an
525  // existing point or it is to close to the endpoint
526  const Position p = positionAtOffset(first.back(), *it, where - seen);
527  first.push_back(p);
528  second.push_back(p);
529  } else {
530  first.push_back(*it);
531  }
532  // add the remaining points to second
533  for (; it != end(); it++) {
534  second.push_back(*it);
535  }
536  assert(first.size() >= 2);
537  assert(second.size() >= 2);
538  assert(first.back() == second.front());
539  assert(fabs(first.length() + second.length() - length()) < 2 * POSITION_EPS);
540  return std::pair<PositionVector, PositionVector>(first, second);
541 }
542 
543 
544 std::ostream&
545 operator<<(std::ostream& os, const PositionVector& geom) {
546  for (PositionVector::const_iterator i = geom.begin(); i != geom.end(); i++) {
547  if (i != geom.begin()) {
548  os << " ";
549  }
550  os << (*i);
551  }
552  return os;
553 }
554 
555 
556 void
558  std::sort(begin(), end(), as_poly_cw_sorter());
559 }
560 
561 
562 void
563 PositionVector::add(double xoff, double yoff, double zoff) {
564  for (int i = 0; i < static_cast<int>(size()); i++) {
565  (*this)[i].add(xoff, yoff, zoff);
566  }
567 }
568 
569 
570 void
572  add(offset.x(), offset.y(), offset.z());
573 }
574 
575 
576 void
578  for (int i = 0; i < static_cast<int>(size()); i++) {
579  (*this)[i].mul(1, -1);
580  }
581 }
582 
583 
585 
586 
587 int
589  return atan2(p1.x(), p1.y()) < atan2(p2.x(), p2.y());
590 }
591 
592 
593 void
595  std::sort(begin(), end(), increasing_x_y_sorter());
596 }
597 
598 
600 
601 
602 int
604  const Position& p2) const {
605  if (p1.x() != p2.x()) {
606  return p1.x() < p2.x();
607  }
608  return p1.y() < p2.y();
609 }
610 
611 
612 double
613 PositionVector::isLeft(const Position& P0, const Position& P1, const Position& P2) const {
614  return (P1.x() - P0.x()) * (P2.y() - P0.y()) - (P2.x() - P0.x()) * (P1.y() - P0.y());
615 }
616 
617 
618 void
619 PositionVector::append(const PositionVector& v, double sameThreshold) {
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(double beginOffset, double 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  double 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  seen += (*i).distanceTo(*(i + 1));
657  i++;
658  }
659  // append end
660  ret.push_back_noDoublePos(endPos);
661  if (ret.size() == 1) {
662  ret.push_back(endPos);
663  }
664  return ret;
665 }
666 
667 
669 PositionVector::getSubpart2D(double beginOffset, double endOffset) const {
670  PositionVector ret;
671  Position begPos = front();
672  if (beginOffset > POSITION_EPS) {
673  begPos = positionAtOffset2D(beginOffset);
674  }
675  Position endPos = back();
676  if (endOffset < length2D() - POSITION_EPS) {
677  endPos = positionAtOffset2D(endOffset);
678  }
679  ret.push_back(begPos);
680 
681  double seen = 0;
682  const_iterator i = begin();
683  // skip previous segments
684  while ((i + 1) != end()
685  &&
686  seen + (*i).distanceTo2D(*(i + 1)) < beginOffset) {
687  seen += (*i).distanceTo2D(*(i + 1));
688  i++;
689  }
690  // append segments in between
691  while ((i + 1) != end()
692  &&
693  seen + (*i).distanceTo2D(*(i + 1)) < endOffset) {
694 
695  ret.push_back_noDoublePos(*(i + 1));
696  seen += (*i).distanceTo2D(*(i + 1));
697  i++;
698  }
699  // append end
700  ret.push_back_noDoublePos(endPos);
701  if (ret.size() == 1) {
702  ret.push_back(endPos);
703  }
704  return ret;
705 }
706 
707 
709 PositionVector::getSubpartByIndex(int beginIndex, int count) const {
710  if (beginIndex < 0) {
711  beginIndex += (int)size();
712  }
713  assert(count >= 0);
714  assert(beginIndex < (int)size());
715  assert(beginIndex + count <= (int)size());
716  PositionVector result;
717  for (int i = beginIndex; i < beginIndex + count; ++i) {
718  result.push_back((*this)[i]);
719  }
720  return result;
721 }
722 
723 
724 double
726  return front().angleTo2D(back());
727 }
728 
729 
730 double
731 PositionVector::nearest_offset_to_point2D(const Position& p, bool perpendicular) const {
732  double minDist = std::numeric_limits<double>::max();
733  double nearestPos = GeomHelper::INVALID_OFFSET;
734  double seen = 0;
735  for (const_iterator i = begin(); i != end() - 1; i++) {
736  const double pos =
737  GeomHelper::nearest_offset_on_line_to_point2D(*i, *(i + 1), p, perpendicular);
738  const double dist = pos == GeomHelper::INVALID_OFFSET ? minDist : p.distanceTo2D(positionAtOffset2D(*i, *(i + 1), pos));
739  if (dist < minDist) {
740  nearestPos = pos + seen;
741  minDist = dist;
742  }
743  if (perpendicular && i != begin() && pos == GeomHelper::INVALID_OFFSET) {
744  // even if perpendicular is set we still need to check the distance to the inner points
745  const double cornerDist = p.distanceTo2D(*i);
746  if (cornerDist < minDist) {
747  const double pos1 =
748  GeomHelper::nearest_offset_on_line_to_point2D(*(i - 1), *i, p, false);
749  const double pos2 =
750  GeomHelper::nearest_offset_on_line_to_point2D(*i, *(i + 1), p, false);
751  if (pos1 == (*(i - 1)).distanceTo2D(*i) && pos2 == 0.) {
752  nearestPos = seen;
753  minDist = cornerDist;
754  }
755  }
756  }
757  seen += (*i).distanceTo2D(*(i + 1));
758  }
759  return nearestPos;
760 }
761 
762 
763 Position
765  // @toDo this duplicates most of the code in nearest_offset_to_point2D. It should be refactored
766  if (extend) {
767  PositionVector extended = *this;
768  const double dist = 2 * distance2D(p);
769  extended.extrapolate(dist);
770  return extended.transformToVectorCoordinates(p) - Position(dist, 0);
771  }
772  double minDist = std::numeric_limits<double>::max();
773  double nearestPos = -1;
774  double seen = 0;
775  int sign = 1;
776  for (const_iterator i = begin(); i != end() - 1; i++) {
777  const double pos =
778  GeomHelper::nearest_offset_on_line_to_point2D(*i, *(i + 1), p, true);
779  const double dist = pos < 0 ? minDist : p.distanceTo2D(positionAtOffset(*i, *(i + 1), pos));
780  if (dist < minDist) {
781  nearestPos = pos + seen;
782  minDist = dist;
783  sign = isLeft(*i, *(i + 1), p) >= 0 ? -1 : 1;
784  }
785  if (i != begin() && pos == GeomHelper::INVALID_OFFSET) {
786  // even if perpendicular is set we still need to check the distance to the inner points
787  const double cornerDist = p.distanceTo2D(*i);
788  if (cornerDist < minDist) {
789  const double pos1 =
790  GeomHelper::nearest_offset_on_line_to_point2D(*(i - 1), *i, p, false);
791  const double pos2 =
792  GeomHelper::nearest_offset_on_line_to_point2D(*i, *(i + 1), p, false);
793  if (pos1 == (*(i - 1)).distanceTo2D(*i) && pos2 == 0.) {
794  nearestPos = seen;
795  minDist = cornerDist;
796  sign = isLeft(*(i - 1), *i, p) >= 0 ? -1 : 1;
797  }
798  }
799  }
800  seen += (*i).distanceTo2D(*(i + 1));
801  }
802  if (nearestPos != -1) {
803  return Position(nearestPos, sign * minDist);
804  } else {
805  return Position::INVALID;
806  }
807 }
808 
809 
810 int
812  assert(size() > 0);
813  double minDist = std::numeric_limits<double>::max();
814  double dist;
815  int closest = 0;
816  for (int i = 0; i < (int)size(); i++) {
817  dist = p.distanceTo((*this)[i]);
818  if (dist < minDist) {
819  closest = i;
820  minDist = dist;
821  }
822  }
823  return closest;
824 }
825 
826 
827 int
829  double minDist = std::numeric_limits<double>::max();
830  int insertionIndex = 1;
831  for (int i = 0; i < (int)size() - 1; i++) {
832  const double length = GeomHelper::nearest_offset_on_line_to_point2D((*this)[i], (*this)[i + 1], p, false);
833  const Position& outIntersection = PositionVector::positionAtOffset2D((*this)[i], (*this)[i + 1], length);
834  const double dist = p.distanceTo2D(outIntersection);
835  if (dist < minDist) {
836  insertionIndex = i + 1;
837  minDist = dist;
838  }
839  }
840  insert(begin() + insertionIndex, p);
841  return insertionIndex;
842 }
843 
844 
845 int
847  if (size() == 0) {
848  return -1;
849  }
850  double minDist = std::numeric_limits<double>::max();
851  int removalIndex = 0;
852  for (int i = 0; i < (int)size(); i++) {
853  const double dist = p.distanceTo2D((*this)[i]);
854  if (dist < minDist) {
855  removalIndex = i;
856  minDist = dist;
857  }
858  }
859  erase(begin() + removalIndex);
860  return removalIndex;
861 }
862 
863 
864 std::vector<double>
866  std::vector<double> ret;
867  for (const_iterator i = other.begin(); i != other.end() - 1; i++) {
868  std::vector<double> atSegment = intersectsAtLengths2D(*i, *(i + 1));
869  copy(atSegment.begin(), atSegment.end(), back_inserter(ret));
870  }
871  return ret;
872 }
873 
874 
875 std::vector<double>
877  std::vector<double> ret;
878  double pos = 0;
879  for (const_iterator i = begin(); i != end() - 1; i++) {
880  const Position& p1 = *i;
881  const Position& p2 = *(i + 1);
882  double x, y, m;
883  if (intersects(p1, p2, lp1, lp2, 0., &x, &y, &m)) {
884  ret.push_back(Position(x, y).distanceTo2D(p1) + pos);
885  }
886  pos += p1.distanceTo2D(p2);
887  }
888  return ret;
889 }
890 
891 
892 void
893 PositionVector::extrapolate(const double val, const bool onlyFirst, const bool onlyLast) {
894  assert(size() > 1);
895  Position& p1 = (*this)[0];
896  Position& p2 = (*this)[1];
897  const Position offset = (p2 - p1) * (val / p1.distanceTo(p2));
898  if (!onlyLast) {
899  p1.sub(offset);
900  }
901  if (!onlyFirst) {
902  if (size() == 2) {
903  p2.add(offset);
904  } else {
905  const Position& e1 = (*this)[-2];
906  Position& e2 = (*this)[-1];
907  e2.sub((e1 - e2) * (val / e1.distanceTo(e2)));
908  }
909  }
910 }
911 
912 
913 void
914 PositionVector::extrapolate2D(const double val, const bool onlyFirst) {
915  assert(size() > 1);
916  Position& p1 = (*this)[0];
917  Position& p2 = (*this)[1];
918  const Position offset = (p2 - p1) * (val / p1.distanceTo2D(p2));
919  p1.sub(offset);
920  if (!onlyFirst) {
921  if (size() == 2) {
922  p2.add(offset);
923  } else {
924  const Position& e1 = (*this)[-2];
925  Position& e2 = (*this)[-1];
926  e2.sub((e1 - e2) * (val / e1.distanceTo2D(e2)));
927  }
928  }
929 }
930 
931 
934  PositionVector ret;
935  for (const_reverse_iterator i = rbegin(); i != rend(); i++) {
936  ret.push_back(*i);
937  }
938  return ret;
939 }
940 
941 
942 Position
943 PositionVector::sideOffset(const Position& beg, const Position& end, const double amount) {
944  const double scale = amount / beg.distanceTo2D(end);
945  return Position((beg.y() - end.y()) * scale, (end.x() - beg.x()) * scale);
946 }
947 
948 
949 void
951  if (size() < 2) {
952  return;
953  }
955  if (length2D() == 0) {
956  return;
957  }
958  PositionVector shape;
959  for (int i = 0; i < static_cast<int>(size()); i++) {
960  if (i == 0) {
961  const Position& from = (*this)[i];
962  const Position& to = (*this)[i + 1];
963  if (from != to) {
964  shape.push_back(from - sideOffset(from, to, amount));
965  }
966  } else if (i == static_cast<int>(size()) - 1) {
967  const Position& from = (*this)[i - 1];
968  const Position& to = (*this)[i];
969  if (from != to) {
970  shape.push_back(to - sideOffset(from, to, amount));
971  }
972  } else {
973  const Position& from = (*this)[i - 1];
974  const Position& me = (*this)[i];
975  const Position& to = (*this)[i + 1];
976  PositionVector fromMe(from, me);
977  fromMe.extrapolate2D(me.distanceTo2D(to));
978  const double extrapolateDev = fromMe[1].distanceTo2D(to);
979  if (fabs(extrapolateDev) < POSITION_EPS) {
980  // parallel case, just shift the middle point
981  shape.push_back(me - sideOffset(from, to, amount));
982  } else if (fabs(extrapolateDev - 2 * me.distanceTo2D(to)) < POSITION_EPS) {
983  // counterparallel case, just shift the middle point
984  PositionVector fromMe(from, me);
985  fromMe.extrapolate2D(amount);
986  shape.push_back(fromMe[1]);
987  } else {
988  Position offsets = sideOffset(from, me, amount);
989  Position offsets2 = sideOffset(me, to, amount);
990  PositionVector l1(from - offsets, me - offsets);
991  PositionVector l2(me - offsets2, to - offsets2);
992  Position meNew = l1.intersectionPosition2D(l2[0], l2[1], 100);
993  if (meNew == Position::INVALID) {
994  throw InvalidArgument("no line intersection");
995  }
996  meNew = meNew + Position(0, 0, me.z());
997  shape.push_back(meNew);
998  }
999  // copy original z value
1000  shape.back().set(shape.back().x(), shape.back().y(), me.z());
1001  }
1002  }
1003  *this = shape;
1004 }
1005 
1006 
1007 double
1009  assert((int)size() > pos + 1);
1010  return (*this)[pos].angleTo2D((*this)[pos + 1]);
1011 }
1012 
1013 
1014 void
1016  if (size() == 0 || (*this)[0] == back()) {
1017  return;
1018  }
1019  push_back((*this)[0]);
1020 }
1021 
1022 
1023 std::vector<double>
1024 PositionVector::distances(const PositionVector& s, bool perpendicular) const {
1025  std::vector<double> ret;
1026  const_iterator i;
1027  for (i = begin(); i != end(); i++) {
1028  const double dist = s.distance2D(*i, perpendicular);
1029  if (dist != GeomHelper::INVALID_OFFSET) {
1030  ret.push_back(dist);
1031  }
1032  }
1033  for (i = s.begin(); i != s.end(); i++) {
1034  const double dist = distance2D(*i, perpendicular);
1035  if (dist != GeomHelper::INVALID_OFFSET) {
1036  ret.push_back(dist);
1037  }
1038  }
1039  return ret;
1040 }
1041 
1042 
1043 double
1044 PositionVector::distance2D(const Position& p, bool perpendicular) const {
1045  if (size() == 0) {
1047  } else if (size() == 1) {
1048  return front().distanceTo(p);
1049  }
1050  const double nearestOffset = nearest_offset_to_point2D(p, perpendicular);
1051  if (nearestOffset == GeomHelper::INVALID_OFFSET) {
1053  } else {
1054  return p.distanceTo2D(positionAtOffset2D(nearestOffset));
1055  }
1056 }
1057 
1058 
1059 void
1061  if (size() == 0 || !p.almostSame(back())) {
1062  push_back(p);
1063  }
1064 }
1065 
1066 
1067 void
1069  if (size() == 0 || !p.almostSame(front())) {
1070  insert(begin(), p);
1071  }
1072 }
1073 
1074 
1075 void
1076 PositionVector::insert_noDoublePos(const std::vector<Position>::iterator& at, const Position& p) {
1077  if (at == begin()) {
1079  } else if (at == end()) {
1081  } else {
1082  if (!p.almostSame(*at) && !p.almostSame(*(at - 1))) {
1083  insert(at, p);
1084  }
1085  }
1086 }
1087 
1088 
1089 bool
1091  return size() >= 2 && (*this)[0] == back();
1092 }
1093 
1094 
1095 void
1096 PositionVector::removeDoublePoints(double minDist, bool assertLength) {
1097  if (size() > 1) {
1098  iterator last = begin();
1099  for (iterator i = begin() + 1; i != end() && (!assertLength || size() > 2);) {
1100  if (last->almostSame(*i, minDist)) {
1101  i = erase(i);
1102  } else {
1103  last = i;
1104  ++i;
1105  }
1106  }
1107  }
1108 }
1109 
1110 
1111 bool
1113  return static_cast<vp>(*this) == static_cast<vp>(v2);
1114 }
1115 
1116 
1117 bool
1119  return static_cast<vp>(*this) != static_cast<vp>(v2);
1120 }
1121 
1124  if (length() != v2.length()) {
1125  WRITE_ERROR("Trying to substract PositionVectors of different lengths.");
1126  }
1127  PositionVector pv;
1128  auto i1 = begin();
1129  auto i2 = v2.begin();
1130  while (i1 != end()) {
1131  pv.add(*i1 - *i2);
1132  }
1133  return pv;
1134 }
1135 
1138  if (length() != v2.length()) {
1139  WRITE_ERROR("Trying to substract PositionVectors of different lengths.");
1140  }
1141  PositionVector pv;
1142  auto i1 = begin();
1143  auto i2 = v2.begin();
1144  while (i1 != end()) {
1145  pv.add(*i1 + *i2);
1146  }
1147  return pv;
1148 }
1149 
1150 bool
1152  if (size() < 2) {
1153  return false;
1154  }
1155  for (const_iterator i = begin(); i != end() - 1; i++) {
1156  if ((*i).z() != (*(i + 1)).z()) {
1157  return true;
1158  }
1159  }
1160  return false;
1161 }
1162 
1163 
1164 bool
1165 PositionVector::intersects(const Position& p11, const Position& p12, const Position& p21, const Position& p22, const double withinDist, double* x, double* y, double* mu) {
1166  const double eps = std::numeric_limits<double>::epsilon();
1167  const double denominator = (p22.y() - p21.y()) * (p12.x() - p11.x()) - (p22.x() - p21.x()) * (p12.y() - p11.y());
1168  const double numera = (p22.x() - p21.x()) * (p11.y() - p21.y()) - (p22.y() - p21.y()) * (p11.x() - p21.x());
1169  const double numerb = (p12.x() - p11.x()) * (p11.y() - p21.y()) - (p12.y() - p11.y()) * (p11.x() - p21.x());
1170  /* Are the lines coincident? */
1171  if (fabs(numera) < eps && fabs(numerb) < eps && fabs(denominator) < eps) {
1172  double a1;
1173  double a2;
1174  double a3;
1175  double a4;
1176  double a = -1e12;
1177  if (p11.x() != p12.x()) {
1178  a1 = p11.x() < p12.x() ? p11.x() : p12.x();
1179  a2 = p11.x() < p12.x() ? p12.x() : p11.x();
1180  a3 = p21.x() < p22.x() ? p21.x() : p22.x();
1181  a4 = p21.x() < p22.x() ? p22.x() : p21.x();
1182  } else {
1183  a1 = p11.y() < p12.y() ? p11.y() : p12.y();
1184  a2 = p11.y() < p12.y() ? p12.y() : p11.y();
1185  a3 = p21.y() < p22.y() ? p21.y() : p22.y();
1186  a4 = p21.y() < p22.y() ? p22.y() : p21.y();
1187  }
1188  if (a1 <= a3 && a3 <= a2) {
1189  if (a4 < a2) {
1190  a = (a3 + a4) / 2;
1191  } else {
1192  a = (a2 + a3) / 2;
1193  }
1194  }
1195  if (a3 <= a1 && a1 <= a4) {
1196  if (a2 < a4) {
1197  a = (a1 + a2) / 2;
1198  } else {
1199  a = (a1 + a4) / 2;
1200  }
1201  }
1202  if (a != -1e12) {
1203  if (x != 0) {
1204  if (p11.x() != p12.x()) {
1205  *mu = (a - p11.x()) / (p12.x() - p11.x());
1206  *x = a;
1207  *y = p11.y() + (*mu) * (p12.y() - p11.y());
1208  } else {
1209  *x = p11.x();
1210  *y = a;
1211  if (p12.y() == p11.y()) {
1212  *mu = 0;
1213  } else {
1214  *mu = (a - p11.y()) / (p12.y() - p11.y());
1215  }
1216  }
1217  }
1218  return true;
1219  }
1220  return false;
1221  }
1222  /* Are the lines parallel */
1223  if (fabs(denominator) < eps) {
1224  return false;
1225  }
1226  /* Is the intersection along the segments */
1227  double mua = numera / denominator;
1228  /* reduce rounding errors for lines ending in the same point */
1229  if (fabs(p12.x() - p22.x()) < eps && fabs(p12.y() - p22.y()) < eps) {
1230  mua = 1.;
1231  } else {
1232  const double offseta = withinDist / p11.distanceTo2D(p12);
1233  const double offsetb = withinDist / p21.distanceTo2D(p22);
1234  const double mub = numerb / denominator;
1235  if (mua < -offseta || mua > 1 + offseta || mub < -offsetb || mub > 1 + offsetb) {
1236  return false;
1237  }
1238  }
1239  if (x != 0) {
1240  *x = p11.x() + mua * (p12.x() - p11.x());
1241  *y = p11.y() + mua * (p12.y() - p11.y());
1242  *mu = mua;
1243  }
1244  return true;
1245 }
1246 
1247 
1248 void
1250  const double s = sin(angle);
1251  const double c = cos(angle);
1252  for (int i = 0; i < (int)size(); i++) {
1253  const double x = (*this)[i].x();
1254  const double y = (*this)[i].y();
1255  const double z = (*this)[i].z();
1256  const double xnew = x * c - y * s;
1257  const double ynew = x * s + y * c;
1258  (*this)[i].set(xnew, ynew, z);
1259  }
1260 }
1261 
1262 
1265  PositionVector result = *this;
1266  bool changed = true;
1267  while (changed && result.size() > 3) {
1268  changed = false;
1269  for (int i = 0; i < (int)result.size(); i++) {
1270  const Position& p1 = result[i];
1271  const Position& p2 = result[(i + 2) % result.size()];
1272  const int middleIndex = (i + 1) % result.size();
1273  const Position& p0 = result[middleIndex];
1274  // https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line#Line_defined_by_two_points
1275  const double triangleArea2 = fabs((p2.y() - p1.y()) * p0.x() - (p2.x() - p1.x()) * p0.y() + p2.x() * p1.y() - p2.y() * p1.x());
1276  const double distIK = p1.distanceTo2D(p2);
1277  if (distIK > NUMERICAL_EPS && triangleArea2 / distIK < NUMERICAL_EPS) {
1278  changed = true;
1279  result.erase(result.begin() + middleIndex);
1280  break;
1281  }
1282  }
1283  }
1284  return result;
1285 }
1286 
1287 
1289 PositionVector::getOrthogonal(const Position& p, double extend, bool before, double length) const {
1290  PositionVector result;
1291  PositionVector tmp = *this;
1292  tmp.extrapolate2D(extend);
1293  const double baseOffset = tmp.nearest_offset_to_point2D(p);
1294  if (baseOffset == GeomHelper::INVALID_OFFSET || size() < 2) {
1295  // fail
1296  return result;
1297  }
1298  Position base = tmp.positionAtOffset2D(baseOffset);
1299  const int closestIndex = tmp.indexOfClosest(base);
1300  result.push_back(base);
1301  if (fabs(baseOffset - tmp.offsetAtIndex2D(closestIndex)) > NUMERICAL_EPS) {
1302  result.push_back(tmp[closestIndex]);
1303  } else if (before) {
1304  // take the segment before closestIndex if possible
1305  if (closestIndex > 0) {
1306  result.push_back(tmp[closestIndex - 1]);
1307  } else {
1308  result.push_back(tmp[1]);
1309  }
1310  } else {
1311  // take the segment after closestIndex if possible
1312  if (closestIndex < (int)size() - 1) {
1313  result.push_back(tmp[closestIndex + 1]);
1314  } else {
1315  result.push_back(tmp[-1]);
1316  }
1317  }
1318  result = result.getSubpart2D(0, length);
1319  // rotate around base
1320  result.add(base * -1);
1321  result.rotate2D(DEG2RAD(90));
1322  result.add(base);
1323  return result;
1324 }
1325 
1326 
1329  PositionVector result = *this;
1330  const double z0 = (*this)[0].z();
1331  // the z-delta of the first segment
1332  const double dz = (*this)[1].z() - z0;
1333  // if the shape only has 2 points it is as smooth as possible already
1334  if (size() > 2 && dz != 0) {
1335  dist = MIN2(dist, length());
1336  // check wether we need to insert a new point at dist
1337  Position pDist = positionAtOffset(dist);
1338  int iLast = indexOfClosest(pDist);
1339  // prevent close spacing to reduce impact of rounding errors in z-axis
1340  if (pDist.distanceTo2D((*this)[iLast]) > POSITION_EPS * 20) {
1341  iLast = result.insertAtClosest(pDist);
1342  }
1343  double dist2 = result.offsetAtIndex2D(iLast);
1344  const double dz2 = result[iLast].z() - z0;
1345  double seen = 0;
1346  for (int i = 1; i < iLast; ++i) {
1347  seen += result[i].distanceTo2D(result[i - 1]);
1348  result[i].set(result[i].x(), result[i].y(), z0 + dz2 * seen / dist2);
1349  }
1350  }
1351  return result;
1352 
1353 }
1354 
1355 
1356 double
1358  if (index < 0 || index >= (int)size()) {
1360  }
1361  double seen = 0;
1362  for (int i = 1; i <= index; ++i) {
1363  seen += (*this)[i].distanceTo2D((*this)[i - 1]);
1364  }
1365  return seen;
1366 }
1367 
1368 
1369 double
1371  double result = 0;
1372  for (int i = 1; i < (int)size(); ++i) {
1373  const Position& p1 = (*this)[i - 1];
1374  const Position& p2 = (*this)[i];
1375  result = MAX2(result, (double)fabs((p1.z() - p2.z()) / p1.distanceTo2D(p2)));
1376  }
1377  return result;
1378 }
1379 
1380 /****************************************************************************/
1381 
clase for increasing Sorter
double z() const
Returns the z-position.
Definition: Position.h:73
bool hasElevation() const
return whether two positions differ in z-coordinate
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition: Position.h:250
void append(const PositionVector &v, double sameThreshold=2.0)
void sortAsPolyCWByAngle()
short as polygon CV by angle
Position intersectionPosition2D(const Position &p1, const Position &p2, const double withinDist=0.) const
Returns the position of the intersection.
void add(const Position &pos)
Adds the given position to this one.
Definition: Position.h:133
virtual bool around(const Position &p, double offset=0) const =0
bool around(const Position &p, double offset=0) const
Returns the information whether the position vector describes a polygon lying around the given point...
double nearest_offset_to_point2D(const Position &p, bool perpendicular=true) const
return the nearest offest to point 2D
friend std::ostream & operator<<(std::ostream &os, const PositionVector &geom)
bool operator!=(const PositionVector &v2) const
comparing operation
double x() const
Returns the x-position.
Definition: Position.h:63
std::vector< double > intersectsAtLengths2D(const PositionVector &other) const
For all intersections between this vector and other, return the 2D-length of the subvector from this ...
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.
double 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) ...
T MAX2(T a, T b)
Definition: StdDefs.h:74
double slopeDegreeAtOffset(double pos) const
Returns the slope at the given length.
PositionVector getSubpartByIndex(int beginIndex, int count) const
get subpart of a position vector using index and a cout
PositionVector getSubpart2D(double beginOffset, double endOffset) const
get subpart of a position vector in two dimensions (Z is ignored)
#define RAD2DEG(x)
Definition: GeomHelper.h:46
PositionVector getOrthogonal(const Position &p, double extend, bool before, double length=1.0) const
return orthogonal through p (extending this vector if necessary)
void insert_noDoublePos(const std::vector< Position >::iterator &at, const Position &p)
insert in front a non double position
PositionVector operator-(const PositionVector &v2) const
substracts two vectors (requires vectors of the same length)
bool isClosed() const
check if PositionVector is closed
const Position & operator[](int index) const
returns the constat position at the given index !!! exceptions?
A class that stores a 2D geometrical boundary.
Definition: Boundary.h:48
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:200
bool overlapsWith(const AbstractPoly &poly, double offset=0) const
Returns the information whether the given polygon overlaps with this.
static double legacyDegree(const double angle, const bool positive=false)
Definition: GeomHelper.cpp:206
PositionVector reverse() const
reverse position vector
~PositionVector()
Destructor.
double getOverlapWith(const PositionVector &poly, double zThreshold) const
Returns the maximum overlaps between this and the given polygon (when not separated by at least zThre...
double isLeft(const Position &P0, const Position &P1, const Position &P2) const
get left
void extrapolate2D(const double val, const bool onlyFirst=false)
extrapolate position vector in two dimensions (Z is ignored)
void push_front_noDoublePos(const Position &p)
insert in front a non double position
double area() const
Returns the area (0 for non-closed)
void removeDoublePoints(double minDist=POSITION_EPS, bool assertLength=false)
Removes positions if too near.
std::vector< double > distances(const PositionVector &s, bool perpendicular=false) const
distances of all my points to s and all of s points to myself
#define max(a, b)
Definition: polyfonts.c:65
static double nearest_offset_on_line_to_point2D(const Position &lineStart, const Position &lineEnd, const Position &p, bool perpendicular=true)
Definition: GeomHelper.cpp:96
PositionVector simplified() const
return the same shape with intermediate colinear points removed
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:56
void scaleAbsolute(double offset)
enlarges/shrinks the polygon by an absolute offset based at the centroid
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:46
std::vector< Position > vp
vector of position
A list of positions.
double rotationDegreeAtOffset(double pos) const
Returns the rotation at the given length.
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
double y() const
Returns the y-position.
Definition: Position.h:68
static double 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:90
virtual bool crosses(const Position &p1, const Position &p2) const =0
double length() const
Returns the length.
bool partialWithin(const AbstractPoly &poly, double offset=0) const
Returns the information whether this polygon lies partially within the given polygon.
T MIN2(T a, T b)
Definition: StdDefs.h:68
PositionVector operator+(const PositionVector &v2) const
adds two vectors (requires vectors of the same length)
#define POSITION_EPS
Definition: config.h:176
Position positionAtOffset2D(double pos, double lateralOffset=0) const
Returns the position at the given length.
int insertAtClosest(const Position &p)
inserts p between the two closest positions and returns the insertion index
#define DEG2RAD(x)
Definition: GeomHelper.h:45
static const double INVALID_OFFSET
a value to signify offsets outside the range of [0, Line.length()]
Definition: GeomHelper.h:59
void sortByIncreasingXY()
shory by increasing X-Y Psitions
void move2side(double amount)
move position vector to side using certain ammount
double distanceTo(const Position &p2) const
returns the euclidean distance in 3 dimension
Definition: Position.h:240
bool operator==(const PositionVector &v2) const
comparing operation
double getMaxGrade() const
return the maximum grade of all segments as a fraction of zRange/length2D
bool almostSame(const Position &p2, double maxDiv=POSITION_EPS) const
checki if two position is almost the sme as other
Definition: Position.h:235
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:206
PositionVector()
Constructor. Creates an empty position vector.
PositionVector smoothedZFront(double dist=std::numeric_limits< double >::max()) const
returned vector that is smoothed at the front (within dist)
void rotate2D(double angle)
double rotationAtOffset(double pos) const
Returns the rotation at the given length.
void extrapolate(const double val, const bool onlyFirst=false, const bool onlyLast=false)
extrapolate position vector
#define sign(a)
Definition: polyfonts.c:68
double length2D() const
Returns the length.
Position positionAtOffset(double pos, double lateralOffset=0) const
Returns the position at the given length.
#define M_PI
Definition: odrSpiral.cpp:40
static Position sideOffset(const Position &beg, const Position &end, const double amount)
get a side position of position vector using a offset
void scaleRelative(double factor)
enlarges/shrinks the polygon by a factor based at the centroid
Position getLineCenter() const
get line center
PositionVector getSubpart(double beginOffset, double endOffset) const
get subpart of a position vector
std::pair< PositionVector, PositionVector > splitAt(double where) const
Returns the two lists made when this list vector is splitted at the given point.
#define NUMERICAL_EPS
Definition: config.h:152
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
double offsetAtIndex2D(int index) const
return the offset at the given index
virtual bool partialWithin(const AbstractPoly &poly, double offset=0) const =0
Position getPolygonCenter() const
Returns the arithmetic of all corner points.
void add(double x, double y, double z=0)
Makes the boundary include the given coordinate.
Definition: Boundary.cpp:86
void add(double xoff, double yoff, double zoff)
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
int removeClosest(const Position &p)
removes the point closest to p and return the removal index
double angleAt2D(int pos) const
get angle in certain position of position vector
double angleTo2D(const Position &other) const
returns the angle in the plane of the vector pointing from here to the other position ...
Definition: Position.h:260
double beginEndAngle() const
returns the angle in radians of the line connecting the first and the last position ...
static const Position INVALID
used to indicate that a position is valid
Definition: Position.h:278
Position transformToVectorCoordinates(const Position &p, bool extend=false) const
return position p within the length-wise coordinate system defined by this position vector...
void sub(double dx, double dy)
Substracts the given position from this one.
Definition: Position.h:153