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