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 4575 : MSDevice_Transportable::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into, const bool isContainer) {
48 4575 : MSDevice_Transportable* device = new MSDevice_Transportable(v, isContainer ? "container_" + v.getID() : "person_" + v.getID(), isContainer);
49 4575 : into.push_back(device);
50 4575 : return device;
51 : }
52 :
53 :
54 : // ---------------------------------------------------------------------------
55 : // MSDevice_Transportable-methods
56 : // ---------------------------------------------------------------------------
57 4575 : MSDevice_Transportable::MSDevice_Transportable(SUMOVehicle& holder, const std::string& id, const bool isContainer) :
58 : MSVehicleDevice(holder, id),
59 4575 : myAmContainer(isContainer),
60 : myTransportables(),
61 4575 : myStopped(holder.isStopped())
62 4575 : { }
63 :
64 :
65 9150 : MSDevice_Transportable::~MSDevice_Transportable() {
66 : // flush any unfortunate riders still remaining
67 4585 : for (auto it = myTransportables.begin(); it != myTransportables.end();) {
68 10 : MSTransportable* transportable = *it;
69 40 : 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 9150 : }
83 :
84 : void
85 13662 : 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 13662 : notifyMove(const_cast<SUMOTrafficObject&>(veh), -1, travelledDistanceFrontOnLane, veh.getEdge()->getVehicleMaxSpeed(&veh));
94 13662 : }
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 68854 : MSDevice_Transportable::willTransferAtJoin(const MSTransportable* t, const MSBaseVehicle* joinVeh) {
139 68854 : 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 1001196 : MSDevice_Transportable::notifyMove(SUMOTrafficObject& /*tObject*/, double /*oldPos*/, double newPos, double newSpeed) {
149 1001196 : SUMOVehicle& veh = myHolder;
150 1001196 : const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
151 1001196 : if (myStopped) {
152 548899 : if (!veh.isStopped()) {
153 5586 : const SUMOTime freeFlowTimeCorrection = MSGlobals::gUseMesoSim ? TIME2STEPS(newPos / newSpeed) : 0;
154 17301 : for (MSTransportable* const transportable : myTransportables) {
155 11715 : transportable->setDeparted(currentTime - freeFlowTimeCorrection);
156 : }
157 5586 : myStopped = false;
158 : }
159 : } else {
160 452297 : if (veh.isStopped()) {
161 64369 : myStopped = true;
162 64369 : MSStop& stop = veh.getNextStop();
163 64369 : const MSVehicle* joinVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle(stop.pars.join));
164 64369 : const SUMOTime boardingDuration = veh.getVehicleType().getLoadingDuration(!myAmContainer);
165 80273 : for (std::vector<MSTransportable*>::iterator i = myTransportables.begin(); i != myTransportables.end();) {
166 75989 : MSTransportable* transportable = *i;
167 75989 : MSStageDriving* const stage = dynamic_cast<MSStageDriving*>(transportable->getCurrentStage());
168 75989 : if (stage->canLeaveVehicle(transportable, myHolder, stop) && !willTransferAtJoin(transportable, joinVeh)) {
169 68848 : SUMOTime& timeForNext = myAmContainer ? stop.timeToLoadNextContainer : stop.timeToBoardNextPerson;
170 68848 : MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(myHolder.getDevice(typeid(MSDevice_Taxi)));
171 56522 : if (taxiDevice != nullptr && timeForNext == 0 && !MSGlobals::gUseMesoSim) {
172 : // taxi passengers must leave at the end of the stop duration
173 905 : timeForNext = stop.pars.started + stop.pars.duration;
174 : }
175 68848 : if (timeForNext - DELTA_T > currentTime) {
176 : // try deboarding again in the next step
177 60085 : myStopped = false;
178 60085 : break;
179 : }
180 8763 : if (stage->getDestinationStop() != nullptr) {
181 4630 : stage->getDestinationStop()->addTransportable(transportable);
182 : }
183 :
184 : SUMOTime arrivalTime = currentTime;
185 8763 : if (MSGlobals::gUseMesoSim) {
186 : // no boarding / unboarding time in meso
187 1594 : arrivalTime += 1;
188 : } else {
189 7169 : const SUMOTime boardingTime = (SUMOTime)((double)boardingDuration * transportable->getVehicleType().getBoardingFactor());
190 7169 : if (timeForNext > currentTime - DELTA_T) {
191 5937 : timeForNext += boardingTime;
192 : } else {
193 1232 : timeForNext = currentTime + boardingTime;
194 : }
195 : }
196 : //ensure that vehicle stops long enough for deboarding
197 8763 : stop.duration = MAX2(stop.duration, timeForNext - currentTime);
198 :
199 8763 : i = myTransportables.erase(i); // erase first in case proceed throws an exception
200 8763 : if (taxiDevice != nullptr) {
201 1870 : taxiDevice->customerArrived(transportable);
202 : }
203 8763 : if (!transportable->proceed(MSNet::getInstance(), arrivalTime)) {
204 4385 : if (myAmContainer) {
205 241 : MSNet::getInstance()->getContainerControl().erase(transportable);
206 : } else {
207 4144 : MSNet::getInstance()->getPersonControl().erase(transportable);
208 : }
209 : }
210 8763 : if (MSStopOut::active()) {
211 : SUMOVehicle* vehicle = dynamic_cast<SUMOVehicle*>(&veh);
212 1672 : if (myAmContainer) {
213 118 : MSStopOut::getInstance()->unloadedContainers(vehicle, 1);
214 : } else {
215 1554 : MSStopOut::getInstance()->unloadedPersons(vehicle, 1);
216 : }
217 : }
218 8763 : continue;
219 8763 : }
220 : ++i;
221 : }
222 : }
223 : }
224 1001196 : return true;
225 : }
226 :
227 :
228 : bool
229 49790 : MSDevice_Transportable::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
230 49790 : if (reason == MSMoveReminder::NOTIFICATION_DEPARTED) {
231 2460 : const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
232 5352 : for (MSTransportable* const transportable : myTransportables) {
233 2892 : transportable->setDeparted(currentTime);
234 : }
235 : }
236 49790 : if (MSGlobals::gUseMesoSim) {
237 : // to trigger vehicle leaving
238 14085 : notifyMove(veh, -1., -1., -1.);
239 : }
240 49790 : return true;
241 : }
242 :
243 :
244 : bool
245 50781 : MSDevice_Transportable::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/,
246 : MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
247 50781 : if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
248 7775 : for (std::vector<MSTransportable*>::iterator i = myTransportables.begin(); i != myTransportables.end();) {
249 3929 : MSTransportableControl& tc = myAmContainer ? MSNet::getInstance()->getContainerControl() : MSNet::getInstance()->getPersonControl();
250 3929 : MSTransportable* transportable = *i;
251 3929 : if (transportable->getDestination() != veh.getEdge()) {
252 142 : WRITE_WARNING((myAmContainer ? "Teleporting container '" : "Teleporting person '") + transportable->getID() +
253 : "' from vehicle destination edge '" + veh.getEdge()->getID() +
254 : "' to intended destination edge '" + transportable->getDestination()->getID() + "' time=" + time2string(SIMSTEP));
255 : tc.registerTeleportWrongDest();
256 : }
257 3929 : if (!transportable->proceed(MSNet::getInstance(), MSNet::getInstance()->getCurrentTimeStep(), true)) {
258 3712 : tc.erase(transportable);
259 : }
260 3929 : i = myTransportables.erase(i);
261 : }
262 : }
263 50781 : return true;
264 : }
265 :
266 :
267 : void
268 12892 : MSDevice_Transportable::addTransportable(MSTransportable* transportable) {
269 12892 : myTransportables.push_back(transportable);
270 12892 : if (MSStopOut::active()) {
271 2674 : if (myAmContainer) {
272 187 : MSStopOut::getInstance()->loadedContainers(&myHolder, 1);
273 : } else {
274 2487 : MSStopOut::getInstance()->loadedPersons(&myHolder, 1);
275 : }
276 : }
277 12892 : MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(myHolder.getDevice(typeid(MSDevice_Taxi)));
278 : if (taxiDevice != nullptr) {
279 1881 : taxiDevice->customerEntered(transportable);
280 : }
281 12892 : }
282 :
283 :
284 : void
285 178 : MSDevice_Transportable::removeTransportable(MSTransportable* transportable) {
286 178 : auto it = std::find(myTransportables.begin(), myTransportables.end(), transportable);
287 178 : if (it != myTransportables.end()) {
288 178 : myTransportables.erase(it);
289 178 : if (MSStopOut::active() && myHolder.isStopped()) {
290 55 : if (myAmContainer) {
291 20 : MSStopOut::getInstance()->unloadedContainers(&myHolder, 1);
292 : } else {
293 35 : MSStopOut::getInstance()->unloadedPersons(&myHolder, 1);
294 : }
295 : }
296 178 : MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(myHolder.getDevice(typeid(MSDevice_Taxi)));
297 : if (taxiDevice != nullptr) {
298 11 : taxiDevice->customerArrived(transportable);
299 : }
300 : }
301 178 : }
302 :
303 :
304 : void
305 9 : MSDevice_Transportable::saveState(OutputDevice& out) const {
306 9 : out.openTag(SUMO_TAG_DEVICE);
307 : out.writeAttr(SUMO_ATTR_ID, getID());
308 : std::vector<std::string> internals;
309 9 : internals.push_back(toString(myStopped));
310 9 : out.writeAttr(SUMO_ATTR_STATE, toString(internals));
311 9 : out.closeTag();
312 9 : }
313 :
314 :
315 : void
316 0 : MSDevice_Transportable::loadState(const SUMOSAXAttributes& attrs) {
317 0 : std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
318 0 : bis >> myStopped;
319 0 : }
320 :
321 :
322 : std::string
323 5 : MSDevice_Transportable::getParameter(const std::string& key) const {
324 5 : if (key == "IDList") {
325 : std::vector<std::string> ids;
326 10 : for (const MSTransportable* t : myTransportables) {
327 5 : ids.push_back(t->getID());
328 : }
329 10 : return toString(ids);
330 5 : }
331 0 : throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
332 : }
333 :
334 :
335 : /****************************************************************************/
|