Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2002-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 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 5158 : struct VehicleEvent {
48 1936 : VehicleEvent(SUMOTime _time, bool _isEntry, const std::string& _id, Notification _reason):
49 1936 : 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 32411 : 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 8211 : myFirstVehicle = vehID;
144 3129 : }
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 9328513 : 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 : bool foundSignal() const {
175 : return myFoundSignal;
176 : }
177 :
178 : static void init();
179 :
180 : static bool hasRS(const MSEdge* cur, const MSEdge* next);
181 :
182 : /// @brief Whether veh must yield to the foe train
183 : static bool mustYield(const Approaching& veh, const Approaching& foe);
184 :
185 : /// @brief construct a new driveway by searching along the given route until all block structures are found
186 : static MSDriveWay* buildDriveWay(const std::string& id, const MSLink* link, MSRouteIterator first, MSRouteIterator end);
187 :
188 : /// @brief return logicID_linkIndex in a way that allows clicking in sumo-gui
189 : static std::string getClickableTLLinkID(const MSLink* link);
190 :
191 : static const MSDriveWay* getDepartureDriveway(const SUMOVehicle* veh, bool init = false);
192 :
193 : static void writeDepatureBlocks(OutputDevice& od, bool writeVehicles);
194 :
195 : /** @brief Save driveway occupancy into the given stream */
196 : static void saveState(OutputDevice& out);
197 : static void loadState(const SUMOSAXAttributes& attrs, int tag);
198 :
199 : protected:
200 :
201 : /// @brief global driveway index
202 : int myNumericalID;
203 :
204 : /// @brief the link that enters this driveway or nullptr for a departure driveWay
205 : const MSLink* myOrigin;
206 :
207 : /// @brief whether the current signal is switched green for a train approaching this block
208 : const SUMOVehicle* myActive;
209 :
210 : /// @brief list of edges for matching against train routes
211 : std::vector<const MSEdge*> myRoute;
212 :
213 : /// @brief number of edges in myRoute where overlap with other driveways is forbidden
214 : int myCoreSize;
215 :
216 : /// @brief number of normal edges in myForward
217 : int myForwardEdgeCount;
218 :
219 : /// @brief whether this driveway ends its forward section with a rail signal (and thus comprises a full block)
220 : bool myFoundSignal;
221 : bool myFoundJump;
222 : bool myTerminateRoute;
223 : /// @brief whether driveway building was aborted due to MAX_BLOCK_LENGTH
224 : bool myAbortedBuild;
225 : /// @brief whether driveway building was aborted when no further bidi edge was found
226 : bool myBidiEnded;
227 : bool myIsSubDriveway;
228 :
229 : /* @brief the actual driveway part up to the next railsignal (halting position)
230 : * This must be free of other trains */
231 : std::vector<const MSLane*> myForward;
232 :
233 : /* @brief the list of bidirectional edges that can enter the forward
234 : * section and which must also be free of traffic
235 : * (up to the first element that could give protection) */
236 : std::vector<const MSLane*> myBidi;
237 :
238 : /* @brief the list of bidirectional edges that can enter the forward
239 : * section and which might contain deadlock-relevant traffic */
240 : std::vector<const MSLane*> myBidiExtended;
241 :
242 : /* @brief the list of edges that merge with the forward section
243 : * (found via backward search, up to the first element that could give protection) */
244 : std::vector<const MSLane*> myFlank;
245 :
246 : /// @brief the lanes that must be clear of trains before this signal can switch to green
247 : std::vector<const MSLane*> myConflictLanes;
248 :
249 : /* The conflict links for this block
250 : * Conflict resolution must be performed if vehicles are approaching the
251 : * current link and any of the conflict links */
252 : std::vector<MSLink*> myConflictLinks;
253 :
254 : /// @brief Whether the approaching vehicle is prevent from driving by another vehicle approaching the given link
255 : bool hasLinkConflict(const Approaching& closest, const MSLink* foeLink) const;
256 :
257 : /// @brief Wether this driveway (route) overlaps with the given one
258 : bool overlap(const MSDriveWay& other) const;
259 :
260 : /* @brief determine route that identifies this driveway (a subset of the
261 : * vehicle route)
262 : * collects:
263 : * myRoute
264 : * myForward
265 : * myBidi
266 : * myProtectedBidi
267 : *
268 : * returns edge that is assumed to safe from oncoming-deadlock or nullptr
269 : */
270 : void buildRoute(const MSLink* origin, MSRouteIterator next, MSRouteIterator end, LaneVisitedMap& visited, std::set<MSLink*, MSLink::ComparatorNumericalLaneIdLess>&);
271 :
272 : /* @brief find switches that threaten this driveway
273 : * @param[out] flankSwitches collect the switches
274 : */
275 : void checkFlanks(const MSLink* originLink, const std::vector<const MSLane*>& lanes, const LaneVisitedMap& visited,
276 : bool allFoes, bool movingBlock, std::set<MSLink*, MSLink::ComparatorNumericalLaneIdLess>& flankSwitches) const;
277 :
278 : /* @brief find links that cross the driveway without entering it
279 : * @param[out] flankSwitches collect the switches
280 : */
281 : void checkCrossingFlanks(MSLink* dwLink, const LaneVisitedMap& visited, std::set<MSLink*, MSLink::ComparatorNumericalLaneIdLess>& flankSwitches) const;
282 :
283 : /* @brief find upstream protection from the given link
284 : * @param[out] flank: the stored flank lanes
285 : */
286 : void findFlankProtection(MSLink* link, MSLink* origLink, std::vector<const MSLane*>& flank);
287 :
288 : /// @brief add all driveWays that start at the given link as foes
289 : void addFoes(const MSLink* link);
290 :
291 : /// @brief add sidings for the given foe
292 : void addSidings(MSDriveWay* foe, bool addToFoe = false);
293 :
294 : /// @brief derive foe driveways based on myBidi or myBidiExtended
295 : void addBidiFoes(const MSRailSignal* ownSignal, bool extended);
296 :
297 : /// @brief derive foe driveways that start at the same signal
298 : void addParallelFoes(const MSLink* link, const MSEdge* first);
299 :
300 : /// @brief derive foe driveways that enter the bidi section by reversing
301 : void addReversalFoes(bool movingBlock);
302 :
303 : /* @brief build shortened driveway that ends where the foe train leaves the conflict zone of this driveway
304 : * @return whether the foe has received a new entry in myFoes
305 : */
306 : bool buildSubFoe(MSDriveWay* foe, bool movingBlock);
307 :
308 : /// @brief add symmetical conflict link for foes when building a new driveway
309 : void addConflictLink(const MSLink* link);
310 :
311 : /// @brief return whether a siding can be used. If a siding exist but is occupied, also return the occupied driveway in the siding
312 : std::pair<bool, const MSDriveWay*> canUseSiding(const SUMOVehicle* ego, const MSDriveWay* foe, bool recurse = true) const;
313 :
314 : bool isFoeOrSubFoe(const MSDriveWay* foe) const;
315 :
316 : bool forwardEndOnRoute(const MSDriveWay* foe) const;
317 :
318 : void addSwitchFoes(MSLink* link);
319 :
320 : bool haveSubTrains() const;
321 :
322 : /// @brief compute distance along the forward section up to lastIndex
323 : double getForwardDistance(int lastIndex) const;
324 :
325 : /* @brief whether the train would have matched this driveway in it's past
326 : * @return If matching, returns the number of edges the vehicle has gone past the start of the driveway,
327 : * Indicate no-match by returning a negative value */
328 : int matchesPastRoute(SUMOVehicle& sveh) const;
329 :
330 : /// @brief helper method for notifyEnter
331 : void enterDriveWay(SUMOVehicle& sveh, Notification reason);
332 :
333 : static bool hasJoin(const SUMOVehicle* ego, const SUMOVehicle* foe);
334 :
335 : static bool isSwitch(const MSLink* link);
336 :
337 : void _saveState(OutputDevice& out) const;
338 :
339 : /// @brief return logicID_linkIndex
340 : static std::string getTLLinkID(const MSLink* link);
341 :
342 : /// @brief return junctionID_junctionLinkIndex
343 : static std::string getJunctionLinkID(const MSLink* link);
344 :
345 : /// @brief print link descriptions
346 : static std::string formatVisitedMap(const LaneVisitedMap& visited);
347 :
348 : /// @brief append to map by map index and avoid undefined behavior
349 : static void appendMapIndex(LaneVisitedMap& map, const MSLane* lane);
350 :
351 : private:
352 :
353 : struct Siding {
354 2551 : Siding(int s, int e, double l) : start(s), end(e), length(l) {}
355 : // indices along route
356 : int start;
357 : int end;
358 : double length;
359 : };
360 :
361 : std::set<SUMOVehicle*, ComparatorNumericalIdLess> myTrains;
362 :
363 : std::vector<VehicleEvent> myVehicleEvents;
364 : std::vector<MSDriveWay*> myFoes;
365 : std::map<const MSDriveWay*, std::vector<Siding>, ComparatorIdLess> mySidings;
366 : std::vector<std::set <const MSDriveWay*> > myDeadlocks;
367 :
368 : /* @brief shortened versions of this driveway to be used as foes instead of the long original
369 : * (ends as soon as the train has left a particular conflict section)
370 : * they are never attached to a LinkInfo and thus never the target of the match() function */
371 : std::vector<MSDriveWay*> mySubDriveWays;
372 :
373 : /// @brief track own occurences in myReversalDriveWays for cleanup in destructor
374 : std::vector<const MSEdge*> myReversals;
375 :
376 : /// @brief the first vehicle using this driveway
377 : std::string myFirstVehicle;
378 :
379 : static int myGlobalDriveWayIndex;
380 : static bool myWriteVehicles;
381 : static double myMovingBlockMaxDist;
382 : static std::set<const MSEdge*> myBlockLengthWarnings;
383 :
384 : /// @brief all driveways passing the given switch (used to look up flank foes)
385 : static std::map<const MSLink*, std::vector<MSDriveWay*> > mySwitchDriveWays;
386 :
387 : /// @brief all driveways reversing on the given switch (used to look up flank foes)
388 : static std::map<const MSEdge*, std::vector<MSDriveWay*> > myReversalDriveWays;
389 :
390 : /// @brief all driveways that do not start at a rail signal (and are only used at departure)
391 : static std::map<const MSEdge*, std::vector<MSDriveWay*>, ComparatorNumericalIdLess > myDepartureDriveways;
392 : static std::map<const MSJunction*, int> myDepartDrivewayIndex;
393 : /// @brief all driveways that do not start at a rail signal (and are only used at departure) by end edge
394 : static std::map<const MSEdge*, std::vector<MSDriveWay*> > myDepartureDrivewaysEnds;
395 :
396 : /// @brief all driveways that end on the given edge
397 : static std::map<const MSEdge*, std::vector<MSDriveWay*>, ComparatorNumericalIdLess> myEndingDriveways;
398 :
399 : /// @brief lookup table for state loading
400 : static std::map<ConstMSEdgeVector, MSDriveWay*> myDriveWayRouteLookup;
401 : static std::map<std::string, MSDriveWay*> myDriveWayLookup;
402 :
403 : };
|