Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2009-2026 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_Vehroutes.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Laura Bieker
17 : /// @author Michael Behrisch
18 : /// @author Jakob Erdmann
19 : /// @date Fri, 30.01.2009
20 : ///
21 : // A device which collects info on the vehicle trip
22 : /****************************************************************************/
23 : #include <config.h>
24 :
25 : #include <microsim/MSGlobals.h>
26 : #include <microsim/MSNet.h>
27 : #include <microsim/MSLane.h>
28 : #include <microsim/MSEdge.h>
29 : #include <microsim/MSRoute.h>
30 : #include <microsim/MSStop.h>
31 : #include <microsim/MSVehicle.h>
32 : #include <microsim/MSVehicleType.h>
33 : #include <microsim/transportables/MSTransportableControl.h>
34 : #include <utils/vehicle/SUMOVehicle.h>
35 : #include <utils/options/OptionsCont.h>
36 : #include <utils/iodevices/OutputDevice_String.h>
37 : #include <utils/xml/SUMOSAXAttributes.h>
38 : #include "MSDevice_Vehroutes.h"
39 :
40 :
41 : // ===========================================================================
42 : // static member variables
43 : // ===========================================================================
44 : bool MSDevice_Vehroutes::mySaveExits = false;
45 : bool MSDevice_Vehroutes::myLastRouteOnly = false;
46 : bool MSDevice_Vehroutes::myDUAStyle = false;
47 : bool MSDevice_Vehroutes::myWriteCosts = false;
48 : bool MSDevice_Vehroutes::mySorted = false;
49 : bool MSDevice_Vehroutes::myIntendedDepart = false;
50 : bool MSDevice_Vehroutes::myRouteLength = false;
51 : bool MSDevice_Vehroutes::mySkipPTLines = false;
52 : bool MSDevice_Vehroutes::myIncludeIncomplete = false;
53 : bool MSDevice_Vehroutes::myWriteStopPriorEdges = false;
54 : bool MSDevice_Vehroutes::myWriteInternal = false;
55 : MSDevice_Vehroutes::StateListener MSDevice_Vehroutes::myStateListener;
56 : MSDevice_Vehroutes::SortedRouteInfo MSDevice_Vehroutes::myRouteInfos;
57 :
58 :
59 : // ===========================================================================
60 : // method definitions
61 : // ===========================================================================
62 : // ---------------------------------------------------------------------------
63 : // static initialisation methods
64 : // ---------------------------------------------------------------------------
65 : void
66 43118 : MSDevice_Vehroutes::init() {
67 43118 : const OptionsCont& oc = OptionsCont::getOptions();
68 86236 : if (oc.isSet("vehroute-output")) {
69 13306 : OutputDevice::createDeviceByOption("vehroute-output", "routes", "routes_file.xsd");
70 13288 : OutputDevice& od = OutputDevice::getDeviceByOption("vehroute-output");
71 6644 : if (!od.isXML()) {
72 4 : WRITE_WARNING("Vehroute output does not fully support tabular formats. Sorting and stop output will not work.");
73 : }
74 6644 : mySaveExits = oc.getBool("vehroute-output.exit-times");
75 6644 : myLastRouteOnly = oc.getBool("vehroute-output.last-route");
76 6644 : myDUAStyle = oc.getBool("vehroute-output.dua");
77 6644 : myWriteCosts = oc.getBool("vehroute-output.cost");
78 6644 : mySorted = myDUAStyle || oc.getBool("vehroute-output.sorted");
79 6644 : myIntendedDepart = oc.getBool("vehroute-output.intended-depart");
80 6644 : myRouteLength = oc.getBool("vehroute-output.route-length");
81 6644 : mySkipPTLines = oc.getBool("vehroute-output.skip-ptlines");
82 6644 : myIncludeIncomplete = oc.getBool("vehroute-output.incomplete");
83 6644 : myWriteStopPriorEdges = oc.getBool("vehroute-output.stop-edges");
84 6644 : myWriteInternal = oc.getBool("vehroute-output.internal");
85 6644 : MSNet::getInstance()->addVehicleStateListener(&myStateListener);
86 6644 : myRouteInfos.routeOut = &od;
87 : }
88 43112 : }
89 :
90 :
91 : void
92 46292 : MSDevice_Vehroutes::insertOptions(OptionsCont& oc) {
93 46292 : oc.addOptionSubTopic("Vehroutes Device");
94 92584 : insertDefaultAssignmentOptions("vehroute", "Vehroutes Device", oc);
95 46292 : }
96 :
97 :
98 : MSDevice_Vehroutes*
99 6523095 : MSDevice_Vehroutes::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into, int maxRoutes) {
100 6523095 : if (maxRoutes < std::numeric_limits<int>::max()) {
101 2067016 : return new MSDevice_Vehroutes(v, "vehroute_" + v.getID(), maxRoutes);
102 : }
103 5489587 : if (mySkipPTLines && v.getParameter().line != "") {
104 : return nullptr;
105 : }
106 5488319 : OptionsCont& oc = OptionsCont::getOptions();
107 10976638 : if (equippedByDefaultAssignmentOptions(oc, "vehroute", v, oc.isSet("vehroute-output"))) {
108 145699 : if (myLastRouteOnly) {
109 : maxRoutes = 0;
110 : }
111 145699 : myStateListener.myDevices[&v] = new MSDevice_Vehroutes(v, "vehroute_" + v.getID(), maxRoutes);
112 145699 : into.push_back(myStateListener.myDevices[&v]);
113 145699 : return myStateListener.myDevices[&v];
114 : }
115 : return nullptr;
116 : }
117 :
118 :
119 : // ---------------------------------------------------------------------------
120 : // MSDevice_Vehroutes::StateListener-methods
121 : // ---------------------------------------------------------------------------
122 : void
123 566495 : MSDevice_Vehroutes::StateListener::vehicleStateChanged(const SUMOVehicle* const vehicle, MSNet::VehicleState to, const std::string& info) {
124 566495 : if (to == MSNet::VehicleState::NEWROUTE) {
125 : const auto& deviceEntry = myDevices.find(vehicle);
126 112920 : if (deviceEntry != myDevices.end()) {
127 111292 : deviceEntry->second->addRoute(info);
128 : }
129 : }
130 566495 : }
131 :
132 :
133 : // ---------------------------------------------------------------------------
134 : // MSDevice_Vehroutes-methods
135 : // ---------------------------------------------------------------------------
136 1179207 : MSDevice_Vehroutes::MSDevice_Vehroutes(SUMOVehicle& holder, const std::string& id, int maxRoutes) :
137 : MSVehicleDevice(holder, id),
138 1179207 : myCurrentRoute(holder.getRoutePtr()),
139 1179207 : myMaxRoutes(maxRoutes),
140 1179207 : myLastSavedAt(nullptr),
141 1179207 : myLastRouteIndex(-1),
142 1179207 : myDepartLane(-1),
143 1179207 : myDepartPos(-1),
144 1179207 : myDepartSpeed(-1),
145 1179207 : myDepartPosLat(0),
146 1179207 : myStopOut(2) {
147 1179207 : }
148 :
149 :
150 2358288 : MSDevice_Vehroutes::~MSDevice_Vehroutes() {
151 1179144 : myStateListener.myDevices.erase(&myHolder);
152 2358288 : }
153 :
154 :
155 : bool
156 14948377 : MSDevice_Vehroutes::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
157 14948377 : if (reason == MSMoveReminder::NOTIFICATION_DEPARTED) {
158 5251 : if (mySorted && myStateListener.myDevices.count(static_cast<SUMOVehicle*>(&veh)) != 0
159 981275 : && myStateListener.myDevices[static_cast<SUMOVehicle*>(&veh)] == this) {
160 4586 : const SUMOTime departure = myIntendedDepart ? myHolder.getParameter().depart : MSNet::getInstance()->getCurrentTimeStep();
161 4586 : myRouteInfos.departureCounts[departure]++;
162 : }
163 976024 : if (!MSGlobals::gUseMesoSim) {
164 : const MSVehicle& vehicle = static_cast<MSVehicle&>(veh);
165 595735 : myDepartLane = vehicle.getLane()->getIndex();
166 595735 : myDepartPosLat = vehicle.getLateralPositionOnLane();
167 : }
168 976024 : myDepartSpeed = veh.getSpeed();
169 976024 : myDepartPos = veh.getPositionOnLane();
170 : }
171 14948377 : if (myWriteStopPriorEdges) {
172 68 : if (MSGlobals::gUseMesoSim) {
173 48 : const MSEdge* e = veh.getEdge();
174 48 : if (myPriorEdges.empty() || myPriorEdges.back() != e) {
175 12 : myPriorEdges.push_back(e);
176 : }
177 : } else {
178 20 : myPriorEdges.push_back(&enteredLane->getEdge());
179 : }
180 : }
181 14948377 : myLastRouteIndex = myHolder.getRoutePosition();
182 14948377 : return true;
183 : }
184 :
185 :
186 : bool
187 14910754 : MSDevice_Vehroutes::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
188 14910754 : if (mySaveExits && reason != NOTIFICATION_LANE_CHANGE && reason != NOTIFICATION_PARKING && reason != NOTIFICATION_SEGMENT) {
189 345246 : const MSEdge* edge = myWriteInternal ? dynamic_cast<MSBaseVehicle&>(veh).getCurrentEdge() : veh.getEdge();
190 345246 : if (myLastSavedAt != edge) {
191 173174 : myExits.push_back(MSNet::getInstance()->getCurrentTimeStep());
192 173174 : myLastSavedAt = edge;
193 : }
194 : }
195 14910754 : return true;
196 : }
197 :
198 :
199 : void
200 24370 : MSDevice_Vehroutes::notifyStopEnded() {
201 24370 : SUMOVehicleParameter::Stop stop = myHolder.getStops().front().pars;
202 24370 : const bool closeLater = myWriteStopPriorEdges || mySaveExits;
203 24370 : if (mySaveExits) {
204 : // prevent duplicate output
205 1745 : stop.parametersSet &= ~(STOP_STARTED_SET | STOP_ENDED_SET);
206 : }
207 24370 : stop.write(myStopOut, !closeLater);
208 24370 : if (myWriteStopPriorEdges) {
209 : // calculate length
210 16 : double priorEdgesLength = 0;
211 40 : for (int i = 0; i < (int)myPriorEdges.size(); i++) {
212 24 : if (i == 0) {
213 16 : priorEdgesLength += myPriorEdges.at(i)->getLength();
214 8 : } else if (myPriorEdges.at(i)->getID() != myPriorEdges.at(i - 1)->getID()) {
215 8 : priorEdgesLength += myPriorEdges.at(i)->getLength();
216 : }
217 : }
218 16 : myStopOut.writeAttr("priorEdges", myPriorEdges);
219 : myPriorEdges.clear();
220 16 : myStopOut.writeAttr("priorEdgesLength", priorEdgesLength);
221 : }
222 24370 : if (mySaveExits) {
223 1745 : myStopOut.writeAttr(SUMO_ATTR_STARTED, time2string(stop.started));
224 1745 : myStopOut.writeAttr(SUMO_ATTR_ENDED, stop.ended < 0 ? "-1" : time2string(stop.ended));
225 : }
226 24370 : if (closeLater) {
227 3522 : myStopOut.closeTag();
228 : }
229 24370 : }
230 :
231 :
232 : void
233 178220 : MSDevice_Vehroutes::writeXMLRoute(OutputDevice& os, int index) const {
234 11296 : if (index == 0 && !myIncludeIncomplete && myReplacedRoutes[index].route->size() == 2 &&
235 182487 : myReplacedRoutes[index].route->getEdges().front()->isTazConnector() &&
236 0 : myReplacedRoutes[index].route->getEdges().back()->isTazConnector()) {
237 : return;
238 : }
239 : // check if a previous route shall be written
240 : //std::cout << " writeXMLRoute index=" << index << " numReroutes=" << myHolder.getNumberReroutes() << "\n";
241 178220 : const int routesToSkip = myHolder.getParameter().wasSet(VEHPARS_FORCE_REROUTE) ? 1 : 0;
242 178220 : os.openTag(SUMO_TAG_ROUTE);
243 178220 : if (index >= 0) {
244 : assert((int)myReplacedRoutes.size() > index);
245 44072 : if (myDUAStyle || myWriteCosts) {
246 17052 : os.writeAttr(SUMO_ATTR_COST, myReplacedRoutes[index].route->getCosts());
247 : }
248 44072 : if (myWriteCosts) {
249 17052 : os.writeAttr(SUMO_ATTR_SAVINGS, myReplacedRoutes[index].route->getSavings());
250 : }
251 : // write edge on which the vehicle was when the route was valid
252 130753 : os.writeAttr("replacedOnEdge", (myReplacedRoutes[index].edge ?
253 : myReplacedRoutes[index].edge->getID() : ""));
254 44072 : if (myReplacedRoutes[index].lastRouteIndex > 0) {
255 : // do not write the default
256 30225 : os.writeAttr(SUMO_ATTR_REPLACED_ON_INDEX, myReplacedRoutes[index].lastRouteIndex);
257 : }
258 : // write the reason for replacement
259 44072 : os.writeAttr("reason", myReplacedRoutes[index].info);
260 :
261 : // write the time at which the route was replaced
262 44072 : os.writeAttr(SUMO_ATTR_REPLACED_AT_TIME, time2string(myReplacedRoutes[index].time));
263 44072 : os.writeAttr(SUMO_ATTR_PROB, "0");
264 44072 : OutputDevice_String edgesD;
265 : // always write the part that was actually driven and the rest of the current route that wasn't yet driven
266 : int start = 0;
267 206404 : for (int i = routesToSkip; i < index; i++) {
268 162332 : if (myReplacedRoutes[i].edge != nullptr) {
269 161557 : int end = myReplacedRoutes[i].lastRouteIndex;
270 161557 : myReplacedRoutes[i].route->writeEdgeIDs(edgesD, start, end, myWriteInternal, myHolder.getVClass());
271 : }
272 162332 : start = myReplacedRoutes[i].newRouteIndex;
273 : }
274 44072 : myReplacedRoutes[index].route->writeEdgeIDs(edgesD, start, -1, myWriteInternal, myHolder.getVClass());
275 44072 : std::string edgesS = edgesD.getString();
276 : edgesS.pop_back(); // remove last ' '
277 44072 : os.writeAttr(SUMO_ATTR_EDGES, edgesS);
278 44072 : if (myRouteLength) {
279 8558 : const bool includeInternalLengths = MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks();
280 : ConstMSRoutePtr route = myReplacedRoutes[index].route;
281 8558 : const double routeLength = route->getDistanceBetween(myHolder.getDepartPos(), route->getEdges().back()->getLength(),
282 8558 : route->begin(), route->end(), includeInternalLengths);
283 8558 : os.writeAttr("routeLength", routeLength);
284 : }
285 44072 : } else {
286 134148 : if (myDUAStyle || myWriteCosts) {
287 37867 : os.writeAttr(SUMO_ATTR_COST, myHolder.getRoute().getCosts());
288 : }
289 134148 : if (myWriteCosts) {
290 37861 : os.writeAttr(SUMO_ATTR_SAVINGS, myHolder.getRoute().getSavings());
291 : }
292 134148 : OutputDevice_String edgesD;
293 : int numWritten = 0;
294 : int start = 0;
295 134148 : if (myHolder.getNumberReroutes() > 0) {
296 : assert((int)myReplacedRoutes.size() <= myHolder.getNumberReroutes());
297 107753 : for (int i = routesToSkip; i < (int)myReplacedRoutes.size(); i++) {
298 43139 : if (myReplacedRoutes[i].edge != nullptr) {
299 41928 : int end = myReplacedRoutes[i].lastRouteIndex;
300 41928 : numWritten += myReplacedRoutes[i].route->writeEdgeIDs(edgesD, start, end, myWriteInternal, myHolder.getVClass());
301 : }
302 43139 : start = myReplacedRoutes[i].newRouteIndex;
303 : }
304 : }
305 134148 : numWritten += myCurrentRoute->writeEdgeIDs(edgesD, start, -1, myWriteInternal, myHolder.getVClass());
306 134148 : std::string edgesS = edgesD.getString();
307 : edgesS.pop_back(); // remove last ' '
308 134148 : os.writeAttr(SUMO_ATTR_EDGES, edgesS);
309 :
310 134148 : if (mySaveExits) {
311 : std::vector<std::string> exits;
312 152808 : for (SUMOTime t : myExits) {
313 283082 : exits.push_back(time2string(t));
314 : }
315 : assert(numWritten >= (int)myExits.size());
316 22534 : std::vector<std::string> missing(numWritten - (int)myExits.size(), "-1");
317 11267 : exits.insert(exits.end(), missing.begin(), missing.end());
318 11267 : os.writeAttr(SUMO_ATTR_EXITTIMES, exits);
319 11267 : }
320 134148 : }
321 356440 : os.closeTag();
322 : }
323 :
324 :
325 : void
326 132547 : MSDevice_Vehroutes::generateOutput(OutputDevice* /*tripinfoOut*/) const {
327 132547 : writeOutput(true);
328 132547 : }
329 :
330 :
331 : void
332 134154 : MSDevice_Vehroutes::writeOutput(const bool hasArrived) const {
333 134154 : const OptionsCont& oc = OptionsCont::getOptions();
334 134154 : OutputDevice& routeOut = OutputDevice::getDeviceByOption("vehroute-output");
335 134154 : OutputDevice_String stringOut(1);
336 134154 : OutputDevice& od = mySorted && routeOut.isXML() ? stringOut : routeOut;
337 134154 : SUMOVehicleParameter tmp = myHolder.getParameter();
338 134154 : tmp.depart = myIntendedDepart ? myHolder.getParameter().depart : myHolder.getDeparture();
339 134154 : if (!MSGlobals::gUseMesoSim) {
340 98375 : if (tmp.wasSet(VEHPARS_DEPARTLANE_SET)) {
341 15291 : tmp.departLaneProcedure = DepartLaneDefinition::GIVEN;
342 15291 : tmp.departLane = myDepartLane;
343 : }
344 98375 : if (tmp.wasSet(VEHPARS_DEPARTPOSLAT_SET)) {
345 8 : tmp.departPosLatProcedure = (tmp.departPosLatProcedure == DepartPosLatDefinition::RANDOM
346 4 : ? DepartPosLatDefinition::GIVEN_VEHROUTE
347 : : DepartPosLatDefinition::GIVEN);
348 4 : tmp.departPosLat = myDepartPosLat;
349 : }
350 : }
351 134154 : if (tmp.wasSet(VEHPARS_DEPARTPOS_SET)) {
352 72208 : tmp.departPosProcedure = ((tmp.departPosProcedure != DepartPosDefinition::GIVEN
353 36104 : && tmp.departPosProcedure != DepartPosDefinition::STOP)
354 36104 : ? DepartPosDefinition::GIVEN_VEHROUTE
355 : : DepartPosDefinition::GIVEN);
356 36104 : tmp.departPos = myDepartPos;
357 : }
358 134154 : if (tmp.wasSet(VEHPARS_DEPARTSPEED_SET)) {
359 94396 : tmp.departSpeedProcedure = ((tmp.departSpeedProcedure != DepartSpeedDefinition::GIVEN
360 47198 : && tmp.departSpeedProcedure != DepartSpeedDefinition::LIMIT)
361 47198 : ? DepartSpeedDefinition::GIVEN_VEHROUTE
362 : : DepartSpeedDefinition::GIVEN);
363 47198 : tmp.departSpeed = myDepartSpeed;
364 : }
365 400456 : if (oc.getBool("vehroute-output.speedfactor") ||
366 483400 : (oc.isDefault("vehroute-output.speedfactor") && tmp.wasSet(VEHPARS_DEPARTSPEED_SET))) {
367 49198 : tmp.parametersSet |= VEHPARS_SPEEDFACTOR_SET;
368 49198 : tmp.speedFactor = myHolder.getChosenSpeedFactor();
369 : }
370 :
371 134154 : const std::string typeID = myHolder.getVehicleType().getID() != DEFAULT_VTYPE_ID ? myHolder.getVehicleType().getID() : "";
372 134154 : tmp.write(od, oc, SUMO_TAG_VEHICLE, typeID);
373 134154 : if (hasArrived) {
374 265094 : od.writeAttr("arrival", time2string(MSNet::getInstance()->getCurrentTimeStep()));
375 : }
376 134154 : if (myRouteLength) {
377 1134 : const bool includeInternalLengths = MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks();
378 1134 : const double finalPos = hasArrived ? myHolder.getArrivalPos() : myHolder.getPositionOnLane();
379 2268 : const double routeLength = myHolder.getRoute().getDistanceBetween(myHolder.getDepartPos(), finalPos,
380 1134 : myHolder.getRoute().begin(), myHolder.getCurrentRouteEdge(), includeInternalLengths);
381 1134 : od.writeAttr("routeLength", routeLength);
382 : }
383 134154 : if (myDUAStyle) {
384 12 : const RandomDistributor<ConstMSRoutePtr>* const routeDist = MSRoute::distDictionary("!" + myHolder.getID());
385 12 : if (routeDist != nullptr) {
386 : const std::vector<ConstMSRoutePtr>& routes = routeDist->getVals();
387 6 : unsigned index = 0;
388 6 : while (index < routes.size() && routes[index] != myCurrentRoute) {
389 0 : ++index;
390 : }
391 6 : od.openTag(SUMO_TAG_ROUTE_DISTRIBUTION).writeAttr(SUMO_ATTR_LAST, index);
392 : const std::vector<double>& probs = routeDist->getProbs();
393 18 : for (int i = 0; i < (int)routes.size(); ++i) {
394 12 : od.setPrecision();
395 12 : od.openTag(SUMO_TAG_ROUTE);
396 12 : od.writeAttr(SUMO_ATTR_COST, routes[i]->getCosts());
397 12 : if (myWriteCosts) {
398 0 : od.writeAttr(SUMO_ATTR_SAVINGS, routes[i]->getSavings());
399 : }
400 12 : od.setPrecision(8);
401 12 : od.writeAttr(SUMO_ATTR_PROB, probs[i]);
402 12 : od.setPrecision();
403 12 : OutputDevice_String edgesD;
404 12 : routes[i]->writeEdgeIDs(edgesD, 0, -1, myWriteInternal, myHolder.getVClass());
405 12 : std::string edgesS = edgesD.getString();
406 : edgesS.pop_back(); // remove last ' '
407 12 : od.writeAttr(SUMO_ATTR_EDGES, edgesS);
408 24 : od.closeTag();
409 12 : }
410 12 : od.closeTag();
411 : } else {
412 6 : writeXMLRoute(od);
413 : }
414 : } else {
415 : std::string dummyMsg;
416 134142 : const int routesToSkip = (myHolder.getParameter().wasSet(VEHPARS_FORCE_REROUTE)
417 55251 : && !myIncludeIncomplete
418 55131 : && myReplacedRoutes.size() > 0
419 242847 : && !myHolder.hasValidRoute(dummyMsg, myReplacedRoutes[0].route) ? 1 : 0);
420 134142 : if ((int)myReplacedRoutes.size() > routesToSkip) {
421 25099 : od.openTag(SUMO_TAG_ROUTE_DISTRIBUTION);
422 69171 : for (int i = routesToSkip; i < (int)myReplacedRoutes.size(); ++i) {
423 44072 : writeXMLRoute(od, i);
424 : }
425 25099 : writeXMLRoute(od);
426 50198 : od.closeTag();
427 : } else {
428 109043 : writeXMLRoute(od);
429 : }
430 : }
431 134154 : if (routeOut.isXML()) {
432 267608 : od << myStopOut.getString();
433 : }
434 134154 : myHolder.getParameter().writeParams(od);
435 134154 : od.closeTag();
436 134154 : od.lf();
437 134154 : if (mySorted && routeOut.isXML()) {
438 : // numerical id reflects loading order
439 8844 : writeSortedOutput(&myRouteInfos, tmp.depart, myHolder.getNumericalID(), stringOut.getString());
440 : }
441 134154 : }
442 :
443 :
444 : ConstMSRoutePtr
445 0 : MSDevice_Vehroutes::getRoute(int index) const {
446 0 : if (index < (int)myReplacedRoutes.size()) {
447 0 : return myReplacedRoutes[index].route;
448 : } else {
449 : return nullptr;
450 : }
451 : }
452 :
453 :
454 : void
455 111292 : MSDevice_Vehroutes::addRoute(const std::string& info) {
456 111292 : if (myMaxRoutes > 0) {
457 : //std::cout << SIMTIME << " " << getID() << " departed=" << myHolder.hasDeparted() << " lastIndex=" << myLastRouteIndex << " start=" << myHolder.getRoutePosition() << "\n";
458 495508 : myReplacedRoutes.push_back(RouteReplaceInfo(
459 147191 : myHolder.hasDeparted() ? myHolder.getEdge() : nullptr,
460 : MSNet::getInstance()->getCurrentTimeStep(), myCurrentRoute, info,
461 : myLastRouteIndex,
462 147191 : myHolder.hasDeparted() ? myHolder.getRoutePosition() : 0));
463 100563 : if ((int)myReplacedRoutes.size() > myMaxRoutes) {
464 : myReplacedRoutes.erase(myReplacedRoutes.begin());
465 : }
466 : }
467 111292 : myCurrentRoute = myHolder.getRoutePtr();
468 111292 : }
469 :
470 :
471 : void
472 41290 : MSDevice_Vehroutes::writePendingOutput(const bool includeUnfinished) {
473 41290 : MSNet* const net = MSNet::getInstance();
474 :
475 41290 : if (!includeUnfinished) {
476 40809 : if (mySorted) {
477 118 : for (const auto& routeInfo : myRouteInfos.routeXML) {
478 36 : for (const auto& rouXML : routeInfo.second) {
479 20 : (*myRouteInfos.routeOut) << rouXML.second;
480 : }
481 : }
482 102 : if (net->hasPersons()) {
483 23 : const SortedRouteInfo& personRouteInfos = net->getPersonControl().getRouteInfo();
484 23 : if (personRouteInfos.routeOut != myRouteInfos.routeOut) {
485 0 : for (const auto& routeInfo : personRouteInfos.routeXML) {
486 0 : for (const auto& rouXML : routeInfo.second) {
487 0 : (*personRouteInfos.routeOut) << rouXML.second;
488 : }
489 : }
490 : }
491 : }
492 : }
493 40809 : return;
494 : }
495 2088 : for (const auto& it : myStateListener.myDevices) {
496 1607 : if (it.first->hasDeparted()) {
497 1607 : if (it.first->isStopped()) {
498 869 : it.second->notifyStopEnded();
499 : }
500 1607 : it.second->writeOutput(false);
501 : }
502 : }
503 : // unfinished persons
504 481 : if (net->hasPersons()) {
505 271 : MSTransportableControl& pc = net->getPersonControl();
506 377 : while (pc.loadedBegin() != pc.loadedEnd()) {
507 106 : pc.erase(pc.loadedBegin()->second);
508 : }
509 : }
510 : // Flush any remaining sorted outputs that may still be buffered
511 481 : if (mySorted) {
512 4 : for (const auto& routeInfo : myRouteInfos.routeXML) {
513 4 : for (const auto& rouXML : routeInfo.second) {
514 2 : (*myRouteInfos.routeOut) << rouXML.second;
515 : }
516 : }
517 2 : if (net->hasPersons()) {
518 0 : const SortedRouteInfo& personRouteInfos = net->getPersonControl().getRouteInfo();
519 0 : if (personRouteInfos.routeOut != myRouteInfos.routeOut) {
520 0 : for (const auto& routeInfo : personRouteInfos.routeXML) {
521 0 : for (const auto& rouXML : routeInfo.second) {
522 0 : (*personRouteInfos.routeOut) << rouXML.second;
523 : }
524 : }
525 : }
526 : }
527 : }
528 : }
529 :
530 :
531 : void
532 108 : MSDevice_Vehroutes::registerTransportableDepart(SUMOTime depart) {
533 108 : myRouteInfos.departureCounts[depart]++;
534 108 : }
535 :
536 :
537 : void
538 4544 : MSDevice_Vehroutes::writeSortedOutput(MSDevice_Vehroutes::SortedRouteInfo* routeInfo, SUMOTime depart, const SUMOTrafficObject::NumericalID id, const std::string& xmlOutput) {
539 4544 : if (routeInfo->routeOut == myRouteInfos.routeOut) {
540 : routeInfo = &myRouteInfos;
541 : }
542 4544 : routeInfo->routeXML[depart][id] = xmlOutput;
543 4544 : routeInfo->departureCounts[depart]--;
544 : std::map<const SUMOTime, int>::iterator it = routeInfo->departureCounts.begin();
545 7806 : while (it != routeInfo->departureCounts.end() && it->second == 0) {
546 7784 : for (const auto& rouXML : routeInfo->routeXML[it->first]) {
547 4522 : (*routeInfo->routeOut) << rouXML.second;
548 : }
549 : routeInfo->routeXML.erase(it->first);
550 : it = routeInfo->departureCounts.erase(it);
551 : }
552 4544 : }
553 :
554 :
555 : void
556 3167 : MSDevice_Vehroutes::saveState(OutputDevice& out) const {
557 3167 : out.openTag(SUMO_TAG_DEVICE);
558 3167 : out.writeAttr(SUMO_ATTR_ID, getID());
559 : std::vector<std::string> internals;
560 3167 : if (!MSGlobals::gUseMesoSim) {
561 1846 : internals.push_back(toString(myDepartLane));
562 3692 : internals.push_back(toString(myDepartPosLat));
563 : }
564 3167 : internals.push_back(toString(myDepartSpeed));
565 3167 : internals.push_back(toString(myDepartPos));
566 3167 : internals.push_back(toString(myReplacedRoutes.size()));
567 6020 : for (int i = 0; i < (int)myReplacedRoutes.size(); ++i) {
568 2853 : const std::string replacedOnEdge = myReplacedRoutes[i].edge == nullptr ? "!NULL" : myReplacedRoutes[i].edge->getID();
569 2853 : internals.push_back(replacedOnEdge);
570 5706 : internals.push_back(toString(myReplacedRoutes[i].time));
571 2853 : internals.push_back(myReplacedRoutes[i].route->getID());
572 2853 : internals.push_back(myReplacedRoutes[i].info);
573 2853 : internals.push_back(toString(myReplacedRoutes[i].lastRouteIndex));
574 5706 : internals.push_back(toString(myReplacedRoutes[i].newRouteIndex));
575 : }
576 3167 : out.writeAttr(SUMO_ATTR_STATE, toString(internals));
577 3167 : if (mySaveExits && myExits.size() > 0) {
578 11 : out.writeAttr(SUMO_ATTR_EXITTIMES, myExits);
579 11 : out.writeAttr(SUMO_ATTR_EDGE, myLastSavedAt->getID());
580 : }
581 3167 : out.closeTag();
582 3167 : }
583 :
584 :
585 : void
586 2263 : MSDevice_Vehroutes::loadState(const SUMOSAXAttributes& attrs) {
587 2263 : std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
588 2263 : if (!MSGlobals::gUseMesoSim) {
589 1319 : bis >> myDepartLane;
590 1319 : bis >> myDepartPosLat;
591 : }
592 2263 : bis >> myDepartSpeed;
593 2263 : bis >> myDepartPos;
594 : int size;
595 2263 : bis >> size;
596 4093 : for (int i = 0; i < size; ++i) {
597 : std::string edgeID;
598 : SUMOTime time;
599 : std::string routeID;
600 : std::string info;
601 : int lastIndex;
602 : int newIndex;
603 1830 : bis >> edgeID;
604 : bis >> time;
605 1830 : bis >> routeID;
606 1830 : bis >> info;
607 1830 : bis >> lastIndex;
608 1830 : bis >> newIndex;
609 :
610 1830 : ConstMSRoutePtr route = MSRoute::dictionary(routeID);
611 1830 : if (route != nullptr) {
612 2841 : myReplacedRoutes.push_back(RouteReplaceInfo(MSEdge::dictionary(edgeID), time, route, info, lastIndex, newIndex));
613 : }
614 : }
615 2263 : if (mySaveExits && attrs.hasAttribute(SUMO_ATTR_EXITTIMES)) {
616 11 : bool ok = true;
617 30 : for (const std::string& t : attrs.get<std::vector<std::string> >(SUMO_ATTR_EXITTIMES, nullptr, ok)) {
618 19 : myExits.push_back(StringUtils::toLong(t));
619 11 : }
620 11 : if (attrs.hasAttribute(SUMO_ATTR_EDGE)) {
621 11 : myLastSavedAt = MSEdge::dictionary(attrs.getString(SUMO_ATTR_EDGE));
622 : }
623 : }
624 2263 : if (myHolder.hasDeparted()) {
625 787 : myLastRouteIndex = myHolder.getRoutePosition();
626 : }
627 2263 : }
628 :
629 :
630 : /****************************************************************************/
|