|
SUMO - Simulation of Urban MObility
|
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