SUMO - Simulation of Urban MObility

PositionVector.cpp

Go to the documentation of this file.
00001 /****************************************************************************/
00010 // A list of 2D-positions
00011 /****************************************************************************/
00012 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/
00013 // Copyright (C) 2001-2012 DLR (http://www.dlr.de/) and contributors
00014 /****************************************************************************/
00015 //
00016 //   This file is part of SUMO.
00017 //   SUMO is free software: you can redistribute it and/or modify
00018 //   it under the terms of the GNU General Public License as published by
00019 //   the Free Software Foundation, either version 3 of the License, or
00020 //   (at your option) any later version.
00021 //
00022 /****************************************************************************/
00023 
00024 
00025 // ===========================================================================
00026 // included modules
00027 // ===========================================================================
00028 #ifdef _MSC_VER
00029 #include <windows_config.h>
00030 #else
00031 #include <config.h>
00032 #endif
00033 
00034 #include <queue>
00035 #include <cmath>
00036 #include <iostream>
00037 #include <algorithm>
00038 #include <cassert>
00039 #include <iterator>
00040 #include <limits>
00041 #include <utils/common/StdDefs.h>
00042 #include <utils/common/MsgHandler.h>
00043 #include <utils/common/ToString.h>
00044 #include "AbstractPoly.h"
00045 #include "Position.h"
00046 #include "PositionVector.h"
00047 #include "GeomHelper.h"
00048 #include "Line.h"
00049 #include "Helper_ConvexHull.h"
00050 
00051 #ifdef CHECK_MEMORY_LEAKS
00052 #include <foreign/nvwa/debug_new.h>
00053 #endif // CHECK_MEMORY_LEAKS
00054 
00055 
00056 // ===========================================================================
00057 // method definitions
00058 // ===========================================================================
00059 PositionVector::PositionVector() {}
00060 
00061 
00062 PositionVector::PositionVector(const std::vector<Position> &v) {
00063     std::copy(v.begin(), v.end(), std::back_inserter(myCont));
00064 }
00065 
00066 
00067 PositionVector::~PositionVector() {}
00068 
00069 
00070 // ------------ Adding items to the container
00071 void
00072 PositionVector::push_back(const Position& p) {
00073     myCont.push_back(p);
00074 }
00075 
00076 
00077 void
00078 PositionVector::push_back(const PositionVector& p) {
00079     copy(p.myCont.begin(), p.myCont.end(), back_inserter(myCont));
00080 }
00081 
00082 
00083 void
00084 PositionVector::push_front(const Position& p) {
00085     myCont.insert(myCont.begin(), p);
00086 }
00087 
00088 
00089 bool
00090 PositionVector::around(const Position& p, SUMOReal offset) const {
00091     if (offset != 0) {
00092         //throw 1; // !!! not yet implemented
00093     }
00094     SUMOReal angle = 0;
00095     for (ContType::const_iterator i = myCont.begin(); i != myCont.end() - 1; i++) {
00096         Position p1(
00097             (*i).x() - p.x(),
00098             (*i).y() - p.y());
00099         Position p2(
00100             (*(i + 1)).x() - p.x(),
00101             (*(i + 1)).y() - p.y());
00102         angle += GeomHelper::Angle2D(p1.x(), p1.y(), p2.x(), p2.y());
00103     }
00104     Position p1(
00105         (*(myCont.end() - 1)).x() - p.x(),
00106         (*(myCont.end() - 1)).y() - p.y());
00107     Position p2(
00108         (*(myCont.begin())).x() - p.x(),
00109         (*(myCont.begin())).y() - p.y());
00110     angle += GeomHelper::Angle2D(p1.x(), p1.y(), p2.x(), p2.y());
00111     return (!(fabs(angle) < PI));
00112 }
00113 
00114 
00115 bool
00116 PositionVector::overlapsWith(const AbstractPoly& poly, SUMOReal offset) const {
00117     for (ContType::const_iterator i = myCont.begin(); i != myCont.end() - 1; i++) {
00118         if (poly.around(*i, offset)) {
00119             return true;
00120         }
00121     }
00122     return false;
00123 }
00124 
00125 
00126 bool
00127 PositionVector::intersects(const Position& p1, const Position& p2) const {
00128     if (size() < 2) {
00129         return false;
00130     }
00131     for (ContType::const_iterator i = myCont.begin(); i != myCont.end() - 1; i++) {
00132         if (GeomHelper::intersects(*i, *(i + 1), p1, p2)) {
00133             return true;
00134         }
00135     }
00136     //return GeomHelper::intersects(*(myCont.end()-1), *(myCont.begin()), p1, p2);
00137     return false;
00138 }
00139 
00140 
00141 bool
00142 PositionVector::intersects(const PositionVector& v1) const {
00143     if (size() < 2) {
00144         return false;
00145     }
00146     for (ContType::const_iterator i = myCont.begin(); i != myCont.end() - 1; i++) {
00147         if (v1.intersects(*i, *(i + 1))) {
00148             return true;
00149         }
00150     }
00151     //return v1.intersects(*(myCont.end()-1), *(myCont.begin()));
00152     return false;
00153 }
00154 
00155 
00156 Position
00157 PositionVector::intersectsAtPoint(const Position& p1,
00158                                   const Position& p2) const {
00159     for (ContType::const_iterator i = myCont.begin(); i != myCont.end() - 1; i++) {
00160         if (GeomHelper::intersects(*i, *(i + 1), p1, p2)) {
00161             return GeomHelper::intersection_position(*i, *(i + 1), p1, p2);
00162         }
00163     }
00164     return Position(-1, -1);
00165 }
00166 
00167 
00168 Position
00169 PositionVector::intersectsAtPoint(const PositionVector& v1) const {
00170     for (ContType::const_iterator i = myCont.begin(); i != myCont.end() - 1; i++) {
00171         if (v1.intersects(*i, *(i + 1))) {
00172             return v1.intersectsAtPoint(*i, *(i + 1));
00173         }
00174     }
00175     /*
00176     if(v1.intersects(*(myCont.end()-1), *(myCont.begin()))) {
00177         return v1.intersectsAtPoint(*(myCont.end()-1), *(myCont.begin()));
00178     }
00179     */
00180     return Position(-1, -1);
00181 }
00182 
00183 
00184 void
00185 PositionVector::clear() {
00186     myCont.clear();
00187 }
00188 
00189 
00190 const Position&
00191 PositionVector::operator[](int index) const {
00192     if (index >= 0) {
00193         return myCont[index];
00194     } else {
00195         return myCont[myCont.size() + index];
00196     }
00197 }
00198 
00199 
00200 Position&
00201 PositionVector::operator[](int index) {
00202     if (index >= 0) {
00203         return myCont[index];
00204     } else {
00205         return myCont[myCont.size() + index];
00206     }
00207 }
00208 
00209 
00210 size_t
00211 PositionVector::size() const {
00212     return myCont.size();
00213 }
00214 
00215 
00216 
00217 Position
00218 PositionVector::positionAtLengthPosition(SUMOReal pos) const {
00219     ContType::const_iterator i = myCont.begin();
00220     SUMOReal seenLength = 0;
00221     do {
00222         SUMOReal nextLength = (*i).distanceTo(*(i + 1));
00223         if (seenLength + nextLength > pos) {
00224             return positionAtLengthPosition(*i, *(i + 1), pos - seenLength);
00225         }
00226         seenLength += nextLength;
00227     } while (++i != myCont.end() - 1);
00228     return myCont.back();
00229 }
00230 
00231 
00232 SUMOReal
00233 PositionVector::rotationDegreeAtLengthPosition(SUMOReal pos) const {
00234     ContType::const_iterator i = myCont.begin();
00235     SUMOReal seenLength = 0;
00236     do {
00237         SUMOReal nextLength = (*i).distanceTo(*(i + 1));
00238         if (seenLength + nextLength > pos) {
00239             Line l(*i, *(i + 1));
00240             return l.atan2DegreeAngle();
00241         }
00242         seenLength += nextLength;
00243     } while (++i != myCont.end() - 1);
00244     Line l(*(myCont.end() - 2), *(myCont.end() - 1));
00245     return l.atan2DegreeAngle();
00246 }
00247 
00248 
00249 Position
00250 PositionVector::positionAtLengthPosition(const Position& p1,
00251         const Position& p2,
00252         SUMOReal pos) {
00253     SUMOReal dist = p1.distanceTo(p2);
00254     if (dist < pos) {
00255         return Position(-1, -1);
00256     }
00257     SUMOReal x = p1.x() + (p2.x() - p1.x()) / dist * pos;
00258     SUMOReal y = p1.y() + (p2.y() - p1.y()) / dist * pos;
00259     return Position(x, y);
00260 }
00261 
00262 
00263 Boundary
00264 PositionVector::getBoxBoundary() const {
00265     Boundary ret;
00266     for (ContType::const_iterator i = myCont.begin(); i != myCont.end(); i++) {
00267         ret.add(*i);
00268     }
00269     return ret;
00270 }
00271 
00272 
00273 Position
00274 PositionVector::getPolygonCenter() const {
00275     SUMOReal x = 0;
00276     SUMOReal y = 0;
00277     for (ContType::const_iterator i = myCont.begin(); i != myCont.end(); i++) {
00278         x += (*i).x();
00279         y += (*i).y();
00280     }
00281     return Position(x / (SUMOReal) myCont.size(), y / (SUMOReal) myCont.size());
00282 }
00283 
00284 
00285 Position
00286 PositionVector::getCentroid() const {
00287     PositionVector tmp = *this;
00288     if (!isClosed()) { // make sure its closed
00289         tmp.push_back(tmp[0]);
00290     }
00291     const int endIndex = (int)tmp.size() - 1;
00292     SUMOReal div = 0; // 6 * area including sign
00293     SUMOReal x = 0;
00294     SUMOReal y = 0;
00295     if (tmp.area() != 0) { // numerical instability ?
00296         // http://en.wikipedia.org/wiki/Polygon
00297         for (int i = 0; i < endIndex; i++) {
00298             const SUMOReal z = tmp[i].x() * tmp[i + 1].y() - tmp[i + 1].x() * tmp[i].y();
00299             div += z; // area formula
00300             x += (tmp[i].x() + tmp[i + 1].x()) * z;
00301             y += (tmp[i].y() + tmp[i + 1].y()) * z;
00302         }
00303         div *= 3; //  6 / 2, the 2 comes from the area formula
00304         return Position(x / div, y / div);
00305     } else {
00306         // compute by decomposing into line segments
00307         // http://en.wikipedia.org/wiki/Centroid#By_geometric_decomposition
00308         SUMOReal lengthSum = 0;
00309         for (int i = 0; i < endIndex; i++) {
00310             SUMOReal length = tmp[i].distanceTo(tmp[i + 1]);
00311             x += (tmp[i].x() + tmp[i + 1].x()) * length / 2;
00312             y += (tmp[i].y() + tmp[i + 1].y()) * length / 2;
00313             lengthSum += length;
00314         }
00315         return Position(x / lengthSum, y / lengthSum);
00316     }
00317 }
00318 
00319 
00320 void
00321 PositionVector::scaleSize(SUMOReal factor) {
00322     Position centroid = getCentroid();
00323     for (size_t i = 0; i < size(); i++) {
00324         myCont[i] = centroid + ((myCont[i] - centroid) * factor);
00325     }
00326 }
00327 
00328 
00329 Position
00330 PositionVector::getLineCenter() const {
00331     if (myCont.size() == 1) {
00332         return myCont[0];
00333     }
00334     return positionAtLengthPosition(SUMOReal((length() / 2.)));
00335 }
00336 
00337 
00338 SUMOReal
00339 PositionVector::length() const {
00340     SUMOReal len = 0;
00341     for (ContType::const_iterator i = myCont.begin(); i != myCont.end() - 1; i++) {
00342         len += (*i).distanceTo(*(i + 1));
00343     }
00344     return len;
00345 }
00346 
00347 
00348 SUMOReal
00349 PositionVector::area() const {
00350     SUMOReal area = 0;
00351     PositionVector tmp = *this;
00352     if (!isClosed()) { // make sure its closed
00353         tmp.push_back(tmp[0]);
00354     }
00355     const int endIndex = (int)tmp.size() - 1;
00356     // http://en.wikipedia.org/wiki/Polygon
00357     for (int i = 0; i < endIndex; i++) {
00358         area += tmp[i].x() * tmp[i + 1].y() - tmp[i + 1].x() * tmp[i].y();
00359     }
00360     if (area < 0) { // we whether we had cw or ccw order
00361         area *= -1;
00362     }
00363     return area / 2;
00364 }
00365 
00366 
00367 bool
00368 PositionVector::partialWithin(const AbstractPoly& poly, SUMOReal offset) const {
00369     for (ContType::const_iterator i = myCont.begin(); i != myCont.end() - 1; i++) {
00370         if (poly.around(*i, offset)) {
00371             return true;
00372         }
00373     }
00374     return false;
00375 }
00376 
00377 
00378 
00379 bool
00380 PositionVector::crosses(const Position& p1, const Position& p2) const {
00381     return intersects(p1, p2);
00382 }
00383 
00384 
00385 
00386 const Position&
00387 PositionVector::getBegin() const {
00388     return myCont[0];
00389 }
00390 
00391 
00392 const Position&
00393 PositionVector::getEnd() const {
00394     return myCont.back();
00395 }
00396 
00397 
00398 std::pair<PositionVector, PositionVector>
00399 PositionVector::splitAt(SUMOReal where) const {
00400     if (size() < 2) {
00401         throw InvalidArgument("Vector to short for splitting");
00402     }
00403     if (where <= POSITION_EPS || where >= length() - POSITION_EPS) {
00404         WRITE_WARNING("Splitting vector close to end (pos: " + toString(where) + ", length: " + toString(length()) + ")");
00405     }
00406     PositionVector first, second;
00407     first.push_back(myCont[0]);
00408     SUMOReal seen = 0;
00409     ContType::const_iterator it = myCont.begin() + 1;
00410     SUMOReal next = first.getEnd().distanceTo(*it);
00411     // see how many points we can add to first
00412     while (where >= seen + next + POSITION_EPS) {
00413         seen += next;
00414         first.push_back(*it);
00415         it++;
00416         next = first.getEnd().distanceTo(*it);
00417     }
00418     if (fabs(where - (seen + next)) > POSITION_EPS || it == myCont.end() - 1) {
00419         // we need to insert a new point because 'where' is not close to an
00420         // existing point or it is to close to the endpoint
00421         Line tmpL(first.getEnd(), *it);
00422         Position p = tmpL.getPositionAtDistance(where - seen);
00423         first.push_back(p);
00424         second.push_back(p);
00425     } else {
00426         first.push_back(*it);
00427     }
00428     // add the remaining points to second
00429     for (; it != myCont.end(); it++) {
00430         second.push_back(*it);
00431     }
00432     assert(first.size() >= 2);
00433     assert(second.size() >= 2);
00434     assert(first.getEnd() == second.getBegin());
00435     assert(fabs(first.length() + second.length() - length()) < 2 * POSITION_EPS);
00436     return std::pair<PositionVector, PositionVector>(first, second);
00437 }
00438 
00439 
00440 std::ostream&
00441 operator<<(std::ostream& os, const PositionVector& geom) {
00442     for (PositionVector::ContType::const_iterator i = geom.myCont.begin(); i != geom.myCont.end(); i++) {
00443         if (i != geom.myCont.begin()) {
00444             os << " ";
00445         }
00446         os << (*i);
00447     }
00448     return os;
00449 }
00450 
00451 
00452 void
00453 PositionVector::sortAsPolyCWByAngle() {
00454     std::sort(myCont.begin(), myCont.end(), as_poly_cw_sorter());
00455 }
00456 
00457 
00458 void
00459 PositionVector::reshiftRotate(SUMOReal xoff, SUMOReal yoff, SUMOReal rot) {
00460     for (size_t i = 0; i < size(); i++) {
00461         myCont[i].reshiftRotate(xoff, yoff, rot);
00462     }
00463 }
00464 
00465 
00466 int
00467 PositionVector::as_poly_cw_sorter::operator()(const Position& p1,
00468         const Position& p2) const {
00469     return atan2(p1.x(), p1.y()) < atan2(p2.x(), p2.y());
00470 }
00471 
00472 
00473 
00474 void
00475 PositionVector::sortByIncreasingXY() {
00476     std::sort(myCont.begin(), myCont.end(), increasing_x_y_sorter());
00477 }
00478 
00479 
00480 
00481 PositionVector::increasing_x_y_sorter::increasing_x_y_sorter() {}
00482 
00483 
00484 
00485 int
00486 PositionVector::increasing_x_y_sorter::operator()(const Position& p1,
00487         const Position& p2) const {
00488     if (p1.x() != p2.x()) {
00489         return p1.x() < p2.x();
00490     }
00491     return p1.y() < p2.y();
00492 }
00493 
00494 
00495 
00496 SUMOReal
00497 PositionVector::isLeft(const Position& P0, const Position& P1,
00498                        const Position& P2) const {
00499     return (P1.x() - P0.x()) * (P2.y() - P0.y()) - (P2.x() - P0.x()) * (P1.y() - P0.y());
00500 }
00501 
00502 
00503 PositionVector
00504 PositionVector::convexHull() const {
00505     PositionVector ret = *this;
00506     ret.sortAsPolyCWByAngle();
00507     return simpleHull_2D(ret);
00508 }
00509 
00510 
00511 void
00512 PositionVector::set(size_t pos, const Position& p) {
00513     myCont[pos] = p;
00514 }
00515 
00516 
00517 PositionVector 
00518 PositionVector::intersectionPoints2D(const Line& line) const {
00519     PositionVector ret;
00520     for (ContType::const_iterator i = myCont.begin(); i != myCont.end() - 1; i++) {
00521         if (GeomHelper::intersects(*i, *(i + 1), line.p1(), line.p2())) {
00522             ret.push_back_noDoublePos(GeomHelper::intersection_position(
00523                         *i, *(i + 1), line.p1(), line.p2()));
00524         }
00525     }
00526     return ret;
00527 }
00528 
00529 
00530 int
00531 PositionVector::appendWithCrossingPoint(const PositionVector& v) {
00532     if (myCont.back().distanceTo(v.myCont[0]) < 2) { // !!! heuristic
00533         copy(v.myCont.begin() + 1, v.myCont.end(), back_inserter(myCont));
00534         return 1;
00535     }
00536     //
00537     Line l1(myCont[myCont.size() - 2], myCont.back());
00538     l1.extrapolateBy(100);
00539     Line l2(v.myCont[0], v.myCont[1]);
00540     l2.extrapolateBy(100);
00541     if (l1.intersects(l2) && l1.intersectsAtLength2D(l2) < l1.length2D() - 100) { // !!! heuristic
00542         Position p = l1.intersectsAt(l2);
00543         myCont[myCont.size() - 1] = p;
00544         copy(v.myCont.begin() + 1, v.myCont.end(), back_inserter(myCont));
00545         return 2;
00546     } else {
00547         copy(v.myCont.begin(), v.myCont.end(), back_inserter(myCont));
00548         return 3;
00549     }
00550 }
00551 
00552 
00553 PositionVector
00554 PositionVector::getSubpart(SUMOReal begin, SUMOReal end) const {
00555     PositionVector ret;
00556     Position begPos = myCont.front();
00557     if (begin > POSITION_EPS) {
00558         begPos = positionAtLengthPosition(begin);
00559     }
00560     Position endPos = myCont.back();
00561     if (end < length() - POSITION_EPS) {
00562         endPos = positionAtLengthPosition(end);
00563     }
00564     ret.push_back(begPos);
00565 
00566     SUMOReal seen = 0;
00567     ContType::const_iterator i = myCont.begin();
00568     // skip previous segments
00569     while ((i + 1) != myCont.end()
00570             &&
00571             seen + (*i).distanceTo(*(i + 1)) < begin) {
00572         seen += (*i).distanceTo(*(i + 1));
00573         i++;
00574     }
00575     // append segments in between
00576     while ((i + 1) != myCont.end()
00577             &&
00578             seen + (*i).distanceTo(*(i + 1)) < end) {
00579 
00580         ret.push_back_noDoublePos(*(i + 1));
00581         /*
00582         if(ret.at(-1)!=*(i+1)) {
00583             ret.push_back(*(i+1));
00584         }
00585         */
00586         seen += (*i).distanceTo(*(i + 1));
00587         i++;
00588     }
00589     // append end
00590     ret.push_back_noDoublePos(endPos);
00591     return ret;
00592 }
00593 
00594 
00595 void
00596 PositionVector::pruneFromBeginAt(const Position& p) {
00597     // find minimum distance (from the begin)
00598     size_t pos = 0;
00599     SUMOReal dist = 1000000;
00600     size_t currPos = 0;
00601     SUMOReal currDist = GeomHelper::distancePointLine(p,
00602                         GeomHelper::extrapolate_first(*(myCont.begin()), *(myCont.begin() + 1), 100),
00603                         *(myCont.begin() + 1));
00604 //    assert(currDist>=0);
00605     if (currDist >= 0 && currDist < dist) {
00606         dist = currDist;
00607         pos = currPos;
00608     }
00609 
00610     for (ContType::iterator i = myCont.begin(); i != myCont.end() - 1; i++, currPos++) {
00611         SUMOReal currDist = GeomHelper::distancePointLine(p, *i, *(i + 1));
00612         if (currDist >= 0 && currDist < dist) {
00613             dist = currDist;
00614             pos = currPos;
00615         }
00616     }
00617     // remove leading items
00618     for (size_t j = 0; j < pos; j++) {
00619         myCont.erase(myCont.begin());
00620     }
00621     // replace first item by the new position
00622     SUMOReal lpos = GeomHelper::nearest_position_on_line_to_point2D(
00623                         myCont[0], myCont[1], p);
00624     if (lpos == -1) {
00625         return;
00626     }
00627     Position np = positionAtLengthPosition(lpos);
00628     if (np != *(myCont.begin())) {
00629         myCont.erase(myCont.begin());
00630         if (np != *(myCont.begin())) {
00631             myCont.insert(myCont.begin(), p);
00632             assert(myCont.size() > 1);
00633             assert(*(myCont.begin()) != *(myCont.end() - 1));
00634         }
00635     }
00636 }
00637 
00638 
00639 void
00640 PositionVector::pruneFromEndAt(const Position& p) {
00641     // find minimum distance (from the end)
00642     size_t pos = 0;
00643     SUMOReal dist = 1000000;
00644     size_t currPos = 0;
00645     SUMOReal currDist = GeomHelper::distancePointLine(p,
00646                         *(myCont.end() - 1),
00647                         GeomHelper::extrapolate_second(*(myCont.end() - 2), *(myCont.end() - 1), 100));
00648 //    assert(currDist>=0);
00649     if (currDist >= 0 && currDist < dist) {
00650         dist = currDist;
00651         pos = currPos;
00652     }
00653 
00654     for (ContType::reverse_iterator i = myCont.rbegin(); i != myCont.rend() - 1; i++, currPos++) {
00655         SUMOReal currDist = GeomHelper::distancePointLine(p, *(i), *(i + 1));
00656         if (currDist >= 0 && currDist < dist) {
00657             dist = currDist;
00658             pos = currPos;
00659         }
00660     }
00661     // remove trailing items
00662     for (size_t j = 0; j < pos; j++) {
00663         myCont.erase(myCont.end() - 1);
00664     }
00665     // replace last item by the new position
00666     SUMOReal lpos =
00667         GeomHelper::nearest_position_on_line_to_point2D(
00668             myCont[myCont.size() - 1], myCont[myCont.size() - 2], p);
00669     if (lpos == -1) {
00670         return;
00671     }
00672     Position np = positionAtLengthPosition(
00673                       length() - lpos);
00674     if (np != *(myCont.end() - 1)) {
00675         myCont.erase(myCont.end() - 1);
00676         if (np != *(myCont.end() - 1)) {
00677             myCont.push_back(np);
00678             assert(myCont.size() > 1);
00679             assert(*(myCont.begin()) != *(myCont.end() - 1));
00680         }
00681     }
00682 }
00683 
00684 
00685 SUMOReal
00686 PositionVector::beginEndAngle() const {
00687     Line tmp(getBegin(), getEnd());
00688     return tmp.atan2Angle();
00689 }
00690 
00691 
00692 void
00693 PositionVector::eraseAt(int i) {
00694     if (i >= 0) {
00695         myCont.erase(myCont.begin() + i);
00696     } else {
00697         myCont.erase(myCont.end() + i);
00698     }
00699 }
00700 
00701 
00702 SUMOReal
00703 PositionVector::nearest_position_on_line_to_point(const Position& p, bool perpendicular) const {
00704     SUMOReal shortestDist = -1;
00705     SUMOReal nearestPos = -1;
00706     SUMOReal seen = 0;
00707     for (ContType::const_iterator i = myCont.begin(); i != myCont.end() - 1; i++) {
00708         SUMOReal pos =
00709             GeomHelper::nearest_position_on_line_to_point2D(*i, *(i + 1), p, perpendicular);
00710         SUMOReal dist =
00711             pos < 0 ? -1 : p.distanceTo(positionAtLengthPosition(pos + seen));
00712         //
00713         if (dist >= 0 && (shortestDist < 0 || shortestDist > dist)) {
00714             nearestPos = pos + seen;
00715             shortestDist = dist;
00716         }
00717         seen += (*i).distanceTo(*(i + 1));
00718         //
00719     }
00720     return nearestPos;
00721 }
00722 
00723 
00724 int
00725 PositionVector::indexOfClosest(const Position& p) const {
00726     assert(size() > 0);
00727     SUMOReal minDist = std::numeric_limits<SUMOReal>::max();
00728     SUMOReal dist;
00729     int closest = 0;
00730     for (int i = 1; i < (int)size(); i++) {
00731         dist = p.distanceTo(myCont[i]);
00732         if (dist < minDist) {
00733             closest = i;
00734             minDist = dist;
00735         }
00736     }
00737     return closest;
00738 }
00739 
00740 
00741 void
00742 PositionVector::insertAtClosest(const Position& p) {
00743     Position outIntersection = Position();
00744     SUMOReal minDist = std::numeric_limits<SUMOReal>::max();
00745     SUMOReal dist;
00746     int insertionIndex = 1;
00747     for (int i = 1; i < (int)size() - 1; i++) {
00748         dist = GeomHelper::closestDistancePointLine(p, myCont[i], myCont[i + 1], outIntersection);
00749         if (dist < minDist) {
00750             insertionIndex = i + 1;
00751             minDist = dist;
00752         }
00753     }
00754     insertAt(insertionIndex, p);
00755 }
00756 
00757 
00758 SUMOReal
00759 PositionVector::distance(const Position& p) const {
00760     Position outIntersection = Position();
00761     SUMOReal minDist = std::numeric_limits<double>::max();
00762     for (ContType::const_iterator i = myCont.begin(); i != myCont.end() - 1; i++) {
00763         minDist = MIN2(minDist, GeomHelper::closestDistancePointLine(
00764                            p, *i, *(i + 1), outIntersection));
00765     }
00766     return minDist;
00767 }
00768 
00769 
00770 DoubleVector
00771 PositionVector::intersectsAtLengths2D(const PositionVector& other) const {
00772     DoubleVector ret;
00773     for (ContType::const_iterator i = other.myCont.begin(); i != other.myCont.end() - 1; i++) {
00774         DoubleVector atSegment = intersectsAtLengths2D(Line(*i, *(i+1)));
00775         copy(atSegment.begin(), atSegment.end(), back_inserter(ret));
00776     }
00777     return ret;
00778 }
00779 
00780 
00781 DoubleVector
00782 PositionVector::intersectsAtLengths2D(const Line& line) const {
00783     DoubleVector ret;
00784     SUMOReal pos = 0;
00785     for (ContType::const_iterator i = myCont.begin(); i != myCont.end() - 1; i++) {
00786         Line l((*i), *(i + 1));
00787         if (GeomHelper::intersects(l.p1(), l.p2(), line.p1(), line.p2())) {
00788             Position p =
00789                 GeomHelper::intersection_position(l.p1(), l.p2(), line.p1(), line.p2());
00790             SUMOReal atLength = p.distanceTo2D(l.p1());
00791             ret.push_back(atLength + pos);
00792         }
00793         pos += l.length2D();
00794     }
00795     return ret;
00796 }
00797 
00798 
00799 void
00800 PositionVector::extrapolate(SUMOReal val) {
00801     assert(myCont.size() > 1);
00802     Position nb =
00803         GeomHelper::extrapolate_first(myCont[0], myCont[1], val);
00804     Position ne =
00805         GeomHelper::extrapolate_second(
00806             myCont[myCont.size() - 2], myCont[myCont.size() - 1], val);
00807     myCont.erase(myCont.begin());
00808     push_front(nb);
00809     myCont.erase(myCont.end() - 1);
00810     push_back(ne);
00811 }
00812 
00813 
00814 PositionVector
00815 PositionVector::reverse() const {
00816     PositionVector ret;
00817     for (ContType::const_reverse_iterator i = myCont.rbegin(); i != myCont.rend(); i++) {
00818         ret.push_back(*i);
00819     }
00820     return ret;
00821 }
00822 
00823 
00824 void
00825 PositionVector::move2side(SUMOReal amount, int index) {
00826     if (index < 0) {
00827         index = (int) myCont.size() + index;
00828     }
00829     if (/*i==myGeom.size()-2||*/index == 0) {
00830         Position from = myCont[index];
00831         Position to = myCont[index + 1];
00832         std::pair<SUMOReal, SUMOReal> offsets = GeomHelper::getNormal90D_CW(from, to, amount);
00833         myCont[index] = Position(from.x() - offsets.first, from.y() - offsets.second);
00834     } else if (index == (int) myCont.size() - 1) {
00835         Position from = myCont[index - 1];
00836         Position to = myCont[index];
00837         std::pair<SUMOReal, SUMOReal> offsets = GeomHelper::getNormal90D_CW(from, to, amount);
00838         myCont[index] = Position(to.x() - offsets.first, to.y() - offsets.second);
00839     } else {
00840         Position from = myCont[index - 1];
00841         Position me = myCont[index];
00842         Position to = myCont[index + 1];
00843         std::pair<SUMOReal, SUMOReal> offsets = GeomHelper::getNormal90D_CW(from, me, amount);
00844         std::pair<SUMOReal, SUMOReal> offsets2 = GeomHelper::getNormal90D_CW(me, to, amount);
00845         Line l1(
00846             Position(from.x() - offsets.first, from.y() - offsets.second),
00847             Position(me.x() - offsets.first, me.y() - offsets.second));
00848         l1.extrapolateBy(100);
00849         Line l2(
00850             Position(me.x() - offsets2.first, me.y() - offsets2.second),
00851             Position(to.x() - offsets2.first, to.y() - offsets2.second));
00852         l2.extrapolateBy(100);
00853         if (l1.intersects(l2)) {
00854             myCont[index] = l1.intersectsAt(l2);
00855         } else {
00856             throw InvalidArgument("no line intersection");
00857         }
00858     }
00859 
00860 }
00861 
00862 void
00863 PositionVector::move2side(SUMOReal amount) {
00864     if (myCont.size() < 2) {
00865         return;
00866     }
00867     PositionVector shape;
00868     for (size_t i = 0; i < myCont.size(); i++) {
00869         if (/*i==myGeom.size()-2||*/i == 0) {
00870             Position from = myCont[i];
00871             Position to = myCont[i + 1];
00872             std::pair<SUMOReal, SUMOReal> offsets =
00873                 GeomHelper::getNormal90D_CW(from, to, amount);
00874             shape.push_back(//.push_back(
00875                 // (methode umbenennen; was heisst hier "-")
00876                 Position(from.x() - offsets.first, from.y() - offsets.second));
00877         } else if (i == myCont.size() - 1) {
00878             Position from = myCont[i - 1];
00879             Position to = myCont[i];
00880             std::pair<SUMOReal, SUMOReal> offsets =
00881                 GeomHelper::getNormal90D_CW(from, to, amount);
00882             shape.push_back(//.push_back(
00883                 // (methode umbenennen; was heisst hier "-")
00884                 Position(to.x() - offsets.first, to.y() - offsets.second));
00885         } else {
00886             Position from = myCont[i - 1];
00887             Position me = myCont[i];
00888             Position to = myCont[i + 1];
00889             double sinAngle = sin(GeomHelper::Angle2D(from.x() - me.x(), from.y() - me.y(),
00890                                   me.x() - to.x(), me.y() - to.y()) / 2);
00891             double maxDev = 2 * (from.distanceTo(me) + me.distanceTo(to)) * sinAngle;
00892             if (fabs(maxDev) < POSITION_EPS) {
00893                 // parallel case, just shift the middle point
00894                 std::pair<SUMOReal, SUMOReal> off =
00895                     GeomHelper::getNormal90D_CW(from, to, amount);
00896                 shape.push_back(Position(me.x() - off.first, me.y() - off.second));
00897                 continue;
00898             }
00899             std::pair<SUMOReal, SUMOReal> offsets =
00900                 GeomHelper::getNormal90D_CW(from, me, amount);
00901             std::pair<SUMOReal, SUMOReal> offsets2 =
00902                 GeomHelper::getNormal90D_CW(me, to, amount);
00903             Line l1(
00904                 Position(from.x() - offsets.first, from.y() - offsets.second),
00905                 Position(me.x() - offsets.first, me.y() - offsets.second));
00906             l1.extrapolateBy(100);
00907             Line l2(
00908                 Position(me.x() - offsets2.first, me.y() - offsets2.second),
00909                 Position(to.x() - offsets2.first, to.y() - offsets2.second));
00910             l2.extrapolateBy(100);
00911             if (l1.intersects(l2)) {
00912                 shape.push_back(//.push_back(
00913                     // (methode umbenennen; was heisst hier "-")
00914                     l1.intersectsAt(l2));
00915             } else {
00916                 throw InvalidArgument("no line intersection");
00917             }
00918         }
00919     }
00920 
00921     /*
00922     ContType newCont;
00923     std::pair<SUMOReal, SUMOReal> p;
00924     Position newPos;
00925     // first point
00926     newPos = (*(myCont.begin()));
00927     p = GeomHelper::getNormal90D_CW(*(myCont.begin()), *(myCont.begin()+1), amount);
00928     newPos.add(p.first, p.second);
00929     newCont.push_back(newPos);
00930     // middle points
00931     for(ContType::const_iterator i=myCont.begin()+1; i!=myCont.end()-1; i++) {
00932         std::pair<SUMOReal, SUMOReal> oldp = p;
00933         newPos = *i;
00934         newPos.add(p.first, p.second);
00935         newCont.push_back(newPos);
00936         p = GeomHelper::getNormal90D_CW(*i, *(i+1), amount);
00937     //        Position newPos(*i);
00938     //        newPos.add((p.first+oldp.first)/2.0, (p.second+oldp.second)/2.0);
00939     //        newCont.push_back(newPos);
00940     }
00941     // last point
00942     newPos = (*(myCont.end()-1));
00943     newPos.add(p.first, p.second);
00944     newCont.push_back(newPos);
00945     myCont = newCont;
00946     */
00947     myCont = shape.myCont;
00948 }
00949 
00950 
00951 Line
00952 PositionVector::lineAt(size_t pos) const {
00953     assert(myCont.size() > pos + 1);
00954     return Line(myCont[pos], myCont[pos + 1]);
00955 }
00956 
00957 
00958 Line
00959 PositionVector::getBegLine() const {
00960     return lineAt(0);
00961 }
00962 
00963 
00964 Line
00965 PositionVector::getEndLine() const {
00966     return lineAt(myCont.size() - 2);
00967 }
00968 
00969 
00970 void
00971 PositionVector::closePolygon() {
00972     if (myCont[0] == myCont.back()) {
00973         return;
00974     }
00975     push_back(myCont[0]);
00976 }
00977 
00978 
00979 DoubleVector
00980 PositionVector::distances(const PositionVector& s) const {
00981     DoubleVector ret;
00982     ContType::const_iterator i;
00983     for (i = myCont.begin(); i != myCont.end(); i++) {
00984         ret.push_back(s.distance(*i));
00985     }
00986     for (i = s.myCont.begin(); i != s.myCont.end(); i++) {
00987         ret.push_back(distance(*i));
00988     }
00989     return ret;
00990 }
00991 
00992 
00993 Position
00994 PositionVector::pop_back() {
00995     Position last = myCont.back();
00996     myCont.erase(myCont.end() - 1);
00997     return last;
00998 }
00999 
01000 
01001 Position
01002 PositionVector::pop_front() {
01003     Position first = myCont.front();
01004     myCont.erase(myCont.begin());
01005     return first;
01006 }
01007 
01008 
01009 void
01010 PositionVector::insertAt(int index, const Position& p) {
01011     if (index >= 0) {
01012         myCont.insert(myCont.begin() + index, p);
01013     } else {
01014         myCont.insert(myCont.end() + index, p);
01015     }
01016 }
01017 
01018 
01019 void
01020 PositionVector::push_back_noDoublePos(const Position& p) {
01021     if (size() == 0 || !p.almostSame(myCont.back())) {
01022         myCont.push_back(p);
01023     }
01024 }
01025 
01026 
01027 void
01028 PositionVector::push_front_noDoublePos(const Position& p) {
01029     if (size() == 0 || !p.almostSame(myCont.front())) {
01030         myCont.insert(myCont.begin(), p);
01031     }
01032 }
01033 
01034 
01035 void
01036 PositionVector::replaceAt(size_t index, const Position& by) {
01037     assert(size() > index);
01038     myCont[index] = by;
01039 }
01040 
01041 
01042 bool
01043 PositionVector::isClosed() const {
01044     return myCont.size() >= 2 && myCont[0] == myCont.back();
01045 }
01046 
01047 
01048 void
01049 PositionVector::removeDoublePoints() {
01050     if (myCont.size() > 1) {
01051         ContType::iterator last = myCont.begin();
01052         for (ContType::iterator i = myCont.begin() + 1; i != myCont.end();) {
01053             if (last->almostSame(*i)) {
01054                 i = myCont.erase(i);
01055             } else {
01056                 last = i;
01057                 ++i;
01058             }
01059         }
01060     }
01061 }
01062 
01063 
01064 void
01065 PositionVector::removeColinearPoints() {
01066     if (myCont.size() > 2) {
01067         Position& last = myCont.front();
01068         for (ContType::iterator i = myCont.begin() + 1; i != myCont.end() - 1;) {
01069             if (GeomHelper::distancePointLine(*i, last, *(i + 1)) < 0.001) {
01070                 i = myCont.erase(i);
01071             } else {
01072                 last = *i;
01073                 ++i;
01074             }
01075         }
01076     }
01077 }
01078 
01079 
01080 bool
01081 PositionVector::operator==(const PositionVector& v2) const {
01082     if (size() == v2.size()) {
01083         for (int i = 0; i < (int)size(); i++) {
01084             if ((*this)[i] != v2[i]) {
01085                 return false;
01086             }
01087         }
01088         return true;
01089     } else {
01090         return false;
01091     }
01092 }
01093 
01094 
01095 
01096 /****************************************************************************/
01097 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Defines