Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-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 MSVehicleTransfer.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @date Sep 2003
19 : ///
20 : // A mover of vehicles that got stucked due to grid locks
21 : /****************************************************************************/
22 : #include <config.h>
23 :
24 : #include <iostream>
25 : #include <utils/common/MsgHandler.h>
26 : #include <utils/xml/SUMOSAXAttributes.h>
27 : #include "MSNet.h"
28 : #include "MSLane.h"
29 : #include "MSEdge.h"
30 : #include "MSVehicle.h"
31 : #include "MSParkingArea.h"
32 : #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
33 : #include <microsim/devices/MSDevice_Taxi.h>
34 : #include "MSVehicleControl.h"
35 : #include "MSInsertionControl.h"
36 : #include "MSVehicleTransfer.h"
37 :
38 :
39 : // ===========================================================================
40 : // static member definitions
41 : // ===========================================================================
42 : MSVehicleTransfer* MSVehicleTransfer::myInstance = nullptr;
43 : const double MSVehicleTransfer::TeleportMinSpeed = 1;
44 :
45 :
46 : // ===========================================================================
47 : // member method definitions
48 : // ===========================================================================
49 : bool
50 37995575 : MSVehicleTransfer::VehicleInformation::operator<(const VehicleInformation& v2) const {
51 37995575 : return myVeh->getNumericalID() < v2.myVeh->getNumericalID();
52 : }
53 :
54 :
55 : void
56 28749 : MSVehicleTransfer::add(const SUMOTime t, MSVehicle* veh) {
57 28749 : const bool jumping = veh->isJumping();
58 28749 : const SUMOTime proceed = jumping ? MAX2(t + veh->getPastStops().back().jump, veh->getPastStops().back().jumpUntil) : -1;
59 28749 : if (veh->isParking()) {
60 15451 : veh->getLaneChangeModel().endLaneChangeManeuver(MSMoveReminder::NOTIFICATION_PARKING);
61 15451 : MSNet::getInstance()->informVehicleStateListener(veh, MSNet::VehicleState::STARTING_PARKING);
62 15451 : veh->onRemovalFromNet(MSMoveReminder::NOTIFICATION_PARKING);
63 : } else {
64 13298 : veh->getLaneChangeModel().endLaneChangeManeuver(MSMoveReminder::NOTIFICATION_TELEPORT);
65 13298 : MSNet::getInstance()->informVehicleStateListener(veh, MSNet::VehicleState::STARTING_TELEPORT);
66 13298 : if (veh->succEdge(1) == nullptr) {
67 7503 : WRITE_WARNINGF(TL("Vehicle '%' teleports beyond arrival edge '%', time=%."), veh->getID(), veh->getEdge()->getID(), time2string(t));
68 2501 : veh->onRemovalFromNet(MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED);
69 2501 : MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
70 2501 : return;
71 : }
72 10797 : veh->onRemovalFromNet(MSMoveReminder::NOTIFICATION_TELEPORT);
73 10797 : veh->enterLaneAtMove(veh->succEdge(1)->getLanes()[0], true);
74 : }
75 26248 : myVehicles.push_back(VehicleInformation(t, veh, proceed, veh->isParking(), jumping));
76 : }
77 :
78 :
79 : void
80 2949745 : MSVehicleTransfer::remove(MSVehicle* veh) {
81 : auto& vehInfos = myVehicles.getContainer();
82 3783821 : for (auto i = vehInfos.begin(); i != vehInfos.end(); ++i) {
83 834097 : if (i->myVeh == veh) {
84 21 : if (i->myParking) {
85 21 : veh->getMutableLane()->removeParking(veh);
86 : }
87 : vehInfos.erase(i);
88 21 : break;
89 : }
90 : }
91 : myVehicles.unlock();
92 2949745 : }
93 :
94 :
95 : void
96 63625736 : MSVehicleTransfer::checkInsertions(SUMOTime time) {
97 : // go through vehicles
98 : auto& vehInfos = myVehicles.getContainer();
99 63625736 : std::sort(vehInfos.begin(), vehInfos.end());
100 72286448 : for (auto i = vehInfos.begin(); i != vehInfos.end();) {
101 : // vehicle information cannot be const because we need to assign the proceed time
102 : VehicleInformation& desc = *i;
103 :
104 8660712 : if (desc.myParking) {
105 : // handle parking vehicles
106 8367209 : if (time != desc.myTransferTime) {
107 : // avoid calling processNextStop twice in the transfer step
108 8351758 : const MSLane* lane = desc.myVeh->getLane();
109 : // lane must be locked because pedestrians may be added in during stop processing while existing passengers are being drawn simultaneously
110 8351758 : if (lane != nullptr) {
111 8351758 : lane->getVehiclesSecure();
112 : }
113 8351758 : desc.myVeh->processNextStop(1);
114 8351758 : desc.myVeh->updateParkingState();
115 8351758 : if (lane != nullptr) {
116 8351758 : lane->releaseVehicles();
117 : }
118 : }
119 8367209 : if (desc.myVeh->keepStopping(true)) {
120 : i++;
121 8249949 : continue;
122 : }
123 : // parking finished, head back into traffic
124 : }
125 410763 : const SUMOVehicleClass vclass = desc.myVeh->getVehicleType().getVehicleClass();
126 410763 : const MSEdge* e = desc.myVeh->getEdge();
127 410763 : const MSEdge* nextEdge = desc.myVeh->succEdge(1);
128 :
129 :
130 410763 : if (desc.myParking) {
131 117260 : MSParkingArea* pa = desc.myVeh->getCurrentParkingArea();
132 117260 : const double departPos = pa != nullptr ? pa->getInsertionPosition(*desc.myVeh) : desc.myVeh->getPositionOnLane();
133 : // handle parking vehicles
134 117260 : desc.myVeh->setIdling(true);
135 117260 : if (desc.myVeh->getMutableLane()->isInsertionSuccess(desc.myVeh, 0, departPos, desc.myVeh->getLateralPositionOnLane(),
136 : false, MSMoveReminder::NOTIFICATION_PARKING)) {
137 11981 : MSNet::getInstance()->informVehicleStateListener(desc.myVeh, MSNet::VehicleState::ENDING_PARKING);
138 11981 : desc.myVeh->getMutableLane()->removeParking(desc.myVeh);
139 : // at this point we are in the lane, blocking traffic & if required we configure the exit manoeuvre
140 11981 : if (MSGlobals::gModelParkingManoeuver && desc.myVeh->setExitManoeuvre()) {
141 64 : MSNet::getInstance()->informVehicleStateListener(desc.myVeh, MSNet::VehicleState::MANEUVERING);
142 : }
143 11981 : desc.myVeh->setIdling(false);
144 : i = vehInfos.erase(i);
145 : } else {
146 : // blocked from entering the road - engine assumed to be idling.
147 105279 : desc.myVeh->workOnIdleReminders();
148 105279 : if (!desc.myVeh->signalSet(MSVehicle::VEH_SIGNAL_BLINKER_LEFT | MSVehicle::VEH_SIGNAL_BLINKER_RIGHT)) {
149 : // signal wish to re-enter the road
150 1723 : desc.myVeh->switchOnSignal(MSGlobals::gLefthand ? MSVehicle::VEH_SIGNAL_BLINKER_RIGHT : MSVehicle::VEH_SIGNAL_BLINKER_LEFT);
151 1723 : if (pa) {
152 : // update freePosition so other vehicles can help with insertion
153 1284 : desc.myVeh->getCurrentParkingArea()->notifyEgressBlocked();
154 : }
155 : }
156 : i++;
157 : }
158 293503 : } else if (desc.myJumping && desc.myProceedTime > time) {
159 : ++i;
160 : } else {
161 : const double departPos = 0;
162 : // get the lane on which this vehicle should continue
163 : // first select all the lanes which allow continuation onto nextEdge
164 : // then pick the one which is least occupied
165 288344 : MSLane* l = (nextEdge != nullptr ? e->getFreeLane(e->allowedLanes(*nextEdge, vclass), vclass, departPos) :
166 89832 : e->getFreeLane(nullptr, vclass, departPos));
167 : // handle teleporting vehicles, lane may be 0 because permissions were modified by a closing rerouter or TraCI
168 288344 : const bool busyBidi = l != nullptr && l->getBidiLane() != nullptr && l->getBidiLane()->getVehicleNumberWithPartials() > 0;
169 574682 : if (l != nullptr && !busyBidi && l->freeInsertion(*(desc.myVeh), MIN2(l->getSpeedLimit(), desc.myVeh->getMaxSpeed()), 0, MSMoveReminder::NOTIFICATION_TELEPORT)) {
170 10414 : if (!desc.myJumping) {
171 39860 : WRITE_WARNINGF(TL("Vehicle '%' ends teleporting on edge '%', time=%."), desc.myVeh->getID(), e->getID(), time2string(time));
172 : }
173 20828 : MSNet::getInstance()->informVehicleStateListener(desc.myVeh, MSNet::VehicleState::ENDING_TELEPORT);
174 : i = vehInfos.erase(i);
175 277930 : } else if (desc.myJumping) {
176 : // try again later
177 : ++i;
178 : } else {
179 : // vehicle is visible while show-route is active. Make its state more obvious
180 275597 : desc.myVeh->computeAngle();
181 275597 : desc.myVeh->setLateralPositionOnLane(-desc.myVeh->getLane()->getWidth() / 2);
182 275597 : desc.myVeh->invalidateCachedPosition();
183 : // could not insert. maybe we should proceed in virtual space
184 275597 : if (desc.myProceedTime < 0) {
185 : // initialize proceed time (delayed to avoid lane-order dependency in executeMove)
186 2943 : desc.myProceedTime = time + TIME2STEPS(e->getCurrentTravelTime(TeleportMinSpeed));
187 272654 : } else if (desc.myProceedTime < time) {
188 6176 : if (desc.myVeh->succEdge(1) == nullptr) {
189 287 : if (desc.myVeh->getDevice(typeid(MSDevice_Taxi)) != nullptr) {
190 : // never teleport a taxi beyond the end of it's route
191 20 : desc.myProceedTime = time + TIME2STEPS(e->getCurrentTravelTime(TeleportMinSpeed));
192 : } else {
193 1068 : WRITE_WARNINGF(TL("Vehicle '%' teleports beyond arrival edge '%', time=%."), desc.myVeh->getID(), e->getID(), time2string(time));
194 267 : desc.myVeh->leaveLane(MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED);
195 267 : MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(desc.myVeh);
196 : i = vehInfos.erase(i);
197 : }
198 287 : continue;
199 : }
200 : // let the vehicle move to the next edge
201 5889 : desc.myVeh->leaveLane(MSMoveReminder::NOTIFICATION_TELEPORT_CONTINUATION);
202 : // active move reminders (i.e. rerouters)
203 5889 : const std::vector<MSLane*>* allowedLanes = nextEdge->allowedLanes(vclass);
204 11778 : MSLane* laneToEnter = (allowedLanes != nullptr) ? allowedLanes->at(0) : nextEdge->getLanes()[0];
205 5889 : desc.myVeh->enterLaneAtMove(laneToEnter, true);
206 : // use current travel time to determine when to move the vehicle forward
207 5889 : desc.myProceedTime = time + TIME2STEPS(e->getCurrentTravelTime(TeleportMinSpeed));
208 : }
209 : ++i;
210 : }
211 : }
212 : }
213 : myVehicles.unlock();
214 63625736 : }
215 :
216 :
217 : MSVehicleTransfer*
218 66643763 : MSVehicleTransfer::getInstance() {
219 66643763 : if (myInstance == nullptr) {
220 38672 : myInstance = new MSVehicleTransfer();
221 : }
222 66643763 : return myInstance;
223 : }
224 :
225 :
226 38672 : MSVehicleTransfer::MSVehicleTransfer() : myVehicles(MSGlobals::gNumSimThreads > 1) {}
227 :
228 :
229 77340 : MSVehicleTransfer::~MSVehicleTransfer() {
230 38670 : myInstance = nullptr;
231 77340 : }
232 :
233 :
234 : void
235 476 : MSVehicleTransfer::saveState(OutputDevice& out) {
236 676 : for (const VehicleInformation& vehInfo : myVehicles.getContainer()) {
237 200 : out.openTag(SUMO_TAG_VEHICLETRANSFER);
238 200 : out.writeAttr(SUMO_ATTR_ID, vehInfo.myVeh->getID());
239 200 : out.writeAttr(SUMO_ATTR_DEPART, vehInfo.myProceedTime);
240 200 : if (vehInfo.myParking) {
241 198 : out.writeAttr(SUMO_ATTR_PARKING, vehInfo.myVeh->getLane()->getID());
242 : }
243 200 : if (vehInfo.myJumping) {
244 0 : out.writeAttr(SUMO_ATTR_JUMP, true);
245 : }
246 400 : out.closeTag();
247 : }
248 : myVehicles.unlock();
249 476 : }
250 :
251 :
252 : void
253 187 : MSVehicleTransfer::clearState() {
254 187 : myVehicles.clear();
255 187 : }
256 :
257 :
258 : void
259 200 : MSVehicleTransfer::loadState(const SUMOSAXAttributes& attrs, const SUMOTime offset, MSVehicleControl& vc) {
260 200 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vc.getVehicle(attrs.getString(SUMO_ATTR_ID)));
261 200 : if (veh == nullptr) {
262 : // deleted
263 0 : return;
264 : }
265 200 : SUMOTime proceedTime = (SUMOTime)attrs.getLong(SUMO_ATTR_DEPART);
266 200 : MSLane* parkingLane = attrs.hasAttribute(SUMO_ATTR_PARKING) ? MSLane::dictionary(attrs.getString(SUMO_ATTR_PARKING)) : nullptr;
267 200 : bool ok = true;
268 200 : const bool jumping = attrs.getOpt<bool>(SUMO_ATTR_JUMP, veh->getID().c_str(), ok, false);
269 200 : myVehicles.push_back(VehicleInformation(-1, veh, proceedTime - offset, parkingLane != nullptr, jumping));
270 200 : if (parkingLane != nullptr) {
271 198 : parkingLane->addParking(veh);
272 198 : veh->setTentativeLaneAndPosition(parkingLane, veh->getPositionOnLane());
273 198 : veh->processNextStop(veh->getSpeed());
274 : }
275 200 : MSNet::getInstance()->getInsertionControl().alreadyDeparted(veh);
276 : }
277 :
278 :
279 : /****************************************************************************/
|