Eclipse SUMO - Simulation of Urban MObility
MSParkingArea.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2015-2020 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 /****************************************************************************/
19 // A area where vehicles can park next to the road
20 /****************************************************************************/
21 #include <config.h>
22 
23 #include <cassert>
26 #include <utils/geom/Position.h>
27 #include <utils/geom/GeomHelper.h>
29 #include <microsim/MSNet.h>
30 #include <microsim/MSVehicleType.h>
31 #include "MSLane.h"
33 #include "MSParkingArea.h"
34 #include "MSGlobals.h"
35 
36 //#define DEBUG_RESERVATIONS
37 //#define DEBUG_COND2(obj) (obj.getID() == "v.3")
38 #define DEBUG_COND2(obj) (obj.isSelected())
39 
40 
41 // ===========================================================================
42 // method definitions
43 // ===========================================================================
44 MSParkingArea::MSParkingArea(const std::string& id,
45  const std::vector<std::string>& lines,
46  MSLane& lane,
47  double begPos, double endPos,
48  int capacity,
49  double width, double length, double angle, const std::string& name,
50  bool onRoad) :
51  MSStoppingPlace(id, lines, lane, begPos, endPos, name),
52  myCapacity(0),
53  myOnRoad(onRoad),
54  myWidth(width),
55  myLength(length),
56  myAngle(angle),
57  myEgressBlocked(false),
58  myReservationTime(-1),
59  myReservations(0),
60  myReservationMaxLength(0),
61  myNumAlternatives(0),
62  myLastStepOccupancy(0),
63  myUpdateEvent(nullptr) {
64  // initialize unspecified defaults
65  if (myWidth == 0) {
67  }
68  const double spaceDim = capacity > 0 ? myLane.interpolateLanePosToGeometryPos((myEndPos - myBegPos) / capacity) : 7.5;
69  if (myLength == 0) {
70  myLength = spaceDim;
71  }
72 
73  const double offset = MSGlobals::gLefthand ? -1 : 1;
74  myShape = lane.getShape().getSubpart(
76  lane.interpolateLanePosToGeometryPos(endPos));
77  if (!myOnRoad) {
78  myShape.move2side((lane.getWidth() / 2. + myWidth / 2.) * offset);
79  }
80  // Initialize space occupancies if there is a road-side capacity
81  // The overall number of lots is fixed and each lot accepts one vehicle regardless of size
82  for (int i = 0; i < capacity; ++i) {
83  const Position f = myShape.positionAtOffset(spaceDim * (i));
84  const Position s = myShape.positionAtOffset(spaceDim * (i + 1));
85 
86  Position pos;
87  if (myAngle == 0) {
88  // parking parallel to the road
89  pos = s;
90  } else {
91  // angled parking
92  double hlp_angle = fabs(((double)atan2((s.x() - f.x()), (f.y() - s.y())) * (double) 180.0 / (double)M_PI) - 180);
93  if (myAngle >= 0 && myAngle <= 90) {
94  pos.setx((f.x() + s.x()) / 2 - (myWidth / 2) * (1 - cos(myAngle / 180 * M_PI))*cos(hlp_angle / 180 * M_PI));
95  pos.sety((f.y() + s.y()) / 2 + (myWidth / 2) * (1 - cos(myAngle / 180 * M_PI))*sin(hlp_angle / 180 * M_PI));
96  pos.setz((f.z() + s.z()) / 2);
97  } else if (myAngle > 90 && myAngle <= 180) {
98  pos.setx((f.x() + s.x()) / 2 - (myWidth / 2) * (1 + cos(myAngle / 180 * M_PI))*cos(hlp_angle / 180 * M_PI));
99  pos.sety((f.y() + s.y()) / 2 + (myWidth / 2) * (1 + cos(myAngle / 180 * M_PI))*sin(hlp_angle / 180 * M_PI));
100  pos.setz((f.z() + s.z()) / 2);
101  } else if (myAngle > 180 && myAngle <= 270) {
102  pos.setx((f.x() + s.x()) / 2 - (myLength)*sin((myAngle - hlp_angle) / 180 * M_PI) - (myWidth / 2) * (1 + cos(myAngle / 180 * M_PI))*cos(hlp_angle / 180 * M_PI));
103  pos.sety((f.y() + s.y()) / 2 + (myLength)*cos((myAngle - hlp_angle) / 180 * M_PI) + (myWidth / 2) * (1 + cos(myAngle / 180 * M_PI))*sin(hlp_angle / 180 * M_PI));
104  pos.setz((f.z() + s.z()) / 2);
105  } else if (myAngle > 270 && myAngle < 360) {
106  pos.setx((f.x() + s.x()) / 2 - (myLength)*sin((myAngle - hlp_angle) / 180 * M_PI) - (myWidth / 2) * (1 - cos(myAngle / 180 * M_PI))*cos(hlp_angle / 180 * M_PI));
107  pos.sety((f.y() + s.y()) / 2 + (myLength)*cos((myAngle - hlp_angle) / 180 * M_PI) + (myWidth / 2) * (1 - cos(myAngle / 180 * M_PI))*sin(hlp_angle / 180 * M_PI));
108  pos.setz((f.z() + s.z()) / 2);
109  } else {
110  pos = (f + s) * 0.5;
111  }
112  }
113 
114  addLotEntry(pos.x(), pos.y(), pos.z(),
115  myWidth, myLength,
116  ((double) atan2((s.x() - f.x()), (f.y() - s.y())) * (double) 180.0 / (double) M_PI) + myAngle);
117  mySpaceOccupancies.back().myEndPos = myBegPos + MAX2(POSITION_EPS, spaceDim * (i + 1));
118  }
120 }
121 
123 
124 void
125 MSParkingArea::addLotEntry(double x, double y, double z,
126  double width, double length, double angle) {
127  LotSpaceDefinition lsd;
128  lsd.index = (int)mySpaceOccupancies.size();
129  lsd.vehicle = nullptr;
130  lsd.myPosition = Position(x, y, z);
131  lsd.myWidth = width;
132  lsd.myLength = length;
133  lsd.myRotation = angle;
134  // If we are modelling parking set the end position to the lot position relative to the lane
135  // rather than the end of the parking area - this results in vehicles stopping nearer the space
136  // and re-entering the lane nearer the space. (If we are not modelling parking the vehicle will usually
137  // enter the space and re-enter at the end of the parking area.)
139  const double offset = this->getLane().getShape().nearest_offset_to_point2D(lsd.myPosition);
140  if (offset < getBeginLanePosition()) {
141  lsd.myEndPos = getBeginLanePosition() + POSITION_EPS;
142  } else {
143  if (this->getLane().getLength() > offset) {
144  lsd.myEndPos = offset;
145  } else {
146  lsd.myEndPos = this->getLane().getLength() - POSITION_EPS;
147  }
148  }
149  // Work out the angle of the lot relative to the lane (-90 adjusts for the way the bay is drawn )
150  double relativeAngle = fmod(lsd.myRotation - 90., 360) - fmod(RAD2DEG(this->getLane().getShape().rotationAtOffset(lsd.myEndPos)), 360) + 0.5;
151  if (relativeAngle < 0.) {
152  relativeAngle += 360.;
153  }
154  lsd.myManoeuverAngle = relativeAngle;
155 
156  // if p2.y is -ve the lot is on LHS of lane relative to lane direction
157  // we need to know this because it inverts the complexity of the parking manoeuver
159  if (p2.y() < (0. + POSITION_EPS)) {
160  lsd.mySideIsLHS = true;
161  } else {
162  lsd.mySideIsLHS = false;
163  }
164  } else {
165  lsd.myEndPos = myEndPos;
166  lsd.myManoeuverAngle = int(angle); // unused unless gModelParkingManoeuver is true
167  lsd.mySideIsLHS = true;
168  }
169 
170 
171  mySpaceOccupancies.push_back(lsd);
172  myCapacity++;
174 }
175 
176 int
178  assert(myLastFreeLot >= 0);
179  assert(myLastFreeLot < (int)mySpaceOccupancies.size());
180 
182  if (lsd.mySideIsLHS) {
183  return abs(int(lsd.myManoeuverAngle)) % 180;
184  } else {
185  return abs(abs(int(lsd.myManoeuverAngle)) % 180 - 180) % 180;
186  }
187 }
188 
189 double
191  assert(myLastFreeLot >= 0);
192  assert(myLastFreeLot < (int)mySpaceOccupancies.size());
193 
195  if (lsd.myManoeuverAngle > 180.) {
196  return DEG2RAD(lsd.myManoeuverAngle - 360.);
197  } else {
198  return DEG2RAD(lsd.myManoeuverAngle);
199  }
200 }
201 
202 
203 double
204 MSParkingArea::getLastFreePos(const SUMOVehicle& forVehicle) const {
205  if (myCapacity == (int)myEndPositions.size()) {
206  // keep enough space so that parking vehicles can leave
207  return myLastFreePos - forVehicle.getVehicleType().getMinGap() - POSITION_EPS;
208  } else {
209  // XXX if (forVehicle.getLane() == myLane && forVehicle.getPositionOnLane() > myLastFreePos) {
210  // find freePos beyond vehicle position }
211  return myLastFreePos;
212  }
213 }
214 
215 Position
217  for (const auto& lsd : mySpaceOccupancies) {
218  if (lsd.vehicle == &forVehicle) {
219  return lsd.myPosition;
220  }
221  }
222  return Position::INVALID;
223 }
224 
225 
226 double
228  for (const auto& lsd : mySpaceOccupancies) {
229  if (lsd.vehicle == &forVehicle) {
230  return lsd.myEndPos;
231  }
232  }
233  return -1;
234 }
235 
236 
237 double
238 MSParkingArea::getVehicleAngle(const SUMOVehicle& forVehicle) const {
239  for (const auto& lsd : mySpaceOccupancies) {
240  if (lsd.vehicle == &forVehicle) {
241  return (lsd.myRotation - 90.) * (double) M_PI / (double) 180.0;
242  }
243  }
244  return 0;
245 }
246 
247 double
248 MSParkingArea::getGUIAngle(const SUMOVehicle& forVehicle) const {
249  for (const auto& lsd : mySpaceOccupancies) {
250  if (lsd.vehicle == &forVehicle) {
251  if (lsd.myManoeuverAngle > 180.) {
252  return DEG2RAD(lsd.myManoeuverAngle - 360.);
253  } else {
254  return DEG2RAD(lsd.myManoeuverAngle);
255  }
256  }
257  }
258  return 0.;
259 }
260 
261 int
263  for (const auto& lsd : mySpaceOccupancies) {
264  if (lsd.vehicle == &forVehicle) {
265  if (lsd.mySideIsLHS) {
266  return abs(int(lsd.myManoeuverAngle)) % 180;
267  } else {
268  return abs(abs(int(lsd.myManoeuverAngle)) % 180 - 180) % 180;
269  }
270  }
271  }
272  return 0;
273 }
274 
275 
276 void
278  double beg = veh->getPositionOnLane() + veh->getVehicleType().getMinGap();
279  double end = veh->getPositionOnLane() - veh->getVehicleType().getLength();
280  assert(myLastFreePos >= 0);
281  assert(myLastFreeLot < (int)mySpaceOccupancies.size());
282  if (myUpdateEvent == nullptr) {
285  }
286  mySpaceOccupancies[myLastFreeLot].vehicle = veh;
287  myEndPositions[veh] = std::pair<double, double>(beg, end);
289 }
290 
291 
292 void
294  assert(myEndPositions.find(what) != myEndPositions.end());
295  if (myUpdateEvent == nullptr) {
298  }
299  for (auto& lsd : mySpaceOccupancies) {
300  if (lsd.vehicle == what) {
301  lsd.vehicle = nullptr;
302  break;
303  }
304  }
305  myEndPositions.erase(myEndPositions.find(what));
307 }
308 
309 
310 SUMOTime
313  myUpdateEvent = nullptr;
314  return 0;
315 }
316 
317 
318 void
320  myLastFreeLot = -1;
322  myEgressBlocked = false;
323  for (auto& lsd : mySpaceOccupancies) {
324  if (lsd.vehicle == nullptr
325  || (getOccupancy() == getCapacity()
326  && lsd.vehicle->remainingStopDuration() <= 0
327  && !lsd.vehicle->isStoppedTriggered())) {
328  if (lsd.vehicle == nullptr) {
329  myLastFreeLot = lsd.index;
330  myLastFreePos = lsd.myEndPos;
331  } else {
332  // vehicle wants to exit the parking area
333  myLastFreeLot = lsd.index;
334  myLastFreePos = lsd.myEndPos - lsd.vehicle->getVehicleType().getLength() - POSITION_EPS;
335  myEgressBlocked = true;
336  }
337  break;
338  } else {
340  lsd.myEndPos - lsd.vehicle->getVehicleType().getLength() - NUMERICAL_EPS);
341  }
342  }
343 }
344 
345 
346 double
348  if (forVehicle.getLane() != &myLane) {
349  // for different lanes, do not consider reservations to avoid lane-order
350  // dependency in parallel simulation
351 #ifdef DEBUG_RESERVATIONS
352  if (DEBUG_COND2(forVehicle)) {
353  std::cout << SIMTIME << " pa=" << getID() << " freePosRes veh=" << forVehicle.getID() << " other lane\n";
354  }
355 #endif
356  if (myNumAlternatives > 0 && getOccupancy() == getCapacity()) {
357  // ensure that the vehicle reaches the rerouter lane
358  return MAX2(myBegPos, MIN2(POSITION_EPS, myEndPos));
359  } else {
360  return getLastFreePos(forVehicle);
361  }
362  }
363  if (t > myReservationTime) {
364 #ifdef DEBUG_RESERVATIONS
365  if (DEBUG_COND2(forVehicle)) {
366  std::cout << SIMTIME << " pa=" << getID() << " freePosRes veh=" << forVehicle.getID() << " first reservation\n";
367  }
368 #endif
369  myReservationTime = t;
370  myReservations = 1;
372  for (const auto& lsd : mySpaceOccupancies) {
373  if (lsd.vehicle != nullptr) {
374  myReservationMaxLength = MAX2(myReservationMaxLength, lsd.vehicle->getVehicleType().getLength());
375  }
376  }
377  return getLastFreePos(forVehicle);
378  } else {
380 #ifdef DEBUG_RESERVATIONS
381  if (DEBUG_COND2(forVehicle)) {
382  std::cout << SIMTIME << " pa=" << getID() << " freePosRes veh=" << forVehicle.getID() << " res=" << myReservations << " enough space\n";
383  }
384 #endif
385  myReservations++;
387  return getLastFreePos(forVehicle);
388  } else {
389  if (myCapacity == 0) {
390  return getLastFreePos(forVehicle);
391  } else {
392 #ifdef DEBUG_RESERVATIONS
393  if (DEBUG_COND2(forVehicle)) std::cout << SIMTIME << " pa=" << getID() << " freePosRes veh=" << forVehicle.getID()
394  << " res=" << myReservations << " resTime=" << myReservationTime << " reserved full, maxLen=" << myReservationMaxLength << " endPos=" << mySpaceOccupancies[0].myEndPos << "\n";
395 #endif
396  return (mySpaceOccupancies[0].myEndPos
398  - forVehicle.getVehicleType().getMinGap()
399  - NUMERICAL_EPS);
400  }
401  }
402  }
403 }
404 
405 
406 double
408  return myWidth;
409 }
410 
411 
412 double
414  return myLength;
415 }
416 
417 
418 double
420  return myAngle;
421 }
422 
423 
424 int
426  return myCapacity;
427 }
428 
429 
430 int
432  return (int)myEndPositions.size() - (myEgressBlocked ? 1 : 0);
433 }
434 
435 
436 int
438  return (int)myEndPositions.size();
439 }
440 
441 void
444 }
445 
446 
447 /****************************************************************************/
#define DEG2RAD(x)
Definition: GeomHelper.h:35
#define RAD2DEG(x)
Definition: GeomHelper.h:36
#define DEBUG_COND2(obj)
#define SIMTIME
Definition: SUMOTime.h:60
long long int SUMOTime
Definition: SUMOTime.h:31
const double SUMO_const_laneWidth
Definition: StdDefs.h:47
T MIN2(T a, T b)
Definition: StdDefs.h:73
T MAX2(T a, T b)
Definition: StdDefs.h:79
virtual void addEvent(Command *operation, SUMOTime execTimeStep=-1)
Adds an Event.
static bool gModelParkingManoeuver
whether parking simulation includes manoeuver time and any associated lane blocking
Definition: MSGlobals.h:127
static bool gLefthand
Whether lefthand-drive is being simulated.
Definition: MSGlobals.h:136
Representation of a lane in the micro simulation.
Definition: MSLane.h:82
double getLength() const
Returns the lane's length.
Definition: MSLane.h:539
const PositionVector & getShape() const
Returns this lane's shape.
Definition: MSLane.h:476
double interpolateLanePosToGeometryPos(double lanePos) const
Definition: MSLane.h:497
double getWidth() const
Returns the lane's width.
Definition: MSLane.h:555
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:171
MSEventControl * getEndOfTimestepEvents()
Returns the event control for events executed at the end of a time step.
Definition: MSNet.h:474
void notifyEgressBlocked()
update state so that vehicles wishing to enter cooperate with exiting vehicles
double getAngle() const
Returns the lot rectangle angle.
void leaveFrom(SUMOVehicle *what)
Called if a vehicle leaves this stop.
int myCapacity
Stop area capacity.
int getCapacity() const
Returns the area capacity.
void enter(SUMOVehicle *veh)
Called if a vehicle enters this stop.
int myLastStepOccupancy
Changes to the occupancy in the current time step.
bool myOnRoad
Whether vehicles stay on the road.
int myLastFreeLot
Last free lot number (-1 no free lot)
PositionVector myShape
The roadside shape of this parkingArea.
double getLength() const
Returns the lot rectangle length.
SUMOTime myReservationTime
track parking reservations from the lane for the current time step
double getWidth() const
Returns the lot rectangle width.
virtual ~MSParkingArea()
Destructor.
SUMOTime updateOccupancy(SUMOTime currentTime)
Called at the end of the time step.
int getLastFreeLotAngle() const
Return the angle of myLastFreeLot - the next parking lot only expected to be called after we have est...
double myAngle
The default angle of each parking space.
double myReservationMaxLength
int myNumAlternatives
the number of alternative parkingAreas that are assigned to parkingAreaRerouter
double myWidth
The default width of each parking space.
double myLength
The default length of each parking space.
void computeLastFreePos()
Computes the last free position on this stop.
int getOccupancyIncludingBlocked() const
Returns the area occupancy.
double getLastFreeLotGUIAngle() const
Return the GUI angle of myLastFreeLot - the angle the GUI uses to rotate into the next parking lot as...
int getManoeuverAngle(const SUMOVehicle &forVehicle) const
Return the manoeuver angle of the lot where the vehicle is parked.
int getOccupancy() const
Returns the area occupancy.
virtual void addLotEntry(double x, double y, double z, double width, double length, double angle)
Add a lot entry to parking area.
double getVehicleAngle(const SUMOVehicle &forVehicle) const
Returns the angle of parked vehicle.
double getLastFreePosWithReservation(SUMOTime t, const SUMOVehicle &forVehicle)
Returns the last free position on this stop including reservatiosn from the current lane and time ste...
Command * myUpdateEvent
Event for updating the occupancy.
std::vector< LotSpaceDefinition > mySpaceOccupancies
All the spaces in this parking area.
double getInsertionPosition(const SUMOVehicle &forVehicle) const
Returns the insertion position of a parked vehicle.
MSParkingArea(const std::string &id, const std::vector< std::string > &lines, MSLane &lane, double begPos, double endPos, int capacity, double width, double length, double angle, const std::string &name, bool onRoad)
Constructor.
Position getVehiclePosition(const SUMOVehicle &forVehicle) const
Returns the position of parked vehicle.
double getGUIAngle(const SUMOVehicle &forVehicle) const
Return the GUI angle of the lot where the vehicle is parked.
bool myEgressBlocked
whether a vehicle wants to exit but is blocked
A lane area vehicles can halt at.
const double myBegPos
The begin position this bus stop is located at.
double getBeginLanePosition() const
Returns the begin position of this stop.
const MSLane & myLane
The lane this bus stop is located at.
std::map< const SUMOVehicle *, std::pair< double, double >, ComparatorNumericalIdLess > myEndPositions
A map from objects (vehicles) to the areas they acquire after entering the stop.
const double myEndPos
The end position this bus stop is located at.
const MSLane & getLane() const
Returns the lane this stop is located at.
double myLastFreePos
The last free position at this stop (variable)
double getLastFreePos() const
double getMinGap() const
Get the free space in front of vehicles of this class.
double getLength() const
Get vehicle's length [m].
const std::string & getID() const
Returns the id.
Definition: Named.h:73
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:36
void setx(double x)
set position x
Definition: Position.h:69
static const Position INVALID
used to indicate that a position is valid
Definition: Position.h:282
double x() const
Returns the x-position.
Definition: Position.h:54
void setz(double z)
set position z
Definition: Position.h:79
double z() const
Returns the z-position.
Definition: Position.h:64
void sety(double y)
set position y
Definition: Position.h:74
double y() const
Returns the y-position.
Definition: Position.h:59
Position positionAtOffset(double pos, double lateralOffset=0) const
Returns the position at the given length.
double nearest_offset_to_point2D(const Position &p, bool perpendicular=true) const
return the nearest offest to point 2D
void move2side(double amount, double maxExtension=100)
move position vector to side using certain ammount
PositionVector getSubpart(double beginOffset, double endOffset) const
get subpart of a position vector
Position transformToVectorCoordinates(const Position &p, bool extend=false) const
return position p within the length-wise coordinate system defined by this position vector....
virtual const MSVehicleType & getVehicleType() const =0
Returns the object's "vehicle" type.
virtual const MSLane * getLane() const =0
Returns the lane the object is currently at.
virtual double getPositionOnLane() const =0
Get the object's position along the lane.
Representation of a vehicle.
Definition: SUMOVehicle.h:58
A wrapper for a Command function.
#define M_PI
Definition: odrSpiral.cpp:40
Representation of a single lot space.
Position myPosition
The position of the vehicle when parking in this space.
bool mySideIsLHS
Whether the lot is on the LHS of the lane relative to the lane direction.
SUMOVehicle * vehicle
The last parked vehicle or 0.
double myEndPos
The position along the lane that the vehicle needs to reach for entering this lot.
double myManoeuverAngle
The angle between lane and lot through which a vehicle must manoeuver to enter the lot.