Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2015-2024 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 :
38 : //#define DEBUG_RESERVATIONS
39 : //#define DEBUG_GET_LAST_FREE_POS
40 : //#define DEBUG_COND2(obj) (obj.getID() == "v.3")
41 : #define DEBUG_COND2(obj) (obj.isSelected())
42 :
43 :
44 : // ===========================================================================
45 : // method definitions
46 : // ===========================================================================
47 13278 : MSParkingArea::MSParkingArea(const std::string& id, const std::vector<std::string>& lines,
48 : const std::vector<std::string>& badges, MSLane& lane,
49 : double begPos, double endPos, int capacity, double width, double length,
50 : double angle, const std::string& name, bool onRoad,
51 13278 : const std::string& departPos, bool lefthand) :
52 : MSStoppingPlace(id, SUMO_TAG_PARKING_AREA, lines, lane, begPos, endPos, name),
53 13278 : myRoadSideCapacity(capacity),
54 13278 : myCapacity(0),
55 13278 : myOnRoad(onRoad),
56 13278 : myWidth(width),
57 13278 : myLength(length),
58 13278 : myAngle(lefthand ? -angle : angle),
59 13278 : myAcceptedBadges(badges.begin(), badges.end()),
60 13278 : myEgressBlocked(false),
61 13278 : myReservationTime(-1),
62 13278 : myReservations(0),
63 13278 : myReservationMaxLength(0),
64 13278 : myNumAlternatives(0),
65 13278 : myLastStepOccupancy(0),
66 13278 : myDepartPos(-1),
67 13278 : myDepartPosDefinition(DepartPosDefinition::DEFAULT),
68 26570 : myUpdateEvent(nullptr) {
69 : // initialize unspecified defaults
70 13278 : if (myWidth == 0) {
71 11319 : myWidth = SUMO_const_laneWidth;
72 : }
73 :
74 13278 : if (departPos != "") {
75 : std::string error;
76 58 : if (!SUMOVehicleParameter::parseDepartPos(departPos, toString(myElement), getID(), myDepartPos, myDepartPosDefinition, error)) {
77 0 : throw ProcessError(error);
78 : }
79 29 : if (myDepartPosDefinition != DepartPosDefinition::GIVEN) {
80 : // maybe allow other methods at a later time
81 0 : throw ProcessError("Only a numerical departPos is supported for " + toString(myElement) + " '" + getID() + "'");
82 29 : } else if (myDepartPos < 0 || myDepartPos > lane.getLength()) {
83 0 : throw ProcessError("Invalid departPos for " + toString(myElement) + " '" + getID() + "'");
84 : }
85 : }
86 :
87 13278 : const double offset = (MSGlobals::gLefthand != lefthand) ? -1 : 1;
88 26556 : myShape = lane.getShape().getSubpart(
89 : lane.interpolateLanePosToGeometryPos(begPos),
90 : lane.interpolateLanePosToGeometryPos(endPos));
91 13278 : if (!myOnRoad) {
92 13217 : myShape.move2side((lane.getWidth() / 2. + myWidth / 2.) * offset);
93 : }
94 13278 : setRoadsideCapacity(capacity);
95 13278 : }
96 :
97 :
98 25831 : MSParkingArea::~MSParkingArea() {}
99 :
100 :
101 : void
102 48519 : MSParkingArea::addLotEntry(double x, double y, double z, double width, double length, double angle, double slope) {
103 : // create LotSpaceDefinition
104 48519 : LotSpaceDefinition lsd((int)mySpaceOccupancies.size(), nullptr, x, y, z, angle, slope, width, length);
105 : // If we are modelling parking set the end position to the lot position relative to the lane
106 : // rather than the end of the parking area - this results in vehicles stopping nearer the space
107 : // and re-entering the lane nearer the space. (If we are not modelling parking the vehicle will usually
108 : // enter the space and re-enter at the end of the parking area.)
109 48519 : if (MSGlobals::gModelParkingManoeuver) {
110 30 : const double offset = this->getLane().getShape().nearest_offset_to_point2D(lsd.position);
111 30 : if (offset < getBeginLanePosition()) {
112 0 : lsd.endPos = getBeginLanePosition() + POSITION_EPS;
113 : } else {
114 30 : if (this->getLane().getLength() > offset) {
115 30 : lsd.endPos = offset;
116 : } else {
117 0 : lsd.endPos = this->getLane().getLength() - POSITION_EPS;
118 : }
119 : }
120 : // Work out the angle of the lot relative to the lane (-90 adjusts for the way the bay is drawn )
121 30 : double relativeAngle = fmod(lsd.rotation - 90., 360) - fmod(RAD2DEG(this->getLane().getShape().rotationAtOffset(lsd.endPos)), 360) + 0.5;
122 30 : if (relativeAngle < 0.) {
123 10 : relativeAngle += 360.;
124 : }
125 30 : lsd.manoeuverAngle = relativeAngle;
126 :
127 : // if p2.y is -ve the lot is on LHS of lane relative to lane direction
128 : // we need to know this because it inverts the complexity of the parking manoeuver
129 30 : Position p2 = this->getLane().getShape().transformToVectorCoordinates(lsd.position);
130 30 : if (p2.y() < (0. + POSITION_EPS)) {
131 30 : lsd.sideIsLHS = true;
132 : } else {
133 0 : lsd.sideIsLHS = false;
134 : }
135 : } else {
136 48489 : lsd.endPos = myEndPos;
137 48489 : lsd.manoeuverAngle = int(angle); // unused unless gModelParkingManoeuver is true
138 48489 : lsd.sideIsLHS = true;
139 : }
140 48519 : mySpaceOccupancies.push_back(lsd);
141 48519 : myCapacity++;
142 48519 : computeLastFreePos();
143 48519 : }
144 :
145 : int
146 30 : MSParkingArea::getLastFreeLotAngle() const {
147 : assert(myLastFreeLot >= 0);
148 : assert(myLastFreeLot < (int)mySpaceOccupancies.size());
149 :
150 30 : const LotSpaceDefinition& lsd = mySpaceOccupancies[myLastFreeLot];
151 30 : if (lsd.sideIsLHS) {
152 30 : return abs(int(lsd.manoeuverAngle)) % 180;
153 : } else {
154 0 : return abs(abs(int(lsd.manoeuverAngle)) % 180 - 180) % 180;
155 : }
156 : }
157 :
158 : double
159 30 : MSParkingArea::getLastFreeLotGUIAngle() const {
160 : assert(myLastFreeLot >= 0);
161 : assert(myLastFreeLot < (int)mySpaceOccupancies.size());
162 :
163 30 : const LotSpaceDefinition& lsd = mySpaceOccupancies[myLastFreeLot];
164 30 : if (lsd.manoeuverAngle > 180.) {
165 15 : return DEG2RAD(lsd.manoeuverAngle - 360.);
166 : } else {
167 15 : return DEG2RAD(lsd.manoeuverAngle);
168 : }
169 : }
170 :
171 :
172 : double
173 1323719 : MSParkingArea::getLastFreePos(const SUMOVehicle& forVehicle, double brakePos) const {
174 1323719 : if (myCapacity == (int)myEndPositions.size()) {
175 : // keep enough space so that parking vehicles can leave
176 : #ifdef DEBUG_GET_LAST_FREE_POS
177 : if (DEBUG_COND2(forVehicle)) {
178 : std::cout << SIMTIME << " getLastFreePos veh=" << forVehicle.getID() << " allOccupied\n";
179 : }
180 : #endif
181 763575 : return myLastFreePos - forVehicle.getVehicleType().getMinGap() - POSITION_EPS;
182 : } else {
183 560144 : const double minPos = MIN2(myEndPos, brakePos);
184 560144 : if (myLastFreePos >= minPos) {
185 : #ifdef DEBUG_GET_LAST_FREE_POS
186 : if (DEBUG_COND2(forVehicle)) {
187 : std::cout << SIMTIME << " getLastFreePos veh=" << forVehicle.getID() << " brakePos=" << brakePos << " myEndPos=" << myEndPos << " using myLastFreePos=" << myLastFreePos << "\n";
188 : }
189 : #endif
190 : return myLastFreePos;
191 : } else {
192 : // find free pos after minPos
193 39490 : for (const auto& lsd : mySpaceOccupancies) {
194 38773 : if (lsd.vehicle == nullptr && lsd.endPos >= minPos) {
195 : #ifdef DEBUG_GET_LAST_FREE_POS
196 : if (DEBUG_COND2(forVehicle)) {
197 : std::cout << SIMTIME << " getLastFreePos veh=" << forVehicle.getID() << " brakePos=" << brakePos << " myEndPos=" << myEndPos << " nextFreePos=" << lsd.endPos << "\n";
198 : }
199 : #endif
200 : return lsd.endPos;
201 : }
202 : }
203 : // shouldn't happen. No good solution seems possible
204 : #ifdef DEBUG_GET_LAST_FREE_POS
205 : if (DEBUG_COND2(forVehicle)) {
206 : std::cout << SIMTIME << " getLastFreePos veh=" << forVehicle.getID() << " brakePos=" << brakePos << " myEndPos=" << myEndPos << " noGoodFreePos blockedAt=" << brakePos << "\n";
207 : }
208 : #endif
209 : return brakePos;
210 : }
211 : }
212 : }
213 :
214 : Position
215 14432 : MSParkingArea::getVehiclePosition(const SUMOVehicle& forVehicle) const {
216 35336 : for (const auto& lsd : mySpaceOccupancies) {
217 35336 : if (lsd.vehicle == &forVehicle) {
218 14432 : return lsd.position;
219 : }
220 : }
221 0 : return Position::INVALID;
222 : }
223 :
224 :
225 : double
226 69056 : MSParkingArea::getInsertionPosition(const SUMOVehicle& forVehicle) const {
227 69056 : if (myDepartPosDefinition == DepartPosDefinition::GIVEN) {
228 250 : return myDepartPos;
229 : }
230 193988 : for (const auto& lsd : mySpaceOccupancies) {
231 193980 : if (lsd.vehicle == &forVehicle) {
232 68798 : return lsd.endPos;
233 : }
234 : }
235 : return -1;
236 : }
237 :
238 :
239 : double
240 12635 : MSParkingArea::getVehicleAngle(const SUMOVehicle& forVehicle) const {
241 34434 : for (const auto& lsd : mySpaceOccupancies) {
242 34417 : if (lsd.vehicle == &forVehicle) {
243 12618 : return (lsd.rotation - 90.) * (double) M_PI / (double) 180.0;
244 : }
245 : }
246 : return 0;
247 : }
248 :
249 : double
250 3621 : MSParkingArea::getVehicleSlope(const SUMOVehicle& forVehicle) const {
251 12171 : for (const auto& lsd : mySpaceOccupancies) {
252 12171 : if (lsd.vehicle == &forVehicle) {
253 3621 : return lsd.slope;
254 : }
255 : }
256 : return 0;
257 : }
258 :
259 : double
260 30 : MSParkingArea::getGUIAngle(const SUMOVehicle& forVehicle) const {
261 60 : for (const auto& lsd : mySpaceOccupancies) {
262 60 : if (lsd.vehicle == &forVehicle) {
263 30 : if (lsd.manoeuverAngle > 180.) {
264 15 : return DEG2RAD(lsd.manoeuverAngle - 360.);
265 : } else {
266 15 : return DEG2RAD(lsd.manoeuverAngle);
267 : }
268 : }
269 : }
270 : return 0.;
271 : }
272 :
273 : int
274 30 : MSParkingArea::getManoeuverAngle(const SUMOVehicle& forVehicle) const {
275 60 : for (const auto& lsd : mySpaceOccupancies) {
276 60 : if (lsd.vehicle == &forVehicle) {
277 30 : if (lsd.sideIsLHS) {
278 30 : return abs(int(lsd.manoeuverAngle)) % 180;
279 : } else {
280 0 : return abs(abs(int(lsd.manoeuverAngle)) % 180 - 180) % 180;
281 : }
282 : }
283 : }
284 : return 0;
285 : }
286 :
287 : int
288 46662 : MSParkingArea::getLotIndex(const SUMOVehicle* veh) const {
289 46662 : if (veh->getPositionOnLane() > myLastFreePos) {
290 : // vehicle has gone past myLastFreePos and we need to find the actual lot
291 : int closestLot = -1;
292 10022 : for (int i = 0; i < (int)mySpaceOccupancies.size(); i++) {
293 9686 : const LotSpaceDefinition lsd = mySpaceOccupancies[i];
294 9686 : if (lsd.vehicle == nullptr) {
295 : closestLot = i;
296 3766 : if (lsd.endPos >= veh->getPositionOnLane()) {
297 : return i;
298 : }
299 : }
300 : }
301 336 : return closestLot;
302 : }
303 44942 : if (myOnRoad && myLastFreePos - veh->getPositionOnLane() > POSITION_EPS) {
304 : // for on-road parking we need to be precise
305 : return -1;
306 : }
307 7182 : return myLastFreeLot;
308 : }
309 :
310 : void
311 7362 : MSParkingArea::enter(SUMOVehicle* veh) {
312 7362 : double beg = veh->getPositionOnLane() + veh->getVehicleType().getMinGap();
313 7362 : double end = veh->getPositionOnLane() - veh->getVehicleType().getLength();
314 7362 : if (myUpdateEvent == nullptr) {
315 6961 : myUpdateEvent = new WrappingCommand<MSParkingArea>(this, &MSParkingArea::updateOccupancy);
316 6961 : MSNet::getInstance()->getEndOfTimestepEvents()->addEvent(myUpdateEvent);
317 : }
318 7362 : int lotIndex = getLotIndex(veh);
319 7362 : if (lotIndex < 0) {
320 0 : WRITE_WARNING("Unsuitable parking position for vehicle '" + veh->getID() + "' at parkingArea '" + getID() + "' time=" + time2string(SIMSTEP));
321 0 : lotIndex = myLastFreeLot;
322 : }
323 : #ifdef DEBUG_GET_LAST_FREE_POS
324 : ((SUMOVehicleParameter&)veh->getParameter()).setParameter("lotIndex", toString(lotIndex));
325 : #endif
326 : assert(myLastFreePos >= 0);
327 : assert(lotIndex < (int)mySpaceOccupancies.size());
328 7362 : mySpaceOccupancies[lotIndex].vehicle = veh;
329 7362 : myEndPositions[veh] = std::pair<double, double>(beg, end);
330 7362 : computeLastFreePos();
331 : // current search ends here
332 7362 : veh->setNumberParkingReroutes(0);
333 7362 : }
334 :
335 :
336 : void
337 6068 : MSParkingArea::leaveFrom(SUMOVehicle* what) {
338 : assert(myEndPositions.find(what) != myEndPositions.end());
339 6068 : if (myUpdateEvent == nullptr) {
340 5993 : myUpdateEvent = new WrappingCommand<MSParkingArea>(this, &MSParkingArea::updateOccupancy);
341 5993 : MSNet::getInstance()->getEndOfTimestepEvents()->addEvent(myUpdateEvent);
342 : }
343 17869 : for (auto& lsd : mySpaceOccupancies) {
344 17869 : if (lsd.vehicle == what) {
345 6068 : lsd.vehicle = nullptr;
346 6068 : break;
347 : }
348 : }
349 : myEndPositions.erase(myEndPositions.find(what));
350 6068 : computeLastFreePos();
351 6068 : }
352 :
353 :
354 : SUMOTime
355 12954 : MSParkingArea::updateOccupancy(SUMOTime /* currentTime */) {
356 12954 : myLastStepOccupancy = getOccupancy();
357 12954 : myUpdateEvent = nullptr;
358 12954 : return 0;
359 : }
360 :
361 :
362 0 : MSParkingArea::LotSpaceDefinition::LotSpaceDefinition() :
363 0 : index(-1),
364 0 : vehicle(nullptr),
365 0 : rotation(0),
366 0 : slope(0),
367 0 : width(0),
368 0 : length(0),
369 0 : endPos(0),
370 0 : manoeuverAngle(0),
371 0 : sideIsLHS(false) {
372 0 : }
373 :
374 :
375 48519 : MSParkingArea::LotSpaceDefinition::LotSpaceDefinition(int index_, SUMOVehicle* vehicle_, double x, double y, double z, double rotation_, double slope_, double width_, double length_) :
376 48519 : index(index_),
377 48519 : vehicle(vehicle_),
378 : position(Position(x, y, z)),
379 48519 : rotation(rotation_),
380 48519 : slope(slope_),
381 48519 : width(width_),
382 48519 : length(length_),
383 48519 : endPos(0),
384 48519 : manoeuverAngle(0),
385 48519 : sideIsLHS(false) {
386 48519 : }
387 :
388 :
389 : void
390 63062 : MSParkingArea::computeLastFreePos() {
391 63062 : myLastFreeLot = -1;
392 63062 : myLastFreePos = myBegPos;
393 63062 : myEgressBlocked = false;
394 89806 : for (auto& lsd : mySpaceOccupancies) {
395 87294 : if (lsd.vehicle == nullptr
396 87294 : || (getOccupancy() == getCapacity()
397 8199 : && lsd.vehicle->remainingStopDuration() <= 0
398 961 : && !lsd.vehicle->isStoppedTriggered())) {
399 60550 : if (lsd.vehicle == nullptr) {
400 59692 : myLastFreeLot = lsd.index;
401 59692 : myLastFreePos = lsd.endPos;
402 : } else {
403 : // vehicle wants to exit the parking area
404 858 : myLastFreeLot = lsd.index;
405 858 : myLastFreePos = lsd.endPos - lsd.vehicle->getVehicleType().getLength() - POSITION_EPS;
406 858 : myEgressBlocked = true;
407 : }
408 : break;
409 : } else {
410 26744 : myLastFreePos = MIN2(myLastFreePos,
411 26744 : lsd.endPos - lsd.vehicle->getVehicleType().getLength() - NUMERICAL_EPS);
412 : }
413 : }
414 63062 : }
415 :
416 :
417 : double
418 732815 : MSParkingArea::getLastFreePosWithReservation(SUMOTime t, const SUMOVehicle& forVehicle, double brakePos) {
419 732815 : if (forVehicle.getLane() != &myLane) {
420 : // for different lanes, do not consider reservations to avoid lane-order
421 : // dependency in parallel simulation
422 : #ifdef DEBUG_RESERVATIONS
423 : if (DEBUG_COND2(forVehicle)) {
424 : std::cout << SIMTIME << " pa=" << getID() << " freePosRes veh=" << forVehicle.getID() << " other lane\n";
425 : }
426 : #endif
427 560478 : if (myNumAlternatives > 0 && getOccupancy() == getCapacity()) {
428 : // ensure that the vehicle reaches the rerouter lane
429 155650 : return MAX2(myBegPos, MIN2(POSITION_EPS, myEndPos));
430 : } else {
431 404828 : return getLastFreePos(forVehicle, brakePos);
432 : }
433 : }
434 172337 : if (t > myReservationTime) {
435 : #ifdef DEBUG_RESERVATIONS
436 : if (DEBUG_COND2(forVehicle)) {
437 : std::cout << SIMTIME << " pa=" << getID() << " freePosRes veh=" << forVehicle.getID() << " first reservation\n";
438 : }
439 : #endif
440 91698 : myReservationTime = t;
441 91698 : myReservations = 1;
442 91698 : myReservationMaxLength = forVehicle.getVehicleType().getLength();
443 868484 : for (const auto& lsd : mySpaceOccupancies) {
444 776786 : if (lsd.vehicle != nullptr) {
445 456140 : myReservationMaxLength = MAX2(myReservationMaxLength, lsd.vehicle->getVehicleType().getLength());
446 : }
447 : }
448 91698 : return getLastFreePos(forVehicle, brakePos);
449 : } else {
450 80639 : if (myCapacity > getOccupancy() + myReservations) {
451 : #ifdef DEBUG_RESERVATIONS
452 : if (DEBUG_COND2(forVehicle)) {
453 : std::cout << SIMTIME << " pa=" << getID() << " freePosRes veh=" << forVehicle.getID() << " res=" << myReservations << " enough space\n";
454 : }
455 : #endif
456 34823 : myReservations++;
457 34823 : myReservationMaxLength = MAX2(myReservationMaxLength, forVehicle.getVehicleType().getLength());
458 34823 : return getLastFreePos(forVehicle, brakePos);
459 : } else {
460 45816 : if (myCapacity == 0) {
461 620 : return getLastFreePos(forVehicle, brakePos);
462 : } else {
463 : #ifdef DEBUG_RESERVATIONS
464 : if (DEBUG_COND2(forVehicle)) std::cout << SIMTIME << " pa=" << getID() << " freePosRes veh=" << forVehicle.getID()
465 : << " res=" << myReservations << " resTime=" << myReservationTime << " reserved full, maxLen=" << myReservationMaxLength << " endPos=" << mySpaceOccupancies[0].endPos << "\n";
466 : #endif
467 45196 : return (mySpaceOccupancies[0].endPos
468 45196 : - myReservationMaxLength
469 45196 : - forVehicle.getVehicleType().getMinGap()
470 45196 : - NUMERICAL_EPS);
471 : }
472 : }
473 : }
474 : }
475 :
476 :
477 : double
478 600 : MSParkingArea::getWidth() const {
479 600 : return myWidth;
480 : }
481 :
482 :
483 : double
484 600 : MSParkingArea::getLength() const {
485 600 : return myLength;
486 : }
487 :
488 :
489 : double
490 600 : MSParkingArea::getAngle() const {
491 600 : return myAngle;
492 : }
493 :
494 :
495 : int
496 743671 : MSParkingArea::getCapacity() const {
497 743671 : return myCapacity;
498 : }
499 :
500 :
501 : bool
502 381358 : MSParkingArea::parkOnRoad() const {
503 381358 : return myOnRoad;
504 : }
505 :
506 :
507 : int
508 584566 : MSParkingArea::getOccupancy() const {
509 584566 : return (int)myEndPositions.size() - (myEgressBlocked ? 1 : 0);
510 : }
511 :
512 :
513 : int
514 139483 : MSParkingArea::getOccupancyIncludingBlocked() const {
515 139483 : return (int)myEndPositions.size();
516 : }
517 :
518 :
519 : int
520 49436 : MSParkingArea::getLastStepOccupancy() const {
521 49436 : return myLastStepOccupancy;
522 : }
523 :
524 :
525 : void
526 0 : MSParkingArea::accept(std::string badge) {
527 : myAcceptedBadges.insert(badge);
528 0 : }
529 :
530 :
531 : void
532 0 : MSParkingArea::accept(std::vector<std::string> badges) {
533 : myAcceptedBadges.insert(badges.begin(), badges.end());
534 0 : }
535 :
536 :
537 : void
538 0 : MSParkingArea::refuse(std::string badge) {
539 : myAcceptedBadges.erase(badge);
540 0 : }
541 :
542 :
543 : bool
544 16379 : MSParkingArea::accepts(MSBaseVehicle* veh) const {
545 16379 : if (myAcceptedBadges.size() == 0) {
546 : return true;
547 : } else {
548 21 : std::vector<std::string> vehicleBadges = veh->getParkingBadges();
549 21 : for (auto badge : vehicleBadges) {
550 : if (myAcceptedBadges.count(badge) != 0) {
551 : return true;
552 : }
553 : }
554 7 : return false;
555 21 : }
556 : }
557 :
558 :
559 : void
560 1113 : MSParkingArea::notifyEgressBlocked() {
561 1113 : computeLastFreePos();
562 1113 : }
563 :
564 :
565 : int
566 0 : MSParkingArea::getNumAlternatives() const {
567 0 : return myNumAlternatives;
568 : }
569 :
570 :
571 : void
572 12590 : MSParkingArea::setNumAlternatives(int alternatives) {
573 12590 : myNumAlternatives = MAX2(myNumAlternatives, alternatives);
574 12590 : }
575 :
576 :
577 : void
578 22898 : MSParkingArea::setRoadsideCapacity(int capacity) {
579 : // reinit parking lot generation process
580 22898 : myRoadSideCapacity = capacity;
581 :
582 : // Initialize space occupancies if there is a road-side capacity
583 : // The overall number of lots is fixed and each lot accepts one vehicle regardless of size
584 22898 : const double spaceDim = myRoadSideCapacity > 0 ? myLane.interpolateLanePosToGeometryPos((myEndPos - myBegPos) / myRoadSideCapacity) : 7.5;
585 22898 : if (myLength == 0) {
586 10542 : myLength = spaceDim;
587 : }
588 : mySpaceOccupancies.clear();
589 22898 : myCapacity = 0;
590 70817 : for (int i = 0; i < myRoadSideCapacity; ++i) {
591 : // calculate pos, angle and slope of parking lot space
592 47919 : const Position pos = GeomHelper::calculateLotSpacePosition(myShape, i, spaceDim, myAngle, myWidth, myLength);
593 47919 : double spaceAngle = GeomHelper::calculateLotSpaceAngle(myShape, i, spaceDim, myAngle);
594 47919 : double spaceSlope = GeomHelper::calculateLotSpaceSlope(myShape, i, spaceDim);
595 : // add lotEntry
596 47919 : addLotEntry(pos.x(), pos.y(), pos.z(), myWidth, myLength, spaceAngle, spaceSlope);
597 : // update endPos
598 141743 : mySpaceOccupancies.back().endPos = MIN2(myEndPos, myBegPos + MAX2(POSITION_EPS, spaceDim * (i + 1)));
599 : }
600 22898 : }
601 :
602 : /****************************************************************************/
|