Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2015-2025 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/MSVehicle.h>
32 : #include <microsim/MSVehicleType.h>
33 : #include "MSLane.h"
34 : #include <microsim/transportables/MSTransportable.h>
35 : #include "MSParkingArea.h"
36 : #include "MSGlobals.h"
37 : #include <utils/common/MsgHandler.h>
38 :
39 : //#define DEBUG_RESERVATIONS
40 : //#define DEBUG_GET_LAST_FREE_POS
41 : //#define DEBUG_COND2(obj) (obj.getID() == "v.3")
42 : #define DEBUG_COND2(obj) (obj.isSelected())
43 :
44 :
45 : // ===========================================================================
46 : // method definitions
47 : // ===========================================================================
48 14362 : MSParkingArea::MSParkingArea(const std::string& id, const std::vector<std::string>& lines,
49 : const std::vector<std::string>& badges, MSLane& lane,
50 : double begPos, double endPos, int capacity, double width, double length,
51 : double angle, const std::string& name, bool onRoad,
52 14362 : const std::string& departPos, bool lefthand) :
53 : MSStoppingPlace(id, SUMO_TAG_PARKING_AREA, lines, lane, begPos, endPos, name),
54 14362 : myRoadSideCapacity(capacity),
55 14362 : myCapacity(0),
56 14362 : myOnRoad(onRoad),
57 14362 : myWidth(width),
58 14362 : myLength(length),
59 14362 : myAngle(lefthand ? -angle : angle),
60 14362 : myAcceptedBadges(badges.begin(), badges.end()),
61 14362 : myEgressBlocked(false),
62 14362 : myReservationTime(-1),
63 14362 : myLastReservationTime(-1),
64 14362 : myReservations(0),
65 14362 : myLastReservations(0),
66 14362 : myReservationMaxLength(0),
67 14362 : myLastReservationMaxLength(0),
68 14362 : myMaxVehLength(0),
69 14362 : myNumAlternatives(0),
70 14362 : myLastStepOccupancy(0),
71 14362 : myDepartPos(-1),
72 14362 : myDepartPosDefinition(DepartPosDefinition::DEFAULT),
73 28738 : myUpdateEvent(nullptr) {
74 : // initialize unspecified defaults
75 14362 : if (myWidth == 0) {
76 12004 : myWidth = SUMO_const_laneWidth;
77 : }
78 :
79 14362 : if (departPos != "") {
80 : std::string error;
81 60 : if (!SUMOVehicleParameter::parseDepartPos(departPos, toString(myElement), getID(), myDepartPos, myDepartPosDefinition, error)) {
82 0 : throw ProcessError(error);
83 : }
84 30 : if (myDepartPosDefinition != DepartPosDefinition::GIVEN) {
85 : // maybe allow other methods at a later time
86 0 : throw ProcessError(TLF("Only a numerical departPos is supported for % '%'", toString(myElement), getID()));
87 30 : } else if (myDepartPos < 0 || myDepartPos > lane.getLength()) {
88 0 : throw ProcessError(TLF("Invalid departPos for % '%'", toString(myElement), getID()));
89 : }
90 : }
91 :
92 14362 : const double offset = (MSGlobals::gLefthand != lefthand) ? -1 : 1;
93 28724 : myShape = lane.getShape().getSubpart(
94 : lane.interpolateLanePosToGeometryPos(begPos),
95 : lane.interpolateLanePosToGeometryPos(endPos));
96 14362 : if (!myOnRoad) {
97 14295 : myShape.move2side((lane.getWidth() / 2. + myWidth / 2.) * offset);
98 : }
99 14362 : setRoadsideCapacity(capacity);
100 14362 : }
101 :
102 :
103 42152 : MSParkingArea::~MSParkingArea() {}
104 :
105 :
106 : void
107 50965 : MSParkingArea::addLotEntry(double x, double y, double z, double width, double length, double angle, double slope) {
108 : // create LotSpaceDefinition
109 50965 : LotSpaceDefinition lsd((int)mySpaceOccupancies.size(), nullptr, x, y, z, angle, slope, width, length);
110 : // If we are modelling parking set the end position to the lot position relative to the lane
111 : // rather than the end of the parking area - this results in vehicles stopping nearer the space
112 : // and re-entering the lane nearer the space. (If we are not modelling parking the vehicle will usually
113 : // enter the space and re-enter at the end of the parking area.)
114 50965 : if (MSGlobals::gModelParkingManoeuver) {
115 30 : const double offset = this->getLane().getShape().nearest_offset_to_point2D(lsd.position);
116 30 : if (offset < getBeginLanePosition()) {
117 0 : lsd.endPos = getBeginLanePosition() + POSITION_EPS;
118 : } else {
119 30 : if (this->getLane().getLength() > offset) {
120 30 : lsd.endPos = offset;
121 : } else {
122 0 : lsd.endPos = this->getLane().getLength() - POSITION_EPS;
123 : }
124 : }
125 : // Work out the angle of the lot relative to the lane (-90 adjusts for the way the bay is drawn )
126 30 : double relativeAngle = fmod(lsd.rotation - 90., 360) - fmod(RAD2DEG(this->getLane().getShape().rotationAtOffset(lsd.endPos)), 360) + 0.5;
127 30 : if (relativeAngle < 0.) {
128 10 : relativeAngle += 360.;
129 : }
130 30 : lsd.manoeuverAngle = relativeAngle;
131 :
132 : // if p2.y is -ve the lot is on LHS of lane relative to lane direction
133 : // we need to know this because it inverts the complexity of the parking manoeuver
134 30 : Position p2 = this->getLane().getShape().transformToVectorCoordinates(lsd.position);
135 30 : if (p2.y() < (0. + POSITION_EPS)) {
136 30 : lsd.sideIsLHS = true;
137 : } else {
138 0 : lsd.sideIsLHS = false;
139 : }
140 : } else {
141 50935 : lsd.endPos = myEndPos;
142 50935 : lsd.manoeuverAngle = int(angle); // unused unless gModelParkingManoeuver is true
143 50935 : lsd.sideIsLHS = true;
144 : }
145 50965 : mySpaceOccupancies.push_back(lsd);
146 50965 : myCapacity++;
147 50965 : computeLastFreePos();
148 50965 : }
149 :
150 : int
151 30 : MSParkingArea::getLastFreeLotAngle() const {
152 : assert(myLastFreeLot >= 0);
153 : assert(myLastFreeLot < (int)mySpaceOccupancies.size());
154 :
155 30 : const LotSpaceDefinition& lsd = mySpaceOccupancies[myLastFreeLot];
156 30 : if (lsd.sideIsLHS) {
157 30 : return abs(int(lsd.manoeuverAngle)) % 180;
158 : } else {
159 0 : return abs(abs(int(lsd.manoeuverAngle)) % 180 - 180) % 180;
160 : }
161 : }
162 :
163 : double
164 30 : MSParkingArea::getLastFreeLotGUIAngle() const {
165 : assert(myLastFreeLot >= 0);
166 : assert(myLastFreeLot < (int)mySpaceOccupancies.size());
167 :
168 30 : const LotSpaceDefinition& lsd = mySpaceOccupancies[myLastFreeLot];
169 30 : if (lsd.manoeuverAngle > 180.) {
170 15 : return DEG2RAD(lsd.manoeuverAngle - 360.);
171 : } else {
172 15 : return DEG2RAD(lsd.manoeuverAngle);
173 : }
174 : }
175 :
176 :
177 : double
178 2283455 : MSParkingArea::getLastFreePos(const SUMOVehicle& forVehicle, double brakePos) const {
179 2283455 : if (myCapacity == (int)myEndPositions.size()) {
180 : // keep enough space so that parking vehicles can leave
181 : #ifdef DEBUG_GET_LAST_FREE_POS
182 : if (DEBUG_COND2(forVehicle)) {
183 : std::cout << SIMTIME << " getLastFreePos veh=" << forVehicle.getID() << " allOccupied\n";
184 : }
185 : #endif
186 1546728 : return myLastFreePos - forVehicle.getVehicleType().getMinGap() - POSITION_EPS;
187 : } else {
188 736727 : const double minPos = MIN2(myEndPos, brakePos);
189 736727 : if (myLastFreePos >= minPos) {
190 : #ifdef DEBUG_GET_LAST_FREE_POS
191 : if (DEBUG_COND2(forVehicle)) {
192 : std::cout << SIMTIME << " getLastFreePos veh=" << forVehicle.getID() << " brakePos=" << brakePos << " myEndPos=" << myEndPos << " using myLastFreePos=" << myLastFreePos << "\n";
193 : }
194 : #endif
195 : return myLastFreePos;
196 : } else {
197 : // find free pos after minPos
198 48296 : for (const auto& lsd : mySpaceOccupancies) {
199 48091 : if (lsd.vehicle == nullptr && lsd.endPos >= minPos) {
200 : #ifdef DEBUG_GET_LAST_FREE_POS
201 : if (DEBUG_COND2(forVehicle)) {
202 : std::cout << SIMTIME << " getLastFreePos veh=" << forVehicle.getID() << " brakePos=" << brakePos << " myEndPos=" << myEndPos << " nextFreePos=" << lsd.endPos << "\n";
203 : }
204 : #endif
205 : return lsd.endPos;
206 : }
207 : }
208 : // shouldn't happen. No good solution seems possible
209 : #ifdef DEBUG_GET_LAST_FREE_POS
210 : if (DEBUG_COND2(forVehicle)) {
211 : std::cout << SIMTIME << " getLastFreePos veh=" << forVehicle.getID() << " brakePos=" << brakePos << " myEndPos=" << myEndPos << " noGoodFreePos blockedAt=" << brakePos << "\n";
212 : }
213 : #endif
214 : return brakePos;
215 : }
216 : }
217 : }
218 :
219 : Position
220 22601 : MSParkingArea::getVehiclePosition(const SUMOVehicle& forVehicle) const {
221 50671 : for (const auto& lsd : mySpaceOccupancies) {
222 50671 : if (lsd.vehicle == &forVehicle) {
223 22601 : return lsd.position;
224 : }
225 : }
226 0 : return Position::INVALID;
227 : }
228 :
229 :
230 : double
231 50008 : MSParkingArea::getInsertionPosition(const SUMOVehicle& forVehicle) const {
232 50008 : if (myDepartPosDefinition == DepartPosDefinition::GIVEN) {
233 250 : return myDepartPos;
234 : }
235 135942 : for (const auto& lsd : mySpaceOccupancies) {
236 135932 : if (lsd.vehicle == &forVehicle) {
237 49748 : return lsd.endPos;
238 : }
239 : }
240 : return -1;
241 : }
242 :
243 :
244 : double
245 15650 : MSParkingArea::getVehicleAngle(const SUMOVehicle& forVehicle) const {
246 39622 : for (const auto& lsd : mySpaceOccupancies) {
247 39601 : if (lsd.vehicle == &forVehicle) {
248 15629 : return (lsd.rotation - 90.) * (double) M_PI / (double) 180.0;
249 : }
250 : }
251 : return 0;
252 : }
253 :
254 : double
255 3901 : MSParkingArea::getVehicleSlope(const SUMOVehicle& forVehicle) const {
256 12511 : for (const auto& lsd : mySpaceOccupancies) {
257 12511 : if (lsd.vehicle == &forVehicle) {
258 3901 : return lsd.slope;
259 : }
260 : }
261 : return 0;
262 : }
263 :
264 : double
265 30 : MSParkingArea::getGUIAngle(const SUMOVehicle& forVehicle) const {
266 60 : for (const auto& lsd : mySpaceOccupancies) {
267 60 : if (lsd.vehicle == &forVehicle) {
268 30 : if (lsd.manoeuverAngle > 180.) {
269 15 : return DEG2RAD(lsd.manoeuverAngle - 360.);
270 : } else {
271 15 : return DEG2RAD(lsd.manoeuverAngle);
272 : }
273 : }
274 : }
275 : return 0.;
276 : }
277 :
278 : int
279 30 : MSParkingArea::getManoeuverAngle(const SUMOVehicle& forVehicle) const {
280 60 : for (const auto& lsd : mySpaceOccupancies) {
281 60 : if (lsd.vehicle == &forVehicle) {
282 30 : if (lsd.sideIsLHS) {
283 30 : return abs(int(lsd.manoeuverAngle)) % 180;
284 : } else {
285 0 : return abs(abs(int(lsd.manoeuverAngle)) % 180 - 180) % 180;
286 : }
287 : }
288 : }
289 : return 0;
290 : }
291 :
292 : int
293 26096 : MSParkingArea::getLotIndex(const SUMOVehicle* veh) const {
294 26096 : if (veh->getPositionOnLane() > myLastFreePos) {
295 : // vehicle has gone past myLastFreePos and we need to find the actual lot
296 : int closestLot = -1;
297 6445 : for (int i = 0; i < (int)mySpaceOccupancies.size(); i++) {
298 6397 : const LotSpaceDefinition lsd = mySpaceOccupancies[i];
299 6397 : if (lsd.vehicle == nullptr) {
300 : closestLot = i;
301 2455 : if (lsd.endPos >= veh->getPositionOnLane()) {
302 1102 : return i;
303 : }
304 : }
305 : }
306 48 : return closestLot;
307 : }
308 24946 : if (myOnRoad && myLastFreePos - veh->getPositionOnLane() > POSITION_EPS) {
309 : // for on-road parking we need to be precise
310 : return -1;
311 : }
312 8721 : return myLastFreeLot;
313 : }
314 :
315 : void
316 8932 : MSParkingArea::enter(SUMOVehicle* veh, const bool /* parking */) {
317 8932 : double beg = veh->getPositionOnLane() + veh->getVehicleType().getMinGap();
318 8932 : double end = veh->getPositionOnLane() - veh->getVehicleType().getLength();
319 8932 : if (myUpdateEvent == nullptr) {
320 8218 : myUpdateEvent = new WrappingCommand<MSParkingArea>(this, &MSParkingArea::updateOccupancy);
321 8218 : MSNet::getInstance()->getEndOfTimestepEvents()->addEvent(myUpdateEvent);
322 : }
323 8932 : int lotIndex = getLotIndex(veh);
324 8932 : if (lotIndex < 0) {
325 0 : WRITE_WARNING("Unsuitable parking position for vehicle '" + veh->getID() + "' at parkingArea '" + getID() + "' time=" + time2string(SIMSTEP));
326 0 : lotIndex = myLastFreeLot;
327 : }
328 : #ifdef DEBUG_GET_LAST_FREE_POS
329 : ((SUMOVehicleParameter&)veh->getParameter()).setParameter("lotIndex", toString(lotIndex));
330 : #endif
331 : assert(myLastFreePos >= 0);
332 : assert(lotIndex < (int)mySpaceOccupancies.size());
333 8932 : mySpaceOccupancies[lotIndex].vehicle = veh;
334 8932 : myEndPositions[veh] = std::pair<double, double>(beg, end);
335 8932 : computeLastFreePos();
336 8932 : myMaxVehLength = MAX2(myMaxVehLength, veh->getLength());
337 : // current search ends here
338 8932 : veh->setNumberParkingReroutes(0);
339 8932 : }
340 :
341 :
342 : void
343 7530 : MSParkingArea::leaveFrom(SUMOVehicle* what) {
344 : assert(myEndPositions.find(what) != myEndPositions.end());
345 7530 : if (myUpdateEvent == nullptr) {
346 7418 : myUpdateEvent = new WrappingCommand<MSParkingArea>(this, &MSParkingArea::updateOccupancy);
347 7418 : MSNet::getInstance()->getEndOfTimestepEvents()->addEvent(myUpdateEvent);
348 : }
349 20439 : for (auto& lsd : mySpaceOccupancies) {
350 20439 : if (lsd.vehicle == what) {
351 7530 : lsd.vehicle = nullptr;
352 7530 : break;
353 : }
354 : }
355 7530 : if (what->getLength() == myMaxVehLength) {
356 7455 : myMaxVehLength = 0;
357 32929 : for (auto item : myEndPositions) {
358 50878 : myMaxVehLength = MAX2(myMaxVehLength, item.first->getLength());
359 : }
360 : }
361 : myEndPositions.erase(myEndPositions.find(what));
362 7530 : computeLastFreePos();
363 7530 : }
364 :
365 :
366 : SUMOTime
367 15636 : MSParkingArea::updateOccupancy(SUMOTime /* currentTime */) {
368 15636 : myLastStepOccupancy = getOccupancy();
369 15636 : myUpdateEvent = nullptr;
370 15636 : return 0;
371 : }
372 :
373 :
374 0 : MSParkingArea::LotSpaceDefinition::LotSpaceDefinition() :
375 0 : index(-1),
376 0 : vehicle(nullptr),
377 0 : rotation(0),
378 0 : slope(0),
379 0 : width(0),
380 0 : length(0),
381 0 : endPos(0),
382 0 : manoeuverAngle(0),
383 0 : sideIsLHS(false) {
384 0 : }
385 :
386 :
387 50965 : MSParkingArea::LotSpaceDefinition::LotSpaceDefinition(int index_, SUMOVehicle* vehicle_, double x, double y, double z, double rotation_, double slope_, double width_, double length_) :
388 50965 : index(index_),
389 50965 : vehicle(vehicle_),
390 : position(Position(x, y, z)),
391 50965 : rotation(rotation_),
392 50965 : slope(slope_),
393 50965 : width(width_),
394 50965 : length(length_),
395 50965 : endPos(0),
396 50965 : manoeuverAngle(0),
397 50965 : sideIsLHS(false) {
398 50965 : }
399 :
400 :
401 : void
402 68751 : MSParkingArea::computeLastFreePos() {
403 68751 : myLastFreeLot = -1;
404 68751 : myLastFreePos = myBegPos;
405 68751 : myEgressBlocked = false;
406 100206 : for (auto& lsd : mySpaceOccupancies) {
407 96003 : if (lsd.vehicle == nullptr
408 96003 : || (getOccupancy() == getCapacity()
409 11683 : && lsd.vehicle->remainingStopDuration() <= 0
410 946 : && !lsd.vehicle->isStoppedTriggered())) {
411 64548 : if (lsd.vehicle == nullptr) {
412 63713 : myLastFreeLot = lsd.index;
413 63713 : myLastFreePos = lsd.endPos;
414 : } else {
415 : // vehicle wants to exit the parking area
416 835 : myLastFreeLot = lsd.index;
417 835 : myLastFreePos = lsd.endPos - lsd.vehicle->getVehicleType().getLength() - POSITION_EPS;
418 835 : myEgressBlocked = true;
419 : }
420 : break;
421 : } else {
422 31455 : myLastFreePos = MIN2(myLastFreePos,
423 31455 : lsd.endPos - lsd.vehicle->getVehicleType().getLength() - NUMERICAL_EPS);
424 : }
425 : }
426 68751 : }
427 :
428 :
429 : double
430 1568054 : MSParkingArea::getLastFreePosWithReservation(SUMOTime t, const SUMOVehicle& forVehicle, double brakePos) {
431 : // do not perform reservation when far away
432 1568054 : if (forVehicle.getLane() != &myLane || forVehicle.getPositionOnLane() < (myBegPos - myMaxVehLength - forVehicle.getVehicleType().getMinGap())) {
433 : // for different lanes, do not consider reservations to avoid lane-order
434 : // dependency in parallel simulation
435 : #ifdef DEBUG_RESERVATIONS
436 : if (DEBUG_COND2(forVehicle)) {
437 : std::cout << SIMTIME << " pa=" << getID() << " freePosRes veh=" << forVehicle.getID() << " other lane\n";
438 : }
439 : #endif
440 1374376 : if (myNumAlternatives > 0 && getOccupancy() == getCapacity()) {
441 : // ensure that the vehicle reaches the rerouter lane
442 167875 : if (mySpaceOccupancies.size() > 0) {
443 : assert(mySpaceOccupancies[0].vehicle != nullptr);
444 167367 : const double waitPos = (mySpaceOccupancies[0].endPos
445 167367 : - mySpaceOccupancies[0].vehicle->getLength()
446 167367 : - forVehicle.getVehicleType().getMinGap()
447 167367 : - NUMERICAL_EPS);
448 167367 : return MAX2(waitPos, MIN2(POSITION_EPS, myEndPos));
449 : } else {
450 508 : return MAX2(myBegPos, MIN2(POSITION_EPS, myEndPos));
451 : }
452 : } else {
453 : // check if there is a reservation from the last time step
454 : // (this could also be in myReserations, if myLane wasn't processed before the forVehicle-lane)
455 1206501 : const SUMOTime last = t - DELTA_T;
456 1206501 : if (DEBUG_COND2(forVehicle)) {
457 0 : std::cout << SIMTIME << " last=" << time2string(last) << " lastRes=" << time2string(myLastReservationTime) << " resTime=" << toString(myReservationTime) << "\n";
458 : }
459 1206501 : if (myLastReservationTime == last || myReservationTime == last) {
460 830255 : int res = myLastReservationTime == last ? myLastReservations : myReservations;
461 830255 : if (myCapacity <= getOccupancy() + res) {
462 806021 : double maxLen = myLastReservationTime == last ? myLastReservationMaxLength : myReservationMaxLength;
463 : #ifdef DEBUG_RESERVATIONS
464 : if (DEBUG_COND2(forVehicle)) std::cout << SIMTIME << " pa=" << getID() << " freePosRes veh=" << forVehicle.getID()
465 : << " lastRes=" << res << " resTime=" << myReservationTime << " reserved full, maxLen=" << maxLen << " endPos=" << mySpaceOccupancies[0].endPos << "\n";
466 : #endif
467 806021 : return (mySpaceOccupancies[0].endPos
468 806021 : - maxLen
469 806021 : - forVehicle.getVehicleType().getMinGap()
470 806021 : - NUMERICAL_EPS);
471 : }
472 : }
473 400480 : return getLastFreePos(forVehicle, brakePos);
474 : }
475 : }
476 193678 : if (t > myReservationTime) {
477 : #ifdef DEBUG_RESERVATIONS
478 : if (DEBUG_COND2(forVehicle)) {
479 : std::cout << SIMTIME << " pa=" << getID() << " freePosRes veh=" << forVehicle.getID() << " first reservation\n";
480 : }
481 : #endif
482 148017 : myLastReservationTime = myReservationTime;
483 148017 : myLastReservations = myReservations;
484 148017 : myLastReservationMaxLength = myReservationMaxLength;
485 148017 : myReservationTime = t;
486 148017 : myReservations = 1;
487 148017 : myReservationMaxLength = forVehicle.getVehicleType().getLength();
488 : myReservedVehicles.clear();
489 148017 : myReservedVehicles.insert(&forVehicle);
490 726821 : for (const auto& lsd : mySpaceOccupancies) {
491 578804 : if (lsd.vehicle != nullptr) {
492 644674 : myReservationMaxLength = MAX2(myReservationMaxLength, lsd.vehicle->getVehicleType().getLength());
493 : }
494 : }
495 148017 : return getLastFreePos(forVehicle, brakePos);
496 : } else {
497 45661 : if (myCapacity > getOccupancy() + myReservations) {
498 : #ifdef DEBUG_RESERVATIONS
499 : if (DEBUG_COND2(forVehicle)) {
500 : std::cout << SIMTIME << " pa=" << getID() << " freePosRes veh=" << forVehicle.getID() << " res=" << myReservations << " enough space\n";
501 : }
502 : #endif
503 6410 : myReservations++;
504 6410 : myReservationMaxLength = MAX2(myReservationMaxLength, forVehicle.getVehicleType().getLength());
505 6410 : myReservedVehicles.insert(&forVehicle);
506 6410 : return getLastFreePos(forVehicle, brakePos);
507 : } else {
508 39251 : if (myCapacity == 0) {
509 380 : return getLastFreePos(forVehicle, brakePos);
510 : } else {
511 : #ifdef DEBUG_RESERVATIONS
512 : if (DEBUG_COND2(forVehicle)) std::cout << SIMTIME << " pa=" << getID() << " freePosRes veh=" << forVehicle.getID()
513 : << " res=" << myReservations << " resTime=" << myReservationTime << " reserved full, maxLen=" << myReservationMaxLength << " endPos=" << mySpaceOccupancies[0].endPos << "\n";
514 : #endif
515 38871 : return (mySpaceOccupancies[0].endPos
516 38871 : - myReservationMaxLength
517 38871 : - forVehicle.getVehicleType().getMinGap()
518 38871 : - NUMERICAL_EPS);
519 : }
520 : }
521 : }
522 : }
523 :
524 :
525 : double
526 805 : MSParkingArea::getWidth() const {
527 805 : return myWidth;
528 : }
529 :
530 :
531 : double
532 805 : MSParkingArea::getLength() const {
533 805 : return myLength;
534 : }
535 :
536 :
537 : double
538 805 : MSParkingArea::getAngle() const {
539 805 : return myAngle;
540 : }
541 :
542 :
543 : int
544 1403024 : MSParkingArea::getCapacity() const {
545 1403024 : return myCapacity;
546 : }
547 :
548 :
549 : bool
550 399040 : MSParkingArea::parkOnRoad() const {
551 399040 : return myOnRoad;
552 : }
553 :
554 :
555 : int
556 1905449 : MSParkingArea::getOccupancy() const {
557 1905449 : return (int)myEndPositions.size() - (myEgressBlocked ? 1 : 0);
558 : }
559 :
560 :
561 : int
562 5 : MSParkingArea::getOccupancyIncludingBlocked() const {
563 5 : return (int)myEndPositions.size();
564 : }
565 :
566 : int
567 231809 : MSParkingArea::getOccupancyIncludingReservations(const SUMOVehicle* forVehicle) const {
568 : if (myReservedVehicles.count(forVehicle) != 0) {
569 79757 : return (int)myEndPositions.size();
570 : } else {
571 152052 : return (int)myEndPositions.size() + myReservations;
572 : }
573 : }
574 :
575 : int
576 81835 : MSParkingArea::getLastStepOccupancy() const {
577 81835 : return myLastStepOccupancy;
578 : }
579 :
580 :
581 : void
582 0 : MSParkingArea::accept(std::string badge) {
583 : myAcceptedBadges.insert(badge);
584 0 : }
585 :
586 :
587 : void
588 0 : MSParkingArea::accept(std::vector<std::string> badges) {
589 : myAcceptedBadges.insert(badges.begin(), badges.end());
590 0 : }
591 :
592 :
593 : void
594 0 : MSParkingArea::refuse(std::string badge) {
595 : myAcceptedBadges.erase(badge);
596 0 : }
597 :
598 :
599 : bool
600 202235 : MSParkingArea::accepts(SUMOVehicle* veh) const {
601 202235 : if (myAcceptedBadges.size() == 0) {
602 : return true;
603 : } else {
604 1656 : std::vector<std::string> vehicleBadges = veh->getParkingBadges();
605 1656 : for (auto badge : vehicleBadges) {
606 : if (myAcceptedBadges.count(badge) != 0) {
607 : return true;
608 : }
609 : }
610 687 : return false;
611 1656 : }
612 : }
613 :
614 :
615 : void
616 1324 : MSParkingArea::notifyEgressBlocked() {
617 1324 : computeLastFreePos();
618 1324 : }
619 :
620 :
621 : int
622 0 : MSParkingArea::getNumAlternatives() const {
623 0 : return myNumAlternatives;
624 : }
625 :
626 :
627 : void
628 13515 : MSParkingArea::setNumAlternatives(int alternatives) {
629 13515 : myNumAlternatives = MAX2(myNumAlternatives, alternatives);
630 13515 : }
631 :
632 :
633 : std::vector<std::string>
634 28 : MSParkingArea::getAcceptedBadges() const {
635 28 : std::vector<std::string> result(myAcceptedBadges.begin(), myAcceptedBadges.end());
636 28 : return result;
637 : }
638 :
639 :
640 : void
641 10 : MSParkingArea::setAcceptedBadges(const std::vector<std::string>& badges) {
642 : myAcceptedBadges.clear();
643 : myAcceptedBadges.insert(badges.begin(), badges.end());
644 10 : }
645 :
646 :
647 : const std::vector<MSParkingArea::LotSpaceDefinition>&
648 122 : MSParkingArea::getSpaceOccupancies() const {
649 122 : return mySpaceOccupancies;
650 : }
651 :
652 :
653 : const PositionVector&
654 5 : MSParkingArea::getShape() const {
655 5 : return myShape;
656 : }
657 :
658 :
659 : void
660 24191 : MSParkingArea::setRoadsideCapacity(int capacity) {
661 : // reinit parking lot generation process
662 24191 : myRoadSideCapacity = capacity;
663 :
664 : // Initialize space occupancies if there is a road-side capacity
665 : // The overall number of lots is fixed and each lot accepts one vehicle regardless of size
666 24191 : const double spaceDim = myRoadSideCapacity > 0 ? myLane.interpolateLanePosToGeometryPos((myEndPos - myBegPos) / myRoadSideCapacity) : 7.5;
667 24191 : if (myLength == 0) {
668 11190 : myLength = spaceDim;
669 : }
670 : mySpaceOccupancies.clear();
671 24191 : myCapacity = 0;
672 74351 : for (int i = 0; i < myRoadSideCapacity; ++i) {
673 : // calculate pos, angle and slope of parking lot space
674 50160 : const Position pos = GeomHelper::calculateLotSpacePosition(myShape, i, spaceDim, myAngle, myWidth, myLength);
675 50160 : double spaceAngle = GeomHelper::calculateLotSpaceAngle(myShape, i, spaceDim, myAngle);
676 50160 : double spaceSlope = GeomHelper::calculateLotSpaceSlope(myShape, i, spaceDim);
677 : // add lotEntry
678 50160 : addLotEntry(pos.x(), pos.y(), pos.z(), myWidth, myLength, spaceAngle, spaceSlope);
679 : // update endPos
680 148315 : mySpaceOccupancies.back().endPos = MIN2(myEndPos, myBegPos + MAX2(POSITION_EPS, spaceDim * (i + 1)));
681 : }
682 24191 : }
683 :
684 : /****************************************************************************/
|