Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2015-2026 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file MSParkingArea.cpp
15 : /// @author Mirco Sturari
16 : /// @author Jakob Erdmann
17 : /// @author Mirko Barthauer
18 : /// @date Tue, 19.01.2016
19 : ///
20 : // A area where vehicles can park next to the road
21 : /****************************************************************************/
22 : #include <config.h>
23 :
24 : #include <cassert>
25 : #include <utils/common/WrappingCommand.h>
26 : #include <utils/vehicle/SUMOVehicle.h>
27 : #include <utils/geom/Position.h>
28 : #include <utils/geom/GeomHelper.h>
29 : #include <microsim/MSEventControl.h>
30 : #include <microsim/MSNet.h>
31 : #include <microsim/MSEdge.h>
32 : #include <microsim/MSVehicle.h>
33 : #include <microsim/MSVehicleType.h>
34 : #include "MSLane.h"
35 : #include <microsim/transportables/MSTransportable.h>
36 : #include "MSParkingArea.h"
37 : #include "MSGlobals.h"
38 : #include <utils/common/MsgHandler.h>
39 :
40 : //#define DEBUG_RESERVATIONS
41 : //#define DEBUG_GET_LAST_FREE_POS
42 : //#define DEBUG_COND2(obj) (obj.getID() == "v.3")
43 : #define DEBUG_COND2(obj) (obj.isSelected())
44 :
45 :
46 : // ===========================================================================
47 : // method definitions
48 : // ===========================================================================
49 17406 : MSParkingArea::MSParkingArea(const std::string& id, const std::vector<std::string>& lines,
50 : const std::vector<std::string>& badges, MSLane& lane,
51 : double begPos, double endPos, int capacity, double width, double length,
52 : double angle, const std::string& name, bool onRoad,
53 17406 : const std::string& departPos, bool lefthand, bool reservable) :
54 : MSStoppingPlace(id, SUMO_TAG_PARKING_AREA, lines, lane, begPos, endPos, name),
55 17406 : myRoadSideCapacity(capacity),
56 17406 : myCapacity(0),
57 17406 : myOnRoad(onRoad),
58 17406 : myReservable(reservable),
59 17406 : myWidth(width),
60 17406 : myLength(length),
61 17406 : myAngle(lefthand ? -angle : angle),
62 17406 : myAcceptedBadges(badges.begin(), badges.end()),
63 17406 : myEgressBlocked(false),
64 17406 : myReservationTime(-1),
65 17406 : myLastReservationTime(-1),
66 17406 : myReservations(0),
67 17406 : myLastReservations(0),
68 17406 : myReservationMaxLength(0),
69 17406 : myLastReservationMaxLength(0),
70 17406 : myMaxVehLength(0),
71 17406 : myNumAlternatives(0),
72 17406 : myLastStepOccupancy(0),
73 17406 : myDepartPos(-1),
74 17406 : myDepartPosDefinition(DepartPosDefinition::DEFAULT),
75 34826 : myUpdateEvent(nullptr) {
76 : // initialize unspecified defaults
77 17406 : if (myWidth == 0) {
78 15048 : myWidth = SUMO_const_laneWidth;
79 : }
80 :
81 17406 : if (departPos != "") {
82 : std::string error;
83 60 : if (!SUMOVehicleParameter::parseDepartPos(departPos, toString(myElement), getID(), myDepartPos, myDepartPosDefinition, error)) {
84 0 : throw ProcessError(error);
85 : }
86 30 : if (myDepartPosDefinition != DepartPosDefinition::GIVEN) {
87 : // maybe allow other methods at a later time
88 0 : throw ProcessError(TLF("Only a numerical departPos is supported for % '%'", toString(myElement), getID()));
89 30 : } else if (myDepartPos < 0 || myDepartPos > lane.getLength()) {
90 0 : throw ProcessError(TLF("Invalid departPos for % '%'", toString(myElement), getID()));
91 : }
92 : }
93 :
94 17406 : const double offset = (MSGlobals::gLefthand != lefthand) ? -1 : 1;
95 34812 : myShape = lane.getShape().getSubpart(
96 : lane.interpolateLanePosToGeometryPos(begPos),
97 : lane.interpolateLanePosToGeometryPos(endPos));
98 17406 : if (!myOnRoad) {
99 17266 : myShape.move2side((lane.getWidth() / 2. + myWidth / 2.) * offset);
100 : }
101 17406 : setRoadsideCapacity(capacity);
102 17406 : }
103 :
104 :
105 51228 : MSParkingArea::~MSParkingArea() {}
106 :
107 :
108 : void
109 54124 : MSParkingArea::addLotEntry(double x, double y, double z, double width, double length, double angle, double slope) {
110 : // create LotSpaceDefinition
111 54124 : LotSpaceDefinition lsd((int)mySpaceOccupancies.size(), nullptr, x, y, z, angle, slope, width, length);
112 : // If we are modelling parking set the end position to the lot position relative to the lane
113 : // rather than the end of the parking area - this results in vehicles stopping nearer the space
114 : // and re-entering the lane nearer the space. (If we are not modelling parking the vehicle will usually
115 : // enter the space and re-enter at the end of the parking area.)
116 54124 : if (MSGlobals::gModelParkingManoeuver) {
117 30 : const double offset = this->getLane().getShape().nearest_offset_to_point2D(lsd.position);
118 30 : if (offset < getBeginLanePosition()) {
119 0 : lsd.endPos = getBeginLanePosition() + POSITION_EPS;
120 : } else {
121 30 : if (this->getLane().getLength() > offset) {
122 30 : lsd.endPos = offset;
123 : } else {
124 0 : lsd.endPos = this->getLane().getLength() - POSITION_EPS;
125 : }
126 : }
127 : // Work out the angle of the lot relative to the lane (-90 adjusts for the way the bay is drawn )
128 30 : double relativeAngle = fmod(lsd.rotation - 90., 360) - fmod(RAD2DEG(this->getLane().getShape().rotationAtOffset(lsd.endPos)), 360) + 0.5;
129 30 : if (relativeAngle < 0.) {
130 10 : relativeAngle += 360.;
131 : }
132 30 : lsd.manoeuverAngle = relativeAngle;
133 :
134 : // if p2.y is -ve the lot is on LHS of lane relative to lane direction
135 : // we need to know this because it inverts the complexity of the parking manoeuver
136 30 : Position p2 = this->getLane().getShape().transformToVectorCoordinates(lsd.position);
137 30 : if (p2.y() < (0. + POSITION_EPS)) {
138 30 : lsd.sideIsLHS = true;
139 : } else {
140 0 : lsd.sideIsLHS = false;
141 : }
142 : } else {
143 54094 : lsd.endPos = myEndPos;
144 54094 : lsd.manoeuverAngle = int(angle); // unused unless gModelParkingManoeuver is true
145 54094 : lsd.sideIsLHS = true;
146 : }
147 54124 : mySpaceOccupancies.push_back(lsd);
148 54124 : myCapacity++;
149 54124 : computeLastFreePos();
150 54124 : }
151 :
152 : int
153 30 : MSParkingArea::getLastFreeLotAngle() const {
154 : assert(myLastFreeLot >= 0);
155 : assert(myLastFreeLot < (int)mySpaceOccupancies.size());
156 :
157 30 : const LotSpaceDefinition& lsd = mySpaceOccupancies[myLastFreeLot];
158 30 : if (lsd.sideIsLHS) {
159 30 : return abs(int(lsd.manoeuverAngle)) % 180;
160 : } else {
161 0 : return abs(abs(int(lsd.manoeuverAngle)) % 180 - 180) % 180;
162 : }
163 : }
164 :
165 : double
166 30 : MSParkingArea::getLastFreeLotGUIAngle() const {
167 : assert(myLastFreeLot >= 0);
168 : assert(myLastFreeLot < (int)mySpaceOccupancies.size());
169 :
170 30 : const LotSpaceDefinition& lsd = mySpaceOccupancies[myLastFreeLot];
171 30 : if (lsd.manoeuverAngle > 180.) {
172 15 : return DEG2RAD(lsd.manoeuverAngle - 360.);
173 : } else {
174 15 : return DEG2RAD(lsd.manoeuverAngle);
175 : }
176 : }
177 :
178 :
179 : double
180 2719074 : MSParkingArea::getLastFreePos(const SUMOVehicle& forVehicle, double brakePos) const {
181 2719074 : if (myCapacity == (int)myEndPositions.size()) {
182 : // keep enough space so that parking vehicles can leave
183 : #ifdef DEBUG_GET_LAST_FREE_POS
184 : if (DEBUG_COND2(forVehicle)) {
185 : std::cout << SIMTIME << " getLastFreePos veh=" << forVehicle.getID() << " allOccupied\n";
186 : }
187 : #endif
188 1787531 : return myLastFreePos - forVehicle.getVehicleType().getMinGap() - POSITION_EPS;
189 931543 : } else if (mustAdvance(forVehicle.getVClass())) {
190 : // vehicles cannot overtake so we must fill from the downstream end
191 148505 : int skipN = SIMSTEP == myReservationTime ? myReservations - 1 : 0;
192 : //std::cout << SIMTIME << " v=" << forVehicle.getID() << " t=" << SIMTIME << " resTime=" << STEPS2TIME(myReservationTime) << " myR=" << myReservations << " skip=" << skipN << " rV=" << toString(myReservedVehicles) << "\n";
193 384186 : for (auto it_lsd = mySpaceOccupancies.rbegin(); it_lsd != mySpaceOccupancies.rend(); it_lsd++) {
194 383944 : if (it_lsd->vehicle == nullptr) {
195 153858 : if (skipN > 0) {
196 : // skip reservations
197 5595 : skipN--;
198 5595 : continue;
199 : }
200 : #ifdef DEBUG_GET_LAST_FREE_POS
201 : if (DEBUG_COND2(forVehicle)) {
202 : std::cout << SIMTIME << " getLastFreePos (onRoad-upstream) veh=" << forVehicle.getID() << " brakePos=" << brakePos << " myEndPos=" << myEndPos << " nextFreePos=" << it_lsd->endPos << "\n";
203 : }
204 : #endif
205 148263 : return it_lsd->endPos;
206 : }
207 : }
208 : // should not happen
209 : return brakePos;
210 : } else {
211 783038 : const double minPos = MIN2(myEndPos, brakePos);
212 783038 : if (myLastFreePos >= minPos) {
213 : #ifdef DEBUG_GET_LAST_FREE_POS
214 : if (DEBUG_COND2(forVehicle)) {
215 : std::cout << SIMTIME << " getLastFreePos veh=" << forVehicle.getID() << " brakePos=" << brakePos << " myEndPos=" << myEndPos << " using myLastFreePos=" << myLastFreePos << "\n";
216 : }
217 : #endif
218 : return myLastFreePos;
219 : } else {
220 : // find free pos after minPos
221 58492 : for (const auto& lsd : mySpaceOccupancies) {
222 58289 : if (lsd.vehicle == nullptr && lsd.endPos >= minPos) {
223 : #ifdef DEBUG_GET_LAST_FREE_POS
224 : if (DEBUG_COND2(forVehicle)) {
225 : std::cout << SIMTIME << " getLastFreePos veh=" << forVehicle.getID() << " brakePos=" << brakePos << " myEndPos=" << myEndPos << " nextFreePos=" << lsd.endPos << "\n";
226 : }
227 : #endif
228 : return lsd.endPos;
229 : }
230 : }
231 : // shouldn't happen. No good solution seems possible
232 : #ifdef DEBUG_GET_LAST_FREE_POS
233 : if (DEBUG_COND2(forVehicle)) {
234 : std::cout << SIMTIME << " getLastFreePos veh=" << forVehicle.getID() << " brakePos=" << brakePos << " myEndPos=" << myEndPos << " noGoodFreePos blockedAt=" << brakePos << "\n";
235 : }
236 : #endif
237 : return brakePos;
238 : }
239 : }
240 : }
241 :
242 : bool
243 1196266 : MSParkingArea::mustAdvance(SUMOVehicleClass svc) const {
244 1196266 : return myOnRoad && cannotChange(svc);
245 : }
246 :
247 : bool
248 450635 : MSParkingArea::cannotChange(SUMOVehicleClass svc) const {
249 450635 : const MSLane* left = myLane.getParallelLane(1, false);
250 450635 : const MSLane* right = myLane.getParallelLane(-1, false);
251 37499 : return ((left == nullptr || !left->allowsVehicleClass(svc) || !myLane.allowsChangingLeft(svc))
252 450635 : && (right == nullptr || !right->allowsVehicleClass(svc) || !myLane.allowsChangingRight(svc)));
253 : }
254 :
255 :
256 : Position
257 22057 : MSParkingArea::getVehiclePosition(const SUMOVehicle& forVehicle) const {
258 51127 : for (const auto& lsd : mySpaceOccupancies) {
259 51127 : if (lsd.vehicle == &forVehicle) {
260 22057 : return lsd.position;
261 : }
262 : }
263 0 : return Position::INVALID;
264 : }
265 :
266 :
267 : double
268 56336 : MSParkingArea::getInsertionPosition(const SUMOVehicle& forVehicle) const {
269 56336 : if (myDepartPosDefinition == DepartPosDefinition::GIVEN) {
270 250 : return myDepartPos;
271 : }
272 141108 : for (const auto& lsd : mySpaceOccupancies) {
273 141098 : if (lsd.vehicle == &forVehicle) {
274 56076 : return lsd.endPos;
275 : }
276 : }
277 : return -1;
278 : }
279 :
280 :
281 : double
282 15713 : MSParkingArea::getVehicleAngle(const SUMOVehicle& forVehicle) const {
283 39332 : for (const auto& lsd : mySpaceOccupancies) {
284 39311 : if (lsd.vehicle == &forVehicle) {
285 15692 : return (lsd.rotation - 90.) * (double) M_PI / (double) 180.0;
286 : }
287 : }
288 : return 0;
289 : }
290 :
291 : double
292 3901 : MSParkingArea::getVehicleSlope(const SUMOVehicle& forVehicle) const {
293 12511 : for (const auto& lsd : mySpaceOccupancies) {
294 12511 : if (lsd.vehicle == &forVehicle) {
295 3901 : return lsd.slope;
296 : }
297 : }
298 : return 0;
299 : }
300 :
301 : double
302 30 : MSParkingArea::getGUIAngle(const SUMOVehicle& forVehicle) const {
303 60 : for (const auto& lsd : mySpaceOccupancies) {
304 60 : if (lsd.vehicle == &forVehicle) {
305 30 : if (lsd.manoeuverAngle > 180.) {
306 15 : return DEG2RAD(lsd.manoeuverAngle - 360.);
307 : } else {
308 15 : return DEG2RAD(lsd.manoeuverAngle);
309 : }
310 : }
311 : }
312 : return 0.;
313 : }
314 :
315 : int
316 30 : MSParkingArea::getManoeuverAngle(const SUMOVehicle& forVehicle) const {
317 60 : for (const auto& lsd : mySpaceOccupancies) {
318 60 : if (lsd.vehicle == &forVehicle) {
319 30 : if (lsd.sideIsLHS) {
320 30 : return abs(int(lsd.manoeuverAngle)) % 180;
321 : } else {
322 0 : return abs(abs(int(lsd.manoeuverAngle)) % 180 - 180) % 180;
323 : }
324 : }
325 : }
326 : return 0;
327 : }
328 :
329 : int
330 41342 : MSParkingArea::getLotIndex(const SUMOVehicle* veh) const {
331 41342 : if (veh->getPositionOnLane() > myLastFreePos) {
332 : // vehicle has gone past myLastFreePos and we need to find the actual lot
333 : int closestLot = -1;
334 19447 : for (int i = 0; i < (int)mySpaceOccupancies.size(); i++) {
335 19375 : const LotSpaceDefinition lsd = mySpaceOccupancies[i];
336 19375 : if (lsd.vehicle == nullptr) {
337 : closestLot = i;
338 14165 : if (lsd.endPos >= veh->getPositionOnLane()) {
339 5270 : return i;
340 : }
341 : }
342 : }
343 72 : return closestLot;
344 : }
345 36000 : if (myOnRoad && myLastFreePos - veh->getPositionOnLane() > POSITION_EPS) {
346 : // for on-road parking we need to be precise
347 : return -1;
348 : }
349 9216 : return myLastFreeLot;
350 : }
351 :
352 : void
353 9853 : MSParkingArea::enter(SUMOVehicle* veh, const bool /* parking */) {
354 9853 : removeSpaceReservation(veh);
355 9853 : double beg = veh->getPositionOnLane() + veh->getVehicleType().getMinGap();
356 9853 : double end = veh->getPositionOnLane() - veh->getVehicleType().getLength();
357 9853 : if (myUpdateEvent == nullptr) {
358 0 : myUpdateEvent = new WrappingCommand<MSParkingArea>(this, &MSParkingArea::updateOccupancy);
359 0 : MSNet::getInstance()->getEndOfTimestepEvents()->addEvent(myUpdateEvent);
360 : }
361 9853 : int lotIndex = getLotIndex(veh);
362 9853 : if (lotIndex < 0) {
363 0 : WRITE_WARNING("Unsuitable parking position for vehicle '" + veh->getID() + "' at parkingArea '" + getID() + "' time=" + time2string(SIMSTEP));
364 0 : lotIndex = myLastFreeLot;
365 : }
366 : #ifdef DEBUG_GET_LAST_FREE_POS
367 : ((SUMOVehicleParameter&)veh->getParameter()).setParameter("lotIndex", toString(lotIndex));
368 : #endif
369 : assert(myLastFreePos >= 0);
370 : assert(lotIndex < (int)mySpaceOccupancies.size());
371 9853 : mySpaceOccupancies[lotIndex].vehicle = veh;
372 9853 : myEndPositions[veh] = std::pair<double, double>(beg, end);
373 9853 : computeLastFreePos();
374 9853 : myMaxVehLength = MAX2(myMaxVehLength, veh->getLength());
375 : // current search ends here
376 9853 : veh->setNumberParkingReroutes(0);
377 9853 : }
378 :
379 :
380 : void
381 30 : MSParkingArea::addSpaceReservation(const SUMOVehicle* veh) {
382 : myRemoteReservedVehicles.insert(veh);
383 30 : if (myUpdateEvent == nullptr) {
384 25 : myUpdateEvent = new WrappingCommand<MSParkingArea>(this, &MSParkingArea::updateOccupancy);
385 25 : MSNet::getInstance()->getEndOfTimestepEvents()->addEvent(myUpdateEvent);
386 : }
387 30 : }
388 :
389 : void
390 9873 : MSParkingArea::removeSpaceReservation(const SUMOVehicle* veh) {
391 : myRemoteReservedVehicles.erase(veh);
392 9873 : if (myUpdateEvent == nullptr) {
393 9088 : myUpdateEvent = new WrappingCommand<MSParkingArea>(this, &MSParkingArea::updateOccupancy);
394 9088 : MSNet::getInstance()->getEndOfTimestepEvents()->addEvent(myUpdateEvent);
395 : }
396 9873 : }
397 :
398 : void
399 8375 : MSParkingArea::leaveFrom(SUMOVehicle* what) {
400 : assert(myEndPositions.find(what) != myEndPositions.end());
401 8375 : if (myUpdateEvent == nullptr) {
402 8097 : myUpdateEvent = new WrappingCommand<MSParkingArea>(this, &MSParkingArea::updateOccupancy);
403 8097 : MSNet::getInstance()->getEndOfTimestepEvents()->addEvent(myUpdateEvent);
404 : }
405 22234 : for (auto& lsd : mySpaceOccupancies) {
406 22234 : if (lsd.vehicle == what) {
407 8375 : lsd.vehicle = nullptr;
408 8375 : break;
409 : }
410 : }
411 8375 : if (what->getLength() == myMaxVehLength) {
412 8300 : myMaxVehLength = 0;
413 35163 : for (auto item : myEndPositions) {
414 53656 : myMaxVehLength = MAX2(myMaxVehLength, item.first->getLength());
415 : }
416 : }
417 : myEndPositions.erase(myEndPositions.find(what));
418 8375 : computeLastFreePos();
419 8375 : }
420 :
421 :
422 : SUMOTime
423 17210 : MSParkingArea::updateOccupancy(SUMOTime /* currentTime */) {
424 17210 : myLastStepOccupancy = getOccupancy();
425 : myLastRemoteReservedVehicles = myRemoteReservedVehicles;
426 17210 : myUpdateEvent = nullptr;
427 17210 : return 0;
428 : }
429 :
430 :
431 0 : MSParkingArea::LotSpaceDefinition::LotSpaceDefinition() :
432 0 : index(-1),
433 0 : vehicle(nullptr),
434 0 : rotation(0),
435 0 : slope(0),
436 0 : width(0),
437 0 : length(0),
438 0 : endPos(0),
439 0 : manoeuverAngle(0),
440 0 : sideIsLHS(false) {
441 0 : }
442 :
443 :
444 54124 : MSParkingArea::LotSpaceDefinition::LotSpaceDefinition(int index_, SUMOVehicle* vehicle_, double x, double y, double z, double rotation_, double slope_, double width_, double length_) :
445 54124 : index(index_),
446 54124 : vehicle(vehicle_),
447 : position(Position(x, y, z)),
448 54124 : rotation(rotation_),
449 54124 : slope(slope_),
450 54124 : width(width_),
451 54124 : length(length_),
452 54124 : endPos(0),
453 54124 : manoeuverAngle(0),
454 54124 : sideIsLHS(false) {
455 54124 : }
456 :
457 :
458 : void
459 104113 : MSParkingArea::computeLastFreePos() {
460 104113 : myLastFreeLot = -1;
461 104113 : myLastFreePos = myBegPos;
462 104113 : myEgressBlocked = false;
463 135782 : for (auto& lsd : mySpaceOccupancies) {
464 118137 : if (lsd.vehicle == nullptr
465 118137 : || (getOccupancy() == getCapacity()
466 11585 : && lsd.vehicle->remainingStopDuration() <= 0
467 1633 : && !lsd.vehicle->isStoppedTriggered())) {
468 86468 : if (lsd.vehicle == nullptr) {
469 85553 : myLastFreeLot = lsd.index;
470 85553 : myLastFreePos = lsd.endPos;
471 : } else {
472 : // vehicle wants to exit the parking area
473 915 : myLastFreeLot = lsd.index;
474 915 : myLastFreePos = lsd.endPos - lsd.vehicle->getVehicleType().getLength() - POSITION_EPS;
475 915 : myEgressBlocked = true;
476 : }
477 : break;
478 : } else {
479 31669 : myLastFreePos = MIN2(myLastFreePos,
480 31669 : lsd.endPos - lsd.vehicle->getVehicleType().getLength() - NUMERICAL_EPS);
481 : }
482 : }
483 104113 : }
484 :
485 :
486 : double
487 1632209 : MSParkingArea::getLastFreePosWithReservation(SUMOTime t, const SUMOVehicle& forVehicle, double brakePos) {
488 : // do not perform reservation when far away
489 1632209 : if (forVehicle.getLane() != &myLane || forVehicle.getPositionOnLane() < (myBegPos - myMaxVehLength - forVehicle.getVehicleType().getMinGap())) {
490 : // for different lanes, do not consider reservations to avoid lane-order
491 : // dependency in parallel simulation
492 : #ifdef DEBUG_RESERVATIONS
493 : if (DEBUG_COND2(forVehicle)) {
494 : std::cout << SIMTIME << " pa=" << getID() << " freePosRes veh=" << forVehicle.getID() << " other lane\n";
495 : }
496 : #endif
497 1422665 : if (myNumAlternatives > 0 && getOccupancy() == getCapacity()) {
498 : // ensure that the vehicle reaches the rerouter lane
499 175947 : if (mySpaceOccupancies.size() > 0) {
500 : assert(mySpaceOccupancies[0].vehicle != nullptr);
501 175094 : const double waitPos = (mySpaceOccupancies[0].endPos
502 175094 : - mySpaceOccupancies[0].vehicle->getLength()
503 175094 : - forVehicle.getVehicleType().getMinGap()
504 175094 : - NUMERICAL_EPS);
505 175094 : return MAX2(waitPos, MIN2(POSITION_EPS, myEndPos));
506 : } else {
507 853 : return MAX2(myBegPos, MIN2(POSITION_EPS, myEndPos));
508 : }
509 : } else {
510 : // check if there is a reservation from the last time step
511 : // (this could also be in myReserations, if myLane wasn't processed before the forVehicle-lane)
512 1246718 : const SUMOTime last = t - DELTA_T;
513 : #ifdef DEBUG_RESERVATIONS
514 : if (DEBUG_COND2(forVehicle)) {
515 : std::cout << SIMTIME << " last=" << time2string(last) << " lastRes=" << time2string(myLastReservationTime) << " resTime=" << toString(myReservationTime) << "\n";
516 : }
517 : #endif
518 1246718 : if (myLastReservationTime == last || myReservationTime == last) {
519 839907 : int res = myLastReservationTime == last ? myLastReservations : myReservations;
520 839907 : if (myCapacity <= getOccupancy() + res) {
521 810896 : double maxLen = myLastReservationTime == last ? myLastReservationMaxLength : myReservationMaxLength;
522 : #ifdef DEBUG_RESERVATIONS
523 : if (DEBUG_COND2(forVehicle)) std::cout << SIMTIME << " pa=" << getID() << " freePosRes veh=" << forVehicle.getID()
524 : << " lastRes=" << res << " resTime=" << myReservationTime << " reserved full, maxLen=" << maxLen << " endPos=" << mySpaceOccupancies[0].endPos << "\n";
525 : #endif
526 810896 : return (mySpaceOccupancies[0].endPos
527 810896 : - maxLen
528 810896 : - forVehicle.getVehicleType().getMinGap()
529 810896 : - NUMERICAL_EPS);
530 : }
531 : }
532 435822 : return getLastFreePos(forVehicle, brakePos);
533 : }
534 : }
535 209544 : if (t > myReservationTime) {
536 : #ifdef DEBUG_RESERVATIONS
537 : if (DEBUG_COND2(forVehicle)) {
538 : std::cout << SIMTIME << " pa=" << getID() << " freePosRes veh=" << forVehicle.getID() << " first reservation\n";
539 : }
540 : #endif
541 161359 : myLastReservationTime = myReservationTime;
542 161359 : myLastReservations = myReservations;
543 161359 : myLastReservationMaxLength = myReservationMaxLength;
544 161359 : myReservationTime = t;
545 161359 : myReservations = 1;
546 161359 : myReservationMaxLength = forVehicle.getVehicleType().getLength();
547 : myReservedVehicles.clear();
548 161359 : myReservedVehicles.insert(&forVehicle);
549 779570 : for (const auto& lsd : mySpaceOccupancies) {
550 618211 : if (lsd.vehicle != nullptr) {
551 682802 : myReservationMaxLength = MAX2(myReservationMaxLength, lsd.vehicle->getVehicleType().getLength());
552 : }
553 : }
554 161359 : return getLastFreePos(forVehicle, brakePos);
555 : } else {
556 48185 : if (myCapacity > getOccupancy() + myReservations) {
557 : #ifdef DEBUG_RESERVATIONS
558 : if (DEBUG_COND2(forVehicle)) {
559 : std::cout << SIMTIME << " pa=" << getID() << " freePosRes veh=" << forVehicle.getID() << " res=" << myReservations << " enough space\n";
560 : }
561 : #endif
562 9561 : myReservations++;
563 9561 : myReservationMaxLength = MAX2(myReservationMaxLength, forVehicle.getVehicleType().getLength());
564 9561 : myReservedVehicles.insert(&forVehicle);
565 9561 : return getLastFreePos(forVehicle, brakePos);
566 : } else {
567 38624 : if (myCapacity == 0) {
568 0 : return getLastFreePos(forVehicle, brakePos);
569 : } else {
570 : #ifdef DEBUG_RESERVATIONS
571 : if (DEBUG_COND2(forVehicle)) std::cout << SIMTIME << " pa=" << getID() << " freePosRes veh=" << forVehicle.getID()
572 : << " res=" << myReservations << " resTime=" << myReservationTime << " reserved full, maxLen=" << myReservationMaxLength << " endPos=" << mySpaceOccupancies[0].endPos << "\n";
573 : #endif
574 38624 : return (mySpaceOccupancies[0].endPos
575 38624 : - myReservationMaxLength
576 38624 : - forVehicle.getVehicleType().getMinGap()
577 38624 : - NUMERICAL_EPS);
578 : }
579 : }
580 : }
581 : }
582 :
583 :
584 : double
585 655 : MSParkingArea::getWidth() const {
586 655 : return myWidth;
587 : }
588 :
589 :
590 : double
591 655 : MSParkingArea::getLength() const {
592 655 : return myLength;
593 : }
594 :
595 :
596 : double
597 655 : MSParkingArea::getAngle() const {
598 655 : return myAngle;
599 : }
600 :
601 :
602 : int
603 1497547 : MSParkingArea::getCapacity() const {
604 1497547 : return myCapacity;
605 : }
606 :
607 :
608 : bool
609 1337469 : MSParkingArea::parkOnRoad() const {
610 1337469 : return myOnRoad;
611 : }
612 :
613 :
614 : int
615 1972670 : MSParkingArea::getOccupancy() const {
616 1972670 : return (int)myEndPositions.size() - (myEgressBlocked ? 1 : 0);
617 : }
618 :
619 :
620 : int
621 5 : MSParkingArea::getOccupancyIncludingBlocked() const {
622 5 : return (int)myEndPositions.size();
623 : }
624 :
625 : int
626 250787 : MSParkingArea::getOccupancyIncludingReservations(const SUMOVehicle* forVehicle) const {
627 : const bool reservedLocal = myReservedVehicles.count(forVehicle) != 0;
628 : const bool reservedRemote = myRemoteReservedVehicles.count(forVehicle) != 0;
629 : return ((int)myEndPositions.size()
630 250787 : + (reservedLocal ? 0 : myReservations)
631 250787 : + (reservedRemote ? 0 : myRemoteReservedVehicles.size()));
632 : }
633 :
634 :
635 : int
636 96448 : MSParkingArea::getOccupancyIncludingRemoteReservations(const SUMOVehicle* forVehicle) const {
637 : const bool reservedRemote = myRemoteReservedVehicles.count(forVehicle) != 0;
638 96448 : return getOccupancy() + (int)myRemoteReservedVehicles.size() - (reservedRemote ? 1 : 0);
639 : }
640 :
641 :
642 : int
643 0 : MSParkingArea::getLastStepOccupancy() const {
644 0 : return myLastStepOccupancy;
645 : }
646 :
647 :
648 : int
649 93721 : MSParkingArea::getLastStepOccupancyIncludingRemoteReservations(const SUMOVehicle* forVehicle) const {
650 : const bool reservedRemote = myLastRemoteReservedVehicles.count(forVehicle) != 0;
651 93721 : return myLastStepOccupancy - (int)myLastRemoteReservedVehicles.size() + (reservedRemote ? 1 : 0);
652 : }
653 :
654 :
655 : void
656 0 : MSParkingArea::accept(std::string badge) {
657 : myAcceptedBadges.insert(badge);
658 0 : }
659 :
660 :
661 : void
662 0 : MSParkingArea::accept(std::vector<std::string> badges) {
663 : myAcceptedBadges.insert(badges.begin(), badges.end());
664 0 : }
665 :
666 :
667 : void
668 0 : MSParkingArea::refuse(std::string badge) {
669 : myAcceptedBadges.erase(badge);
670 0 : }
671 :
672 :
673 : bool
674 231409 : MSParkingArea::accepts(SUMOVehicle* veh) const {
675 231409 : if (myAcceptedBadges.size() == 0) {
676 : return true;
677 : } else {
678 1656 : std::vector<std::string> vehicleBadges = veh->getParkingBadges();
679 1656 : for (auto badge : vehicleBadges) {
680 : if (myAcceptedBadges.count(badge) != 0) {
681 : return true;
682 : }
683 : }
684 687 : return false;
685 1656 : }
686 : }
687 :
688 :
689 : void
690 1406 : MSParkingArea::notifyEgressBlocked() {
691 1406 : computeLastFreePos();
692 1406 : }
693 :
694 :
695 : int
696 0 : MSParkingArea::getNumAlternatives() const {
697 0 : return myNumAlternatives;
698 : }
699 :
700 :
701 : void
702 13581 : MSParkingArea::setNumAlternatives(int alternatives) {
703 13581 : myNumAlternatives = MAX2(myNumAlternatives, alternatives);
704 13581 : }
705 :
706 :
707 : std::vector<std::string>
708 28 : MSParkingArea::getAcceptedBadges() const {
709 28 : std::vector<std::string> result(myAcceptedBadges.begin(), myAcceptedBadges.end());
710 28 : return result;
711 : }
712 :
713 :
714 : void
715 10 : MSParkingArea::setAcceptedBadges(const std::vector<std::string>& badges) {
716 : myAcceptedBadges.clear();
717 : myAcceptedBadges.insert(badges.begin(), badges.end());
718 10 : }
719 :
720 :
721 : const std::vector<MSParkingArea::LotSpaceDefinition>&
722 90 : MSParkingArea::getSpaceOccupancies() const {
723 90 : return mySpaceOccupancies;
724 : }
725 :
726 :
727 : const PositionVector&
728 5 : MSParkingArea::getShape() const {
729 5 : return myShape;
730 : }
731 :
732 :
733 : void
734 30355 : MSParkingArea::setRoadsideCapacity(int capacity) {
735 : // reinit parking lot generation process
736 30355 : myRoadSideCapacity = capacity;
737 :
738 : // Initialize space occupancies if there is a road-side capacity
739 : // The overall number of lots is fixed and each lot accepts one vehicle regardless of size
740 30355 : const double spaceDim = myRoadSideCapacity > 0 ? myLane.interpolateLanePosToGeometryPos((myEndPos - myBegPos) / myRoadSideCapacity) : 7.5;
741 30355 : const double spaceOffset = myRoadSideCapacity > 0 ? (myEndPos - myBegPos) / myRoadSideCapacity : 7.5;
742 30355 : if (myLength == 0) {
743 14227 : myLength = spaceDim;
744 : }
745 : mySpaceOccupancies.clear();
746 30355 : myCapacity = 0;
747 83824 : for (int i = 0; i < myRoadSideCapacity; ++i) {
748 : // calculate pos, angle and slope of parking lot space
749 53469 : const Position pos = GeomHelper::calculateLotSpacePosition(myShape, i, spaceDim, myAngle, myWidth, myLength);
750 53469 : double spaceAngle = GeomHelper::calculateLotSpaceAngle(myShape, i, spaceDim, myAngle);
751 53469 : double spaceSlope = GeomHelper::calculateLotSpaceSlope(myShape, i, spaceDim);
752 : // add lotEntry
753 53469 : addLotEntry(pos.x(), pos.y(), pos.z(), myWidth, myLength, spaceAngle, spaceSlope);
754 : // update endPos
755 159122 : mySpaceOccupancies.back().endPos = MIN2(myEndPos, myBegPos + MAX2(POSITION_EPS, spaceOffset * (i + 1)));
756 : }
757 : // recompute after modifying the last endPos
758 30355 : computeLastFreePos();
759 30355 : }
760 :
761 : /****************************************************************************/
|