Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-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 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 "MSVehicleControl.h"
34 : #include "MSInsertionControl.h"
35 : #include "MSVehicleTransfer.h"
36 :
37 :
38 : // ===========================================================================
39 : // static member definitions
40 : // ===========================================================================
41 : MSVehicleTransfer* MSVehicleTransfer::myInstance = nullptr;
42 : const double MSVehicleTransfer::TeleportMinSpeed = 1;
43 :
44 :
45 : // ===========================================================================
46 : // member method definitions
47 : // ===========================================================================
48 : bool
49 35809205 : MSVehicleTransfer::VehicleInformation::operator<(const VehicleInformation& v2) const {
50 35809205 : return myVeh->getNumericalID() < v2.myVeh->getNumericalID();
51 : }
52 :
53 :
54 : void
55 21934 : MSVehicleTransfer::add(const SUMOTime t, MSVehicle* veh) {
56 21934 : const bool jumping = veh->isJumping();
57 21934 : const SUMOTime proceed = jumping ? t + veh->getPastStops().back().jump : -1;
58 21934 : if (veh->isParking()) {
59 12477 : veh->getLaneChangeModel().endLaneChangeManeuver(MSMoveReminder::NOTIFICATION_PARKING);
60 12477 : MSNet::getInstance()->informVehicleStateListener(veh, MSNet::VehicleState::STARTING_PARKING);
61 12477 : veh->onRemovalFromNet(MSMoveReminder::NOTIFICATION_PARKING);
62 : } else {
63 9457 : veh->getLaneChangeModel().endLaneChangeManeuver(MSMoveReminder::NOTIFICATION_TELEPORT);
64 9457 : MSNet::getInstance()->informVehicleStateListener(veh, MSNet::VehicleState::STARTING_TELEPORT);
65 9457 : if (veh->succEdge(1) == nullptr) {
66 7122 : WRITE_WARNINGF(TL("Vehicle '%' teleports beyond arrival edge '%', time=%."), veh->getID(), veh->getEdge()->getID(), time2string(t));
67 2374 : veh->onRemovalFromNet(MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED);
68 2374 : MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
69 2374 : return;
70 : }
71 7083 : veh->onRemovalFromNet(MSMoveReminder::NOTIFICATION_TELEPORT);
72 7083 : veh->enterLaneAtMove(veh->succEdge(1)->getLanes()[0], true);
73 : }
74 19560 : myVehicles.push_back(VehicleInformation(t, veh, proceed, veh->isParking(), jumping));
75 : }
76 :
77 :
78 : void
79 2777162 : MSVehicleTransfer::remove(MSVehicle* veh) {
80 : auto& vehInfos = myVehicles.getContainer();
81 3545893 : for (auto i = vehInfos.begin(); i != vehInfos.end(); ++i) {
82 768747 : if (i->myVeh == veh) {
83 16 : if (i->myParking) {
84 16 : veh->getMutableLane()->removeParking(veh);
85 : }
86 : vehInfos.erase(i);
87 16 : break;
88 : }
89 : }
90 : myVehicles.unlock();
91 2777162 : }
92 :
93 :
94 : void
95 91771637 : MSVehicleTransfer::checkInsertions(SUMOTime time) {
96 : // go through vehicles
97 : auto& vehInfos = myVehicles.getContainer();
98 91771637 : std::sort(vehInfos.begin(), vehInfos.end());
99 99566712 : for (auto i = vehInfos.begin(); i != vehInfos.end();) {
100 : // vehicle information cannot be const because we need to assign the proceed time
101 : VehicleInformation& desc = *i;
102 :
103 7795075 : if (desc.myParking) {
104 : // handle parking vehicles
105 7512599 : if (time != desc.myTransferTime) {
106 : // avoid calling processNextStop twice in the transfer step
107 7500122 : const MSLane* lane = desc.myVeh->getLane();
108 : // lane must be locked because pedestrians may be added in during stop processing while existing passengers are being drawn simultaneously
109 7500122 : if (lane != nullptr) {
110 7500122 : lane->getVehiclesSecure();
111 : }
112 7500122 : desc.myVeh->processNextStop(1);
113 7500122 : desc.myVeh->updateParkingState();
114 7500122 : if (lane != nullptr) {
115 7500122 : lane->releaseVehicles();
116 : }
117 : }
118 7512599 : if (desc.myVeh->keepStopping(true)) {
119 : i++;
120 7428987 : continue;
121 : }
122 : // parking finished, head back into traffic
123 : }
124 366088 : const SUMOVehicleClass vclass = desc.myVeh->getVehicleType().getVehicleClass();
125 366088 : const MSEdge* e = desc.myVeh->getEdge();
126 366088 : const MSEdge* nextEdge = desc.myVeh->succEdge(1);
127 :
128 :
129 366088 : if (desc.myParking) {
130 83612 : MSParkingArea* pa = desc.myVeh->getCurrentParkingArea();
131 83612 : const double departPos = pa != nullptr ? pa->getInsertionPosition(*desc.myVeh) : desc.myVeh->getPositionOnLane();
132 : // handle parking vehicles
133 83612 : desc.myVeh->setIdling(true);
134 83612 : if (desc.myVeh->getMutableLane()->isInsertionSuccess(desc.myVeh, 0, departPos, desc.myVeh->getLateralPositionOnLane(),
135 : false, MSMoveReminder::NOTIFICATION_PARKING)) {
136 9194 : MSNet::getInstance()->informVehicleStateListener(desc.myVeh, MSNet::VehicleState::ENDING_PARKING);
137 9194 : desc.myVeh->getMutableLane()->removeParking(desc.myVeh);
138 : // at this point we are in the lane, blocking traffic & if required we configure the exit manoeuvre
139 9194 : if (MSGlobals::gModelParkingManoeuver && desc.myVeh->setExitManoeuvre()) {
140 64 : MSNet::getInstance()->informVehicleStateListener(desc.myVeh, MSNet::VehicleState::MANEUVERING);
141 : }
142 9194 : desc.myVeh->setIdling(false);
143 : i = vehInfos.erase(i);
144 : } else {
145 : // blocked from entering the road - engine assumed to be idling.
146 74418 : desc.myVeh->workOnIdleReminders();
147 74418 : if (!desc.myVeh->signalSet(MSVehicle::VEH_SIGNAL_BLINKER_LEFT | MSVehicle::VEH_SIGNAL_BLINKER_RIGHT)) {
148 : // signal wish to re-enter the road
149 1450 : desc.myVeh->switchOnSignal(MSGlobals::gLefthand ? MSVehicle::VEH_SIGNAL_BLINKER_RIGHT : MSVehicle::VEH_SIGNAL_BLINKER_LEFT);
150 1450 : if (pa) {
151 : // update freePosition so other vehicles can help with insertion
152 1115 : desc.myVeh->getCurrentParkingArea()->notifyEgressBlocked();
153 : }
154 : }
155 : i++;
156 : }
157 282476 : } else if (desc.myJumping && desc.myProceedTime > time) {
158 : ++i;
159 : } else {
160 : const double departPos = 0;
161 : // get the lane on which this vehicle should continue
162 : // first select all the lanes which allow continuation onto nextEdge
163 : // then pick the one which is least occupied
164 281432 : MSLane* l = (nextEdge != nullptr ? e->getFreeLane(e->allowedLanes(*nextEdge, vclass), vclass, departPos) :
165 89738 : e->getFreeLane(nullptr, vclass, departPos));
166 : // handle teleporting vehicles, lane may be 0 because permissions were modified by a closing rerouter or TraCI
167 281432 : const bool busyBidi = l != nullptr && l->getBidiLane() != nullptr && l->getBidiLane()->getVehicleNumberWithPartials() > 0;
168 560926 : if (l != nullptr && !busyBidi && l->freeInsertion(*(desc.myVeh), MIN2(l->getSpeedLimit(), desc.myVeh->getMaxSpeed()), 0, MSMoveReminder::NOTIFICATION_TELEPORT)) {
169 6690 : if (!desc.myJumping) {
170 26100 : WRITE_WARNINGF(TL("Vehicle '%' ends teleporting on edge '%', time=%."), desc.myVeh->getID(), e->getID(), time2string(time));
171 : }
172 13380 : MSNet::getInstance()->informVehicleStateListener(desc.myVeh, MSNet::VehicleState::ENDING_TELEPORT);
173 : i = vehInfos.erase(i);
174 274742 : } else if (desc.myJumping) {
175 : // try again later
176 : ++i;
177 : } else {
178 : // vehicle is visible while show-route is active. Make its state more obvious
179 273447 : desc.myVeh->computeAngle();
180 273447 : desc.myVeh->setLateralPositionOnLane(-desc.myVeh->getLane()->getWidth() / 2);
181 273447 : desc.myVeh->invalidateCachedPosition();
182 : // could not insert. maybe we should proceed in virtual space
183 273447 : if (desc.myProceedTime < 0) {
184 : // initialize proceed time (delayed to avoid lane-order dependency in executeMove)
185 2896 : desc.myProceedTime = time + TIME2STEPS(e->getCurrentTravelTime(TeleportMinSpeed));
186 270551 : } else if (desc.myProceedTime < time) {
187 6207 : if (desc.myVeh->succEdge(1) == nullptr) {
188 1124 : WRITE_WARNINGF(TL("Vehicle '%' teleports beyond arrival edge '%', time=%."), desc.myVeh->getID(), e->getID(), time2string(time));
189 281 : desc.myVeh->leaveLane(MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED);
190 281 : MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(desc.myVeh);
191 : i = vehInfos.erase(i);
192 281 : continue;
193 : }
194 : // let the vehicle move to the next edge
195 5926 : desc.myVeh->leaveLane(MSMoveReminder::NOTIFICATION_TELEPORT_CONTINUATION);
196 : // active move reminders (i.e. rerouters)
197 5926 : const std::vector<MSLane*>* allowedLanes = nextEdge->allowedLanes(vclass);
198 11852 : MSLane* laneToEnter = (allowedLanes != nullptr) ? allowedLanes->at(0) : nextEdge->getLanes()[0];
199 5926 : desc.myVeh->enterLaneAtMove(laneToEnter, true);
200 : // use current travel time to determine when to move the vehicle forward
201 5926 : desc.myProceedTime = time + TIME2STEPS(e->getCurrentTravelTime(TeleportMinSpeed));
202 : }
203 : ++i;
204 : }
205 : }
206 : }
207 : myVehicles.unlock();
208 91771637 : }
209 :
210 :
211 : MSVehicleTransfer*
212 94611795 : MSVehicleTransfer::getInstance() {
213 94611795 : if (myInstance == nullptr) {
214 40277 : myInstance = new MSVehicleTransfer();
215 : }
216 94611795 : return myInstance;
217 : }
218 :
219 :
220 40277 : MSVehicleTransfer::MSVehicleTransfer() : myVehicles(MSGlobals::gNumSimThreads > 1) {}
221 :
222 :
223 80550 : MSVehicleTransfer::~MSVehicleTransfer() {
224 40275 : myInstance = nullptr;
225 80550 : }
226 :
227 :
228 : void
229 425 : MSVehicleTransfer::saveState(OutputDevice& out) {
230 610 : for (const VehicleInformation& vehInfo : myVehicles.getContainer()) {
231 185 : out.openTag(SUMO_TAG_VEHICLETRANSFER);
232 185 : out.writeAttr(SUMO_ATTR_ID, vehInfo.myVeh->getID());
233 185 : out.writeAttr(SUMO_ATTR_DEPART, vehInfo.myProceedTime);
234 185 : if (vehInfo.myParking) {
235 183 : out.writeAttr(SUMO_ATTR_PARKING, vehInfo.myVeh->getLane()->getID());
236 : }
237 185 : if (vehInfo.myJumping) {
238 0 : out.writeAttr(SUMO_ATTR_JUMP, true);
239 : }
240 370 : out.closeTag();
241 : }
242 : myVehicles.unlock();
243 425 : }
244 :
245 :
246 : void
247 177 : MSVehicleTransfer::clearState() {
248 177 : myVehicles.clear();
249 177 : }
250 :
251 :
252 : void
253 185 : MSVehicleTransfer::loadState(const SUMOSAXAttributes& attrs, const SUMOTime offset, MSVehicleControl& vc) {
254 185 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vc.getVehicle(attrs.getString(SUMO_ATTR_ID)));
255 185 : if (veh == nullptr) {
256 : // deleted
257 0 : return;
258 : }
259 185 : SUMOTime proceedTime = (SUMOTime)attrs.getLong(SUMO_ATTR_DEPART);
260 185 : MSLane* parkingLane = attrs.hasAttribute(SUMO_ATTR_PARKING) ? MSLane::dictionary(attrs.getString(SUMO_ATTR_PARKING)) : nullptr;
261 185 : bool ok = true;
262 185 : const bool jumping = attrs.getOpt<bool>(SUMO_ATTR_JUMP, veh->getID().c_str(), ok, false);
263 185 : myVehicles.push_back(VehicleInformation(-1, veh, proceedTime - offset, parkingLane != nullptr, jumping));
264 185 : if (parkingLane != nullptr) {
265 183 : parkingLane->addParking(veh);
266 183 : veh->setTentativeLaneAndPosition(parkingLane, veh->getPositionOnLane());
267 183 : veh->processNextStop(veh->getSpeed());
268 : }
269 185 : MSNet::getInstance()->getInsertionControl().alreadyDeparted(veh);
270 : }
271 :
272 :
273 : /****************************************************************************/
|