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 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 1327339 : MSDevice_Transportable::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into, const bool isContainer) {
48 2649782 : MSDevice_Transportable* device = new MSDevice_Transportable(v, isContainer ? "container_" + v.getID() : "person_" + v.getID(), isContainer);
49 4896 : into.push_back(device);
50 4896 : return device;
51 : }
52 :
53 :
54 : // ---------------------------------------------------------------------------
55 : // MSDevice_Transportable-methods
56 : // ---------------------------------------------------------------------------
57 1327339 : MSDevice_Transportable::MSDevice_Transportable(SUMOVehicle& holder, const std::string& id, const bool isContainer) :
58 : MSVehicleDevice(holder, id),
59 1327339 : myAmContainer(isContainer),
60 : myTransportables(),
61 1327339 : myStopped(holder.isStopped()),
62 1327339 : myOriginalType(&holder.getVehicleType()),
63 2654678 : myLoadedType(nullptr) {
64 1327339 : const std::string key = "device." + deviceName() + ".loadedType";
65 3977121 : const std::string loadedTypeID = holder.getStringParam(key);
66 1327339 : if (loadedTypeID != "") {
67 1322455 : myLoadedType = MSNet::getInstance()->getVehicleControl().getVType(loadedTypeID, getEquipmentRNG());
68 1322455 : if (myLoadedType == nullptr) {
69 3967329 : throw InvalidArgument(TLF("Vehicle type '%' in parameter '%' of vehicle '%' is not known.", loadedTypeID, key, holder.getID()));
70 : }
71 : }
72 2649782 : }
73 :
74 :
75 9792 : MSDevice_Transportable::~MSDevice_Transportable() {
76 : // flush any unfortunate riders still remaining
77 4906 : for (auto it = myTransportables.begin(); it != myTransportables.end();) {
78 10 : MSTransportable* transportable = *it;
79 40 : WRITE_WARNING((myAmContainer ? "Removing container '" : "Removing person '") + transportable->getID() +
80 : "' at removal of vehicle '" + myHolder.getID() + "'");
81 10 : MSStageDriving* const stage = dynamic_cast<MSStageDriving*>(transportable->getCurrentStage());
82 10 : if (stage != nullptr) {
83 10 : stage->setVehicle(nullptr);
84 : }
85 10 : if (myAmContainer) {
86 0 : MSNet::getInstance()->getContainerControl().erase(transportable);
87 : } else {
88 10 : MSNet::getInstance()->getPersonControl().erase(transportable);
89 : }
90 10 : it = myTransportables.erase(it);
91 : }
92 9792 : }
93 :
94 : void
95 23506 : MSDevice_Transportable::notifyMoveInternal(const SUMOTrafficObject& veh,
96 : const double /* frontOnLane */,
97 : const double /* timeOnLane */,
98 : const double /* meanSpeedFrontOnLane */,
99 : const double /* meanSpeedVehicleOnLane */,
100 : const double travelledDistanceFrontOnLane,
101 : const double /* travelledDistanceVehicleOnLane */,
102 : const double /* meanLengthOnLane */) {
103 23506 : notifyMove(const_cast<SUMOTrafficObject&>(veh), -1, travelledDistanceFrontOnLane, veh.getEdge()->getVehicleMaxSpeed(&veh));
104 23506 : }
105 :
106 : bool
107 44 : MSDevice_Transportable::anyLeavingAtStop(const MSStop& stop) const {
108 54 : for (const MSTransportable* t : myTransportables) {
109 44 : MSStageDriving* const stage = dynamic_cast<MSStageDriving*>(t->getCurrentStage());
110 44 : if (stage->canLeaveVehicle(t, myHolder, stop)) {
111 : return true;
112 : }
113 : }
114 : return false;
115 : }
116 :
117 :
118 : void
119 12 : MSDevice_Transportable::transferAtSplitOrJoin(MSBaseVehicle* otherVeh) {
120 12 : const MSStop& stop = myHolder.getNextStop();
121 30 : for (auto it = myTransportables.begin(); it != myTransportables.end();) {
122 18 : MSTransportable* t = *it;
123 18 : if (t->getNumRemainingStages() > 1) {
124 12 : MSStageDriving* const stage = dynamic_cast<MSStageDriving*>(t->getCurrentStage());
125 12 : if (stage->canLeaveVehicle(t, myHolder, stop)) {
126 12 : MSStageDriving* const stage2 = dynamic_cast<MSStageDriving*>(t->getNextStage(1));
127 12 : if (stage2 && stage2->isWaitingFor(otherVeh)) {
128 12 : it = myTransportables.erase(it);
129 : // proceeding registers t as waiting on edge
130 12 : t->proceed(MSNet::getInstance(), SIMSTEP);
131 12 : MSTransportableControl& tc = (t->isPerson() ?
132 3 : MSNet::getInstance()->getPersonControl() :
133 9 : MSNet::getInstance()->getContainerControl());
134 12 : tc.abortWaitingForVehicle(t);
135 12 : t->getEdge()->removeTransportable(t);
136 12 : otherVeh->addTransportable(t);
137 12 : stage2->setVehicle(otherVeh);
138 12 : continue;
139 12 : }
140 : }
141 : }
142 : it++;
143 : }
144 12 : }
145 :
146 :
147 : bool
148 77869 : MSDevice_Transportable::willTransferAtJoin(const MSTransportable* t, const MSBaseVehicle* joinVeh) {
149 77869 : if (joinVeh && t->getNumRemainingStages() > 1) {
150 6 : MSStageDriving* const stage2 = dynamic_cast<MSStageDriving*>(t->getNextStage(1));
151 6 : return stage2->isWaitingFor(joinVeh);
152 : }
153 : return false;
154 : }
155 :
156 :
157 : bool
158 1347054 : MSDevice_Transportable::notifyMove(SUMOTrafficObject& /*tObject*/, double /*oldPos*/, double newPos, double newSpeed) {
159 1347054 : SUMOVehicle& veh = myHolder;
160 1347054 : const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
161 1347054 : if (myStopped) {
162 709650 : if (!veh.isStopped()) {
163 6616 : const SUMOTime freeFlowTimeCorrection = MSGlobals::gUseMesoSim ? TIME2STEPS(newPos / newSpeed) : 0;
164 18955 : for (MSTransportable* const transportable : myTransportables) {
165 12339 : transportable->setDeparted(currentTime - freeFlowTimeCorrection);
166 : }
167 6616 : myStopped = false;
168 : }
169 : } else {
170 637404 : if (veh.isStopped()) {
171 73819 : myStopped = true;
172 73819 : MSStop& stop = veh.getNextStopMutable();
173 73819 : const MSVehicle* joinVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle(stop.pars.join));
174 73819 : const SUMOTime boardingDuration = veh.getVehicleType().getLoadingDuration(!myAmContainer);
175 : int numUnloaded = 0;
176 91026 : for (std::vector<MSTransportable*>::iterator i = myTransportables.begin(); i != myTransportables.end();) {
177 85819 : MSTransportable* transportable = *i;
178 85819 : MSStageDriving* const stage = dynamic_cast<MSStageDriving*>(transportable->getCurrentStage());
179 85819 : if (stage->canLeaveVehicle(transportable, myHolder, stop) && !willTransferAtJoin(transportable, joinVeh)) {
180 77863 : SUMOTime& timeForNext = myAmContainer ? stop.timeToLoadNextContainer : stop.timeToBoardNextPerson;
181 77863 : MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(myHolder.getDevice(typeid(MSDevice_Taxi)));
182 64709 : if (taxiDevice != nullptr && timeForNext == 0 && !MSGlobals::gUseMesoSim) {
183 : // taxi passengers must leave at the end of the stop duration
184 1046 : timeForNext = stop.pars.started + stop.pars.duration;
185 : }
186 77863 : if (timeForNext - DELTA_T > currentTime) {
187 : // try deboarding again in the next step
188 68612 : myStopped = false;
189 68612 : break;
190 : }
191 9251 : if (stage->getDestinationStop() != nullptr) {
192 4844 : stage->getDestinationStop()->addTransportable(transportable);
193 : }
194 :
195 : SUMOTime arrivalTime = currentTime;
196 9251 : if (MSGlobals::gUseMesoSim) {
197 : // no boarding / unboarding time in meso
198 1687 : arrivalTime += 1;
199 : } else {
200 7564 : const SUMOTime boardingTime = (SUMOTime)((double)boardingDuration * transportable->getVehicleType().getBoardingFactor());
201 7564 : if (timeForNext > currentTime - DELTA_T) {
202 6246 : timeForNext += boardingTime;
203 : } else {
204 1318 : timeForNext = currentTime + boardingTime;
205 : }
206 : }
207 : //ensure that vehicle stops long enough for deboarding
208 9251 : stop.duration = MAX2(stop.duration, timeForNext - currentTime);
209 :
210 9251 : veh.removeTransportableMass(transportable);
211 9251 : i = myTransportables.erase(i); // erase first in case proceed throws an exception
212 9251 : numUnloaded++;
213 9251 : if (taxiDevice != nullptr) {
214 2077 : taxiDevice->customerArrived(transportable);
215 : }
216 9251 : if (!transportable->proceed(MSNet::getInstance(), arrivalTime)) {
217 4752 : if (myAmContainer) {
218 369 : MSNet::getInstance()->getContainerControl().erase(transportable);
219 : } else {
220 4383 : MSNet::getInstance()->getPersonControl().erase(transportable);
221 : }
222 : }
223 9251 : if (MSStopOut::active()) {
224 : SUMOVehicle* vehicle = dynamic_cast<SUMOVehicle*>(&veh);
225 1887 : if (myAmContainer) {
226 118 : MSStopOut::getInstance()->unloadedContainers(vehicle, 1);
227 : } else {
228 1769 : MSStopOut::getInstance()->unloadedPersons(vehicle, 1);
229 : }
230 : }
231 9251 : continue;
232 9251 : }
233 : ++i;
234 : }
235 73819 : if (numUnloaded != 0) {
236 5630 : changeAttached();
237 : }
238 : }
239 : }
240 1347054 : return true;
241 : }
242 :
243 :
244 : bool
245 76859 : MSDevice_Transportable::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
246 76859 : if (reason == MSMoveReminder::NOTIFICATION_DEPARTED) {
247 2503 : const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
248 5446 : for (MSTransportable* const transportable : myTransportables) {
249 2943 : transportable->setDeparted(currentTime);
250 : }
251 : }
252 76859 : if (MSGlobals::gUseMesoSim) {
253 : // to trigger vehicle leaving
254 23973 : notifyMove(veh, -1., -1., -1.);
255 : }
256 76859 : return true;
257 : }
258 :
259 :
260 : bool
261 78061 : MSDevice_Transportable::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/,
262 : MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
263 78061 : if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
264 8217 : for (std::vector<MSTransportable*>::iterator i = myTransportables.begin(); i != myTransportables.end();) {
265 4197 : MSTransportableControl& tc = myAmContainer ? MSNet::getInstance()->getContainerControl() : MSNet::getInstance()->getPersonControl();
266 4197 : MSTransportable* transportable = *i;
267 4197 : if (transportable->getDestination() != veh.getEdge()) {
268 182 : WRITE_WARNINGF("Teleporting % '%' from vehicle destination edge '%' to intended destination edge '%' time=%",
269 : myAmContainer ? "container" : "person", transportable->getID(), veh.getEdge()->getID(),
270 : transportable->getDestination()->getID(), time2string(SIMSTEP));
271 : tc.registerTeleportWrongDest();
272 : }
273 4197 : if (!transportable->proceed(MSNet::getInstance(), MSNet::getInstance()->getCurrentTimeStep(), true)) {
274 3964 : tc.erase(transportable);
275 : }
276 4197 : i = myTransportables.erase(i);
277 : }
278 : }
279 78061 : return true;
280 : }
281 :
282 :
283 : void
284 13673 : MSDevice_Transportable::addTransportable(MSTransportable* transportable) {
285 13673 : if (myTransportables.empty()) {
286 5558 : myOriginalType = &myHolder.getVehicleType();
287 : }
288 13673 : myTransportables.push_back(transportable);
289 13673 : if (MSStopOut::active()) {
290 2889 : if (myAmContainer) {
291 187 : MSStopOut::getInstance()->loadedContainers(&myHolder, 1);
292 : } else {
293 2702 : MSStopOut::getInstance()->loadedPersons(&myHolder, 1);
294 : }
295 : }
296 13673 : MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(myHolder.getDevice(typeid(MSDevice_Taxi)));
297 : if (taxiDevice != nullptr) {
298 2088 : taxiDevice->customerEntered(transportable);
299 : }
300 13673 : changeAttached();
301 13673 : }
302 :
303 :
304 : void
305 203 : MSDevice_Transportable::removeTransportable(MSTransportable* transportable) {
306 203 : auto it = std::find(myTransportables.begin(), myTransportables.end(), transportable);
307 203 : if (it != myTransportables.end()) {
308 203 : myTransportables.erase(it);
309 203 : if (MSStopOut::active() && myHolder.isStopped()) {
310 55 : if (myAmContainer) {
311 20 : MSStopOut::getInstance()->unloadedContainers(&myHolder, 1);
312 : } else {
313 35 : MSStopOut::getInstance()->unloadedPersons(&myHolder, 1);
314 : }
315 : }
316 203 : MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(myHolder.getDevice(typeid(MSDevice_Taxi)));
317 : if (taxiDevice != nullptr) {
318 11 : taxiDevice->customerArrived(transportable);
319 : }
320 203 : changeAttached();
321 : }
322 203 : }
323 :
324 :
325 : void
326 19506 : MSDevice_Transportable::changeAttached() {
327 19506 : if (myLoadedType != nullptr) {
328 168 : int perAttached = myAmContainer ? myLoadedType->getContainerCapacity() : myLoadedType->getPersonCapacity();
329 168 : if (perAttached > 0) {
330 168 : MSBaseVehicle& veh = dynamic_cast<MSBaseVehicle&>(myHolder);
331 168 : SUMOVehicleClass oldVC = myHolder.getVClass();
332 168 : const double numAttached = ceil(myTransportables.size() / perAttached);
333 168 : if (numAttached > 0.) {
334 148 : MSVehicleType* stype = &veh.getSingularType();
335 148 : stype->setVClass(myLoadedType->getVehicleClass());
336 148 : stype->setGUIShape(myLoadedType->getGuiShape());
337 148 : stype->setLength(myOriginalType->getLength() + numAttached * myLoadedType->getLength());
338 148 : stype->setMass(myOriginalType->getMass() + numAttached * myLoadedType->getMass());
339 : SUMOVTypeParameter& sparam = const_cast<SUMOVTypeParameter&>(stype->getParameter());
340 148 : sparam.carriageLength = myLoadedType->getParameter().carriageLength;
341 148 : sparam.locomotiveLength = myLoadedType->getParameter().locomotiveLength;
342 148 : sparam.carriageGap = myLoadedType->getParameter().carriageGap;
343 : } else {
344 20 : myHolder.replaceVehicleType(myOriginalType);
345 : }
346 168 : if (oldVC != myHolder.getVClass()) {
347 24 : veh.reroute(SIMSTEP, "device." + deviceName() + ".loadedType", veh.getRouterTT());
348 : }
349 : }
350 : }
351 19506 : }
352 :
353 :
354 : void
355 9 : MSDevice_Transportable::saveState(OutputDevice& out) const {
356 9 : out.openTag(SUMO_TAG_DEVICE);
357 9 : out.writeAttr(SUMO_ATTR_ID, getID());
358 : std::vector<std::string> internals;
359 9 : internals.push_back(toString(myStopped));
360 9 : out.writeAttr(SUMO_ATTR_STATE, toString(internals));
361 9 : out.closeTag();
362 9 : }
363 :
364 :
365 : void
366 0 : MSDevice_Transportable::loadState(const SUMOSAXAttributes& attrs) {
367 0 : std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
368 0 : bis >> myStopped;
369 0 : }
370 :
371 :
372 : std::string
373 5 : MSDevice_Transportable::getParameter(const std::string& key) const {
374 5 : if (key == "IDList") {
375 : std::vector<std::string> ids;
376 10 : for (const MSTransportable* t : myTransportables) {
377 5 : ids.push_back(t->getID());
378 : }
379 10 : return toString(ids);
380 5 : }
381 0 : throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
382 : }
383 :
384 :
385 : /****************************************************************************/
|