1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2005-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file    MSStoppingPlace.cpp
11 /// @author  Daniel Krajzewicz
12 /// @author  Michael Behrisch
13 /// @date    Mon, 13.12.2005
14 /// @version $Id$
15 ///
16 // A lane area vehicles can halt at
17 /****************************************************************************/
18 
19 
20 // ===========================================================================
21 // included modules
22 // ===========================================================================
23 #include <config.h>
24 
25 #include <cassert>
26 #include <map>
27 #include <utils/vehicle/SUMOVehicle.h>
28 #include <utils/geom/Position.h>
29 #include <microsim/MSVehicleType.h>
30 #include <microsim/MSNet.h>
31 #include "MSLane.h"
32 #include "MSTransportable.h"
33 #include "MSStoppingPlace.h"
34 
35 // ===========================================================================
36 // method definitions
37 // ===========================================================================
MSStoppingPlace(const std::string & id,const std::vector<std::string> & lines,MSLane & lane,double begPos,double endPos,const std::string name,int capacity)38 MSStoppingPlace::MSStoppingPlace(const std::string& id,
39                                  const std::vector<std::string>& lines,
40                                  MSLane& lane,
41                                  double begPos, double endPos, const std::string name,
42                                  int capacity) :
43     Named(id), myLines(lines), myLane(lane),
44     myBegPos(begPos), myEndPos(endPos), myLastFreePos(endPos),
45     myName(name),
46     myTransportableCapacity(capacity) {
47     computeLastFreePos();
48     for (int i = 0; i < capacity; i++) {
49         myWaitingSpots.insert(i);
50     }
51 }
52 
53 
~MSStoppingPlace()54 MSStoppingPlace::~MSStoppingPlace() {}
55 
56 
57 const MSLane&
getLane() const58 MSStoppingPlace::getLane() const {
59     return myLane;
60 }
61 
62 
63 double
getBeginLanePosition() const64 MSStoppingPlace::getBeginLanePosition() const {
65     return myBegPos;
66 }
67 
68 
69 double
getEndLanePosition() const70 MSStoppingPlace::getEndLanePosition() const {
71     return myEndPos;
72 }
73 
74 
75 void
enter(SUMOVehicle * what,double beg,double end)76 MSStoppingPlace::enter(SUMOVehicle* what, double beg, double end) {
77     myEndPositions[what] = std::pair<double, double>(beg, end);
78     computeLastFreePos();
79 }
80 
81 
82 double
getLastFreePos(const SUMOVehicle & forVehicle) const83 MSStoppingPlace::getLastFreePos(const SUMOVehicle& forVehicle) const {
84     if (myLastFreePos != myEndPos) {
85         const double vehGap = forVehicle.getVehicleType().getMinGap();
86         double pos = myLastFreePos - vehGap;
87         if (!fits(pos, forVehicle)) {
88             // try to find a place ahead of the waiting vehicles
89             const double vehLength = forVehicle.getVehicleType().getLength();
90             std::vector<std::pair<double, std::pair<double, const SUMOVehicle*> > > spaces;
91             for (auto it : myEndPositions) {
92                 spaces.push_back(std::make_pair(it.second.first, std::make_pair(it.second.second, it.first)));
93             }
94             // sorted from myEndPos towars myBegPos
95             std::sort(spaces.begin(), spaces.end());
96             std::reverse(spaces.begin(), spaces.end());
97             double prev = myEndPos;
98             for (auto it : spaces) {
99                 //if (forVehicle.isSelected()) {
100                 //    std::cout << SIMTIME << " fitPosFor " << forVehicle.getID() << " l=" << vehLength << " prev=" << prev << " vehBeg=" << it.first << " vehEnd=" << it.second.first << " found=" << (prev - it.first >= vehLength) << "\n";
101                 //}
102                 if (prev - it.first + NUMERICAL_EPS >= vehLength && (
103                             it.second.second->isParking()
104                             || it.second.second->remainingStopDuration() > TIME2STEPS(10))) {
105                     return prev;
106                 }
107                 prev = it.second.first - vehGap;
108             }
109         }
110         return pos;
111     }
112     return myLastFreePos;
113 }
114 
115 bool
fits(double pos,const SUMOVehicle & veh) const116 MSStoppingPlace::fits(double pos, const SUMOVehicle& veh) const {
117     // always fit at the default position or if at least half the vehicle length
118     // is within the stop range (debatable)
119     return pos + POSITION_EPS >= myEndPos || (pos - myBegPos >= veh.getVehicleType().getLength() / 2);
120 }
121 
122 double
getWaitingPositionOnLane(MSTransportable * t) const123 MSStoppingPlace::getWaitingPositionOnLane(MSTransportable* t) const {
124     auto it = myWaitingTransportables.find(t);
125     if (it != myWaitingTransportables.end() && it->second >= 0) {
126         return myEndPos - (0.5 + (it->second) % getPersonsAbreast()) * SUMO_const_waitingPersonWidth;
127     } else {
128         return (myEndPos + myBegPos) / 2;
129     }
130 }
131 
132 
133 int
getPersonsAbreast(double length)134 MSStoppingPlace::getPersonsAbreast(double length) {
135     return MAX2(1, (int)floor(length / SUMO_const_waitingPersonWidth));
136 }
137 
138 int
getPersonsAbreast() const139 MSStoppingPlace::getPersonsAbreast() const {
140     return getPersonsAbreast(myEndPos - myBegPos);
141 }
142 
143 Position
getWaitPosition(MSTransportable * t) const144 MSStoppingPlace::getWaitPosition(MSTransportable* t) const {
145     double lanePos = getWaitingPositionOnLane(t);
146     int row = 0;
147     auto it = myWaitingTransportables.find(t);
148     if (it != myWaitingTransportables.end()) {
149         if (it->second >= 0) {
150             row = int(it->second / getPersonsAbreast());
151         } else {
152             // invalid position, draw outside bounds
153             row = 1 + myTransportableCapacity / getPersonsAbreast();
154         }
155     }
156     return myLane.getShape().positionAtOffset(myLane.interpolateLanePosToGeometryPos(lanePos),
157             myLane.getWidth() / 2 + row * SUMO_const_waitingPersonDepth);
158 }
159 
160 
161 double
getStoppingPosition(const SUMOVehicle * veh) const162 MSStoppingPlace::getStoppingPosition(const SUMOVehicle* veh) const {
163     std::map<const SUMOVehicle*, std::pair<double, double> >::const_iterator i = myEndPositions.find(veh);
164     if (i != myEndPositions.end()) {
165         return i->second.second;
166     } else {
167         return getLastFreePos(*veh);
168     }
169 }
170 
171 bool
hasSpaceForTransportable() const172 MSStoppingPlace::hasSpaceForTransportable() const {
173     return myWaitingSpots.size() > 0;
174 }
175 
176 bool
addTransportable(MSTransportable * p)177 MSStoppingPlace::addTransportable(MSTransportable* p) {
178     int spot = -1;
179     if (!hasSpaceForTransportable()) {
180         return false;
181     }
182     spot = *myWaitingSpots.begin();
183     myWaitingSpots.erase(myWaitingSpots.begin());
184     myWaitingTransportables[p] = spot;
185     return true;
186 }
187 
188 
189 void
removeTransportable(MSTransportable * p)190 MSStoppingPlace::removeTransportable(MSTransportable* p) {
191     auto i = myWaitingTransportables.find(p);
192     if (i != myWaitingTransportables.end()) {
193         if (i->second >= 0) {
194             myWaitingSpots.insert(i->second);
195         }
196         myWaitingTransportables.erase(i);
197     }
198 }
199 
200 
201 void
leaveFrom(SUMOVehicle * what)202 MSStoppingPlace::leaveFrom(SUMOVehicle* what) {
203     assert(myEndPositions.find(what) != myEndPositions.end());
204     myEndPositions.erase(myEndPositions.find(what));
205     computeLastFreePos();
206 }
207 
208 
209 void
computeLastFreePos()210 MSStoppingPlace::computeLastFreePos() {
211     myLastFreePos = myEndPos;
212     std::map<const SUMOVehicle*, std::pair<double, double> >::iterator i;
213     for (i = myEndPositions.begin(); i != myEndPositions.end(); i++) {
214         if (myLastFreePos > (*i).second.second) {
215             myLastFreePos = (*i).second.second;
216         }
217     }
218 }
219 
220 
221 double
getAccessPos(const MSEdge * edge) const222 MSStoppingPlace::getAccessPos(const MSEdge* edge) const {
223     if (edge == &myLane.getEdge()) {
224         return (myBegPos + myEndPos) / 2.;
225     }
226     for (const auto& access : myAccessPos) {
227         if (edge == &std::get<0>(access)->getEdge()) {
228             return std::get<1>(access);
229         }
230     }
231     return -1.;
232 }
233 
234 
235 double
getAccessDistance(const MSEdge * edge) const236 MSStoppingPlace::getAccessDistance(const MSEdge* edge) const {
237     if (edge == &myLane.getEdge()) {
238         return 0.;
239     }
240     for (const auto& access : myAccessPos) {
241         const MSLane* const accLane = std::get<0>(access);
242         if (edge == &accLane->getEdge()) {
243             const double length = std::get<2>(access);
244             if (length >= 0.) {
245                 return length;
246             }
247             const Position accPos = accLane->geometryPositionAtOffset(std::get<1>(access));
248             const Position stopPos = myLane.geometryPositionAtOffset((myBegPos + myEndPos) / 2.);
249             return accPos.distanceTo(stopPos);
250         }
251     }
252     return -1.;
253 }
254 
255 
256 const std::string&
getMyName() const257 MSStoppingPlace::getMyName() const {
258     return myName;
259 }
260 
261 
262 bool
addAccess(MSLane * lane,const double pos,const double length)263 MSStoppingPlace::addAccess(MSLane* lane, const double pos, const double length) {
264     // prevent multiple accesss on the same lane
265     for (const auto& access : myAccessPos) {
266         if (lane == std::get<0>(access)) {
267             return false;
268         }
269     }
270     myAccessPos.push_back(std::make_tuple(lane, pos, length));
271     return true;
272 }
273 
274 
275 /****************************************************************************/
276