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 MSDevice_Transportable.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @author Laura Bieker
19 : /// @author Melanie Weber
20 : /// @author Andreas Kendziorra
21 : /// @date Fri, 30.01.2009
22 : ///
23 : // A device which is used to keep track of persons and containers riding with a vehicle
24 : /****************************************************************************/
25 : #include <config.h>
26 :
27 : #include <utils/xml/SUMOSAXAttributes.h>
28 : #include <microsim/output/MSStopOut.h>
29 : #include <microsim/MSNet.h>
30 : #include <microsim/MSEdge.h>
31 : #include <microsim/MSStop.h>
32 : #include <microsim/MSStoppingPlace.h>
33 : #include <microsim/transportables/MSPerson.h>
34 : #include <microsim/transportables/MSTransportableControl.h>
35 : #include <microsim/transportables/MSStageDriving.h>
36 : #include "MSDevice_Transportable.h"
37 : #include "MSDevice_Taxi.h"
38 :
39 :
40 : // ===========================================================================
41 : // method definitions
42 : // ===========================================================================
43 : // ---------------------------------------------------------------------------
44 : // static initialisation methods
45 : // ---------------------------------------------------------------------------
46 : MSDevice_Transportable*
47 4777 : MSDevice_Transportable::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into, const bool isContainer) {
48 4777 : MSDevice_Transportable* device = new MSDevice_Transportable(v, isContainer ? "container_" + v.getID() : "person_" + v.getID(), isContainer);
49 4777 : into.push_back(device);
50 4777 : return device;
51 : }
52 :
53 :
54 : // ---------------------------------------------------------------------------
55 : // MSDevice_Transportable-methods
56 : // ---------------------------------------------------------------------------
57 4777 : MSDevice_Transportable::MSDevice_Transportable(SUMOVehicle& holder, const std::string& id, const bool isContainer) :
58 : MSVehicleDevice(holder, id),
59 4777 : myAmContainer(isContainer),
60 : myTransportables(),
61 4777 : myStopped(holder.isStopped())
62 4777 : { }
63 :
64 :
65 9554 : MSDevice_Transportable::~MSDevice_Transportable() {
66 : // flush any unfortunate riders still remaining
67 4787 : for (auto it = myTransportables.begin(); it != myTransportables.end();) {
68 10 : MSTransportable* transportable = *it;
69 30 : WRITE_WARNING((myAmContainer ? "Removing container '" : "Removing person '") + transportable->getID() +
70 : "' at removal of vehicle '" + myHolder.getID() + "'");
71 10 : MSStageDriving* const stage = dynamic_cast<MSStageDriving*>(transportable->getCurrentStage());
72 10 : if (stage != nullptr) {
73 10 : stage->setVehicle(nullptr);
74 : }
75 10 : if (myAmContainer) {
76 0 : MSNet::getInstance()->getContainerControl().erase(transportable);
77 : } else {
78 10 : MSNet::getInstance()->getPersonControl().erase(transportable);
79 : }
80 10 : it = myTransportables.erase(it);
81 : }
82 9554 : }
83 :
84 : void
85 11983 : MSDevice_Transportable::notifyMoveInternal(const SUMOTrafficObject& veh,
86 : const double /* frontOnLane */,
87 : const double /* timeOnLane */,
88 : const double /* meanSpeedFrontOnLane */,
89 : const double /* meanSpeedVehicleOnLane */,
90 : const double travelledDistanceFrontOnLane,
91 : const double /* travelledDistanceVehicleOnLane */,
92 : const double /* meanLengthOnLane */) {
93 11983 : notifyMove(const_cast<SUMOTrafficObject&>(veh), -1, travelledDistanceFrontOnLane, veh.getEdge()->getVehicleMaxSpeed(&veh));
94 11983 : }
95 :
96 : bool
97 44 : MSDevice_Transportable::anyLeavingAtStop(const MSStop& stop) const {
98 54 : for (const MSTransportable* t : myTransportables) {
99 44 : MSStageDriving* const stage = dynamic_cast<MSStageDriving*>(t->getCurrentStage());
100 44 : if (stage->canLeaveVehicle(t, myHolder, stop)) {
101 : return true;
102 : }
103 : }
104 : return false;
105 : }
106 :
107 :
108 : void
109 12 : MSDevice_Transportable::transferAtSplitOrJoin(MSBaseVehicle* otherVeh) {
110 12 : const MSStop& stop = myHolder.getNextStop();
111 30 : for (auto it = myTransportables.begin(); it != myTransportables.end();) {
112 18 : MSTransportable* t = *it;
113 18 : if (t->getNumRemainingStages() > 1) {
114 12 : MSStageDriving* const stage = dynamic_cast<MSStageDriving*>(t->getCurrentStage());
115 12 : if (stage->canLeaveVehicle(t, myHolder, stop)) {
116 12 : MSStageDriving* const stage2 = dynamic_cast<MSStageDriving*>(t->getNextStage(1));
117 12 : if (stage2 && stage2->isWaitingFor(otherVeh)) {
118 12 : it = myTransportables.erase(it);
119 : // proceeding registers t as waiting on edge
120 12 : t->proceed(MSNet::getInstance(), SIMSTEP);
121 12 : MSTransportableControl& tc = (t->isPerson() ?
122 3 : MSNet::getInstance()->getPersonControl() :
123 9 : MSNet::getInstance()->getContainerControl());
124 12 : tc.abortWaitingForVehicle(t);
125 12 : t->getEdge()->removeTransportable(t);
126 12 : otherVeh->addTransportable(t);
127 12 : stage2->setVehicle(otherVeh);
128 12 : continue;
129 12 : }
130 : }
131 : }
132 : it++;
133 : }
134 12 : }
135 :
136 :
137 : bool
138 71536 : MSDevice_Transportable::willTransferAtJoin(const MSTransportable* t, const MSBaseVehicle* joinVeh) {
139 71536 : if (joinVeh && t->getNumRemainingStages() > 1) {
140 6 : MSStageDriving* const stage2 = dynamic_cast<MSStageDriving*>(t->getNextStage(1));
141 6 : return stage2->isWaitingFor(joinVeh);
142 : }
143 : return false;
144 : }
145 :
146 :
147 : bool
148 1340194 : MSDevice_Transportable::notifyMove(SUMOTrafficObject& /*tObject*/, double /*oldPos*/, double newPos, double newSpeed) {
149 1340194 : SUMOVehicle& veh = myHolder;
150 1340194 : const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
151 1340194 : if (myStopped) {
152 854352 : if (!veh.isStopped()) {
153 6206 : const SUMOTime freeFlowTimeCorrection = MSGlobals::gUseMesoSim ? TIME2STEPS(newPos / newSpeed) : 0;
154 20507 : for (MSTransportable* const transportable : myTransportables) {
155 14301 : transportable->setDeparted(currentTime - freeFlowTimeCorrection);
156 : }
157 6206 : myStopped = false;
158 : }
159 : } else {
160 485842 : if (veh.isStopped()) {
161 66115 : myStopped = true;
162 66115 : MSStop& stop = veh.getNextStop();
163 66115 : const MSVehicle* joinVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle(stop.pars.join));
164 66115 : const SUMOTime boardingDuration = veh.getVehicleType().getLoadingDuration(!myAmContainer);
165 88370 : for (std::vector<MSTransportable*>::iterator i = myTransportables.begin(); i != myTransportables.end();) {
166 83526 : MSTransportable* transportable = *i;
167 83526 : MSStageDriving* const stage = dynamic_cast<MSStageDriving*>(transportable->getCurrentStage());
168 83526 : if (stage->canLeaveVehicle(transportable, myHolder, stop) && !willTransferAtJoin(transportable, joinVeh)) {
169 71530 : SUMOTime& timeForNext = myAmContainer ? stop.timeToLoadNextContainer : stop.timeToBoardNextPerson;
170 71530 : MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(myHolder.getDevice(typeid(MSDevice_Taxi)));
171 57535 : if (taxiDevice != nullptr && timeForNext == 0 && !MSGlobals::gUseMesoSim) {
172 : // taxi passengers must leave at the end of the stop duration
173 913 : timeForNext = stop.pars.started + stop.pars.duration;
174 : }
175 71530 : if (timeForNext - DELTA_T > currentTime) {
176 : // try deboarding again in the next step
177 61271 : myStopped = false;
178 61271 : break;
179 : }
180 10259 : if (stage->getDestinationStop() != nullptr) {
181 4815 : stage->getDestinationStop()->addTransportable(transportable);
182 : }
183 :
184 : SUMOTime arrivalTime = currentTime;
185 10259 : if (MSGlobals::gUseMesoSim) {
186 : // no boarding / unboarding time in meso
187 1348 : arrivalTime += 1;
188 : } else {
189 8911 : if (timeForNext > currentTime - DELTA_T) {
190 7259 : timeForNext += boardingDuration;
191 : } else {
192 1652 : timeForNext = currentTime + boardingDuration;
193 : }
194 : }
195 : //ensure that vehicle stops long enough for deboarding
196 10259 : stop.duration = MAX2(stop.duration, timeForNext - currentTime);
197 :
198 10259 : i = myTransportables.erase(i); // erase first in case proceed throws an exception
199 10259 : if (taxiDevice != nullptr) {
200 2094 : taxiDevice->customerArrived(transportable);
201 : }
202 10259 : if (!transportable->proceed(MSNet::getInstance(), arrivalTime)) {
203 4805 : if (myAmContainer) {
204 223 : MSNet::getInstance()->getContainerControl().erase(transportable);
205 : } else {
206 4582 : MSNet::getInstance()->getPersonControl().erase(transportable);
207 : }
208 : }
209 10259 : if (MSStopOut::active()) {
210 : SUMOVehicle* vehicle = dynamic_cast<SUMOVehicle*>(&veh);
211 2339 : if (myAmContainer) {
212 118 : MSStopOut::getInstance()->unloadedContainers(vehicle, 1);
213 : } else {
214 2221 : MSStopOut::getInstance()->unloadedPersons(vehicle, 1);
215 : }
216 : }
217 10259 : continue;
218 10259 : }
219 : ++i;
220 : }
221 : }
222 : }
223 1340194 : return true;
224 : }
225 :
226 :
227 : bool
228 57677 : MSDevice_Transportable::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
229 57677 : if (reason == MSMoveReminder::NOTIFICATION_DEPARTED) {
230 2759 : const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
231 6274 : for (MSTransportable* const transportable : myTransportables) {
232 3515 : transportable->setDeparted(currentTime);
233 : }
234 : }
235 57677 : if (MSGlobals::gUseMesoSim) {
236 : // to trigger vehicle leaving
237 12346 : notifyMove(veh, -1., -1., -1.);
238 : }
239 57677 : return true;
240 : }
241 :
242 :
243 : bool
244 58700 : MSDevice_Transportable::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/,
245 : MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
246 58700 : if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
247 7366 : for (std::vector<MSTransportable*>::iterator i = myTransportables.begin(); i != myTransportables.end();) {
248 3324 : MSTransportableControl& tc = myAmContainer ? MSNet::getInstance()->getContainerControl() : MSNet::getInstance()->getPersonControl();
249 3324 : MSTransportable* transportable = *i;
250 3324 : if (transportable->getDestination() != veh.getEdge()) {
251 112 : WRITE_WARNING((myAmContainer ? "Teleporting container '" : "Teleporting person '") + transportable->getID() +
252 : "' from vehicle destination edge '" + veh.getEdge()->getID() +
253 : "' to intended destination edge '" + transportable->getDestination()->getID() + "' time=" + time2string(SIMSTEP));
254 : tc.registerTeleportWrongDest();
255 : }
256 3324 : if (!transportable->proceed(MSNet::getInstance(), MSNet::getInstance()->getCurrentTimeStep(), true)) {
257 3100 : tc.erase(transportable);
258 : }
259 3324 : i = myTransportables.erase(i);
260 : }
261 : }
262 58700 : return true;
263 : }
264 :
265 :
266 : void
267 13758 : MSDevice_Transportable::addTransportable(MSTransportable* transportable) {
268 13758 : myTransportables.push_back(transportable);
269 13758 : if (MSStopOut::active()) {
270 3343 : if (myAmContainer) {
271 187 : MSStopOut::getInstance()->loadedContainers(&myHolder, 1);
272 : } else {
273 3156 : MSStopOut::getInstance()->loadedPersons(&myHolder, 1);
274 : }
275 : }
276 13758 : MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(myHolder.getDevice(typeid(MSDevice_Taxi)));
277 : if (taxiDevice != nullptr) {
278 2107 : taxiDevice->customerEntered(transportable);
279 : }
280 13758 : }
281 :
282 :
283 : void
284 153 : MSDevice_Transportable::removeTransportable(MSTransportable* transportable) {
285 153 : auto it = std::find(myTransportables.begin(), myTransportables.end(), transportable);
286 153 : if (it != myTransportables.end()) {
287 153 : myTransportables.erase(it);
288 153 : if (MSStopOut::active() && myHolder.isStopped()) {
289 55 : if (myAmContainer) {
290 20 : MSStopOut::getInstance()->unloadedContainers(&myHolder, 1);
291 : } else {
292 35 : MSStopOut::getInstance()->unloadedPersons(&myHolder, 1);
293 : }
294 : }
295 153 : MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(myHolder.getDevice(typeid(MSDevice_Taxi)));
296 : if (taxiDevice != nullptr) {
297 13 : taxiDevice->customerArrived(transportable);
298 : }
299 : }
300 153 : }
301 :
302 :
303 : void
304 14 : MSDevice_Transportable::saveState(OutputDevice& out) const {
305 14 : out.openTag(SUMO_TAG_DEVICE);
306 : out.writeAttr(SUMO_ATTR_ID, getID());
307 : std::vector<std::string> internals;
308 14 : internals.push_back(toString(myStopped));
309 14 : out.writeAttr(SUMO_ATTR_STATE, toString(internals));
310 14 : out.closeTag();
311 14 : }
312 :
313 :
314 : void
315 0 : MSDevice_Transportable::loadState(const SUMOSAXAttributes& attrs) {
316 0 : std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
317 0 : bis >> myStopped;
318 0 : }
319 :
320 :
321 : std::string
322 6 : MSDevice_Transportable::getParameter(const std::string& key) const {
323 6 : if (key == "IDList") {
324 : std::vector<std::string> ids;
325 12 : for (const MSTransportable* t : myTransportables) {
326 6 : ids.push_back(t->getID());
327 : }
328 12 : return toString(ids);
329 6 : }
330 0 : throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
331 : }
332 :
333 :
334 : /****************************************************************************/
|