LCOV - code coverage report
Current view: top level - src/utils/geom - PositionVector.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 742 860 86.3 %
Date: 2024-05-07 15:28:01 Functions: 89 100 89.0 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
       4             : // This program and the accompanying materials are made available under the
       5             : // terms of the Eclipse Public License 2.0 which is available at
       6             : // https://www.eclipse.org/legal/epl-2.0/
       7             : // This Source Code may also be made available under the following Secondary
       8             : // Licenses when the conditions for such availability set forth in the Eclipse
       9             : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10             : // or later which is available at
      11             : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12             : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13             : /****************************************************************************/
      14             : /// @file    PositionVector.cpp
      15             : /// @author  Daniel Krajzewicz
      16             : /// @author  Jakob Erdmann
      17             : /// @author  Michael Behrisch
      18             : /// @author  Walter Bamberger
      19             : /// @date    Sept 2002
      20             : ///
      21             : // A list of positions
      22             : /****************************************************************************/
      23             : #include <config.h>
      24             : 
      25             : #include <queue>
      26             : #include <cmath>
      27             : #include <iostream>
      28             : #include <algorithm>
      29             : #include <numeric>
      30             : #include <cassert>
      31             : #include <iterator>
      32             : #include <limits>
      33             : #include <utils/common/StdDefs.h>
      34             : #include <utils/common/MsgHandler.h>
      35             : #include <utils/common/ToString.h>
      36             : #include "AbstractPoly.h"
      37             : #include "Position.h"
      38             : #include "PositionVector.h"
      39             : #include "GeomHelper.h"
      40             : #include "Boundary.h"
      41             : 
      42             : //#define DEBUG_MOVE2SIDE
      43             : 
      44             : // ===========================================================================
      45             : // static members
      46             : // ===========================================================================
      47             : const PositionVector PositionVector::EMPTY;
      48             : 
      49             : // ===========================================================================
      50             : // method definitions
      51             : // ===========================================================================
      52             : 
      53    57131408 : PositionVector::PositionVector() {}
      54             : 
      55             : 
      56         654 : PositionVector::PositionVector(const std::vector<Position>& v) {
      57             :     std::copy(v.begin(), v.end(), std::back_inserter(*this));
      58         654 : }
      59             : 
      60             : 
      61           0 : PositionVector::PositionVector(const std::vector<Position>::const_iterator beg, const std::vector<Position>::const_iterator end) {
      62             :     std::copy(beg, end, std::back_inserter(*this));
      63           0 : }
      64             : 
      65             : 
      66     9933002 : PositionVector::PositionVector(const Position& p1, const Position& p2) {
      67     9933002 :     push_back(p1);
      68     9933002 :     push_back(p2);
      69     9933002 : }
      70             : 
      71             : 
      72   148111718 : PositionVector::~PositionVector() {}
      73             : 
      74             : 
      75             : bool
      76    41263027 : PositionVector::around(const Position& p, double offset) const {
      77    41263027 :     if (size() < 2) {
      78             :         return false;
      79             :     }
      80    41263019 :     if (offset != 0) {
      81             :         PositionVector tmp(*this);
      82         818 :         tmp.scaleAbsolute(offset);
      83         818 :         return tmp.around(p);
      84         818 :     }
      85             :     double angle = 0;
      86             :     // iterate over all points, and obtain angle between current and next
      87   174231607 :     for (const_iterator i = begin(); i != (end() - 1); i++) {
      88             :         Position p1(
      89             :             i->x() - p.x(),
      90   132969406 :             i->y() - p.y());
      91             :         Position p2(
      92             :             (i + 1)->x() - p.x(),
      93   132969406 :             (i + 1)->y() - p.y());
      94   132969406 :         angle += GeomHelper::angle2D(p1, p2);
      95             :     }
      96             :     // add angle between last and first point
      97             :     Position p1(
      98             :         (end() - 1)->x() - p.x(),
      99    41262201 :         (end() - 1)->y() - p.y());
     100             :     Position p2(
     101             :         begin()->x() - p.x(),
     102    41262201 :         begin()->y() - p.y());
     103    41262201 :     angle += GeomHelper::angle2D(p1, p2);
     104             :     // if angle is less than PI, then point lying in Polygon
     105    41262201 :     return (!(fabs(angle) < M_PI));
     106             : }
     107             : 
     108             : 
     109             : bool
     110     5024156 : PositionVector::overlapsWith(const AbstractPoly& poly, double offset) const {
     111             :     if (
     112             :         // check whether one of my points lies within the given poly
     113    10030192 :         partialWithin(poly, offset) ||
     114             :         // check whether the polygon lies within me
     115     5006036 :         poly.partialWithin(*this, offset)) {
     116       34356 :         return true;
     117             :     }
     118     4989800 :     if (size() >= 2) {
     119    19983233 :         for (const_iterator i = begin(); i != end() - 1; i++) {
     120    14995206 :             if (poly.crosses(*i, *(i + 1))) {
     121             :                 return true;
     122             :             }
     123             :         }
     124     4988027 :         if (size() > 2 && poly.crosses(back(), front())) {
     125           0 :             return true;
     126             :         }
     127             :     }
     128             :     return false;
     129             : }
     130             : 
     131             : 
     132             : double
     133           0 : PositionVector::getOverlapWith(const PositionVector& poly, double zThreshold) const {
     134             :     double result = 0;
     135           0 :     if ((size() == 0) || (poly.size() == 0)) {
     136             :         return result;
     137             :     }
     138             :     // this points within poly
     139           0 :     for (const_iterator i = begin(); i != end() - 1; i++) {
     140           0 :         if (poly.around(*i)) {
     141           0 :             Position closest = poly.positionAtOffset2D(poly.nearest_offset_to_point2D(*i));
     142           0 :             if (fabs(closest.z() - (*i).z()) < zThreshold) {
     143           0 :                 result = MAX2(result, poly.distance2D(*i));
     144             :             }
     145             :         }
     146             :     }
     147             :     // polys points within this
     148           0 :     for (const_iterator i = poly.begin(); i != poly.end() - 1; i++) {
     149           0 :         if (around(*i)) {
     150           0 :             Position closest = positionAtOffset2D(nearest_offset_to_point2D(*i));
     151           0 :             if (fabs(closest.z() - (*i).z()) < zThreshold) {
     152           0 :                 result = MAX2(result, distance2D(*i));
     153             :             }
     154             :         }
     155             :     }
     156             :     return result;
     157             : }
     158             : 
     159             : 
     160             : bool
     161    26651972 : PositionVector::intersects(const Position& p1, const Position& p2) const {
     162    26651972 :     if (size() < 2) {
     163             :         return false;
     164             :     }
     165    92881900 :     for (const_iterator i = begin(); i != end() - 1; i++) {
     166    67732682 :         if (intersects(*i, *(i + 1), p1, p2)) {
     167             :             return true;
     168             :         }
     169             :     }
     170             :     return false;
     171             : }
     172             : 
     173             : 
     174             : bool
     175     1574134 : PositionVector::intersects(const PositionVector& v1) const {
     176     1574134 :     if (size() < 2) {
     177             :         return false;
     178             :     }
     179     1664387 :     for (const_iterator i = begin(); i != end() - 1; i++) {
     180     1516764 :         if (v1.intersects(*i, *(i + 1))) {
     181             :             return true;
     182             :         }
     183             :     }
     184             :     return false;
     185             : }
     186             : 
     187             : 
     188             : Position
     189     2784669 : PositionVector::intersectionPosition2D(const Position& p1, const Position& p2, const double withinDist) const {
     190     2786775 :     for (const_iterator i = begin(); i != end() - 1; i++) {
     191             :         double x, y, m;
     192     2786769 :         if (intersects(*i, *(i + 1), p1, p2, withinDist, &x, &y, &m)) {
     193     2784663 :             return Position(x, y);
     194             :         }
     195             :     }
     196           6 :     return Position::INVALID;
     197             : }
     198             : 
     199             : 
     200             : Position
     201      260256 : PositionVector::intersectionPosition2D(const PositionVector& v1) const {
     202      267575 :     for (const_iterator i = begin(); i != end() - 1; i++) {
     203      263724 :         if (v1.intersects(*i, *(i + 1))) {
     204      256405 :             return v1.intersectionPosition2D(*i, *(i + 1));
     205             :         }
     206             :     }
     207        3851 :     return Position::INVALID;
     208             : }
     209             : 
     210             : 
     211             : const Position&
     212   168543382 : PositionVector::operator[](int index) const {
     213             :     /* bracket operators works as in Python. Examples:
     214             :         - A = {'a', 'b', 'c', 'd'} (size 4)
     215             :         - A [2] returns 'c' because 0 < 2 < 4
     216             :         - A [100] throws an exception because 100 > 4
     217             :         - A [-1] returns 'd' because 4 - 1 = 3
     218             :         - A [-100] throws an exception because (4-100) < 0
     219             :     */
     220   168543382 :     if (index >= 0 && index < (int)size()) {
     221   134486190 :         return at(index);
     222    34057192 :     } else if (index < 0 && -index <= (int)size()) {
     223    34057192 :         return at((int)size() + index);
     224             :     } else {
     225           0 :         throw OutOfBoundsException("Index out of range in bracket operator of PositionVector");
     226             :     }
     227             : }
     228             : 
     229             : 
     230             : Position&
     231   212666927 : PositionVector::operator[](int index) {
     232             :     /* bracket operators works as in Python. Examples:
     233             :         - A = {'a', 'b', 'c', 'd'} (size 4)
     234             :         - A [2] returns 'c' because 0 < 2 < 4
     235             :         - A [100] throws an exception because 100 > 4
     236             :         - A [-1] returns 'd' because 4 - 1 = 3
     237             :         - A [-100] throws an exception because (4-100) < 0
     238             :     */
     239   212666927 :     if (index >= 0 && index < (int)size()) {
     240   210006799 :         return at(index);
     241     2660128 :     } else if (index < 0 && -index <= (int)size()) {
     242     2660128 :         return at((int)size() + index);
     243             :     } else {
     244           0 :         throw OutOfBoundsException("Index out of range in bracket operator of PositionVector");
     245             :     }
     246             : }
     247             : 
     248             : 
     249             : Position
     250  1664848516 : PositionVector::positionAtOffset(double pos, double lateralOffset) const {
     251  1664848516 :     if (size() == 0) {
     252           0 :         return Position::INVALID;
     253             :     }
     254  1664848516 :     if (size() == 1) {
     255           0 :         return front();
     256             :     }
     257             :     const_iterator i = begin();
     258             :     double seenLength = 0;
     259             :     do {
     260  1939973506 :         const double nextLength = (*i).distanceTo(*(i + 1));
     261  1939973506 :         if (seenLength + nextLength > pos) {
     262  1664085790 :             return positionAtOffset(*i, *(i + 1), pos - seenLength, lateralOffset);
     263             :         }
     264             :         seenLength += nextLength;
     265   275887716 :     } while (++i != end() - 1);
     266      762726 :     if (lateralOffset == 0 || size() < 2) {
     267      741932 :         return back();
     268             :     } else {
     269       20794 :         return positionAtOffset(*(end() - 2), *(end() - 1), (*(end() - 2)).distanceTo(*(end() - 1)), lateralOffset);
     270             :     }
     271             : }
     272             : 
     273             : 
     274             : Position
     275      118930 : PositionVector::sidePositionAtAngle(double pos, double lateralOffset, double angle) const {
     276      118930 :     if (size() == 0) {
     277           0 :         return Position::INVALID;
     278             :     }
     279      118930 :     if (size() == 1) {
     280           0 :         return front();
     281             :     }
     282             :     const_iterator i = begin();
     283             :     double seenLength = 0;
     284             :     do {
     285      315531 :         const double nextLength = (*i).distanceTo(*(i + 1));
     286      315531 :         if (seenLength + nextLength > pos) {
     287      118384 :             return sidePositionAtAngle(*i, *(i + 1), pos - seenLength, lateralOffset, angle);
     288             :         }
     289             :         seenLength += nextLength;
     290      197147 :     } while (++i != end() - 1);
     291         546 :     return sidePositionAtAngle(*(end() - 2), *(end() - 1), (*(end() - 2)).distanceTo(*(end() - 1)), lateralOffset, angle);
     292             : }
     293             : 
     294             : 
     295             : Position
     296    25532289 : PositionVector::positionAtOffset2D(double pos, double lateralOffset) const {
     297    25532289 :     if (size() == 0) {
     298           0 :         return Position::INVALID;
     299             :     }
     300    25532289 :     if (size() == 1) {
     301           0 :         return front();
     302             :     }
     303             :     const_iterator i = begin();
     304             :     double seenLength = 0;
     305             :     do {
     306             :         const double nextLength = (*i).distanceTo2D(*(i + 1));
     307    40454949 :         if (seenLength + nextLength > pos) {
     308    20788678 :             return positionAtOffset2D(*i, *(i + 1), pos - seenLength, lateralOffset);
     309             :         }
     310             :         seenLength += nextLength;
     311    19666271 :     } while (++i != end() - 1);
     312     4743611 :     return back();
     313             : }
     314             : 
     315             : 
     316             : double
     317     3855653 : PositionVector::rotationAtOffset(double pos) const {
     318     3855653 :     if ((size() == 0) || (size() == 1)) {
     319             :         return INVALID_DOUBLE;
     320             :     }
     321     3855653 :     if (pos < 0) {
     322        2099 :         pos += length();
     323             :     }
     324             :     const_iterator i = begin();
     325             :     double seenLength = 0;
     326             :     do {
     327             :         const Position& p1 = *i;
     328             :         const Position& p2 = *(i + 1);
     329     6809978 :         const double nextLength = p1.distanceTo(p2);
     330     6809978 :         if (seenLength + nextLength > pos) {
     331     3733480 :             return p1.angleTo2D(p2);
     332             :         }
     333             :         seenLength += nextLength;
     334     3076498 :     } while (++i != end() - 1);
     335      122173 :     const Position& p1 = (*this)[-2];
     336             :     const Position& p2 = back();
     337      122173 :     return p1.angleTo2D(p2);
     338             : }
     339             : 
     340             : 
     341             : double
     342        8473 : PositionVector::rotationDegreeAtOffset(double pos) const {
     343        8473 :     return GeomHelper::legacyDegree(rotationAtOffset(pos));
     344             : }
     345             : 
     346             : 
     347             : double
     348      599366 : PositionVector::slopeDegreeAtOffset(double pos) const {
     349      599366 :     if (size() == 0) {
     350             :         return INVALID_DOUBLE;
     351             :     }
     352             :     const_iterator i = begin();
     353             :     double seenLength = 0;
     354             :     do {
     355             :         const Position& p1 = *i;
     356             :         const Position& p2 = *(i + 1);
     357      739705 :         const double nextLength = p1.distanceTo(p2);
     358      739705 :         if (seenLength + nextLength > pos) {
     359      390870 :             return RAD2DEG(p1.slopeTo2D(p2));
     360             :         }
     361             :         seenLength += nextLength;
     362      348835 :     } while (++i != end() - 1);
     363      208496 :     const Position& p1 = (*this)[-2];
     364             :     const Position& p2 = back();
     365      208496 :     return RAD2DEG(p1.slopeTo2D(p2));
     366             : }
     367             : 
     368             : 
     369             : Position
     370  1666950640 : PositionVector::positionAtOffset(const Position& p1, const Position& p2, double pos, double lateralOffset) {
     371  1666950640 :     const double dist = p1.distanceTo(p2);
     372  1666950640 :     if (pos < 0. || dist < pos) {
     373      860657 :         return Position::INVALID;
     374             :     }
     375  1666089983 :     if (lateralOffset != 0) {
     376    58747587 :         if (dist == 0.) {
     377         288 :             return Position::INVALID;
     378             :         }
     379    58747299 :         const Position offset = sideOffset(p1, p2, -lateralOffset); // move in the same direction as Position::move2side
     380    58747299 :         if (pos == 0.) {
     381             :             return p1 + offset;
     382             :         }
     383    58684435 :         return p1 + (p2 - p1) * (pos / dist) + offset;
     384             :     }
     385  1607342396 :     if (pos == 0.) {
     386     1766216 :         return p1;
     387             :     }
     388  1605576180 :     return p1 + (p2 - p1) * (pos / dist);
     389             : }
     390             : 
     391             : 
     392             : Position
     393      118930 : PositionVector::sidePositionAtAngle(const Position& p1, const Position& p2, double pos, double lateralOffset, double angle) {
     394      118930 :     const double dist = p1.distanceTo(p2);
     395      118930 :     if (pos < 0. || dist < pos || dist == 0) {
     396           1 :         return Position::INVALID;
     397             :     }
     398      118929 :     angle -= DEG2RAD(90);
     399      118929 :     const Position offset(cos(angle) * lateralOffset, sin(angle) * lateralOffset);
     400      118929 :     return p1 + (p2 - p1) * (pos / dist) + offset;
     401             : }
     402             : 
     403             : 
     404             : Position
     405    84163271 : PositionVector::positionAtOffset2D(const Position& p1, const Position& p2, double pos, double lateralOffset) {
     406             :     const double dist = p1.distanceTo2D(p2);
     407    84163271 :     if (pos < 0 || dist < pos) {
     408         151 :         return Position::INVALID;
     409             :     }
     410    84163120 :     if (lateralOffset != 0) {
     411      142313 :         const Position offset = sideOffset(p1, p2, -lateralOffset); // move in the same direction as Position::move2side
     412      142313 :         if (pos == 0.) {
     413             :             return p1 + offset;
     414             :         }
     415      142313 :         return p1 + (p2 - p1) * (pos / dist) + offset;
     416             :     }
     417    84020807 :     if (pos == 0.) {
     418    41018240 :         return p1;
     419             :     }
     420    43002567 :     return p1 + (p2 - p1) * (pos / dist);
     421             : }
     422             : 
     423             : 
     424             : Boundary
     425      806260 : PositionVector::getBoxBoundary() const {
     426      806260 :     Boundary ret;
     427     4495078 :     for (const Position& i : *this) {
     428     3688818 :         ret.add(i);
     429             :     }
     430      806260 :     return ret;
     431           0 : }
     432             : 
     433             : 
     434             : Position
     435       11014 : PositionVector::getPolygonCenter() const {
     436       11014 :     if (size() == 0) {
     437           0 :         return Position::INVALID;
     438             :     }
     439             :     double x = 0;
     440             :     double y = 0;
     441             :     double z = 0;
     442       70854 :     for (const Position& i : *this) {
     443       59840 :         x += i.x();
     444       59840 :         y += i.y();
     445       59840 :         z += i.z();
     446             :     }
     447       11014 :     return Position(x / (double) size(), y / (double) size(), z / (double)size());
     448             : }
     449             : 
     450             : 
     451             : Position
     452      599322 : PositionVector::getCentroid() const {
     453      599322 :     if (size() == 0) {
     454           0 :         return Position::INVALID;
     455      599322 :     } else if (size() == 1) {
     456          48 :         return (*this)[0];
     457      599274 :     } else if (size() == 2) {
     458       80322 :         return ((*this)[0] + (*this)[1]) * 0.5;
     459             :     }
     460             :     PositionVector tmp = *this;
     461      518952 :     if (!isClosed()) { // make sure its closed
     462      486071 :         tmp.push_back(tmp[0]);
     463             :     }
     464             :     // shift to origin to increase numerical stability
     465      518952 :     Position offset = tmp[0];
     466             :     Position result;
     467      518952 :     tmp.sub(offset);
     468      518952 :     const int endIndex = (int)tmp.size() - 1;
     469             :     double div = 0; // 6 * area including sign
     470             :     double x = 0;
     471             :     double y = 0;
     472      518952 :     if (tmp.area() != 0) { // numerical instability ?
     473             :         // http://en.wikipedia.org/wiki/Polygon
     474     6718460 :         for (int i = 0; i < endIndex; i++) {
     475     6217908 :             const double z = tmp[i].x() * tmp[i + 1].y() - tmp[i + 1].x() * tmp[i].y();
     476     6217908 :             div += z; // area formula
     477     6217908 :             x += (tmp[i].x() + tmp[i + 1].x()) * z;
     478     6217908 :             y += (tmp[i].y() + tmp[i + 1].y()) * z;
     479             :         }
     480      500552 :         div *= 3; //  6 / 2, the 2 comes from the area formula
     481      500552 :         result = Position(x / div, y / div);
     482             :     } else {
     483             :         // compute by decomposing into line segments
     484             :         // http://en.wikipedia.org/wiki/Centroid#By_geometric_decomposition
     485             :         double lengthSum = 0;
     486       73470 :         for (int i = 0; i < endIndex; i++) {
     487       55070 :             double length = tmp[i].distanceTo(tmp[i + 1]);
     488       55070 :             x += (tmp[i].x() + tmp[i + 1].x()) * length / 2;
     489       55070 :             y += (tmp[i].y() + tmp[i + 1].y()) * length / 2;
     490       55070 :             lengthSum += length;
     491             :         }
     492       18400 :         if (lengthSum == 0) {
     493             :             // it is probably only one point
     494           0 :             result = tmp[0];
     495             :         }
     496       18400 :         result = Position(x / lengthSum, y / lengthSum) + offset;
     497             :     }
     498             :     return result + offset;
     499      518952 : }
     500             : 
     501             : 
     502             : void
     503       57768 : PositionVector::scaleRelative(double factor) {
     504       57768 :     Position centroid = getCentroid();
     505      173310 :     for (int i = 0; i < static_cast<int>(size()); i++) {
     506      115542 :         (*this)[i] = centroid + (((*this)[i] - centroid) * factor);
     507             :     }
     508       57768 : }
     509             : 
     510             : 
     511             : void
     512         818 : PositionVector::scaleAbsolute(double offset) {
     513         818 :     Position centroid = getCentroid();
     514        6162 :     for (int i = 0; i < static_cast<int>(size()); i++) {
     515        5344 :         (*this)[i] = centroid + (((*this)[i] - centroid) + offset);
     516             :     }
     517         818 : }
     518             : 
     519             : 
     520             : Position
     521        4016 : PositionVector::getLineCenter() const {
     522        4016 :     if (size() == 1) {
     523           0 :         return (*this)[0];
     524             :     } else {
     525        4016 :         return positionAtOffset(double((length() / 2.)));
     526             :     }
     527             : }
     528             : 
     529             : 
     530             : double
     531     7480918 : PositionVector::length() const {
     532     7480918 :     if (size() == 0) {
     533             :         return 0;
     534             :     }
     535             :     double len = 0;
     536    22284967 :     for (const_iterator i = begin(); i != end() - 1; i++) {
     537    14958848 :         len += (*i).distanceTo(*(i + 1));
     538             :     }
     539             :     return len;
     540             : }
     541             : 
     542             : 
     543             : double
     544    28591097 : PositionVector::length2D() const {
     545    28591097 :     if (size() == 0) {
     546             :         return 0;
     547             :     }
     548             :     double len = 0;
     549    75919140 :     for (const_iterator i = begin(); i != end() - 1; i++) {
     550    47328043 :         len += (*i).distanceTo2D(*(i + 1));
     551             :     }
     552             :     return len;
     553             : }
     554             : 
     555             : 
     556             : double
     557      519066 : PositionVector::area() const {
     558      519066 :     if (size() < 3) {
     559             :         return 0;
     560             :     }
     561             :     double area = 0;
     562             :     PositionVector tmp = *this;
     563      519066 :     if (!isClosed()) { // make sure its closed
     564          24 :         tmp.push_back(tmp[0]);
     565             :     }
     566      519066 :     const int endIndex = (int)tmp.size() - 1;
     567             :     // http://en.wikipedia.org/wiki/Polygon
     568     6795142 :     for (int i = 0; i < endIndex; i++) {
     569     6276076 :         area += tmp[i].x() * tmp[i + 1].y() - tmp[i + 1].x() * tmp[i].y();
     570             :     }
     571      519066 :     if (area < 0) { // we whether we had cw or ccw order
     572      489523 :         area *= -1;
     573             :     }
     574      519066 :     return area / 2;
     575      519066 : }
     576             : 
     577             : 
     578             : bool
     579    10031107 : PositionVector::partialWithin(const AbstractPoly& poly, double offset) const {
     580    10031107 :     if (size() < 2) {
     581             :         return false;
     582             :     }
     583    50136837 :     for (const_iterator i = begin(); i != end(); i++) {
     584    40140779 :         if (poly.around(*i, offset)) {
     585             :             return true;
     586             :         }
     587             :     }
     588             :     return false;
     589             : }
     590             : 
     591             : 
     592             : bool
     593    19984121 : PositionVector::crosses(const Position& p1, const Position& p2) const {
     594    19984121 :     return intersects(p1, p2);
     595             : }
     596             : 
     597             : 
     598             : std::pair<PositionVector, PositionVector>
     599      353150 : PositionVector::splitAt(double where, bool use2D) const {
     600      353150 :     const double len = use2D ? length2D() : length();
     601      353150 :     if (size() < 2) {
     602           0 :         throw InvalidArgument("Vector to short for splitting");
     603             :     }
     604      353150 :     if (where < 0 || where > len) {
     605           0 :         throw InvalidArgument("Invalid split position " + toString(where) + " for vector of length " + toString(len));
     606             :     }
     607      353150 :     if (where <= POSITION_EPS || where >= len - POSITION_EPS) {
     608           4 :         WRITE_WARNINGF(TL("Splitting vector close to end (pos: %, length: %)"), toString(where), toString(len));
     609             :     }
     610      353150 :     PositionVector first, second;
     611      353150 :     first.push_back((*this)[0]);
     612             :     double seen = 0;
     613             :     const_iterator it = begin() + 1;
     614      353150 :     double next = use2D ? first.back().distanceTo2D(*it) : first.back().distanceTo(*it);
     615             :     // see how many points we can add to first
     616      478961 :     while (where >= seen + next + POSITION_EPS) {
     617             :         seen += next;
     618      125811 :         first.push_back(*it);
     619             :         it++;
     620      125811 :         next = use2D ? first.back().distanceTo2D(*it) : first.back().distanceTo(*it);
     621             :     }
     622      353150 :     if (fabs(where - (seen + next)) > POSITION_EPS || it == end() - 1) {
     623             :         // we need to insert a new point because 'where' is not close to an
     624             :         // existing point or it is to close to the endpoint
     625             :         const Position p = (use2D
     626             :                             ? positionAtOffset2D(first.back(), *it, where - seen)
     627      340548 :                             : positionAtOffset(first.back(), *it, where - seen));
     628      340548 :         first.push_back(p);
     629      340548 :         second.push_back(p);
     630             :     } else {
     631       12602 :         first.push_back(*it);
     632             :     }
     633             :     // add the remaining points to second
     634      876361 :     for (; it != end(); it++) {
     635      523211 :         second.push_back(*it);
     636             :     }
     637             :     assert(first.size() >= 2);
     638             :     assert(second.size() >= 2);
     639             :     assert(first.back() == second.front());
     640             :     assert(fabs((use2D ? first.length2D() + second.length2D() : first.length() + second.length()) - len) < 2 * POSITION_EPS);
     641      706300 :     return std::pair<PositionVector, PositionVector>(first, second);
     642      353150 : }
     643             : 
     644             : 
     645             : std::ostream&
     646      449214 : operator<<(std::ostream& os, const PositionVector& geom) {
     647     2661005 :     for (PositionVector::const_iterator i = geom.begin(); i != geom.end(); i++) {
     648     2211791 :         if (i != geom.begin()) {
     649     1762582 :             os << " ";
     650             :         }
     651     2211791 :         os << (*i);
     652             :     }
     653      449214 :     return os;
     654             : }
     655             : 
     656             : 
     657             : void
     658           6 : PositionVector::sortAsPolyCWByAngle() {
     659             :     // We take the centroid of the points as an origin for the angle computations
     660             :     // that will follow but other points could be taken (the center of the bounding
     661             :     // box of the polygon for instance). Each of these can potentially lead
     662             :     // to a different result in the case of a non-convex polygon.
     663           6 :     const Position centroid = std::accumulate(begin(), end(), Position(0, 0)) / (double)size();
     664           6 :     sub(centroid);
     665           6 :     std::sort(begin(), end(), as_poly_cw_sorter());
     666           6 :     add(centroid);
     667           6 : }
     668             : 
     669             : 
     670             : void
     671      973182 : PositionVector::add(double xoff, double yoff, double zoff) {
     672     8523853 :     for (int i = 0; i < (int)size(); i++) {
     673     7550671 :         (*this)[i].add(xoff, yoff, zoff);
     674             :     }
     675      973182 : }
     676             : 
     677             : 
     678             : void
     679      519201 : PositionVector::sub(const Position& offset) {
     680      519201 :     add(-offset.x(), -offset.y(), -offset.z());
     681      519201 : }
     682             : 
     683             : 
     684             : void
     685       10558 : PositionVector::add(const Position& offset) {
     686       10558 :     add(offset.x(), offset.y(), offset.z());
     687       10558 : }
     688             : 
     689             : 
     690             : PositionVector
     691           0 : PositionVector::added(const Position& offset) const {
     692           0 :     PositionVector pv;
     693           0 :     for (auto i1 = begin(); i1 != end(); ++i1) {
     694           0 :         pv.push_back(*i1 + offset);
     695             :     }
     696           0 :     return pv;
     697           0 : }
     698             : 
     699             : 
     700             : void
     701        9910 : PositionVector::mirrorX() {
     702       27310 :     for (int i = 0; i < (int)size(); i++) {
     703       17400 :         (*this)[i].mul(1, -1);
     704             :     }
     705        9910 : }
     706             : 
     707             : 
     708           6 : PositionVector::as_poly_cw_sorter::as_poly_cw_sorter() {}
     709             : 
     710             : 
     711             : int
     712          16 : PositionVector::as_poly_cw_sorter::operator()(const Position& p1, const Position& p2) const {
     713          16 :     double angle1 = atAngle2D(p1);
     714          16 :     double angle2 = atAngle2D(p2);
     715          16 :     if (angle1 > angle2) {
     716             :         return true;
     717             :     }
     718           4 :     if (angle1 == angle2) {
     719             :         double squaredDistance1 = p1.dotProduct(p1);
     720             :         double squaredDistance2 = p2.dotProduct(p2);
     721           0 :         if (squaredDistance1 < squaredDistance2) {
     722           0 :             return true;
     723             :         }
     724             :     }
     725             :     return false;
     726             : }
     727             : 
     728             : 
     729             : double
     730          32 : PositionVector::as_poly_cw_sorter::atAngle2D(const Position& p) const {
     731          32 :     double angle = atan2(p.y(), p.x());
     732          32 :     return angle < 0.0 ? angle : angle + 2.0 * M_PI;
     733             : }
     734             : 
     735             : void
     736           0 : PositionVector::sortByIncreasingXY() {
     737           0 :     std::sort(begin(), end(), increasing_x_y_sorter());
     738           0 : }
     739             : 
     740             : 
     741           0 : PositionVector::increasing_x_y_sorter::increasing_x_y_sorter() {}
     742             : 
     743             : 
     744             : int
     745           0 : PositionVector::increasing_x_y_sorter::operator()(const Position& p1, const Position& p2) const {
     746           0 :     if (p1.x() != p2.x()) {
     747           0 :         return p1.x() < p2.x();
     748             :     }
     749           0 :     return p1.y() < p2.y();
     750             : }
     751             : 
     752             : 
     753             : double
     754     2685529 : PositionVector::isLeft(const Position& P0, const Position& P1,  const Position& P2) const {
     755     2685529 :     return (P1.x() - P0.x()) * (P2.y() - P0.y()) - (P2.x() - P0.x()) * (P1.y() - P0.y());
     756             : }
     757             : 
     758             : 
     759             : void
     760     7639846 : PositionVector::append(const PositionVector& v, double sameThreshold) {
     761     7639846 :     if ((size() > 0) && (v.size() > 0) && (back().distanceTo(v[0]) < sameThreshold)) {
     762             :         copy(v.begin() + 1, v.end(), back_inserter(*this));
     763             :     } else {
     764             :         copy(v.begin(), v.end(), back_inserter(*this));
     765             :     }
     766     7639846 : }
     767             : 
     768             : 
     769             : void
     770         470 : PositionVector::prepend(const PositionVector& v, double sameThreshold) {
     771         470 :     if ((size() > 0) && (v.size() > 0) && (front().distanceTo(v.back()) < sameThreshold)) {
     772         185 :         insert(begin(), v.begin(), v.end() - 1);
     773             :     } else {
     774         285 :         insert(begin(), v.begin(), v.end());
     775             :     }
     776         470 : }
     777             : 
     778             : 
     779             : PositionVector
     780      736037 : PositionVector::getSubpart(double beginOffset, double endOffset) const {
     781      736037 :     PositionVector ret;
     782      736037 :     Position begPos = front();
     783      736037 :     if (beginOffset > POSITION_EPS) {
     784       62498 :         begPos = positionAtOffset(beginOffset);
     785             :     }
     786      736037 :     Position endPos = back();
     787      736037 :     if (endOffset < length() - POSITION_EPS) {
     788      229655 :         endPos = positionAtOffset(endOffset);
     789             :     }
     790      736037 :     ret.push_back(begPos);
     791             : 
     792             :     double seen = 0;
     793             :     const_iterator i = begin();
     794             :     // skip previous segments
     795      736037 :     while ((i + 1) != end()
     796      752760 :             &&
     797      752759 :             seen + (*i).distanceTo(*(i + 1)) < beginOffset) {
     798       16723 :         seen += (*i).distanceTo(*(i + 1));
     799             :         i++;
     800             :     }
     801             :     // append segments in between
     802             :     while ((i + 1) != end()
     803      861015 :             &&
     804      860391 :             seen + (*i).distanceTo(*(i + 1)) < endOffset) {
     805             : 
     806      124978 :         ret.push_back_noDoublePos(*(i + 1));
     807      124978 :         seen += (*i).distanceTo(*(i + 1));
     808             :         i++;
     809             :     }
     810             :     // append end
     811      736037 :     ret.push_back_noDoublePos(endPos);
     812      736037 :     if (ret.size() == 1) {
     813          16 :         ret.push_back(endPos);
     814             :     }
     815      736037 :     return ret;
     816           0 : }
     817             : 
     818             : 
     819             : PositionVector
     820     1563758 : PositionVector::getSubpart2D(double beginOffset, double endOffset) const {
     821     1563758 :     if (size() == 0) {
     822           0 :         return PositionVector();
     823             :     }
     824     1563758 :     PositionVector ret;
     825     1563758 :     Position begPos = front();
     826     1563758 :     if (beginOffset > POSITION_EPS) {
     827      808077 :         begPos = positionAtOffset2D(beginOffset);
     828             :     }
     829     1563758 :     Position endPos = back();
     830     1563758 :     if (endOffset < length2D() - POSITION_EPS) {
     831      221899 :         endPos = positionAtOffset2D(endOffset);
     832             :     }
     833     1563758 :     ret.push_back(begPos);
     834             : 
     835             :     double seen = 0;
     836             :     const_iterator i = begin();
     837             :     // skip previous segments
     838     1563758 :     while ((i + 1) != end()
     839     1632972 :             &&
     840     1632972 :             seen + (*i).distanceTo2D(*(i + 1)) < beginOffset) {
     841       69214 :         seen += (*i).distanceTo2D(*(i + 1));
     842             :         i++;
     843             :     }
     844             :     // append segments in between
     845             :     while ((i + 1) != end()
     846     3609241 :             &&
     847     3162271 :             seen + (*i).distanceTo2D(*(i + 1)) < endOffset) {
     848             : 
     849     2045483 :         ret.push_back_noDoublePos(*(i + 1));
     850     2045483 :         seen += (*i).distanceTo2D(*(i + 1));
     851             :         i++;
     852             :     }
     853             :     // append end
     854     1563758 :     ret.push_back_noDoublePos(endPos);
     855     1563758 :     if (ret.size() == 1) {
     856          47 :         ret.push_back(endPos);
     857             :     }
     858             :     return ret;
     859     1563758 : }
     860             : 
     861             : 
     862             : PositionVector
     863      216706 : PositionVector::getSubpartByIndex(int beginIndex, int count) const {
     864      216706 :     if (size() == 0) {
     865           0 :         return PositionVector();
     866             :     }
     867      216706 :     if (beginIndex < 0) {
     868           0 :         beginIndex += (int)size();
     869             :     }
     870             :     assert(count >= 0);
     871             :     assert(beginIndex < (int)size());
     872             :     assert(beginIndex + count <= (int)size());
     873      216706 :     PositionVector result;
     874      623384 :     for (int i = beginIndex; i < beginIndex + count; ++i) {
     875      406678 :         result.push_back((*this)[i]);
     876             :     }
     877             :     return result;
     878      216706 : }
     879             : 
     880             : 
     881             : double
     882      909320 : PositionVector::beginEndAngle() const {
     883      909320 :     if (size() == 0) {
     884             :         return INVALID_DOUBLE;
     885             :     }
     886      909320 :     return front().angleTo2D(back());
     887             : }
     888             : 
     889             : 
     890             : double
     891    23208638 : PositionVector::nearest_offset_to_point2D(const Position& p, bool perpendicular) const {
     892    23208638 :     if (size() == 0) {
     893             :         return INVALID_DOUBLE;
     894             :     }
     895             :     double minDist = std::numeric_limits<double>::max();
     896    23208638 :     double nearestPos = GeomHelper::INVALID_OFFSET;
     897             :     double seen = 0;
     898    85678804 :     for (const_iterator i = begin(); i != end() - 1; i++) {
     899             :         const double pos =
     900    62470166 :             GeomHelper::nearest_offset_on_line_to_point2D(*i, *(i + 1), p, perpendicular);
     901    62470166 :         const double dist2 = pos == GeomHelper::INVALID_OFFSET ? minDist : p.distanceSquaredTo2D(positionAtOffset2D(*i, *(i + 1), pos));
     902    62470166 :         if (dist2 < minDist) {
     903    33453094 :             nearestPos = pos + seen;
     904             :             minDist = dist2;
     905             :         }
     906    62470166 :         if (perpendicular && i != begin() && pos == GeomHelper::INVALID_OFFSET) {
     907             :             // even if perpendicular is set we still need to check the distance to the inner points
     908             :             const double cornerDist2 = p.distanceSquaredTo2D(*i);
     909      604841 :             if (cornerDist2 < minDist) {
     910             :                 const double pos1 =
     911      348687 :                     GeomHelper::nearest_offset_on_line_to_point2D(*(i - 1), *i, p, false);
     912             :                 const double pos2 =
     913      348687 :                     GeomHelper::nearest_offset_on_line_to_point2D(*i, *(i + 1), p, false);
     914      348687 :                 if (pos1 == (*(i - 1)).distanceTo2D(*i) && pos2 == 0.) {
     915             :                     nearestPos = seen;
     916             :                     minDist = cornerDist2;
     917             :                 }
     918             :             }
     919             :         }
     920    62470166 :         seen += (*i).distanceTo2D(*(i + 1));
     921             :     }
     922             :     return nearestPos;
     923             : }
     924             : 
     925             : 
     926             : double
     927       24949 : PositionVector::nearest_offset_to_point25D(const Position& p, bool perpendicular) const {
     928       24949 :     if (size() == 0) {
     929             :         return INVALID_DOUBLE;
     930             :     }
     931             :     double minDist = std::numeric_limits<double>::max();
     932       24949 :     double nearestPos = GeomHelper::INVALID_OFFSET;
     933             :     double seen = 0;
     934       73031 :     for (const_iterator i = begin(); i != end() - 1; i++) {
     935             :         const double pos =
     936       48082 :             GeomHelper::nearest_offset_on_line_to_point2D(*i, *(i + 1), p, perpendicular);
     937       48082 :         const double dist = pos == GeomHelper::INVALID_OFFSET ? minDist : p.distanceTo2D(positionAtOffset2D(*i, *(i + 1), pos));
     938       48082 :         if (dist < minDist) {
     939       37186 :             const double pos25D = pos * (*i).distanceTo(*(i + 1)) / (*i).distanceTo2D(*(i + 1));
     940       37186 :             nearestPos = pos25D + seen;
     941             :             minDist = dist;
     942             :         }
     943       48082 :         if (perpendicular && i != begin() && pos == GeomHelper::INVALID_OFFSET) {
     944             :             // even if perpendicular is set we still need to check the distance to the inner points
     945             :             const double cornerDist = p.distanceTo2D(*i);
     946           0 :             if (cornerDist < minDist) {
     947             :                 const double pos1 =
     948           0 :                     GeomHelper::nearest_offset_on_line_to_point2D(*(i - 1), *i, p, false);
     949             :                 const double pos2 =
     950           0 :                     GeomHelper::nearest_offset_on_line_to_point2D(*i, *(i + 1), p, false);
     951           0 :                 if (pos1 == (*(i - 1)).distanceTo2D(*i) && pos2 == 0.) {
     952             :                     nearestPos = seen;
     953             :                     minDist = cornerDist;
     954             :                 }
     955             :             }
     956             :         }
     957       48082 :         seen += (*i).distanceTo(*(i + 1));
     958             :     }
     959             :     return nearestPos;
     960             : }
     961             : 
     962             : 
     963             : Position
     964     4125694 : PositionVector::transformToVectorCoordinates(const Position& p, bool extend) const {
     965     4125694 :     if (size() == 0) {
     966           0 :         return Position::INVALID;
     967             :     }
     968             :     // @toDo this duplicates most of the code in nearest_offset_to_point2D. It should be refactored
     969     4125694 :     if (extend) {
     970             :         PositionVector extended = *this;
     971     1440749 :         const double dist = 2 * distance2D(p);
     972     1440749 :         extended.extrapolate(dist);
     973     1440749 :         return extended.transformToVectorCoordinates(p) - Position(dist, 0);
     974     1440749 :     }
     975             :     double minDist = std::numeric_limits<double>::max();
     976             :     double nearestPos = -1;
     977             :     double seen = 0;
     978             :     int sign = 1;
     979     7858686 :     for (const_iterator i = begin(); i != end() - 1; i++) {
     980             :         const double pos =
     981     5173741 :             GeomHelper::nearest_offset_on_line_to_point2D(*i, *(i + 1), p, true);
     982     5173741 :         const double dist = pos < 0 ? minDist : p.distanceTo2D(positionAtOffset(*i, *(i + 1), pos));
     983     5173741 :         if (dist < minDist) {
     984     2491851 :             nearestPos = pos + seen;
     985             :             minDist = dist;
     986     2491851 :             sign = isLeft(*i, *(i + 1), p) >= 0 ? -1 : 1;
     987             :         }
     988     5173741 :         if (i != begin() && pos == GeomHelper::INVALID_OFFSET) {
     989             :             // even if perpendicular is set we still need to check the distance to the inner points
     990             :             const double cornerDist = p.distanceTo2D(*i);
     991     1526777 :             if (cornerDist < minDist) {
     992             :                 const double pos1 =
     993      436418 :                     GeomHelper::nearest_offset_on_line_to_point2D(*(i - 1), *i, p, false);
     994             :                 const double pos2 =
     995      436418 :                     GeomHelper::nearest_offset_on_line_to_point2D(*i, *(i + 1), p, false);
     996      436418 :                 if (pos1 == (*(i - 1)).distanceTo2D(*i) && pos2 == 0.) {
     997             :                     nearestPos = seen;
     998             :                     minDist = cornerDist;
     999      193678 :                     sign = isLeft(*(i - 1), *i, p) >= 0 ? -1 : 1;
    1000             :                 }
    1001             :             }
    1002             :         }
    1003     5173741 :         seen += (*i).distanceTo2D(*(i + 1));
    1004             :     }
    1005     2684945 :     if (nearestPos != -1) {
    1006     2662897 :         return Position(nearestPos, sign * minDist);
    1007             :     } else {
    1008       22048 :         return Position::INVALID;
    1009             :     }
    1010             : }
    1011             : 
    1012             : 
    1013             : int
    1014      268497 : PositionVector::indexOfClosest(const Position& p, bool twoD) const {
    1015      268497 :     if (size() == 0) {
    1016             :         return -1;
    1017             :     }
    1018             :     double minDist = std::numeric_limits<double>::max();
    1019             :     double dist;
    1020             :     int closest = 0;
    1021     1916496 :     for (int i = 0; i < (int)size(); i++) {
    1022     1647999 :         const Position& p2 = (*this)[i];
    1023     1647999 :         dist = twoD ? p.distanceTo2D(p2) : p.distanceTo(p2);
    1024     1647999 :         if (dist < minDist) {
    1025             :             closest = i;
    1026             :             minDist = dist;
    1027             :         }
    1028             :     }
    1029             :     return closest;
    1030             : }
    1031             : 
    1032             : 
    1033             : int
    1034      150125 : PositionVector::insertAtClosest(const Position& p, bool interpolateZ) {
    1035      150125 :     if (size() == 0) {
    1036             :         return -1;
    1037             :     }
    1038             :     double minDist = std::numeric_limits<double>::max();
    1039             :     int insertionIndex = 1;
    1040     1159110 :     for (int i = 0; i < (int)size() - 1; i++) {
    1041     1008985 :         const double length = GeomHelper::nearest_offset_on_line_to_point2D((*this)[i], (*this)[i + 1], p, false);
    1042     1008985 :         const Position& outIntersection = PositionVector::positionAtOffset2D((*this)[i], (*this)[i + 1], length);
    1043             :         const double dist = p.distanceTo2D(outIntersection);
    1044     1008985 :         if (dist < minDist) {
    1045             :             insertionIndex = i + 1;
    1046             :             minDist = dist;
    1047             :         }
    1048             :     }
    1049             :     // check if we have to adjust Position Z
    1050      150125 :     if (interpolateZ) {
    1051             :         // obtain previous and next Z
    1052           0 :         const double previousZ = (begin() + (insertionIndex - 1))->z();
    1053             :         const double nextZ = (begin() + insertionIndex)->z();
    1054             :         // insert new position using x and y of p, and the new z
    1055           0 :         insert(begin() + insertionIndex, Position(p.x(), p.y(), ((previousZ + nextZ) / 2.0)));
    1056             :     } else {
    1057      150125 :         insert(begin() + insertionIndex, p);
    1058             :     }
    1059             :     return insertionIndex;
    1060             : }
    1061             : 
    1062             : 
    1063             : int
    1064         340 : PositionVector::removeClosest(const Position& p) {
    1065         340 :     if (size() == 0) {
    1066             :         return -1;
    1067             :     }
    1068             :     double minDist = std::numeric_limits<double>::max();
    1069             :     int removalIndex = 0;
    1070        3252 :     for (int i = 0; i < (int)size(); i++) {
    1071        2912 :         const double dist = p.distanceTo2D((*this)[i]);
    1072        2912 :         if (dist < minDist) {
    1073             :             removalIndex = i;
    1074             :             minDist = dist;
    1075             :         }
    1076             :     }
    1077             :     erase(begin() + removalIndex);
    1078         340 :     return removalIndex;
    1079             : }
    1080             : 
    1081             : 
    1082             : std::vector<double>
    1083     5680014 : PositionVector::intersectsAtLengths2D(const PositionVector& other) const {
    1084             :     std::vector<double> ret;
    1085     5680014 :     if (other.size() == 0) {
    1086             :         return ret;
    1087             :     }
    1088    17723071 :     for (const_iterator i = other.begin(); i != other.end() - 1; i++) {
    1089    12043057 :         std::vector<double> atSegment = intersectsAtLengths2D(*i, *(i + 1));
    1090             :         copy(atSegment.begin(), atSegment.end(), back_inserter(ret));
    1091             :     }
    1092             :     return ret;
    1093             : }
    1094             : 
    1095             : 
    1096             : std::vector<double>
    1097    12043057 : PositionVector::intersectsAtLengths2D(const Position& lp1, const Position& lp2) const {
    1098             :     std::vector<double> ret;
    1099    12043057 :     if (size() == 0) {
    1100             :         return ret;
    1101             :     }
    1102             :     double pos = 0;
    1103    41618415 :     for (const_iterator i = begin(); i != end() - 1; i++) {
    1104             :         const Position& p1 = *i;
    1105             :         const Position& p2 = *(i + 1);
    1106             :         double x, y, m;
    1107    29575358 :         if (intersects(p1, p2, lp1, lp2, 0., &x, &y, &m)) {
    1108     3368362 :             ret.push_back(Position(x, y).distanceTo2D(p1) + pos);
    1109             :         }
    1110    29575358 :         pos += p1.distanceTo2D(p2);
    1111             :     }
    1112             :     return ret;
    1113             : }
    1114             : 
    1115             : 
    1116             : void
    1117     2379466 : PositionVector::extrapolate(const double val, const bool onlyFirst, const bool onlyLast) {
    1118     2379466 :     if (size() > 1) {
    1119     2379466 :         Position& p1 = (*this)[0];
    1120     2379466 :         Position& p2 = (*this)[1];
    1121     2379466 :         const Position offset = (p2 - p1) * (val / p1.distanceTo(p2));
    1122     2379466 :         if (!onlyLast) {
    1123             :             p1.sub(offset);
    1124             :         }
    1125     2379466 :         if (!onlyFirst) {
    1126     2379466 :             if (size() == 2) {
    1127             :                 p2.add(offset);
    1128             :             } else {
    1129      258948 :                 const Position& e1 = (*this)[-2];
    1130      258948 :                 Position& e2 = (*this)[-1];
    1131      258948 :                 e2.sub((e1 - e2) * (val / e1.distanceTo(e2)));
    1132             :             }
    1133             :         }
    1134             :     }
    1135     2379466 : }
    1136             : 
    1137             : 
    1138             : void
    1139     6115294 : PositionVector::extrapolate2D(const double val, const bool onlyFirst) {
    1140     6115294 :     if (size() > 1) {
    1141     6115294 :         Position& p1 = (*this)[0];
    1142     6115294 :         Position& p2 = (*this)[1];
    1143     6115294 :         if (p1.distanceTo2D(p2) > 0) {
    1144     6115294 :             const Position offset = (p2 - p1) * (val / p1.distanceTo2D(p2));
    1145             :             p1.sub(offset);
    1146     6115294 :             if (!onlyFirst) {
    1147     4838700 :                 if (size() == 2) {
    1148             :                     p2.add(offset);
    1149             :                 } else {
    1150      466697 :                     const Position& e1 = (*this)[-2];
    1151      466697 :                     Position& e2 = (*this)[-1];
    1152      466697 :                     e2.sub((e1 - e2) * (val / e1.distanceTo2D(e2)));
    1153             :                 }
    1154             :             }
    1155             :         }
    1156             :     }
    1157     6115294 : }
    1158             : 
    1159             : 
    1160             : PositionVector
    1161    11878493 : PositionVector::reverse() const {
    1162    11878493 :     PositionVector ret;
    1163    41855944 :     for (const_reverse_iterator i = rbegin(); i != rend(); i++) {
    1164    29977451 :         ret.push_back(*i);
    1165             :     }
    1166    11878493 :     return ret;
    1167           0 : }
    1168             : 
    1169             : 
    1170             : Position
    1171    99081015 : PositionVector::sideOffset(const Position& beg, const Position& end, const double amount) {
    1172    99081015 :     const double scale = amount / beg.distanceTo2D(end);
    1173    99081015 :     return Position((beg.y() - end.y()) * scale, (end.x() - beg.x()) * scale);
    1174             : }
    1175             : 
    1176             : 
    1177             : void
    1178    17513320 : PositionVector::move2side(double amount, double maxExtension) {
    1179    17513320 :     if (size() < 2) {
    1180      226986 :         return;
    1181             :     }
    1182    17513320 :     removeDoublePoints(POSITION_EPS, true);
    1183    17513320 :     if (length2D() == 0 || amount == 0) {
    1184             :         return;
    1185             :     }
    1186    17286334 :     PositionVector shape;
    1187             :     std::vector<int>  recheck;
    1188    54946623 :     for (int i = 0; i < static_cast<int>(size()); i++) {
    1189    37660289 :         if (i == 0) {
    1190    17286334 :             const Position& from = (*this)[i];
    1191    17286334 :             const Position& to = (*this)[i + 1];
    1192             :             if (from != to) {
    1193    34572668 :                 shape.push_back(from - sideOffset(from, to, amount));
    1194             : #ifdef DEBUG_MOVE2SIDE
    1195             :                 if (gDebugFlag1) {
    1196             :                     std::cout << " " << i << "a=" << shape.back() << "\n";
    1197             :                 }
    1198             : #endif
    1199             :             }
    1200    20373955 :         } else if (i == static_cast<int>(size()) - 1) {
    1201    17286334 :             const Position& from = (*this)[i - 1];
    1202    17286334 :             const Position& to = (*this)[i];
    1203             :             if (from != to) {
    1204    34572668 :                 shape.push_back(to - sideOffset(from, to, amount));
    1205             : #ifdef DEBUG_MOVE2SIDE
    1206             :                 if (gDebugFlag1) {
    1207             :                     std::cout << " " << i << "b=" << shape.back() << "\n";
    1208             :                 }
    1209             : #endif
    1210             :             }
    1211             :         } else {
    1212     3087621 :             const Position& from = (*this)[i - 1];
    1213     3087621 :             const Position& me = (*this)[i];
    1214     3087621 :             const Position& to = (*this)[i + 1];
    1215     3087621 :             PositionVector fromMe(from, me);
    1216     3087621 :             fromMe.extrapolate2D(me.distanceTo2D(to));
    1217     3087621 :             const double extrapolateDev = fromMe[1].distanceTo2D(to);
    1218     3087621 :             if (fabs(extrapolateDev) < POSITION_EPS) {
    1219             :                 // parallel case, just shift the middle point
    1220     1118138 :                 shape.push_back(me - sideOffset(from, to, amount));
    1221             : #ifdef DEBUG_MOVE2SIDE
    1222             :                 if (gDebugFlag1) {
    1223             :                     std::cout << " " << i << "c=" << shape.back() << "\n";
    1224             :                 }
    1225             : #endif
    1226     2528552 :             } else if (fabs(extrapolateDev - 2 * me.distanceTo2D(to)) < POSITION_EPS) {
    1227             :                 // counterparallel case, just shift the middle point
    1228         451 :                 PositionVector fromMe2(from, me);
    1229         451 :                 fromMe2.extrapolate2D(amount);
    1230         451 :                 shape.push_back(fromMe2[1]);
    1231             : #ifdef DEBUG_MOVE2SIDE
    1232             :                 if (gDebugFlag1) {
    1233             :                     std::cout << " " << i << "d=" << shape.back() << " " << i << "_from=" << from << " " << i << "_me=" << me << " " << i << "_to=" << to << "\n";
    1234             :                 }
    1235             : #endif
    1236         451 :             } else {
    1237     2528101 :                 Position offsets = sideOffset(from, me, amount);
    1238     2528101 :                 Position offsets2 = sideOffset(me, to, amount);
    1239     2528101 :                 PositionVector l1(from - offsets, me - offsets);
    1240     2528101 :                 PositionVector l2(me - offsets2, to - offsets2);
    1241     2528101 :                 Position meNew  = l1.intersectionPosition2D(l2[0], l2[1], maxExtension);
    1242           6 :                 if (meNew == Position::INVALID) {
    1243           6 :                     recheck.push_back(i);
    1244             :                     continue;
    1245             :                 }
    1246     2528095 :                 meNew = meNew + Position(0, 0, me.z());
    1247     2528095 :                 shape.push_back(meNew);
    1248             : #ifdef DEBUG_MOVE2SIDE
    1249             :                 if (gDebugFlag1) {
    1250             :                     std::cout << " " << i << "e=" << shape.back() << "\n";
    1251             :                 }
    1252             : #endif
    1253     2528101 :             }
    1254             :             // copy original z value
    1255             :             shape.back().set(shape.back().x(), shape.back().y(), me.z());
    1256     3087615 :             const double angle = localAngle(from, me, to);
    1257     3087615 :             if (fabs(angle) > NUMERICAL_EPS) {
    1258     2834924 :                 const double length = from.distanceTo2D(me) + me.distanceTo2D(to);
    1259     2834924 :                 const double radius = length / angle;
    1260             : #ifdef DEBUG_MOVE2SIDE
    1261             :                 if (gDebugFlag1) {
    1262             :                     std::cout << " i=" << i << " a=" << RAD2DEG(angle) << " l=" << length << " r=" << radius << " t=" << amount * 1.8 << "\n";
    1263             :                 }
    1264             : #endif
    1265     2834924 :                 if ((radius < 0 && -radius < amount * 1.8) || fabs(RAD2DEG(angle)) > 170)  {
    1266        1604 :                     recheck.push_back(i);
    1267             :                 }
    1268             :             }
    1269     3087621 :         }
    1270             :     }
    1271    17286334 :     if (!recheck.empty()) {
    1272             :         // try to adjust positions to avoid clipping
    1273             :         shape = *this;
    1274        2754 :         for (int i = (int)recheck.size() - 1; i >= 0; i--) {
    1275        1610 :             shape.erase(shape.begin() + recheck[i]);
    1276             :         }
    1277        1144 :         shape.move2side(amount, maxExtension);
    1278             :     }
    1279             :     *this = shape;
    1280    17286334 : }
    1281             : 
    1282             : 
    1283             : void
    1284          52 : PositionVector::move2sideCustom(std::vector<double> amount, double maxExtension) {
    1285          52 :     if (size() < 2) {
    1286           0 :         return;
    1287             :     }
    1288          52 :     if (length2D() == 0) {
    1289             :         return;
    1290             :     }
    1291          52 :     if (size() != amount.size()) {
    1292           0 :         throw InvalidArgument("Numer of offsets (" + toString(amount.size())
    1293           0 :                               + ") does not match number of points (" + toString(size()) + ")");
    1294             :     }
    1295          52 :     PositionVector shape;
    1296        3211 :     for (int i = 0; i < static_cast<int>(size()); i++) {
    1297        3159 :         if (i == 0) {
    1298          52 :             const Position& from = (*this)[i];
    1299          52 :             const Position& to = (*this)[i + 1];
    1300             :             if (from != to) {
    1301         104 :                 shape.push_back(from - sideOffset(from, to, amount[i]));
    1302             :             }
    1303        3107 :         } else if (i == static_cast<int>(size()) - 1) {
    1304          52 :             const Position& from = (*this)[i - 1];
    1305          52 :             const Position& to = (*this)[i];
    1306             :             if (from != to) {
    1307         104 :                 shape.push_back(to - sideOffset(from, to, amount[i]));
    1308             :             }
    1309             :         } else {
    1310        3055 :             const Position& from = (*this)[i - 1];
    1311        3055 :             const Position& me = (*this)[i];
    1312        3055 :             const Position& to = (*this)[i + 1];
    1313        3055 :             PositionVector fromMe(from, me);
    1314        3055 :             fromMe.extrapolate2D(me.distanceTo2D(to));
    1315        3055 :             const double extrapolateDev = fromMe[1].distanceTo2D(to);
    1316        3055 :             if (fabs(extrapolateDev) < POSITION_EPS) {
    1317             :                 // parallel case, just shift the middle point
    1318        5784 :                 shape.push_back(me - sideOffset(from, to, amount[i]));
    1319         163 :             } else if (fabs(extrapolateDev - 2 * me.distanceTo2D(to)) < POSITION_EPS) {
    1320             :                 // counterparallel case, just shift the middle point
    1321           0 :                 PositionVector fromMe2(from, me);
    1322           0 :                 fromMe2.extrapolate2D(amount[i]);
    1323           0 :                 shape.push_back(fromMe2[1]);
    1324           0 :             } else {
    1325         163 :                 Position offsets = sideOffset(from, me, amount[i]);
    1326         163 :                 Position offsets2 = sideOffset(me, to, amount[i]);
    1327         163 :                 PositionVector l1(from - offsets, me - offsets);
    1328         163 :                 PositionVector l2(me - offsets2, to - offsets2);
    1329         163 :                 Position meNew  = l1.intersectionPosition2D(l2[0], l2[1], maxExtension);
    1330           0 :                 if (meNew == Position::INVALID) {
    1331             :                     continue;
    1332             :                 }
    1333         163 :                 meNew = meNew + Position(0, 0, me.z());
    1334         163 :                 shape.push_back(meNew);
    1335         163 :             }
    1336             :             // copy original z value
    1337             :             shape.back().set(shape.back().x(), shape.back().y(), me.z());
    1338        3055 :         }
    1339             :     }
    1340             :     *this = shape;
    1341          52 : }
    1342             : 
    1343             : double
    1344     3087615 : PositionVector::localAngle(const Position& from, const Position& pos, const Position& to) {
    1345     3087615 :     return GeomHelper::angleDiff(from.angleTo2D(pos), pos.angleTo2D(to));
    1346             : }
    1347             : 
    1348             : double
    1349    32038134 : PositionVector::angleAt2D(int pos) const {
    1350    32038134 :     if ((pos + 1) < (int)size()) {
    1351    32038134 :         return (*this)[pos].angleTo2D((*this)[pos + 1]);
    1352             :     }
    1353             :     return INVALID_DOUBLE;
    1354             : }
    1355             : 
    1356             : 
    1357             : void
    1358      699332 : PositionVector::closePolygon() {
    1359      699332 :     if ((size() != 0) && ((*this)[0] != back())) {
    1360      408418 :         push_back((*this)[0]);
    1361             :     }
    1362      699332 : }
    1363             : 
    1364             : 
    1365             : std::vector<double>
    1366     1823248 : PositionVector::distances(const PositionVector& s, bool perpendicular) const {
    1367             :     std::vector<double> ret;
    1368             :     const_iterator i;
    1369     8592327 :     for (i = begin(); i != end(); i++) {
    1370     6769079 :         const double dist = s.distance2D(*i, perpendicular);
    1371     6769079 :         if (dist != GeomHelper::INVALID_OFFSET) {
    1372     6733304 :             ret.push_back(dist);
    1373             :         }
    1374             :     }
    1375     8555517 :     for (i = s.begin(); i != s.end(); i++) {
    1376     6732269 :         const double dist = distance2D(*i, perpendicular);
    1377     6732269 :         if (dist != GeomHelper::INVALID_OFFSET) {
    1378     6726898 :             ret.push_back(dist);
    1379             :         }
    1380             :     }
    1381     1823248 :     return ret;
    1382             : }
    1383             : 
    1384             : 
    1385             : double
    1386    22544920 : PositionVector::distance2D(const Position& p, bool perpendicular) const {
    1387    22544920 :     if (size() == 0) {
    1388             :         return std::numeric_limits<double>::max();
    1389    22544689 :     } else if (size() == 1) {
    1390      604350 :         return front().distanceTo(p);
    1391             :     }
    1392    21940339 :     const double nearestOffset = nearest_offset_to_point2D(p, perpendicular);
    1393    21940339 :     if (nearestOffset == GeomHelper::INVALID_OFFSET) {
    1394             :         return GeomHelper::INVALID_OFFSET;
    1395             :     } else {
    1396    21897478 :         return p.distanceTo2D(positionAtOffset2D(nearestOffset));
    1397             :     }
    1398             : }
    1399             : 
    1400             : 
    1401             : void
    1402      153422 : PositionVector::push_front(const Position& p) {
    1403      153422 :     if (empty()) {
    1404           0 :         push_back(p);
    1405             :     } else {
    1406      153422 :         insert(begin(), p);
    1407             :     }
    1408      153422 : }
    1409             : 
    1410             : 
    1411             : void
    1412           0 : PositionVector::pop_front() {
    1413           0 :     if (empty()) {
    1414           0 :         throw ProcessError("PositionVector is empty");
    1415             :     } else {
    1416             :         erase(begin());
    1417             :     }
    1418           0 : }
    1419             : 
    1420             : 
    1421             : void
    1422     5799552 : PositionVector::push_back_noDoublePos(const Position& p) {
    1423    11469877 :     if (size() == 0 || !p.almostSame(back())) {
    1424     5304064 :         push_back(p);
    1425             :     }
    1426     5799552 : }
    1427             : 
    1428             : 
    1429             : void
    1430      165577 : PositionVector::push_front_noDoublePos(const Position& p) {
    1431      331154 :     if ((size() == 0) || !p.almostSame(front())) {
    1432      153421 :         push_front(p);
    1433             :     }
    1434      165577 : }
    1435             : 
    1436             : 
    1437             : void
    1438           0 : PositionVector::insert_noDoublePos(const std::vector<Position>::iterator& at, const Position& p) {
    1439           0 :     if (at == begin()) {
    1440           0 :         push_front_noDoublePos(p);
    1441           0 :     } else if (at == end()) {
    1442           0 :         push_back_noDoublePos(p);
    1443             :     } else {
    1444           0 :         if (!p.almostSame(*at) && !p.almostSame(*(at - 1))) {
    1445           0 :             insert(at, p);
    1446             :         }
    1447             :     }
    1448           0 : }
    1449             : 
    1450             : 
    1451             : bool
    1452     1038119 : PositionVector::isClosed() const {
    1453     1038119 :     return (size() >= 2) && ((*this)[0] == back());
    1454             : }
    1455             : 
    1456             : 
    1457             : bool
    1458        4824 : PositionVector::isNAN() const {
    1459             :     // iterate over all positions and check if is NAN
    1460       19191 :     for (auto i = begin(); i != end(); i++) {
    1461             :         if (i->isNAN()) {
    1462             :             return true;
    1463             :         }
    1464             :     }
    1465             :     // all ok, then return false
    1466             :     return false;
    1467             : }
    1468             : 
    1469             : 
    1470             : void
    1471    17670128 : PositionVector::removeDoublePoints(double minDist, bool assertLength, int beginOffset, int endOffset, bool resample) {
    1472    17670128 :     int curSize = (int)size() - beginOffset - endOffset;
    1473    17670128 :     if (curSize > 1) {
    1474             :         iterator last = begin() + beginOffset;
    1475    22456795 :         for (iterator i = last + 1; i != (end() - endOffset) && (!assertLength || curSize > 2);) {
    1476     4834909 :             if (last->almostSame(*i, minDist)) {
    1477        3228 :                 if (i + 1 == end() - endOffset) {
    1478             :                     // special case: keep the last point and remove the next-to-last
    1479        1063 :                     if (resample && last > begin() && (last - 1)->distanceTo(*i) >= 2 * minDist) {
    1480             :                         // resample rather than remove point after a long segment
    1481           3 :                         const double shiftBack = minDist - last->distanceTo(*i);
    1482             :                         //if (gDebugFlag1) std::cout << " resample endOffset beforeLast=" << *(last - 1) << " last=" << *last << " i=" << *i;
    1483           3 :                         (*last) = positionAtOffset(*(last - 1), *last, (last - 1)->distanceTo(*last) - shiftBack);
    1484             :                         //if (gDebugFlag1) std::cout << " lastNew=" << *last;
    1485             :                         last = i;
    1486             :                         ++i;
    1487             :                     } else {
    1488             :                         erase(last);
    1489             :                         i = end() - endOffset;
    1490             :                     }
    1491             :                 } else {
    1492        2165 :                     if (resample && i + 1 != end() && last->distanceTo(*(i + 1)) >= 2 * minDist) {
    1493             :                         // resample rather than remove points before a long segment
    1494           2 :                         const double shiftForward = minDist - last->distanceTo(*i);
    1495             :                         //if (gDebugFlag1) std::cout << " resample last=" << *last << " i=" << *i << " next=" << *(i + 1);
    1496           2 :                         (*i) = positionAtOffset(*i, *(i + 1), shiftForward);
    1497             :                         //if (gDebugFlag1) std::cout << " iNew=" << *i << "\n";
    1498             :                         last = i;
    1499             :                         ++i;
    1500             :                     } else {
    1501             :                         i = erase(i);
    1502             :                     }
    1503             :                 }
    1504        3228 :                 curSize--;
    1505             :             } else {
    1506             :                 last = i;
    1507             :                 ++i;
    1508             :             }
    1509             :         }
    1510             :     }
    1511    17670128 : }
    1512             : 
    1513             : 
    1514             : bool
    1515      604734 : PositionVector::operator==(const PositionVector& v2) const {
    1516     1812240 :     return static_cast<vp>(*this) == static_cast<vp>(v2);
    1517             : }
    1518             : 
    1519             : 
    1520             : bool
    1521      313805 : PositionVector::operator!=(const PositionVector& v2) const {
    1522      941415 :     return static_cast<vp>(*this) != static_cast<vp>(v2);
    1523             : }
    1524             : 
    1525             : PositionVector
    1526           0 : PositionVector::operator-(const PositionVector& v2) const {
    1527           0 :     if (length() != v2.length()) {
    1528           0 :         WRITE_ERROR(TL("Trying to subtract PositionVectors of different lengths."));
    1529             :     }
    1530           0 :     PositionVector pv;
    1531             :     auto i1 = begin();
    1532             :     auto i2 = v2.begin();
    1533           0 :     while (i1 != end()) {
    1534           0 :         pv.add(*i1 - *i2);
    1535             :     }
    1536           0 :     return pv;
    1537           0 : }
    1538             : 
    1539             : PositionVector
    1540           0 : PositionVector::operator+(const PositionVector& v2) const {
    1541           0 :     if (length() != v2.length()) {
    1542           0 :         WRITE_ERROR(TL("Trying to add PositionVectors of different lengths."));
    1543             :     }
    1544           0 :     PositionVector pv;
    1545             :     auto i1 = begin();
    1546             :     auto i2 = v2.begin();
    1547           0 :     while (i1 != end()) {
    1548           0 :         pv.add(*i1 + *i2);
    1549             :     }
    1550           0 :     return pv;
    1551           0 : }
    1552             : 
    1553             : bool
    1554        5484 : PositionVector::almostSame(const PositionVector& v2, double maxDiv) const {
    1555        5484 :     if (size() != v2.size()) {
    1556             :         return false;
    1557             :     }
    1558             :     auto i2 = v2.begin();
    1559       10815 :     for (auto i1 = begin(); i1 != end(); i1++) {
    1560        8251 :         if (!i1->almostSame(*i2, maxDiv)) {
    1561             :             return false;
    1562             :         }
    1563             :         i2++;
    1564             :     }
    1565             :     return true;
    1566             : }
    1567             : 
    1568             : bool
    1569     1793336 : PositionVector::hasElevation() const {
    1570     1793336 :     if (size() < 2) {
    1571             :         return false;
    1572             :     }
    1573     7412557 :     for (const_iterator i = begin(); i != end(); i++) {
    1574     5621387 :         if ((*i).z() != 0) {
    1575             :             return true;
    1576             :         }
    1577             :     }
    1578             :     return false;
    1579             : }
    1580             : 
    1581             : 
    1582             : bool
    1583   100094809 : PositionVector::intersects(const Position& p11, const Position& p12, const Position& p21, const Position& p22, const double withinDist, double* x, double* y, double* mu) {
    1584             :     const double eps = std::numeric_limits<double>::epsilon();
    1585   100094809 :     const double denominator = (p22.y() - p21.y()) * (p12.x() - p11.x()) - (p22.x() - p21.x()) * (p12.y() - p11.y());
    1586   100094809 :     const double numera = (p22.x() - p21.x()) * (p11.y() - p21.y()) - (p22.y() - p21.y()) * (p11.x() - p21.x());
    1587   100094809 :     const double numerb = (p12.x() - p11.x()) * (p11.y() - p21.y()) - (p12.y() - p11.y()) * (p11.x() - p21.x());
    1588             :     /* Are the lines coincident? */
    1589   100094809 :     if (fabs(numera) < eps && fabs(numerb) < eps && fabs(denominator) < eps) {
    1590             :         double a1;
    1591             :         double a2;
    1592             :         double a3;
    1593             :         double a4;
    1594             :         double a = -1e12;
    1595       15788 :         if (p11.x() != p12.x()) {
    1596       12044 :             a1 = p11.x() < p12.x() ? p11.x() : p12.x();
    1597       12044 :             a2 = p11.x() < p12.x() ? p12.x() : p11.x();
    1598       12044 :             a3 = p21.x() < p22.x() ? p21.x() : p22.x();
    1599       12044 :             a4 = p21.x() < p22.x() ? p22.x() : p21.x();
    1600             :         } else {
    1601        3744 :             a1 = p11.y() < p12.y() ? p11.y() : p12.y();
    1602        3744 :             a2 = p11.y() < p12.y() ? p12.y() : p11.y();
    1603        3744 :             a3 = p21.y() < p22.y() ? p21.y() : p22.y();
    1604        3744 :             a4 = p21.y() < p22.y() ? p22.y() : p21.y();
    1605             :         }
    1606       15788 :         if (a1 <= a3 && a3 <= a2) {
    1607        9385 :             if (a4 < a2) {
    1608         348 :                 a = (a3 + a4) / 2;
    1609             :             } else {
    1610        9037 :                 a = (a2 + a3) / 2;
    1611             :             }
    1612             :         }
    1613       15788 :         if (a3 <= a1 && a1 <= a4) {
    1614        9467 :             if (a2 < a4) {
    1615         236 :                 a = (a1 + a2) / 2;
    1616             :             } else {
    1617        9231 :                 a = (a1 + a4) / 2;
    1618             :             }
    1619             :         }
    1620       15788 :         if (a != -1e12) {
    1621       12771 :             if (x != nullptr) {
    1622        8915 :                 if (p11.x() != p12.x()) {
    1623        7284 :                     *mu = (a - p11.x()) / (p12.x() - p11.x());
    1624        7284 :                     *x = a;
    1625        7284 :                     *y = p11.y() + (*mu) * (p12.y() - p11.y());
    1626             :                 } else {
    1627        1631 :                     *x = p11.x();
    1628        1631 :                     *y = a;
    1629        1631 :                     if (p12.y() == p11.y()) {
    1630         110 :                         *mu = 0;
    1631             :                     } else {
    1632        1521 :                         *mu = (a - p11.y()) / (p12.y() - p11.y());
    1633             :                     }
    1634             :                 }
    1635             :             }
    1636       12771 :             return true;
    1637             :         }
    1638             :         return false;
    1639             :     }
    1640             :     /* Are the lines parallel */
    1641   100079021 :     if (fabs(denominator) < eps) {
    1642             :         return false;
    1643             :     }
    1644             :     /* Is the intersection along the segments */
    1645    96180200 :     double mua = numera / denominator;
    1646             :     /* reduce rounding errors for lines ending in the same point */
    1647    96180200 :     if (fabs(p12.x() - p22.x()) < eps && fabs(p12.y() - p22.y()) < eps) {
    1648             :         mua = 1.;
    1649             :     } else {
    1650    96177441 :         const double offseta = withinDist / p11.distanceTo2D(p12);
    1651    96177441 :         const double offsetb = withinDist / p21.distanceTo2D(p22);
    1652    96177441 :         const double mub = numerb / denominator;
    1653    96177441 :         if (mua < -offseta || mua > 1 + offseta || mub < -offsetb || mub > 1 + offsetb) {
    1654             :             return false;
    1655             :         }
    1656             :     }
    1657     7643000 :     if (x != nullptr) {
    1658     6144110 :         *x = p11.x() + mua * (p12.x() - p11.x());
    1659     6144110 :         *y = p11.y() + mua * (p12.y() - p11.y());
    1660     6144110 :         *mu = mua;
    1661             :     }
    1662             :     return true;
    1663             : }
    1664             : 
    1665             : 
    1666             : void
    1667        9105 : PositionVector::rotate2D(double angle) {
    1668        9105 :     const double s = sin(angle);
    1669        9105 :     const double c = cos(angle);
    1670      108743 :     for (int i = 0; i < (int)size(); i++) {
    1671       99638 :         const double x = (*this)[i].x();
    1672       99638 :         const double y = (*this)[i].y();
    1673       99638 :         const double z = (*this)[i].z();
    1674       99638 :         const double xnew = x * c - y * s;
    1675       99638 :         const double ynew = x * s + y * c;
    1676       99638 :         (*this)[i].set(xnew, ynew, z);
    1677             :     }
    1678        9105 : }
    1679             : 
    1680             : 
    1681             : PositionVector
    1682       70096 : PositionVector::simplified() const {
    1683             :     PositionVector result = *this;
    1684             :     bool changed = true;
    1685      202010 :     while (changed && result.size() > 3) {
    1686             :         changed = false;
    1687      624279 :         for (int i = 0; i < (int)result.size(); i++) {
    1688      576219 :             const Position& p1 = result[i];
    1689      576219 :             const Position& p2 = result[(i + 2) % result.size()];
    1690      576219 :             const int middleIndex = (i + 1) % result.size();
    1691      576219 :             const Position& p0 = result[middleIndex];
    1692             :             // https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line#Line_defined_by_two_points
    1693      576219 :             const double triangleArea2 = fabs((p2.y() - p1.y()) * p0.x() - (p2.x() - p1.x()) * p0.y() + p2.x() * p1.y()  - p2.y() * p1.x());
    1694             :             const double distIK = p1.distanceTo2D(p2);
    1695      576219 :             if (distIK > NUMERICAL_EPS && triangleArea2 / distIK < NUMERICAL_EPS) {
    1696             :                 changed = true;
    1697             :                 result.erase(result.begin() + middleIndex);
    1698             :                 break;
    1699             :             }
    1700             :         }
    1701             :     }
    1702       70096 :     return result;
    1703           0 : }
    1704             : 
    1705             : 
    1706             : PositionVector
    1707        2579 : PositionVector::getOrthogonal(const Position& p, double extend, bool before, double length, double deg) const {
    1708        2579 :     PositionVector result;
    1709             :     PositionVector tmp = *this;
    1710        2579 :     tmp.extrapolate2D(extend);
    1711        2579 :     const double baseOffset = tmp.nearest_offset_to_point2D(p);
    1712        2579 :     if (baseOffset == GeomHelper::INVALID_OFFSET || size() < 2) {
    1713             :         // fail
    1714             :         return result;
    1715             :     }
    1716        2579 :     Position base = tmp.positionAtOffset2D(baseOffset);
    1717        2579 :     const int closestIndex = tmp.indexOfClosest(base);
    1718        2579 :     const double closestOffset = tmp.offsetAtIndex2D(closestIndex);
    1719        2579 :     result.push_back(base);
    1720        2579 :     if (fabs(baseOffset - closestOffset) > NUMERICAL_EPS) {
    1721        2578 :         result.push_back(tmp[closestIndex]);
    1722        2578 :         if ((closestOffset < baseOffset) != before) {
    1723        1785 :             deg *= -1;
    1724             :         }
    1725           1 :     } else if (before) {
    1726             :         // take the segment before closestIndex if possible
    1727           1 :         if (closestIndex > 0) {
    1728           1 :             result.push_back(tmp[closestIndex - 1]);
    1729             :         } else {
    1730           0 :             result.push_back(tmp[1]);
    1731           0 :             deg *= -1;
    1732             :         }
    1733             :     } else {
    1734             :         // take the segment after closestIndex if possible
    1735           0 :         if (closestIndex < (int)size() - 1) {
    1736           0 :             result.push_back(tmp[closestIndex + 1]);
    1737             :         } else {
    1738           0 :             result.push_back(tmp[-1]);
    1739           0 :             deg *= -1;
    1740             :         }
    1741             :     }
    1742        5158 :     result = result.getSubpart2D(0, length);
    1743             :     // rotate around base
    1744        2579 :     result.add(base * -1);
    1745        2579 :     result.rotate2D(DEG2RAD(deg));
    1746        2579 :     result.add(base);
    1747             :     return result;
    1748        2579 : }
    1749             : 
    1750             : 
    1751             : PositionVector
    1752      236146 : PositionVector::smoothedZFront(double dist) const {
    1753             :     PositionVector result = *this;
    1754      236146 :     if (size() == 0) {
    1755             :         return result;
    1756             :     }
    1757      236146 :     const double z0 = (*this)[0].z();
    1758             :     // the z-delta of the first segment
    1759      236146 :     const double dz = (*this)[1].z() - z0;
    1760             :     // if the shape only has 2 points it is as smooth as possible already
    1761      236146 :     if (size() > 2 && dz != 0) {
    1762        1219 :         dist = MIN2(dist, length2D());
    1763             :         // check wether we need to insert a new point at dist
    1764        1219 :         Position pDist = positionAtOffset2D(dist);
    1765        1219 :         int iLast = indexOfClosest(pDist);
    1766             :         // prevent close spacing to reduce impact of rounding errors in z-axis
    1767        1219 :         if (pDist.distanceTo2D((*this)[iLast]) > POSITION_EPS * 20) {
    1768          11 :             iLast = result.insertAtClosest(pDist, false);
    1769             :         }
    1770        1219 :         double dist2 = result.offsetAtIndex2D(iLast);
    1771        1219 :         const double dz2 = result[iLast].z() - z0;
    1772             :         double seen = 0;
    1773        6561 :         for (int i = 1; i < iLast; ++i) {
    1774        5342 :             seen += result[i].distanceTo2D(result[i - 1]);
    1775        5342 :             result[i].set(result[i].x(), result[i].y(), z0 + dz2 * seen / dist2);
    1776             :         }
    1777             :     }
    1778             :     return result;
    1779             : 
    1780           0 : }
    1781             : 
    1782             : 
    1783             : PositionVector
    1784      320384 : PositionVector::interpolateZ(double zStart, double zEnd) const {
    1785             :     PositionVector result = *this;
    1786      320384 :     if (size() == 0) {
    1787             :         return result;
    1788             :     }
    1789      320384 :     result[0].setz(zStart);
    1790      320384 :     result[-1].setz(zEnd);
    1791      320384 :     const double dz = zEnd - zStart;
    1792      320384 :     const double length = length2D();
    1793             :     double seen = 0;
    1794      518129 :     for (int i = 1; i < (int)size() - 1; ++i) {
    1795      197745 :         seen += result[i].distanceTo2D(result[i - 1]);
    1796      197745 :         result[i].setz(zStart + dz * seen / length);
    1797             :     }
    1798             :     return result;
    1799           0 : }
    1800             : 
    1801             : 
    1802             : PositionVector
    1803           0 : PositionVector::resample(double maxLength, const bool adjustEnd) const {
    1804           0 :     PositionVector result;
    1805           0 :     if (maxLength == 0) {
    1806             :         return result;
    1807             :     }
    1808           0 :     const double length = length2D();
    1809           0 :     if (length < POSITION_EPS) {
    1810             :         return result;
    1811             :     }
    1812           0 :     maxLength = length / ceil(length / maxLength);
    1813           0 :     for (double pos = 0; pos <= length; pos += maxLength) {
    1814           0 :         result.push_back(positionAtOffset2D(pos));
    1815             :     }
    1816             :     // check if we have to adjust last element
    1817           0 :     if (adjustEnd && !result.empty() && (result.back() != back())) {
    1818             :         // add last element
    1819           0 :         result.push_back(back());
    1820             :     }
    1821             :     return result;
    1822           0 : }
    1823             : 
    1824             : 
    1825             : double
    1826        3981 : PositionVector::offsetAtIndex2D(int index) const {
    1827        3981 :     if (index < 0 || index >= (int)size()) {
    1828           0 :         return GeomHelper::INVALID_OFFSET;
    1829             :     }
    1830             :     double seen = 0;
    1831       15605 :     for (int i = 1; i <= index; ++i) {
    1832       11624 :         seen += (*this)[i].distanceTo2D((*this)[i - 1]);
    1833             :     }
    1834             :     return seen;
    1835             : }
    1836             : 
    1837             : 
    1838             : double
    1839        5010 : PositionVector::getMaxGrade(double& maxJump) const {
    1840             :     double result = 0;
    1841       11470 :     for (int i = 1; i < (int)size(); ++i) {
    1842        6460 :         const Position& p1 = (*this)[i - 1];
    1843        6460 :         const Position& p2 = (*this)[i];
    1844        6460 :         const double distZ = fabs(p1.z() - p2.z());
    1845             :         const double dist2D = p1.distanceTo2D(p2);
    1846        6460 :         if (dist2D == 0) {
    1847           0 :             maxJump = MAX2(maxJump, distZ);
    1848             :         } else {
    1849        6460 :             result = MAX2(result, distZ / dist2D);
    1850             :         }
    1851             :     }
    1852        5010 :     return result;
    1853             : }
    1854             : 
    1855             : 
    1856             : PositionVector
    1857      238201 : PositionVector::bezier(int numPoints) {
    1858             :     // inspired by David F. Rogers
    1859             :     assert(size() < 33);
    1860             :     static const double fac[33] = {
    1861             :         1.0, 1.0, 2.0, 6.0, 24.0, 120.0, 720.0, 5040.0, 40320.0, 362880.0, 3628800.0, 39916800.0, 479001600.0,
    1862             :         6227020800.0, 87178291200.0, 1307674368000.0, 20922789888000.0, 355687428096000.0, 6402373705728000.0,
    1863             :         121645100408832000.0, 2432902008176640000.0, 51090942171709440000.0, 1124000727777607680000.0,
    1864             :         25852016738884976640000.0, 620448401733239439360000.0, 15511210043330985984000000.0,
    1865             :         403291461126605635584000000.0, 10888869450418352160768000000.0, 304888344611713860501504000000.0,
    1866             :         8841761993739701954543616000000.0, 265252859812191058636308480000000.0,
    1867             :         8222838654177922817725562880000000.0, 263130836933693530167218012160000000.0
    1868             :     };
    1869      238201 :     PositionVector ret;
    1870      238201 :     const int npts = (int)size();
    1871             :     // calculate the points on the Bezier curve
    1872      238201 :     const double step = (double) 1.0 / (numPoints - 1);
    1873             :     double t = 0.;
    1874             :     Position prev;
    1875     1659484 :     for (int i1 = 0; i1 < numPoints; i1++) {
    1876     1421283 :         if ((1.0 - t) < 5e-6) {
    1877             :             t = 1.0;
    1878             :         }
    1879             :         double x = 0., y = 0., z = 0.;
    1880     5973724 :         for (int i = 0; i < npts; i++) {
    1881     4552441 :             const double ti = (i == 0) ? 1.0 : pow(t, i);
    1882     4552441 :             const double tni = (npts == i + 1) ? 1.0 : pow(1 - t, npts - i - 1);
    1883     4552441 :             const double basis = fac[npts - 1] / (fac[i] * fac[npts - 1 - i]) * ti * tni;
    1884     4552441 :             x += basis * at(i).x();
    1885     4552441 :             y += basis * at(i).y();
    1886     4552441 :             z += basis * at(i).z();
    1887             :         }
    1888     1421283 :         t += step;
    1889             :         Position current(x, y, z);
    1890     1421283 :         if (prev != current && !std::isnan(x) && !std::isnan(y) && !std::isnan(z)) {
    1891     1421283 :             ret.push_back(current);
    1892             :         }
    1893     1421283 :         prev = current;
    1894             :     }
    1895      238201 :     return ret;
    1896           0 : }
    1897             : 
    1898             : 
    1899           6 : bool PositionVector::isClockwiseOriented() {
    1900             :     // The test is based on the computation of a signed area enclosed by the polygon.
    1901             :     // If the polygon is in the upper (resp. the lower) half-plane and the area is
    1902             :     // negatively (resp. positively) signed, then the polygon is CW oriented. In case
    1903             :     // the polygon has points with both positive and negative y-coordinates, we translate
    1904             :     // the polygon to apply the above simple area-based test.
    1905             :     double area = 0.0;
    1906             :     const double y_min = std::min_element(begin(), end(), [](Position p1, Position p2) {
    1907             :         return p1.y() < p2.y();
    1908             :     })->y();
    1909           6 :     const double gap = y_min > 0.0 ? 0.0 : y_min;
    1910           6 :     add(0., gap, 0.);
    1911           6 :     const int last = (int)size() - 1;
    1912          20 :     for (int i = 0; i < last; i++) {
    1913          14 :         const Position& firstPoint = at(i);
    1914          14 :         const Position& secondPoint = at(i + 1);
    1915          14 :         area += (secondPoint.x() - firstPoint.x()) / (secondPoint.y() + firstPoint.y()) / 2.0;
    1916             :     }
    1917           6 :     area += (at(0).x() - at(last).x()) / (at(0).y() + at(last).y()) / 2.0;
    1918           6 :     add(0., -gap, 0.);
    1919           6 :     return area < 0.0;
    1920             : }
    1921             : 
    1922             : 
    1923             : /****************************************************************************/

Generated by: LCOV version 1.14