Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2009-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_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 38602 : MSDevice_Vehroutes::init() {
67 38602 : const OptionsCont& oc = OptionsCont::getOptions();
68 77204 : if (oc.isSet("vehroute-output")) {
69 11544 : OutputDevice::createDeviceByOption("vehroute-output", "routes", "routes_file.xsd");
70 5763 : mySaveExits = oc.getBool("vehroute-output.exit-times");
71 5763 : myLastRouteOnly = oc.getBool("vehroute-output.last-route");
72 5763 : myDUAStyle = oc.getBool("vehroute-output.dua");
73 5763 : myWriteCosts = oc.getBool("vehroute-output.cost");
74 5763 : mySorted = myDUAStyle || oc.getBool("vehroute-output.sorted");
75 5763 : myIntendedDepart = oc.getBool("vehroute-output.intended-depart");
76 5763 : myRouteLength = oc.getBool("vehroute-output.route-length");
77 5763 : mySkipPTLines = oc.getBool("vehroute-output.skip-ptlines");
78 5763 : myIncludeIncomplete = oc.getBool("vehroute-output.incomplete");
79 5763 : myWriteStopPriorEdges = oc.getBool("vehroute-output.stop-edges");
80 5763 : myWriteInternal = oc.getBool("vehroute-output.internal");
81 5763 : MSNet::getInstance()->addVehicleStateListener(&myStateListener);
82 5763 : myRouteInfos.routeOut = &OutputDevice::getDeviceByOption("vehroute-output");
83 : }
84 38596 : }
85 :
86 :
87 : void
88 39784 : MSDevice_Vehroutes::insertOptions(OptionsCont& oc) {
89 39784 : oc.addOptionSubTopic("Vehroutes Device");
90 79568 : insertDefaultAssignmentOptions("vehroute", "Vehroutes Device", oc);
91 39784 : }
92 :
93 :
94 : MSDevice_Vehroutes*
95 6162231 : MSDevice_Vehroutes::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into, int maxRoutes) {
96 6162231 : if (maxRoutes < std::numeric_limits<int>::max()) {
97 1582302 : return new MSDevice_Vehroutes(v, "vehroute_" + v.getID(), maxRoutes);
98 : }
99 5371080 : if (mySkipPTLines && v.getParameter().line != "") {
100 : return nullptr;
101 : }
102 5369954 : OptionsCont& oc = OptionsCont::getOptions();
103 10739908 : if (equippedByDefaultAssignmentOptions(oc, "vehroute", v, oc.isSet("vehroute-output"))) {
104 136780 : if (myLastRouteOnly) {
105 : maxRoutes = 0;
106 : }
107 136780 : myStateListener.myDevices[&v] = new MSDevice_Vehroutes(v, "vehroute_" + v.getID(), maxRoutes);
108 136780 : into.push_back(myStateListener.myDevices[&v]);
109 136780 : return myStateListener.myDevices[&v];
110 : }
111 : return nullptr;
112 : }
113 :
114 :
115 : // ---------------------------------------------------------------------------
116 : // MSDevice_Vehroutes::StateListener-methods
117 : // ---------------------------------------------------------------------------
118 : void
119 519555 : MSDevice_Vehroutes::StateListener::vehicleStateChanged(const SUMOVehicle* const vehicle, MSNet::VehicleState to, const std::string& info) {
120 519555 : if (to == MSNet::VehicleState::NEWROUTE) {
121 : const auto& deviceEntry = myDevices.find(vehicle);
122 98387 : if (deviceEntry != myDevices.end()) {
123 97004 : deviceEntry->second->addRoute(info);
124 : }
125 : }
126 519555 : }
127 :
128 :
129 : // ---------------------------------------------------------------------------
130 : // MSDevice_Vehroutes-methods
131 : // ---------------------------------------------------------------------------
132 927931 : MSDevice_Vehroutes::MSDevice_Vehroutes(SUMOVehicle& holder, const std::string& id, int maxRoutes) :
133 : MSVehicleDevice(holder, id),
134 927931 : myCurrentRoute(holder.getRoutePtr()),
135 927931 : myMaxRoutes(maxRoutes),
136 927931 : myLastSavedAt(nullptr),
137 927931 : myLastRouteIndex(-1),
138 927931 : myDepartLane(-1),
139 927931 : myDepartPos(-1),
140 927931 : myDepartSpeed(-1),
141 927931 : myDepartPosLat(0),
142 927931 : myStopOut(2) {
143 927931 : }
144 :
145 :
146 1855754 : MSDevice_Vehroutes::~MSDevice_Vehroutes() {
147 927877 : myStateListener.myDevices.erase(&myHolder);
148 1855754 : }
149 :
150 :
151 : bool
152 12824017 : MSDevice_Vehroutes::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
153 12824017 : if (reason == MSMoveReminder::NOTIFICATION_DEPARTED) {
154 762748 : if (mySorted && myStateListener.myDevices[static_cast<SUMOVehicle*>(&veh)] == this) {
155 4586 : const SUMOTime departure = myIntendedDepart ? myHolder.getParameter().depart : MSNet::getInstance()->getCurrentTimeStep();
156 4586 : myRouteInfos.departureCounts[departure]++;
157 : }
158 762748 : if (!MSGlobals::gUseMesoSim) {
159 : const MSVehicle& vehicle = static_cast<MSVehicle&>(veh);
160 455213 : myDepartLane = vehicle.getLane()->getIndex();
161 455213 : myDepartPosLat = vehicle.getLateralPositionOnLane();
162 : }
163 762748 : myDepartSpeed = veh.getSpeed();
164 762748 : myDepartPos = veh.getPositionOnLane();
165 : }
166 12824017 : if (myWriteStopPriorEdges) {
167 68 : if (MSGlobals::gUseMesoSim) {
168 48 : const MSEdge* e = veh.getEdge();
169 48 : if (myPriorEdges.empty() || myPriorEdges.back() != e) {
170 12 : myPriorEdges.push_back(e);
171 : }
172 : } else {
173 20 : myPriorEdges.push_back(&enteredLane->getEdge());
174 : }
175 : }
176 12824017 : myLastRouteIndex = myHolder.getRoutePosition();
177 12824017 : return true;
178 : }
179 :
180 :
181 : bool
182 12790167 : MSDevice_Vehroutes::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
183 12790167 : if (mySaveExits && reason != NOTIFICATION_LANE_CHANGE && reason != NOTIFICATION_PARKING && reason != NOTIFICATION_SEGMENT) {
184 275813 : const MSEdge* edge = myWriteInternal ? dynamic_cast<MSBaseVehicle&>(veh).getCurrentEdge() : veh.getEdge();
185 275813 : if (myLastSavedAt != edge) {
186 155598 : myExits.push_back(MSNet::getInstance()->getCurrentTimeStep());
187 155598 : myLastSavedAt = edge;
188 : }
189 : }
190 12790167 : return true;
191 : }
192 :
193 :
194 : void
195 20773 : MSDevice_Vehroutes::notifyStopEnded() {
196 20773 : SUMOVehicleParameter::Stop stop = myHolder.getStops().front().pars;
197 20773 : const bool closeLater = myWriteStopPriorEdges || mySaveExits;
198 20773 : if (mySaveExits) {
199 : // prevent duplicate output
200 1567 : stop.parametersSet &= ~(STOP_STARTED_SET | STOP_ENDED_SET);
201 : }
202 20773 : stop.write(myStopOut, !closeLater);
203 20773 : if (myWriteStopPriorEdges) {
204 : // calculate length
205 16 : double priorEdgesLength = 0;
206 40 : for (int i = 0; i < (int)myPriorEdges.size(); i++) {
207 24 : if (i == 0) {
208 16 : priorEdgesLength += myPriorEdges.at(i)->getLength();
209 8 : } else if (myPriorEdges.at(i)->getID() != myPriorEdges.at(i - 1)->getID()) {
210 8 : priorEdgesLength += myPriorEdges.at(i)->getLength();
211 : }
212 : }
213 32 : myStopOut.writeAttr("priorEdges", myPriorEdges);
214 : myPriorEdges.clear();
215 32 : myStopOut.writeAttr("priorEdgesLength", priorEdgesLength);
216 : }
217 20773 : if (mySaveExits) {
218 1567 : myStopOut.writeAttr(SUMO_ATTR_STARTED, time2string(stop.started));
219 3134 : myStopOut.writeAttr(SUMO_ATTR_ENDED, stop.ended < 0 ? "-1" : time2string(stop.ended));
220 : }
221 20773 : if (closeLater) {
222 3166 : myStopOut.closeTag();
223 : }
224 20773 : }
225 :
226 :
227 : void
228 163413 : MSDevice_Vehroutes::writeXMLRoute(OutputDevice& os, int index) const {
229 9707 : if (index == 0 && !myIncludeIncomplete && myReplacedRoutes[index].route->size() == 2 &&
230 167050 : myReplacedRoutes[index].route->getEdges().front()->isTazConnector() &&
231 0 : myReplacedRoutes[index].route->getEdges().back()->isTazConnector()) {
232 : return;
233 : }
234 : // check if a previous route shall be written
235 : //std::cout << " writeXMLRoute index=" << index << " numReroutes=" << myHolder.getNumberReroutes() << "\n";
236 163413 : const int routesToSkip = myHolder.getParameter().wasSet(VEHPARS_FORCE_REROUTE) ? 1 : 0;
237 163413 : os.openTag(SUMO_TAG_ROUTE);
238 163413 : if (index >= 0) {
239 : assert((int)myReplacedRoutes.size() > index);
240 36933 : if (myDUAStyle || myWriteCosts) {
241 14532 : os.writeAttr(SUMO_ATTR_COST, myReplacedRoutes[index].route->getCosts());
242 : }
243 36933 : if (myWriteCosts) {
244 14532 : os.writeAttr(SUMO_ATTR_SAVINGS, myReplacedRoutes[index].route->getSavings());
245 : }
246 : // write edge on which the vehicle was when the route was valid
247 109454 : os.writeAttr("replacedOnEdge", (myReplacedRoutes[index].edge ?
248 : myReplacedRoutes[index].edge->getID() : ""));
249 36933 : if (myReplacedRoutes[index].lastRouteIndex > 0) {
250 : // do not write the default
251 25161 : os.writeAttr(SUMO_ATTR_REPLACED_ON_INDEX, myReplacedRoutes[index].lastRouteIndex);
252 : }
253 : // write the reason for replacement
254 73866 : os.writeAttr("reason", myReplacedRoutes[index].info);
255 :
256 : // write the time at which the route was replaced
257 36933 : os.writeAttr(SUMO_ATTR_REPLACED_AT_TIME, time2string(myReplacedRoutes[index].time));
258 36933 : os.writeAttr(SUMO_ATTR_PROB, "0");
259 36933 : OutputDevice_String edgesD;
260 : // always write the part that was actually driven and the rest of the current route that wasn't yet driven
261 : int start = 0;
262 157643 : for (int i = routesToSkip; i < index; i++) {
263 120710 : if (myReplacedRoutes[i].edge != nullptr) {
264 119902 : int end = myReplacedRoutes[i].lastRouteIndex;
265 119902 : myReplacedRoutes[i].route->writeEdgeIDs(edgesD, start, end, myWriteInternal, myHolder.getVClass());
266 : }
267 120710 : start = myReplacedRoutes[i].newRouteIndex;
268 : }
269 36933 : myReplacedRoutes[index].route->writeEdgeIDs(edgesD, start, -1, myWriteInternal, myHolder.getVClass());
270 36933 : std::string edgesS = edgesD.getString();
271 : edgesS.pop_back(); // remove last ' '
272 36933 : os.writeAttr(SUMO_ATTR_EDGES, edgesS);
273 36933 : if (myRouteLength) {
274 7133 : const bool includeInternalLengths = MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks();
275 : ConstMSRoutePtr route = myReplacedRoutes[index].route;
276 7133 : const double routeLength = route->getDistanceBetween(myHolder.getDepartPos(), route->getEdges().back()->getLength(),
277 7133 : route->begin(), route->end(), includeInternalLengths);
278 14266 : os.writeAttr("routeLength", routeLength);
279 : }
280 36933 : } else {
281 126480 : if (myDUAStyle || myWriteCosts) {
282 32889 : os.writeAttr(SUMO_ATTR_COST, myHolder.getRoute().getCosts());
283 : }
284 126480 : if (myWriteCosts) {
285 32883 : os.writeAttr(SUMO_ATTR_SAVINGS, myHolder.getRoute().getSavings());
286 : }
287 126480 : OutputDevice_String edgesD;
288 : int numWritten = 0;
289 : int start = 0;
290 126480 : if (myHolder.getNumberReroutes() > 0) {
291 : assert((int)myReplacedRoutes.size() <= myHolder.getNumberReroutes());
292 93703 : for (int i = routesToSkip; i < (int)myReplacedRoutes.size(); i++) {
293 36245 : if (myReplacedRoutes[i].edge != nullptr) {
294 35125 : int end = myReplacedRoutes[i].lastRouteIndex;
295 35125 : numWritten += myReplacedRoutes[i].route->writeEdgeIDs(edgesD, start, end, myWriteInternal, myHolder.getVClass());
296 : }
297 36245 : start = myReplacedRoutes[i].newRouteIndex;
298 : }
299 : }
300 126480 : numWritten += myCurrentRoute->writeEdgeIDs(edgesD, start, -1, myWriteInternal, myHolder.getVClass());
301 126480 : std::string edgesS = edgesD.getString();
302 : edgesS.pop_back(); // remove last ' '
303 126480 : os.writeAttr(SUMO_ATTR_EDGES, edgesS);
304 :
305 126480 : if (mySaveExits) {
306 : std::vector<std::string> exits;
307 134096 : for (SUMOTime t : myExits) {
308 247884 : exits.push_back(time2string(t));
309 : }
310 : assert(numWritten >= (int)myExits.size());
311 20308 : std::vector<std::string> missing(numWritten - (int)myExits.size(), "-1");
312 10154 : exits.insert(exits.end(), missing.begin(), missing.end());
313 10154 : os.writeAttr(SUMO_ATTR_EXITTIMES, exits);
314 10154 : }
315 126480 : }
316 326826 : os.closeTag();
317 : }
318 :
319 :
320 : void
321 125290 : MSDevice_Vehroutes::generateOutput(OutputDevice* /*tripinfoOut*/) const {
322 125290 : writeOutput(true);
323 125290 : }
324 :
325 :
326 : void
327 126486 : MSDevice_Vehroutes::writeOutput(const bool hasArrived) const {
328 126486 : const OptionsCont& oc = OptionsCont::getOptions();
329 126486 : OutputDevice& routeOut = OutputDevice::getDeviceByOption("vehroute-output");
330 126486 : OutputDevice_String od(1);
331 126486 : SUMOVehicleParameter tmp = myHolder.getParameter();
332 126486 : tmp.depart = myIntendedDepart ? myHolder.getParameter().depart : myHolder.getDeparture();
333 126486 : if (!MSGlobals::gUseMesoSim) {
334 90374 : if (tmp.wasSet(VEHPARS_DEPARTLANE_SET)) {
335 14297 : tmp.departLaneProcedure = DepartLaneDefinition::GIVEN;
336 14297 : tmp.departLane = myDepartLane;
337 : }
338 90374 : if (tmp.wasSet(VEHPARS_DEPARTPOSLAT_SET)) {
339 8 : tmp.departPosLatProcedure = (tmp.departPosLatProcedure == DepartPosLatDefinition::RANDOM
340 4 : ? DepartPosLatDefinition::GIVEN_VEHROUTE
341 : : DepartPosLatDefinition::GIVEN);
342 4 : tmp.departPosLat = myDepartPosLat;
343 : }
344 : }
345 126486 : if (tmp.wasSet(VEHPARS_DEPARTPOS_SET)) {
346 72950 : tmp.departPosProcedure = ((tmp.departPosProcedure != DepartPosDefinition::GIVEN
347 36475 : && tmp.departPosProcedure != DepartPosDefinition::STOP)
348 36475 : ? DepartPosDefinition::GIVEN_VEHROUTE
349 : : DepartPosDefinition::GIVEN);
350 36475 : tmp.departPos = myDepartPos;
351 : }
352 126486 : if (tmp.wasSet(VEHPARS_DEPARTSPEED_SET)) {
353 94066 : tmp.departSpeedProcedure = ((tmp.departSpeedProcedure != DepartSpeedDefinition::GIVEN
354 47033 : && tmp.departSpeedProcedure != DepartSpeedDefinition::LIMIT)
355 47033 : ? DepartSpeedDefinition::GIVEN_VEHROUTE
356 : : DepartSpeedDefinition::GIVEN);
357 47033 : tmp.departSpeed = myDepartSpeed;
358 : }
359 377452 : if (oc.getBool("vehroute-output.speedfactor") ||
360 452893 : (oc.isDefault("vehroute-output.speedfactor") && tmp.wasSet(VEHPARS_DEPARTSPEED_SET))) {
361 49033 : tmp.parametersSet |= VEHPARS_SPEEDFACTOR_SET;
362 49033 : tmp.speedFactor = myHolder.getChosenSpeedFactor();
363 : }
364 :
365 126486 : const std::string typeID = myHolder.getVehicleType().getID() != DEFAULT_VTYPE_ID ? myHolder.getVehicleType().getID() : "";
366 126486 : tmp.write(od, oc, SUMO_TAG_VEHICLE, typeID);
367 126486 : if (hasArrived) {
368 250580 : od.writeAttr("arrival", time2string(MSNet::getInstance()->getCurrentTimeStep()));
369 : }
370 126486 : if (myRouteLength) {
371 951 : const bool includeInternalLengths = MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks();
372 951 : const double finalPos = hasArrived ? myHolder.getArrivalPos() : myHolder.getPositionOnLane();
373 1902 : const double routeLength = myHolder.getRoute().getDistanceBetween(myHolder.getDepartPos(), finalPos,
374 951 : myHolder.getRoute().begin(), myHolder.getCurrentRouteEdge(), includeInternalLengths);
375 1902 : od.writeAttr("routeLength", routeLength);
376 : }
377 126486 : if (myDUAStyle) {
378 12 : const RandomDistributor<ConstMSRoutePtr>* const routeDist = MSRoute::distDictionary("!" + myHolder.getID());
379 12 : if (routeDist != nullptr) {
380 : const std::vector<ConstMSRoutePtr>& routes = routeDist->getVals();
381 6 : unsigned index = 0;
382 6 : while (index < routes.size() && routes[index] != myCurrentRoute) {
383 0 : ++index;
384 : }
385 6 : od.openTag(SUMO_TAG_ROUTE_DISTRIBUTION).writeAttr(SUMO_ATTR_LAST, index);
386 : const std::vector<double>& probs = routeDist->getProbs();
387 18 : for (int i = 0; i < (int)routes.size(); ++i) {
388 12 : od.setPrecision();
389 12 : od.openTag(SUMO_TAG_ROUTE);
390 12 : od.writeAttr(SUMO_ATTR_COST, routes[i]->getCosts());
391 12 : if (myWriteCosts) {
392 0 : od.writeAttr(SUMO_ATTR_SAVINGS, routes[i]->getSavings());
393 : }
394 12 : od.setPrecision(8);
395 12 : od.writeAttr(SUMO_ATTR_PROB, probs[i]);
396 12 : od.setPrecision();
397 12 : OutputDevice_String edgesD;
398 12 : routes[i]->writeEdgeIDs(edgesD, 0, -1, myWriteInternal, myHolder.getVClass());
399 12 : std::string edgesS = edgesD.getString();
400 : edgesS.pop_back(); // remove last ' '
401 12 : od.writeAttr(SUMO_ATTR_EDGES, edgesS);
402 24 : od.closeTag();
403 12 : }
404 12 : od.closeTag();
405 : } else {
406 6 : writeXMLRoute(od);
407 : }
408 : } else {
409 : std::string dummyMsg;
410 126474 : const int routesToSkip = (myHolder.getParameter().wasSet(VEHPARS_FORCE_REROUTE)
411 49383 : && !myIncludeIncomplete
412 49263 : && myReplacedRoutes.size() > 0
413 223501 : && !myHolder.hasValidRoute(dummyMsg, myReplacedRoutes[0].route) ? 1 : 0);
414 126474 : if ((int)myReplacedRoutes.size() > routesToSkip) {
415 22012 : od.openTag(SUMO_TAG_ROUTE_DISTRIBUTION);
416 58945 : for (int i = routesToSkip; i < (int)myReplacedRoutes.size(); ++i) {
417 36933 : writeXMLRoute(od, i);
418 : }
419 22012 : writeXMLRoute(od);
420 44024 : od.closeTag();
421 : } else {
422 104462 : writeXMLRoute(od);
423 : }
424 : }
425 126486 : od << myStopOut.getString();
426 126486 : myHolder.getParameter().writeParams(od);
427 126486 : od.closeTag();
428 126486 : od.lf();
429 126486 : if (mySorted) {
430 : // numerical id reflects loading order
431 8844 : writeSortedOutput(&myRouteInfos, tmp.depart, toString(myHolder.getNumericalID()), od.getString());
432 : } else {
433 244128 : routeOut << od.getString();
434 : }
435 126486 : }
436 :
437 :
438 : ConstMSRoutePtr
439 0 : MSDevice_Vehroutes::getRoute(int index) const {
440 0 : if (index < (int)myReplacedRoutes.size()) {
441 0 : return myReplacedRoutes[index].route;
442 : } else {
443 : return nullptr;
444 : }
445 : }
446 :
447 :
448 : void
449 97004 : MSDevice_Vehroutes::addRoute(const std::string& info) {
450 97004 : if (myMaxRoutes > 0) {
451 : //std::cout << SIMTIME << " " << getID() << " departed=" << myHolder.hasDeparted() << " lastIndex=" << myLastRouteIndex << " start=" << myHolder.getRoutePosition() << "\n";
452 423118 : myReplacedRoutes.push_back(RouteReplaceInfo(
453 124961 : myHolder.hasDeparted() ? myHolder.getEdge() : nullptr,
454 : MSNet::getInstance()->getCurrentTimeStep(), myCurrentRoute, info,
455 : myLastRouteIndex,
456 124961 : myHolder.hasDeparted() ? myHolder.getRoutePosition() : 0));
457 86598 : if ((int)myReplacedRoutes.size() > myMaxRoutes) {
458 : myReplacedRoutes.erase(myReplacedRoutes.begin());
459 : }
460 : }
461 97004 : myCurrentRoute = myHolder.getRoutePtr();
462 97004 : }
463 :
464 :
465 : void
466 36910 : MSDevice_Vehroutes::writePendingOutput(const bool includeUnfinished) {
467 36910 : MSNet* const net = MSNet::getInstance();
468 :
469 36910 : if (!includeUnfinished) {
470 36565 : if (mySorted) {
471 117 : for (const auto& routeInfo : myRouteInfos.routeXML) {
472 36 : for (const auto& rouXML : routeInfo.second) {
473 20 : (*myRouteInfos.routeOut) << rouXML.second;
474 : }
475 : }
476 101 : if (net->hasPersons()) {
477 22 : const SortedRouteInfo& personRouteInfos = net->getPersonControl().getRouteInfo();
478 22 : if (personRouteInfos.routeOut != myRouteInfos.routeOut) {
479 0 : for (const auto& routeInfo : personRouteInfos.routeXML) {
480 0 : for (const auto& rouXML : routeInfo.second) {
481 0 : (*personRouteInfos.routeOut) << rouXML.second;
482 : }
483 : }
484 : }
485 : }
486 : }
487 36565 : return;
488 : }
489 1541 : for (const auto& it : myStateListener.myDevices) {
490 1196 : if (it.first->hasDeparted()) {
491 1196 : if (it.first->isStopped()) {
492 593 : it.second->notifyStopEnded();
493 : }
494 1196 : it.second->writeOutput(false);
495 : }
496 : }
497 : // unfinished persons
498 345 : if (net->hasPersons()) {
499 168 : MSTransportableControl& pc = net->getPersonControl();
500 190 : while (pc.loadedBegin() != pc.loadedEnd()) {
501 22 : pc.erase(pc.loadedBegin()->second);
502 : }
503 : }
504 : // Flush any remaining sorted outputs that may still be buffered
505 345 : if (mySorted) {
506 4 : for (const auto& routeInfo : myRouteInfos.routeXML) {
507 4 : for (const auto& rouXML : routeInfo.second) {
508 2 : (*myRouteInfos.routeOut) << rouXML.second;
509 : }
510 : }
511 2 : if (net->hasPersons()) {
512 0 : const SortedRouteInfo& personRouteInfos = net->getPersonControl().getRouteInfo();
513 0 : if (personRouteInfos.routeOut != myRouteInfos.routeOut) {
514 0 : for (const auto& routeInfo : personRouteInfos.routeXML) {
515 0 : for (const auto& rouXML : routeInfo.second) {
516 0 : (*personRouteInfos.routeOut) << rouXML.second;
517 : }
518 : }
519 : }
520 : }
521 : }
522 : }
523 :
524 :
525 : void
526 108 : MSDevice_Vehroutes::registerTransportableDepart(SUMOTime depart) {
527 108 : myRouteInfos.departureCounts[depart]++;
528 108 : }
529 :
530 :
531 : void
532 4544 : MSDevice_Vehroutes::writeSortedOutput(MSDevice_Vehroutes::SortedRouteInfo* routeInfo, SUMOTime depart, const std::string& id, const std::string& xmlOutput) {
533 4544 : if (routeInfo->routeOut == myRouteInfos.routeOut) {
534 : routeInfo = &myRouteInfos;
535 : }
536 4544 : routeInfo->routeXML[depart][id] = xmlOutput;
537 4544 : routeInfo->departureCounts[depart]--;
538 : std::map<const SUMOTime, int>::iterator it = routeInfo->departureCounts.begin();
539 7777 : while (it != routeInfo->departureCounts.end() && it->second == 0) {
540 7755 : for (const auto& rouXML : routeInfo->routeXML[it->first]) {
541 4522 : (*routeInfo->routeOut) << rouXML.second;
542 : }
543 : routeInfo->routeXML.erase(it->first);
544 : it = routeInfo->departureCounts.erase(it);
545 : }
546 4544 : }
547 :
548 :
549 : void
550 3127 : MSDevice_Vehroutes::saveState(OutputDevice& out) const {
551 3127 : out.openTag(SUMO_TAG_DEVICE);
552 3127 : out.writeAttr(SUMO_ATTR_ID, getID());
553 : std::vector<std::string> internals;
554 3127 : if (!MSGlobals::gUseMesoSim) {
555 1838 : internals.push_back(toString(myDepartLane));
556 3676 : internals.push_back(toString(myDepartPosLat));
557 : }
558 3127 : internals.push_back(toString(myDepartSpeed));
559 3127 : internals.push_back(toString(myDepartPos));
560 3127 : internals.push_back(toString(myReplacedRoutes.size()));
561 5985 : for (int i = 0; i < (int)myReplacedRoutes.size(); ++i) {
562 2858 : const std::string replacedOnEdge = myReplacedRoutes[i].edge == nullptr ? "!NULL" : myReplacedRoutes[i].edge->getID();
563 2858 : internals.push_back(replacedOnEdge);
564 5716 : internals.push_back(toString(myReplacedRoutes[i].time));
565 2858 : internals.push_back(myReplacedRoutes[i].route->getID());
566 2858 : internals.push_back(myReplacedRoutes[i].info);
567 2858 : internals.push_back(toString(myReplacedRoutes[i].lastRouteIndex));
568 5716 : internals.push_back(toString(myReplacedRoutes[i].newRouteIndex));
569 : }
570 3127 : out.writeAttr(SUMO_ATTR_STATE, toString(internals));
571 3127 : if (mySaveExits && myExits.size() > 0) {
572 9 : out.writeAttr(SUMO_ATTR_EXITTIMES, myExits);
573 9 : out.writeAttr(SUMO_ATTR_EDGE, myLastSavedAt->getID());
574 : }
575 3127 : out.closeTag();
576 3127 : }
577 :
578 :
579 : void
580 2220 : MSDevice_Vehroutes::loadState(const SUMOSAXAttributes& attrs) {
581 2220 : std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
582 2220 : if (!MSGlobals::gUseMesoSim) {
583 1307 : bis >> myDepartLane;
584 1307 : bis >> myDepartPosLat;
585 : }
586 2220 : bis >> myDepartSpeed;
587 2220 : bis >> myDepartPos;
588 : int size;
589 2220 : bis >> size;
590 4054 : for (int i = 0; i < size; ++i) {
591 : std::string edgeID;
592 : SUMOTime time;
593 : std::string routeID;
594 : std::string info;
595 : int lastIndex;
596 : int newIndex;
597 1834 : bis >> edgeID;
598 : bis >> time;
599 1834 : bis >> routeID;
600 1834 : bis >> info;
601 1834 : bis >> lastIndex;
602 1834 : bis >> newIndex;
603 :
604 1834 : ConstMSRoutePtr route = MSRoute::dictionary(routeID);
605 1834 : if (route != nullptr) {
606 2844 : myReplacedRoutes.push_back(RouteReplaceInfo(MSEdge::dictionary(edgeID), time, route, info, lastIndex, newIndex));
607 : }
608 : }
609 2220 : if (mySaveExits && attrs.hasAttribute(SUMO_ATTR_EXITTIMES)) {
610 9 : bool ok = true;
611 20 : for (const std::string& t : attrs.get<std::vector<std::string> >(SUMO_ATTR_EXITTIMES, nullptr, ok)) {
612 11 : myExits.push_back(StringUtils::toLong(t));
613 9 : }
614 9 : if (attrs.hasAttribute(SUMO_ATTR_EDGE)) {
615 9 : myLastSavedAt = MSEdge::dictionary(attrs.getString(SUMO_ATTR_EDGE));
616 : }
617 : }
618 2220 : if (myHolder.hasDeparted()) {
619 747 : myLastRouteIndex = myHolder.getRoutePosition();
620 : }
621 2220 : }
622 :
623 :
624 : /****************************************************************************/
|