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 36196887 : MSVehicleTransfer::VehicleInformation::operator<(const VehicleInformation& v2) const {
50 36196887 : return myVeh->getNumericalID() < v2.myVeh->getNumericalID();
51 : }
52 :
53 :
54 : void
55 21683 : MSVehicleTransfer::add(const SUMOTime t, MSVehicle* veh) {
56 21683 : const bool jumping = veh->isJumping();
57 21683 : const SUMOTime proceed = jumping ? t + veh->getPastStops().back().jump : -1;
58 21683 : if (veh->isParking()) {
59 12496 : veh->getLaneChangeModel().endLaneChangeManeuver(MSMoveReminder::NOTIFICATION_PARKING);
60 12496 : MSNet::getInstance()->informVehicleStateListener(veh, MSNet::VehicleState::STARTING_PARKING);
61 12496 : veh->onRemovalFromNet(MSMoveReminder::NOTIFICATION_PARKING);
62 : } else {
63 9187 : veh->getLaneChangeModel().endLaneChangeManeuver(MSMoveReminder::NOTIFICATION_TELEPORT);
64 9187 : MSNet::getInstance()->informVehicleStateListener(veh, MSNet::VehicleState::STARTING_TELEPORT);
65 9187 : if (veh->succEdge(1) == nullptr) {
66 7125 : WRITE_WARNINGF(TL("Vehicle '%' teleports beyond arrival edge '%', time=%."), veh->getID(), veh->getEdge()->getID(), time2string(t));
67 2375 : veh->onRemovalFromNet(MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED);
68 2375 : MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
69 2375 : return;
70 : }
71 6812 : veh->onRemovalFromNet(MSMoveReminder::NOTIFICATION_TELEPORT);
72 6812 : veh->enterLaneAtMove(veh->succEdge(1)->getLanes()[0], true);
73 : }
74 19308 : myVehicles.push_back(VehicleInformation(t, veh, proceed, veh->isParking(), jumping));
75 : }
76 :
77 :
78 : void
79 2545279 : MSVehicleTransfer::remove(MSVehicle* veh) {
80 : auto& vehInfos = myVehicles.getContainer();
81 3314739 : for (auto i = vehInfos.begin(); i != vehInfos.end(); ++i) {
82 769476 : 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 2545279 : }
92 :
93 :
94 : void
95 82314054 : MSVehicleTransfer::checkInsertions(SUMOTime time) {
96 : // go through vehicles
97 : auto& vehInfos = myVehicles.getContainer();
98 82314054 : std::sort(vehInfos.begin(), vehInfos.end());
99 90257009 : 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 7942955 : if (desc.myParking) {
104 : // handle parking vehicles
105 7535716 : if (time != desc.myTransferTime) {
106 : // avoid calling processNextStop twice in the transfer step
107 7523220 : 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 7523220 : if (lane != nullptr) {
110 7523220 : lane->getVehiclesSecure();
111 : }
112 7523220 : desc.myVeh->processNextStop(1);
113 7523220 : desc.myVeh->updateParkingState();
114 7523220 : if (lane != nullptr) {
115 7523220 : lane->releaseVehicles();
116 : }
117 : }
118 7535716 : if (desc.myVeh->keepStopping(true)) {
119 : i++;
120 7452136 : continue;
121 : }
122 : // parking finished, head back into traffic
123 : }
124 490819 : const SUMOVehicleClass vclass = desc.myVeh->getVehicleType().getVehicleClass();
125 490819 : const MSEdge* e = desc.myVeh->getEdge();
126 490819 : const MSEdge* nextEdge = desc.myVeh->succEdge(1);
127 :
128 :
129 490819 : if (desc.myParking) {
130 83580 : MSParkingArea* pa = desc.myVeh->getCurrentParkingArea();
131 83580 : const double departPos = pa != nullptr ? pa->getInsertionPosition(*desc.myVeh) : desc.myVeh->getPositionOnLane();
132 : // handle parking vehicles
133 83580 : desc.myVeh->setIdling(true);
134 83580 : if (desc.myVeh->getMutableLane()->isInsertionSuccess(desc.myVeh, 0, departPos, desc.myVeh->getLateralPositionOnLane(),
135 : false, MSMoveReminder::NOTIFICATION_PARKING)) {
136 9163 : MSNet::getInstance()->informVehicleStateListener(desc.myVeh, MSNet::VehicleState::ENDING_PARKING);
137 9163 : 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 9163 : if (MSGlobals::gModelParkingManoeuver && desc.myVeh->setExitManoeuvre()) {
140 64 : MSNet::getInstance()->informVehicleStateListener(desc.myVeh, MSNet::VehicleState::MANEUVERING);
141 : }
142 9163 : desc.myVeh->setIdling(false);
143 : i = vehInfos.erase(i);
144 : } else {
145 : // blocked from entering the road - engine assumed to be idling.
146 74417 : desc.myVeh->workOnIdleReminders();
147 74417 : if (!desc.myVeh->signalSet(MSVehicle::VEH_SIGNAL_BLINKER_LEFT | MSVehicle::VEH_SIGNAL_BLINKER_RIGHT)) {
148 : // signal wish to re-enter the road
149 1449 : desc.myVeh->switchOnSignal(MSGlobals::gLefthand ? MSVehicle::VEH_SIGNAL_BLINKER_RIGHT : MSVehicle::VEH_SIGNAL_BLINKER_LEFT);
150 1449 : if (pa) {
151 : // update freePosition so other vehicles can help with insertion
152 1113 : desc.myVeh->getCurrentParkingArea()->notifyEgressBlocked();
153 : }
154 : }
155 : i++;
156 : }
157 407239 : } 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 406225 : MSLane* l = (nextEdge != nullptr ? e->getFreeLane(e->allowedLanes(*nextEdge, vclass), vclass, departPos) :
165 89740 : e->getFreeLane(nullptr, vclass, departPos));
166 : // handle teleporting vehicles, lane may be 0 because permissions were modified by a closing rerouter or TraCI
167 406225 : const bool busyBidi = l != nullptr && l->getBidiLane() != nullptr && l->getBidiLane()->getVehicleNumberWithPartials() > 0;
168 810510 : if (l != nullptr && !busyBidi && l->freeInsertion(*(desc.myVeh), MIN2(l->getSpeedLimit(), desc.myVeh->getMaxSpeed()), 0, MSMoveReminder::NOTIFICATION_TELEPORT)) {
169 6405 : if (!desc.myJumping) {
170 24976 : WRITE_WARNINGF(TL("Vehicle '%' ends teleporting on edge '%', time=%."), desc.myVeh->getID(), e->getID(), time2string(time));
171 : }
172 12810 : MSNet::getInstance()->informVehicleStateListener(desc.myVeh, MSNet::VehicleState::ENDING_TELEPORT);
173 : i = vehInfos.erase(i);
174 399820 : } 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 398525 : desc.myVeh->computeAngle();
180 398525 : desc.myVeh->setLateralPositionOnLane(-desc.myVeh->getLane()->getWidth() / 2);
181 398525 : desc.myVeh->invalidateCachedPosition();
182 : // could not insert. maybe we should proceed in virtual space
183 398525 : if (desc.myProceedTime < 0) {
184 : // initialize proceed time (delayed to avoid lane-order dependency in executeMove)
185 2633 : desc.myProceedTime = time + TIME2STEPS(e->getCurrentTravelTime(TeleportMinSpeed));
186 395892 : } else if (desc.myProceedTime < time) {
187 12285 : 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 12004 : desc.myVeh->leaveLane(MSMoveReminder::NOTIFICATION_TELEPORT_CONTINUATION);
196 : // active move reminders (i.e. rerouters)
197 12004 : const std::vector<MSLane*>* allowedLanes = nextEdge->allowedLanes(vclass);
198 24008 : MSLane* laneToEnter = (allowedLanes != nullptr) ? allowedLanes->at(0) : nextEdge->getLanes()[0];
199 12004 : desc.myVeh->enterLaneAtMove(laneToEnter, true);
200 : // use current travel time to determine when to move the vehicle forward
201 12004 : desc.myProceedTime = time + TIME2STEPS(e->getCurrentTravelTime(TeleportMinSpeed));
202 : }
203 : ++i;
204 : }
205 : }
206 : }
207 : myVehicles.unlock();
208 82314054 : }
209 :
210 :
211 : MSVehicleTransfer*
212 84921855 : MSVehicleTransfer::getInstance() {
213 84921855 : if (myInstance == nullptr) {
214 40046 : myInstance = new MSVehicleTransfer();
215 : }
216 84921855 : return myInstance;
217 : }
218 :
219 :
220 40046 : MSVehicleTransfer::MSVehicleTransfer() : myVehicles(MSGlobals::gNumSimThreads > 1) {}
221 :
222 :
223 80088 : MSVehicleTransfer::~MSVehicleTransfer() {
224 40044 : myInstance = nullptr;
225 80088 : }
226 :
227 :
228 : void
229 424 : MSVehicleTransfer::saveState(OutputDevice& out) {
230 609 : 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 424 : }
244 :
245 :
246 : void
247 186 : MSVehicleTransfer::clearState() {
248 186 : myVehicles.clear();
249 186 : }
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 : /****************************************************************************/
|