SUMO - Simulation of Urban MObility

PositionVector.cpp

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