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 43193 : MSDevice_Vehroutes::init() {
67 43193 : const OptionsCont& oc = OptionsCont::getOptions();
68 86386 : if (oc.isSet("vehroute-output")) {
69 13418 : OutputDevice::createDeviceByOption("vehroute-output", "routes", "routes_file.xsd");
70 13400 : OutputDevice& od = OutputDevice::getDeviceByOption("vehroute-output");
71 6700 : if (!od.isXML()) {
72 4 : WRITE_WARNING("Vehroute output does not fully support tabular formats. Sorting and stop output will not work.");
73 : }
74 6700 : mySaveExits = oc.getBool("vehroute-output.exit-times");
75 6700 : myLastRouteOnly = oc.getBool("vehroute-output.last-route");
76 6700 : myDUAStyle = oc.getBool("vehroute-output.dua");
77 6700 : myWriteCosts = oc.getBool("vehroute-output.cost");
78 6700 : mySorted = myDUAStyle || oc.getBool("vehroute-output.sorted");
79 6700 : myIntendedDepart = oc.getBool("vehroute-output.intended-depart");
80 6700 : myRouteLength = oc.getBool("vehroute-output.route-length");
81 6700 : mySkipPTLines = oc.getBool("vehroute-output.skip-ptlines");
82 6700 : myIncludeIncomplete = oc.getBool("vehroute-output.incomplete");
83 6700 : myWriteStopPriorEdges = oc.getBool("vehroute-output.stop-edges");
84 6700 : myWriteInternal = oc.getBool("vehroute-output.internal");
85 6700 : MSNet::getInstance()->addVehicleStateListener(&myStateListener);
86 6700 : myRouteInfos.routeOut = &od;
87 : }
88 43187 : }
89 :
90 :
91 : void
92 46427 : MSDevice_Vehroutes::insertOptions(OptionsCont& oc) {
93 46427 : oc.addOptionSubTopic("Vehroutes Device");
94 92854 : insertDefaultAssignmentOptions("vehroute", "Vehroutes Device", oc);
95 46427 : }
96 :
97 :
98 : MSDevice_Vehroutes*
99 6531592 : MSDevice_Vehroutes::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into, int maxRoutes) {
100 6531592 : if (maxRoutes < std::numeric_limits<int>::max()) {
101 2069926 : return new MSDevice_Vehroutes(v, "vehroute_" + v.getID(), maxRoutes);
102 : }
103 5496629 : if (mySkipPTLines && v.getParameter().line != "") {
104 : return nullptr;
105 : }
106 5495361 : OptionsCont& oc = OptionsCont::getOptions();
107 10990722 : if (equippedByDefaultAssignmentOptions(oc, "vehroute", v, oc.isSet("vehroute-output"))) {
108 146119 : if (myLastRouteOnly) {
109 : maxRoutes = 0;
110 : }
111 146119 : myStateListener.myDevices[&v] = new MSDevice_Vehroutes(v, "vehroute_" + v.getID(), maxRoutes);
112 146119 : into.push_back(myStateListener.myDevices[&v]);
113 146119 : return myStateListener.myDevices[&v];
114 : }
115 : return nullptr;
116 : }
117 :
118 :
119 : // ---------------------------------------------------------------------------
120 : // MSDevice_Vehroutes::StateListener-methods
121 : // ---------------------------------------------------------------------------
122 : void
123 567798 : MSDevice_Vehroutes::StateListener::vehicleStateChanged(const SUMOVehicle* const vehicle, MSNet::VehicleState to, const std::string& info) {
124 567798 : if (to == MSNet::VehicleState::NEWROUTE) {
125 : const auto& deviceEntry = myDevices.find(vehicle);
126 113081 : if (deviceEntry != myDevices.end()) {
127 111472 : deviceEntry->second->addRoute(info);
128 : }
129 : }
130 567798 : }
131 :
132 :
133 : // ---------------------------------------------------------------------------
134 : // MSDevice_Vehroutes-methods
135 : // ---------------------------------------------------------------------------
136 1181082 : MSDevice_Vehroutes::MSDevice_Vehroutes(SUMOVehicle& holder, const std::string& id, int maxRoutes) :
137 : MSVehicleDevice(holder, id),
138 1181082 : myCurrentRoute(holder.getRoutePtr()),
139 1181082 : myMaxRoutes(maxRoutes),
140 1181082 : myLastSavedAt(nullptr),
141 1181082 : myLastRouteIndex(-1),
142 1181082 : myDepartLane(-1),
143 1181082 : myDepartPos(-1),
144 1181082 : myDepartSpeed(-1),
145 1181082 : myDepartPosLat(0),
146 1181082 : myStopOut(2) {
147 : std::string dummyMsg;
148 2362164 : myCurrentValid = myHolder.hasValidRoute(dummyMsg, myCurrentRoute);
149 1181082 : }
150 :
151 :
152 2362020 : MSDevice_Vehroutes::~MSDevice_Vehroutes() {
153 1181010 : myStateListener.myDevices.erase(&myHolder);
154 2362020 : }
155 :
156 :
157 : bool
158 14954920 : MSDevice_Vehroutes::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
159 14954920 : if (reason == MSMoveReminder::NOTIFICATION_DEPARTED) {
160 5251 : if (mySorted && myStateListener.myDevices.count(static_cast<SUMOVehicle*>(&veh)) != 0
161 982976 : && myStateListener.myDevices[static_cast<SUMOVehicle*>(&veh)] == this) {
162 4586 : const SUMOTime departure = myIntendedDepart ? myHolder.getParameter().depart : MSNet::getInstance()->getCurrentTimeStep();
163 4586 : myRouteInfos.departureCounts[departure]++;
164 : }
165 977725 : if (!MSGlobals::gUseMesoSim) {
166 : const MSVehicle& vehicle = static_cast<MSVehicle&>(veh);
167 597357 : myDepartLane = vehicle.getLane()->getIndex();
168 597357 : myDepartPosLat = vehicle.getLateralPositionOnLane();
169 : }
170 977725 : myDepartSpeed = veh.getSpeed();
171 977725 : myDepartPos = veh.getPositionOnLane();
172 : }
173 14954920 : if (myWriteStopPriorEdges) {
174 68 : if (MSGlobals::gUseMesoSim) {
175 48 : const MSEdge* e = veh.getEdge();
176 48 : if (myPriorEdges.empty() || myPriorEdges.back() != e) {
177 12 : myPriorEdges.push_back(e);
178 : }
179 : } else {
180 20 : myPriorEdges.push_back(&enteredLane->getEdge());
181 : }
182 : }
183 14954920 : myLastRouteIndex = myHolder.getRoutePosition();
184 14954920 : return true;
185 : }
186 :
187 :
188 : bool
189 14917158 : MSDevice_Vehroutes::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
190 14917158 : if (mySaveExits && reason != NOTIFICATION_LANE_CHANGE && reason != NOTIFICATION_PARKING && reason != NOTIFICATION_SEGMENT) {
191 345036 : const MSEdge* edge = myWriteInternal ? dynamic_cast<MSBaseVehicle&>(veh).getCurrentEdge() : veh.getEdge();
192 345036 : if (myLastSavedAt != edge) {
193 173077 : myExits.push_back(MSNet::getInstance()->getCurrentTimeStep());
194 173077 : myLastSavedAt = edge;
195 : }
196 : }
197 14917158 : return true;
198 : }
199 :
200 :
201 : void
202 24375 : MSDevice_Vehroutes::notifyStopEnded() {
203 24375 : SUMOVehicleParameter::Stop stop = myHolder.getStops().front().pars;
204 24375 : const bool closeLater = myWriteStopPriorEdges || mySaveExits;
205 24375 : if (mySaveExits) {
206 : // prevent duplicate output
207 1745 : stop.parametersSet &= ~(STOP_STARTED_SET | STOP_ENDED_SET);
208 : }
209 24375 : stop.write(myStopOut, !closeLater);
210 24375 : if (myWriteStopPriorEdges) {
211 : // calculate length
212 16 : double priorEdgesLength = 0;
213 40 : for (int i = 0; i < (int)myPriorEdges.size(); i++) {
214 24 : if (i == 0) {
215 16 : priorEdgesLength += myPriorEdges.at(i)->getLength();
216 8 : } else if (myPriorEdges.at(i)->getID() != myPriorEdges.at(i - 1)->getID()) {
217 8 : priorEdgesLength += myPriorEdges.at(i)->getLength();
218 : }
219 : }
220 16 : myStopOut.writeAttr("priorEdges", myPriorEdges);
221 : myPriorEdges.clear();
222 16 : myStopOut.writeAttr("priorEdgesLength", priorEdgesLength);
223 : }
224 24375 : if (mySaveExits) {
225 1745 : myStopOut.writeAttr(SUMO_ATTR_STARTED, time2string(stop.started));
226 1745 : myStopOut.writeAttr(SUMO_ATTR_ENDED, stop.ended < 0 ? "-1" : time2string(stop.ended));
227 : }
228 24375 : if (closeLater) {
229 3522 : myStopOut.closeTag();
230 : }
231 24375 : }
232 :
233 :
234 : void
235 178641 : MSDevice_Vehroutes::writeXMLRoute(OutputDevice& os, int index) const {
236 11333 : if (index == 0 && !myIncludeIncomplete && myReplacedRoutes[index].route->size() == 2 &&
237 182894 : myReplacedRoutes[index].route->getEdges().front()->isTazConnector() &&
238 0 : myReplacedRoutes[index].route->getEdges().back()->isTazConnector()) {
239 : return;
240 : }
241 : // check if a previous route shall be written
242 : //std::cout << " writeXMLRoute index=" << index << " numReroutes=" << myHolder.getNumberReroutes() << "\n";
243 178641 : const int routesToSkip = myHolder.getParameter().wasSet(VEHPARS_FORCE_REROUTE) ? 1 : 0;
244 178641 : os.openTag(SUMO_TAG_ROUTE);
245 178641 : if (index >= 0) {
246 : assert((int)myReplacedRoutes.size() > index);
247 44088 : if (myDUAStyle || myWriteCosts) {
248 17021 : os.writeAttr(SUMO_ATTR_COST, myReplacedRoutes[index].route->getCosts());
249 : }
250 44088 : if (myWriteCosts) {
251 17021 : os.writeAttr(SUMO_ATTR_SAVINGS, myReplacedRoutes[index].route->getSavings());
252 : }
253 : // write edge on which the vehicle was when the route was valid
254 130908 : os.writeAttr("replacedOnEdge", (myReplacedRoutes[index].edge ?
255 : myReplacedRoutes[index].edge->getID() : ""));
256 44088 : if (myReplacedRoutes[index].lastRouteIndex > 0) {
257 : // do not write the default
258 30189 : os.writeAttr(SUMO_ATTR_REPLACED_ON_INDEX, myReplacedRoutes[index].lastRouteIndex);
259 : }
260 : // write the reason for replacement
261 44088 : os.writeAttr("reason", myReplacedRoutes[index].info);
262 :
263 : // write the time at which the route was replaced
264 44088 : os.writeAttr(SUMO_ATTR_REPLACED_AT_TIME, time2string(myReplacedRoutes[index].time));
265 44088 : os.writeAttr(SUMO_ATTR_PROB, "0");
266 44088 : OutputDevice_String edgesD;
267 : // always write the part that was actually driven and the rest of the current route that wasn't yet driven
268 : int start = 0;
269 205546 : for (int i = routesToSkip; i < index; i++) {
270 161458 : if (myReplacedRoutes[i].edge != nullptr) {
271 160683 : int end = myReplacedRoutes[i].lastRouteIndex;
272 160683 : myReplacedRoutes[i].route->writeEdgeIDs(edgesD, start, end, myWriteInternal, myHolder.getVClass());
273 : }
274 161458 : start = myReplacedRoutes[i].newRouteIndex;
275 : }
276 44088 : myReplacedRoutes[index].route->writeEdgeIDs(edgesD, start, -1, myWriteInternal, myHolder.getVClass());
277 44088 : std::string edgesS = edgesD.getString();
278 : edgesS.pop_back(); // remove last ' '
279 44088 : os.writeAttr(SUMO_ATTR_EDGES, edgesS);
280 44088 : if (myRouteLength) {
281 8527 : const bool includeInternalLengths = MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks();
282 : ConstMSRoutePtr route = myReplacedRoutes[index].route;
283 8527 : const double routeLength = route->getDistanceBetween(myHolder.getDepartPos(), route->getEdges().back()->getLength(),
284 8527 : route->begin(), route->end(), includeInternalLengths);
285 8527 : os.writeAttr("routeLength", routeLength);
286 : }
287 44088 : } else {
288 134553 : if (myDUAStyle || myWriteCosts) {
289 37867 : os.writeAttr(SUMO_ATTR_COST, myHolder.getRoute().getCosts());
290 : }
291 134553 : if (myWriteCosts) {
292 37861 : os.writeAttr(SUMO_ATTR_SAVINGS, myHolder.getRoute().getSavings());
293 : }
294 134553 : OutputDevice_String edgesD;
295 : int numWritten = 0;
296 : int start = 0;
297 134553 : if (myHolder.getNumberReroutes() > 0) {
298 : assert((int)myReplacedRoutes.size() <= myHolder.getNumberReroutes());
299 108110 : for (int i = routesToSkip; i < (int)myReplacedRoutes.size(); i++) {
300 43299 : if (myReplacedRoutes[i].edge != nullptr) {
301 42087 : int end = myReplacedRoutes[i].lastRouteIndex;
302 42087 : numWritten += myReplacedRoutes[i].route->writeEdgeIDs(edgesD, start, end, myWriteInternal, myHolder.getVClass());
303 : }
304 43299 : start = myReplacedRoutes[i].newRouteIndex;
305 : }
306 : }
307 134553 : numWritten += myCurrentRoute->writeEdgeIDs(edgesD, start, -1, myWriteInternal, myHolder.getVClass());
308 134553 : std::string edgesS = edgesD.getString();
309 : edgesS.pop_back(); // remove last ' '
310 134553 : os.writeAttr(SUMO_ATTR_EDGES, edgesS);
311 :
312 134553 : if (mySaveExits) {
313 : std::vector<std::string> exits;
314 152711 : for (SUMOTime t : myExits) {
315 282888 : exits.push_back(time2string(t));
316 : }
317 : assert(numWritten >= (int)myExits.size());
318 22534 : std::vector<std::string> missing(numWritten - (int)myExits.size(), "-1");
319 11267 : exits.insert(exits.end(), missing.begin(), missing.end());
320 11267 : os.writeAttr(SUMO_ATTR_EXITTIMES, exits);
321 11267 : }
322 134553 : }
323 357282 : os.closeTag();
324 : }
325 :
326 :
327 : void
328 132952 : MSDevice_Vehroutes::generateOutput(OutputDevice* /*tripinfoOut*/) const {
329 132952 : writeOutput(true);
330 132952 : }
331 :
332 :
333 : void
334 134559 : MSDevice_Vehroutes::writeOutput(const bool hasArrived) const {
335 134559 : const OptionsCont& oc = OptionsCont::getOptions();
336 134559 : OutputDevice& routeOut = OutputDevice::getDeviceByOption("vehroute-output");
337 134559 : OutputDevice_String stringOut(1);
338 134559 : OutputDevice& od = mySorted && routeOut.isXML() ? stringOut : routeOut;
339 134559 : SUMOVehicleParameter tmp = myHolder.getParameter();
340 134559 : tmp.depart = myIntendedDepart ? myHolder.getParameter().depart : myHolder.getDeparture();
341 134559 : if (!MSGlobals::gUseMesoSim) {
342 98715 : if (tmp.wasSet(VEHPARS_DEPARTLANE_SET)) {
343 15434 : tmp.departLaneProcedure = DepartLaneDefinition::GIVEN;
344 15434 : tmp.departLane = myDepartLane;
345 : }
346 98715 : if (tmp.wasSet(VEHPARS_DEPARTPOSLAT_SET)) {
347 8 : tmp.departPosLatProcedure = (tmp.departPosLatProcedure == DepartPosLatDefinition::RANDOM
348 4 : ? DepartPosLatDefinition::GIVEN_VEHROUTE
349 : : DepartPosLatDefinition::GIVEN);
350 4 : tmp.departPosLat = myDepartPosLat;
351 : }
352 : }
353 134559 : if (tmp.wasSet(VEHPARS_DEPARTPOS_SET)) {
354 72210 : tmp.departPosProcedure = ((tmp.departPosProcedure != DepartPosDefinition::GIVEN
355 36105 : && tmp.departPosProcedure != DepartPosDefinition::STOP)
356 36105 : ? DepartPosDefinition::GIVEN_VEHROUTE
357 : : DepartPosDefinition::GIVEN);
358 36105 : tmp.departPos = myDepartPos;
359 : }
360 134559 : if (tmp.wasSet(VEHPARS_DEPARTSPEED_SET)) {
361 94688 : tmp.departSpeedProcedure = ((tmp.departSpeedProcedure != DepartSpeedDefinition::GIVEN
362 47344 : && tmp.departSpeedProcedure != DepartSpeedDefinition::LIMIT)
363 47344 : ? DepartSpeedDefinition::GIVEN_VEHROUTE
364 : : DepartSpeedDefinition::GIVEN);
365 47344 : tmp.departSpeed = myDepartSpeed;
366 : }
367 401671 : if (oc.getBool("vehroute-output.speedfactor") ||
368 484874 : (oc.isDefault("vehroute-output.speedfactor") && tmp.wasSet(VEHPARS_DEPARTSPEED_SET))) {
369 49344 : tmp.parametersSet |= VEHPARS_SPEEDFACTOR_SET;
370 49344 : tmp.speedFactor = myHolder.getChosenSpeedFactor();
371 : }
372 :
373 134559 : const std::string typeID = myHolder.getVehicleType().getID() != DEFAULT_VTYPE_ID ? myHolder.getVehicleType().getID() : "";
374 134559 : tmp.write(od, oc, SUMO_TAG_VEHICLE, typeID);
375 134559 : if (hasArrived) {
376 265904 : od.writeAttr("arrival", time2string(MSNet::getInstance()->getCurrentTimeStep()));
377 : }
378 134559 : if (myRouteLength) {
379 1134 : const bool includeInternalLengths = MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks();
380 1134 : const double finalPos = hasArrived ? myHolder.getArrivalPos() : myHolder.getPositionOnLane();
381 2268 : const double routeLength = myHolder.getRoute().getDistanceBetween(myHolder.getDepartPos(), finalPos,
382 1134 : myHolder.getRoute().begin(), myHolder.getCurrentRouteEdge(), includeInternalLengths);
383 1134 : od.writeAttr("routeLength", routeLength);
384 : }
385 134559 : if (myDUAStyle) {
386 12 : const RandomDistributor<ConstMSRoutePtr>* const routeDist = MSRoute::distDictionary("!" + myHolder.getID());
387 12 : if (routeDist != nullptr) {
388 : const std::vector<ConstMSRoutePtr>& routes = routeDist->getVals();
389 6 : unsigned index = 0;
390 6 : while (index < routes.size() && routes[index] != myCurrentRoute) {
391 0 : ++index;
392 : }
393 6 : od.openTag(SUMO_TAG_ROUTE_DISTRIBUTION).writeAttr(SUMO_ATTR_LAST, index);
394 : const std::vector<double>& probs = routeDist->getProbs();
395 18 : for (int i = 0; i < (int)routes.size(); ++i) {
396 12 : od.setPrecision();
397 12 : od.openTag(SUMO_TAG_ROUTE);
398 12 : od.writeAttr(SUMO_ATTR_COST, routes[i]->getCosts());
399 12 : if (myWriteCosts) {
400 0 : od.writeAttr(SUMO_ATTR_SAVINGS, routes[i]->getSavings());
401 : }
402 12 : od.setPrecision(8);
403 12 : od.writeAttr(SUMO_ATTR_PROB, probs[i]);
404 12 : od.setPrecision();
405 12 : OutputDevice_String edgesD;
406 12 : routes[i]->writeEdgeIDs(edgesD, 0, -1, myWriteInternal, myHolder.getVClass());
407 12 : std::string edgesS = edgesD.getString();
408 : edgesS.pop_back(); // remove last ' '
409 12 : od.writeAttr(SUMO_ATTR_EDGES, edgesS);
410 24 : od.closeTag();
411 12 : }
412 12 : od.closeTag();
413 : } else {
414 6 : writeXMLRoute(od);
415 : }
416 : } else {
417 : std::string dummyMsg;
418 134547 : const int routesToSkip = (myHolder.getParameter().wasSet(VEHPARS_FORCE_REROUTE)
419 55266 : && !myIncludeIncomplete
420 55146 : && myReplacedRoutes.size() > 0
421 188017 : && !myReplacedRoutes[0].isValid ? 1 : 0);
422 134547 : if ((int)myReplacedRoutes.size() > routesToSkip) {
423 25180 : od.openTag(SUMO_TAG_ROUTE_DISTRIBUTION);
424 69268 : for (int i = routesToSkip; i < (int)myReplacedRoutes.size(); ++i) {
425 44088 : writeXMLRoute(od, i);
426 : }
427 25180 : writeXMLRoute(od);
428 50360 : od.closeTag();
429 : } else {
430 109367 : writeXMLRoute(od);
431 : }
432 : }
433 134559 : if (routeOut.isXML()) {
434 268418 : od << myStopOut.getString();
435 : }
436 134559 : myHolder.getParameter().writeParams(od);
437 134559 : od.closeTag();
438 134559 : od.lf();
439 134559 : if (mySorted && routeOut.isXML()) {
440 : // numerical id reflects loading order
441 8844 : writeSortedOutput(&myRouteInfos, tmp.depart, myHolder.getNumericalID(), stringOut.getString());
442 : }
443 134559 : }
444 :
445 :
446 : ConstMSRoutePtr
447 0 : MSDevice_Vehroutes::getRoute(int index) const {
448 0 : if (index < (int)myReplacedRoutes.size()) {
449 0 : return myReplacedRoutes[index].route;
450 : } else {
451 : return nullptr;
452 : }
453 : }
454 :
455 :
456 : void
457 111472 : MSDevice_Vehroutes::addRoute(const std::string& info) {
458 111472 : if (myMaxRoutes > 0) {
459 : //std::cout << SIMTIME << " " << getID() << " departed=" << myHolder.hasDeparted() << " lastIndex=" << myLastRouteIndex << " start=" << myHolder.getRoutePosition() << "\n";
460 496542 : myReplacedRoutes.push_back(RouteReplaceInfo(
461 147531 : myHolder.hasDeparted() ? myHolder.getEdge() : nullptr,
462 : MSNet::getInstance()->getCurrentTimeStep(), myCurrentRoute, info,
463 : myLastRouteIndex,
464 46791 : myHolder.hasDeparted() ? myHolder.getRoutePosition() : 0,
465 100740 : myCurrentValid));
466 100740 : if ((int)myReplacedRoutes.size() > myMaxRoutes) {
467 : myReplacedRoutes.erase(myReplacedRoutes.begin());
468 : }
469 : }
470 : std::string dummyMsg;
471 111472 : myCurrentRoute = myHolder.getRoutePtr();
472 222944 : myCurrentValid = myHolder.hasValidRoute(dummyMsg, myCurrentRoute);
473 111472 : }
474 :
475 :
476 : void
477 41363 : MSDevice_Vehroutes::writePendingOutput(const bool includeUnfinished) {
478 41363 : MSNet* const net = MSNet::getInstance();
479 :
480 41363 : if (!includeUnfinished) {
481 40867 : if (mySorted) {
482 118 : for (const auto& routeInfo : myRouteInfos.routeXML) {
483 36 : for (const auto& rouXML : routeInfo.second) {
484 20 : (*myRouteInfos.routeOut) << rouXML.second;
485 : }
486 : }
487 102 : if (net->hasPersons()) {
488 23 : const SortedRouteInfo& personRouteInfos = net->getPersonControl().getRouteInfo();
489 23 : if (personRouteInfos.routeOut != myRouteInfos.routeOut) {
490 0 : for (const auto& routeInfo : personRouteInfos.routeXML) {
491 0 : for (const auto& rouXML : routeInfo.second) {
492 0 : (*personRouteInfos.routeOut) << rouXML.second;
493 : }
494 : }
495 : }
496 : }
497 : }
498 40867 : return;
499 : }
500 2103 : for (const auto& it : myStateListener.myDevices) {
501 1607 : if (it.first->hasDeparted()) {
502 1607 : if (it.first->isStopped()) {
503 869 : it.second->notifyStopEnded();
504 : }
505 1607 : it.second->writeOutput(false);
506 : }
507 : }
508 : // unfinished persons
509 496 : if (net->hasPersons()) {
510 287 : MSTransportableControl& pc = net->getPersonControl();
511 393 : while (pc.loadedBegin() != pc.loadedEnd()) {
512 106 : pc.erase(pc.loadedBegin()->second);
513 : }
514 : }
515 : // Flush any remaining sorted outputs that may still be buffered
516 496 : if (mySorted) {
517 4 : for (const auto& routeInfo : myRouteInfos.routeXML) {
518 4 : for (const auto& rouXML : routeInfo.second) {
519 2 : (*myRouteInfos.routeOut) << rouXML.second;
520 : }
521 : }
522 2 : if (net->hasPersons()) {
523 0 : const SortedRouteInfo& personRouteInfos = net->getPersonControl().getRouteInfo();
524 0 : if (personRouteInfos.routeOut != myRouteInfos.routeOut) {
525 0 : for (const auto& routeInfo : personRouteInfos.routeXML) {
526 0 : for (const auto& rouXML : routeInfo.second) {
527 0 : (*personRouteInfos.routeOut) << rouXML.second;
528 : }
529 : }
530 : }
531 : }
532 : }
533 : }
534 :
535 :
536 : void
537 108 : MSDevice_Vehroutes::registerTransportableDepart(SUMOTime depart) {
538 108 : myRouteInfos.departureCounts[depart]++;
539 108 : }
540 :
541 :
542 : void
543 4544 : MSDevice_Vehroutes::writeSortedOutput(MSDevice_Vehroutes::SortedRouteInfo* routeInfo, SUMOTime depart, const SUMOTrafficObject::NumericalID id, const std::string& xmlOutput) {
544 4544 : if (routeInfo->routeOut == myRouteInfos.routeOut) {
545 : routeInfo = &myRouteInfos;
546 : }
547 4544 : routeInfo->routeXML[depart][id] = xmlOutput;
548 4544 : routeInfo->departureCounts[depart]--;
549 : std::map<const SUMOTime, int>::iterator it = routeInfo->departureCounts.begin();
550 7806 : while (it != routeInfo->departureCounts.end() && it->second == 0) {
551 7784 : for (const auto& rouXML : routeInfo->routeXML[it->first]) {
552 4522 : (*routeInfo->routeOut) << rouXML.second;
553 : }
554 : routeInfo->routeXML.erase(it->first);
555 : it = routeInfo->departureCounts.erase(it);
556 : }
557 4544 : }
558 :
559 :
560 : void
561 3168 : MSDevice_Vehroutes::saveState(OutputDevice& out) const {
562 3168 : out.openTag(SUMO_TAG_DEVICE);
563 3168 : out.writeAttr(SUMO_ATTR_ID, getID());
564 : std::vector<std::string> internals;
565 3168 : if (!MSGlobals::gUseMesoSim) {
566 1847 : internals.push_back(toString(myDepartLane));
567 3694 : internals.push_back(toString(myDepartPosLat));
568 : }
569 3168 : internals.push_back(toString(myDepartSpeed));
570 3168 : internals.push_back(toString(myDepartPos));
571 3168 : internals.push_back(toString(myReplacedRoutes.size()));
572 6022 : for (int i = 0; i < (int)myReplacedRoutes.size(); ++i) {
573 2854 : const std::string replacedOnEdge = myReplacedRoutes[i].edge == nullptr ? "!NULL" : myReplacedRoutes[i].edge->getID();
574 2854 : internals.push_back(replacedOnEdge);
575 5708 : internals.push_back(toString(myReplacedRoutes[i].time));
576 2854 : internals.push_back(myReplacedRoutes[i].route->getID());
577 2854 : internals.push_back(myReplacedRoutes[i].info);
578 2854 : internals.push_back(toString(myReplacedRoutes[i].lastRouteIndex));
579 2854 : internals.push_back(toString(myReplacedRoutes[i].newRouteIndex));
580 5708 : internals.push_back(toString(myReplacedRoutes[i].isValid));
581 : }
582 3168 : out.writeAttr(SUMO_ATTR_STATE, toString(internals));
583 3168 : if (mySaveExits && myExits.size() > 0) {
584 11 : out.writeAttr(SUMO_ATTR_EXITTIMES, myExits);
585 11 : out.writeAttr(SUMO_ATTR_EDGE, myLastSavedAt->getID());
586 : }
587 3168 : out.closeTag();
588 3168 : }
589 :
590 :
591 : void
592 2264 : MSDevice_Vehroutes::loadState(const SUMOSAXAttributes& attrs) {
593 2264 : std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
594 2264 : if (!MSGlobals::gUseMesoSim) {
595 1320 : bis >> myDepartLane;
596 1320 : bis >> myDepartPosLat;
597 : }
598 2264 : bis >> myDepartSpeed;
599 2264 : bis >> myDepartPos;
600 : int size;
601 2264 : bis >> size;
602 4095 : for (int i = 0; i < size; ++i) {
603 : std::string edgeID;
604 : SUMOTime time;
605 : std::string routeID;
606 : std::string info;
607 : int lastIndex;
608 : int newIndex;
609 1831 : bis >> edgeID;
610 : bis >> time;
611 1831 : bis >> routeID;
612 1831 : bis >> info;
613 1831 : bis >> lastIndex;
614 1831 : bis >> newIndex;
615 1831 : bis >> myCurrentValid;
616 :
617 1831 : ConstMSRoutePtr route = MSRoute::dictionary(routeID);
618 1831 : if (route != nullptr) {
619 2841 : myReplacedRoutes.push_back(RouteReplaceInfo(MSEdge::dictionary(edgeID), time, route, info, lastIndex, newIndex, myCurrentValid));
620 : }
621 : }
622 2264 : if (mySaveExits && attrs.hasAttribute(SUMO_ATTR_EXITTIMES)) {
623 11 : bool ok = true;
624 30 : for (const std::string& t : attrs.get<std::vector<std::string> >(SUMO_ATTR_EXITTIMES, nullptr, ok)) {
625 19 : myExits.push_back(StringUtils::toLong(t));
626 11 : }
627 11 : if (attrs.hasAttribute(SUMO_ATTR_EDGE)) {
628 11 : myLastSavedAt = MSEdge::dictionary(attrs.getString(SUMO_ATTR_EDGE));
629 : }
630 : }
631 2264 : if (myHolder.hasDeparted()) {
632 788 : myLastRouteIndex = myHolder.getRoutePosition();
633 : }
634 2264 : }
635 :
636 :
637 : /****************************************************************************/
|