Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2002-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 MSDriveWay.h
15 : /// @author Jakob Erdmann
16 : /// @date December 2021
17 : ///
18 : // A sequende of rail tracks (lanes) that may be used as a "set route" (Fahrstraße)
19 : /****************************************************************************/
20 : #pragma once
21 : #include <config.h>
22 :
23 : #include <utils/common/Named.h>
24 : #include <microsim/MSMoveReminder.h>
25 : #include <microsim/MSRoute.h>
26 :
27 : // ===========================================================================
28 : // class declarations
29 : // ===========================================================================
30 : class SUMOVehicle;
31 : class MSLane;
32 : class MSLink;
33 : class MSRailSignal;
34 :
35 : // ===========================================================================
36 : // class definitions
37 : // ===========================================================================
38 : /**
39 : * @class MSDriveWay
40 : */
41 : class MSDriveWay : public MSMoveReminder, public Named {
42 : public:
43 : typedef std::pair<const SUMOVehicle* const, const MSLink::ApproachingVehicleInformation> Approaching;
44 : typedef std::set<const MSLane*, ComparatorNumericalIdLess> LaneSet;
45 : typedef std::map<const MSLane*, int, ComparatorNumericalIdLess> LaneVisitedMap;
46 :
47 4754 : struct VehicleEvent {
48 1776 : VehicleEvent(SUMOTime _time, bool _isEntry, const std::string& _id, Notification _reason):
49 1776 : time(_time), isEntry(_isEntry), id(_id), reason(_reason) {}
50 : SUMOTime time;
51 : bool isEntry;
52 : std::string id;
53 : Notification reason;
54 : };
55 :
56 : /* The driveways (Fahrstrassen) for each link index of MSRailSignal
57 : * Each link index has at least one driveway
58 : * A driveway describes one possible route that passes the signal up to
59 : * the next secure point
60 : * When a signal guards a switch (indirect guard) that signal stores two
61 : * or more driveways
62 : */
63 : MSDriveWay(const MSLink* origin, const std::string& id, bool temporary = false);
64 :
65 : /// @brief Destructor
66 : virtual ~MSDriveWay();
67 :
68 : static void cleanup();
69 :
70 : static void clearState();
71 :
72 : static bool haveDriveWays() {
73 491 : return myGlobalDriveWayIndex > 0;
74 : }
75 :
76 : static const MSDriveWay* retrieveDepartDriveWay(const MSEdge* edge, const std::string& id);
77 :
78 : bool notifyEnter(SUMOTrafficObject& veh, Notification reason, const MSLane* enteredLane);
79 : bool notifyLeave(SUMOTrafficObject& veh, double lastPos, Notification reason, const MSLane* enteredLane = 0);
80 : bool notifyLeaveBack(SUMOTrafficObject& veh, Notification reason, const MSLane* leftLane);
81 : bool notifyReroute(SUMOTrafficObject& veh);
82 :
83 : /// @brief Wether there is a flank conflict with the given driveway
84 : bool flankConflict(const MSDriveWay& other) const;
85 :
86 : /// @brief Wether there is a crossing conflict with the given driveway
87 : bool crossingConflict(const MSDriveWay& other) const;
88 :
89 : /// @brief Wether there is a bidi conflict with the given driveway
90 : bool bidiBlockedBy(const MSDriveWay& other) const;
91 :
92 : /// @brief Wether there is a bidi conflict with the end of the given driveway
93 : bool bidiBlockedByEnd(const MSDriveWay& other) const;
94 :
95 : /// @brief Wether the route of other passes into the forward section of this driveway
96 : bool forwardRouteConflict(std::set<const MSEdge*> forward, const MSDriveWay& other, bool secondCheck = false);
97 :
98 : /// @brief whether any of myConflictLanes is occupied (vehicles that are the target of a join must be ignored)
99 : bool conflictLaneOccupied(bool store = true, const SUMOVehicle* ego = nullptr) const;
100 :
101 : /// @brief whether any of myFoes is occupied (vehicles that are the target of a join must be ignored)
102 : bool foeDriveWayOccupied(bool store, const SUMOVehicle* ego, MSEdgeVector& occupied) const;
103 :
104 : /// @brief whether any of my Foes is being approached
105 : bool foeDriveWayApproached() const;
106 :
107 : /// @brief attempt reserve this driveway for the given vehicle
108 : bool reserve(const Approaching& closest, MSEdgeVector& occupied);
109 :
110 : /// @brief Write block items for this driveway
111 : void writeBlocks(OutputDevice& od) const;
112 : void writeBlockVehicles(OutputDevice& od) const;
113 :
114 : const std::vector<const MSEdge*>& getRoute() const {
115 : return myRoute;
116 : }
117 :
118 : const std::vector<const MSLane*>& getFlank() const {
119 : return myFlank;
120 : }
121 :
122 : const std::vector<const MSLane*>& getBidi() const {
123 : return myBidi;
124 : }
125 :
126 : const std::vector<MSLink*>& getConflictLinks() const {
127 : return myConflictLinks;
128 : }
129 :
130 : int getNumericalID() const {
131 22574 : return myNumericalID;
132 : }
133 :
134 : const std::vector<VehicleEvent>& getEvents() const {
135 : return myVehicleEvents;
136 : }
137 :
138 : void setEvents(const std::vector<VehicleEvent>& events) {
139 : myVehicleEvents = events;
140 : }
141 :
142 : void setVehicle(const std::string& vehID) {
143 7206 : myFirstVehicle = vehID;
144 2876 : }
145 :
146 : const std::vector<MSDriveWay*>& getFoes() const {
147 : return myFoes;
148 : }
149 :
150 : const std::vector<const MSLane*>& getForward() const {
151 : return myForward;
152 : }
153 :
154 : /// @brief whether the give route matches this driveway
155 : bool match(MSRouteIterator firstIt, MSRouteIterator endIt) const;
156 :
157 : void addDWDeadlock(const std::vector<const MSDriveWay*>& deadlockFoes);
158 :
159 : bool isDepartDriveway() const {
160 3991444 : return myOrigin == nullptr;
161 : };
162 :
163 : const MSLink* getOrigin() const {
164 : return myOrigin;
165 : }
166 :
167 : /// @brief whether the given train is on this driveway
168 : bool hasTrain(SUMOVehicle* veh) const;
169 :
170 : const std::vector<MSDriveWay*>& getSubDriveWays() const {
171 : return mySubDriveWays;
172 : }
173 :
174 : static void init();
175 :
176 : static bool hasRS(const MSEdge* cur, const MSEdge* next);
177 :
178 : /// @brief Whether veh must yield to the foe train
179 : static bool mustYield(const Approaching& veh, const Approaching& foe);
180 :
181 : /// @brief construct a new driveway by searching along the given route until all block structures are found
182 : static MSDriveWay* buildDriveWay(const std::string& id, const MSLink* link, MSRouteIterator first, MSRouteIterator end);
183 :
184 : /// @brief return logicID_linkIndex in a way that allows clicking in sumo-gui
185 : static std::string getClickableTLLinkID(const MSLink* link);
186 :
187 : static const MSDriveWay* getDepartureDriveway(const SUMOVehicle* veh, bool init = false);
188 :
189 : static void writeDepatureBlocks(OutputDevice& od, bool writeVehicles);
190 :
191 : /** @brief Save driveway occupancy into the given stream */
192 : static void saveState(OutputDevice& out);
193 : static void loadState(const SUMOSAXAttributes& attrs, int tag);
194 :
195 : protected:
196 :
197 : /// @brief global driveway index
198 : int myNumericalID;
199 :
200 : /// @brief the link that enters this driveway or nullptr for a departure driveWay
201 : const MSLink* myOrigin;
202 :
203 : /// @brief whether the current signal is switched green for a train approaching this block
204 : const SUMOVehicle* myActive;
205 :
206 : /// @brief list of edges for matching against train routes
207 : std::vector<const MSEdge*> myRoute;
208 :
209 : /// @brief number of edges in myRoute where overlap with other driveways is forbidden
210 : int myCoreSize;
211 :
212 : /// @brief number of normal edges in myForward
213 : int myForwardEdgeCount;
214 :
215 : /// @brief whether this driveway ends its forward section with a rail signal (and thus comprises a full block)
216 : bool myFoundSignal;
217 : bool myFoundJump;
218 : bool myTerminateRoute;
219 : /// @brief whether driveway building was aborted due to MAX_BLOCK_LENGTH
220 : bool myAbortedBuild;
221 : /// @brief whether driveway building was aborted when no further bidi edge was found
222 : bool myBidiEnded;
223 : bool myIsSubDriveway;
224 :
225 : /* @brief the actual driveway part up to the next railsignal (halting position)
226 : * This must be free of other trains */
227 : std::vector<const MSLane*> myForward;
228 :
229 : /* @brief the list of bidirectional edges that can enter the forward
230 : * section and which must also be free of traffic
231 : * (up to the first element that could give protection) */
232 : std::vector<const MSLane*> myBidi;
233 :
234 : /* @brief the list of bidirectional edges that can enter the forward
235 : * section and which might contain deadlock-relevant traffic */
236 : std::vector<const MSLane*> myBidiExtended;
237 :
238 : /* @brief the list of edges that merge with the forward section
239 : * (found via backward search, up to the first element that could give protection) */
240 : std::vector<const MSLane*> myFlank;
241 :
242 : /// @brief the lanes that must be clear of trains before this signal can switch to green
243 : std::vector<const MSLane*> myConflictLanes;
244 :
245 : /* The conflict links for this block
246 : * Conflict resolution must be performed if vehicles are approaching the
247 : * current link and any of the conflict links */
248 : std::vector<MSLink*> myConflictLinks;
249 :
250 : /// @brief Whether the approaching vehicle is prevent from driving by another vehicle approaching the given link
251 : bool hasLinkConflict(const Approaching& closest, const MSLink* foeLink) const;
252 :
253 : /// @brief Wether this driveway (route) overlaps with the given one
254 : bool overlap(const MSDriveWay& other) const;
255 :
256 : /* @brief determine route that identifies this driveway (a subset of the
257 : * vehicle route)
258 : * collects:
259 : * myRoute
260 : * myForward
261 : * myBidi
262 : * myProtectedBidi
263 : *
264 : * returns edge that is assumed to safe from oncoming-deadlock or nullptr
265 : */
266 : void buildRoute(const MSLink* origin, MSRouteIterator next, MSRouteIterator end, LaneVisitedMap& visited, std::set<MSLink*>&);
267 :
268 : /* @brief find switches that threaten this driveway
269 : * @param[out] flankSwitches collect the switches
270 : */
271 : void checkFlanks(const MSLink* originLink, const std::vector<const MSLane*>& lanes, const LaneVisitedMap& visited, bool allFoes, std::set<MSLink*>& flankSwitches) const;
272 :
273 : /* @brief find links that cross the driveway without entering it
274 : * @param[out] flankSwitches collect the switches
275 : */
276 : void checkCrossingFlanks(MSLink* dwLink, const LaneVisitedMap& visited, std::set<MSLink*>& flankSwitches) const;
277 :
278 : /* @brief find upstream protection from the given link
279 : * @param[out] flank: the stored flank lanes
280 : */
281 : void findFlankProtection(MSLink* link, MSLink* origLink, std::vector<const MSLane*>& flank);
282 :
283 : /// @brief add all driveWays that start at the given link as foes
284 : void addFoes(const MSLink* link);
285 :
286 : /// @brief add sidings for the given foe
287 : void addSidings(MSDriveWay* foe, bool addToFoe = false);
288 :
289 : /// @brief derive foe driveways based on myBidi or myBidiExtended
290 : void addBidiFoes(const MSRailSignal* ownSignal, bool extended);
291 :
292 : /// @brief derive foe driveways that start at the same signal
293 : void addParallelFoes(const MSLink* link, const MSEdge* first);
294 :
295 : /// @brief derive foe driveways that enter the bidi section by reversing
296 : void addReversalFoes(bool movingBlock);
297 :
298 : /* @brief build shortened driveway that ends where the foe train leaves the conflict zone of this driveway
299 : * @return whether the foe has received a new entry in myFoes
300 : */
301 : bool buildSubFoe(MSDriveWay* foe, bool movingBlock);
302 :
303 : /// @brief add symmetical conflict link for foes when building a new driveway
304 : void addConflictLink(const MSLink* link);
305 :
306 : /// @brief return whether a siding can be used. If a siding exist but is occupied, also return the occupied driveway in the siding
307 : std::pair<bool, const MSDriveWay*> canUseSiding(const SUMOVehicle* ego, const MSDriveWay* foe, bool recurse = true) const;
308 :
309 : bool isFoeOrSubFoe(const MSDriveWay* foe) const;
310 :
311 : bool forwardEndOnRoute(const MSDriveWay* foe) const;
312 :
313 : void addSwitchFoes(MSLink* link);
314 :
315 : bool haveSubTrains() const;
316 :
317 : /* @brief whether the train would have matched this driveway in it's past
318 : * @return If matching, returns the number of edges the vehicle has gone past the start of the driveway,
319 : * Indicate no-match by returning a negative value */
320 : int matchesPastRoute(SUMOVehicle& sveh) const;
321 :
322 : /// @brief helper method for notifyEnter
323 : void enterDriveWay(SUMOVehicle& sveh, Notification reason);
324 :
325 : static bool hasJoin(const SUMOVehicle* ego, const SUMOVehicle* foe);
326 :
327 : static bool isSwitch(const MSLink* link);
328 :
329 : void _saveState(OutputDevice& out) const;
330 :
331 : /// @brief return logicID_linkIndex
332 : static std::string getTLLinkID(const MSLink* link);
333 :
334 : /// @brief return junctionID_junctionLinkIndex
335 : static std::string getJunctionLinkID(const MSLink* link);
336 :
337 : /// @brief print link descriptions
338 : static std::string formatVisitedMap(const LaneVisitedMap& visited);
339 :
340 : /// @brief append to map by map index and avoid undefined behavior
341 : static void appendMapIndex(LaneVisitedMap& map, const MSLane* lane);
342 :
343 : private:
344 :
345 : struct Siding {
346 544 : Siding(int s, int e, double l) : start(s), end(e), length(l) {}
347 : // indices along route
348 : int start;
349 : int end;
350 : double length;
351 : };
352 :
353 : std::set<SUMOVehicle*> myTrains;
354 :
355 : std::vector<VehicleEvent> myVehicleEvents;
356 : std::vector<MSDriveWay*> myFoes;
357 : std::map<const MSDriveWay*, std::vector<Siding>, ComparatorIdLess> mySidings;
358 : std::vector<std::set <const MSDriveWay*> > myDeadlocks;
359 :
360 : /* @brief shortened versions of this driveway to be used as foes instead of the long original
361 : * (ends as soon as the train has left a particular conflict section)
362 : * they are never attached to a LinkInfo and thus never the target of the match() function */
363 : std::vector<MSDriveWay*> mySubDriveWays;
364 :
365 : /// @brief track own occurences in myReversalDriveWays for cleanup in destructor
366 : std::vector<const MSEdge*> myReversals;
367 :
368 : /// @brief the first vehicle using this driveway
369 : std::string myFirstVehicle;
370 :
371 : static int myGlobalDriveWayIndex;
372 : static bool myWriteVehicles;
373 : static std::set<const MSEdge*> myBlockLengthWarnings;
374 :
375 : /// @brief all driveways passing the given switch (used to look up flank foes)
376 : static std::map<const MSLink*, std::vector<MSDriveWay*> > mySwitchDriveWays;
377 :
378 : /// @brief all driveways reversing on the given switch (used to look up flank foes)
379 : static std::map<const MSEdge*, std::vector<MSDriveWay*> > myReversalDriveWays;
380 :
381 : /// @brief all driveways that do not start at a rail signal (and are only used at departure)
382 : static std::map<const MSEdge*, std::vector<MSDriveWay*>, ComparatorNumericalIdLess > myDepartureDriveways;
383 : static std::map<const MSJunction*, int> myDepartDrivewayIndex;
384 : /// @brief all driveways that do not start at a rail signal (and are only used at departure) by end edge
385 : static std::map<const MSEdge*, std::vector<MSDriveWay*> > myDepartureDrivewaysEnds;
386 :
387 : /// @brief all driveways that end on the given edge
388 : static std::map<const MSEdge*, std::vector<MSDriveWay*>, ComparatorNumericalIdLess> myEndingDriveways;
389 :
390 : /// @brief lookup table for state loading
391 : static std::map<ConstMSEdgeVector, MSDriveWay*> myDriveWayRouteLookup;
392 : static std::map<std::string, MSDriveWay*> myDriveWayLookup;
393 :
394 : };
|