1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file SUMORouteHandler.cpp
11 /// @author Daniel Krajzewicz
12 /// @author Jakob Erdmann
13 /// @author Sascha Krieg
14 /// @author Michael Behrisch
15 /// @date Mon, 9 Jul 2001
16 /// @version $Id$
17 ///
18 // Parser for routes during their loading
19 /****************************************************************************/
20
21
22 // ===========================================================================
23 // included modules
24 // ===========================================================================
25 #include <config.h>
26
27 #include <string>
28 #include <map>
29 #include <vector>
30 #include <utils/common/MsgHandler.h>
31 #include <utils/common/ToString.h>
32 #include <utils/common/UtilExceptions.h>
33 #include <utils/options/OptionsCont.h>
34 #include <utils/vehicle/SUMOVehicleParameter.h>
35 #include <utils/vehicle/SUMOVTypeParameter.h>
36 #include <utils/xml/SUMOSAXHandler.h>
37 #include <utils/vehicle/SUMOVehicleParserHelper.h>
38 #include <utils/xml/SUMOXMLDefinitions.h>
39 #include <utils/xml/XMLSubSys.h>
40 #include "SUMORouteHandler.h"
41
42
43 // ===========================================================================
44 // method definitions
45 // ===========================================================================
SUMORouteHandler(const std::string & file,const std::string & expectedRoot)46 SUMORouteHandler::SUMORouteHandler(const std::string& file, const std::string& expectedRoot) :
47 SUMOSAXHandler(file, XMLSubSys::isValidating() ? expectedRoot : ""),
48 myVehicleParameter(nullptr),
49 myLastDepart(-1),
50 myActiveRouteColor(nullptr),
51 myCurrentCosts(0.),
52 myCurrentVType(nullptr),
53 myBeginDefault(string2time(OptionsCont::getOptions().getString("begin"))),
54 myEndDefault(string2time(OptionsCont::getOptions().getString("end"))),
55 myFirstDepart(-1), myInsertStopEdgesAt(-1) {
56 }
57
58
~SUMORouteHandler()59 SUMORouteHandler::~SUMORouteHandler() {
60 delete myCurrentVType;
61 }
62
63
64 SUMOTime
getLastDepart() const65 SUMORouteHandler::getLastDepart() const {
66 return myLastDepart;
67 }
68
69
70 bool
checkLastDepart()71 SUMORouteHandler::checkLastDepart() {
72 if (myVehicleParameter->departProcedure == DEPART_GIVEN) {
73 if (myVehicleParameter->depart < myLastDepart) {
74 WRITE_WARNING("Route file should be sorted by departure time, ignoring '" + myVehicleParameter->id + "'!");
75 return false;
76 }
77 }
78 return true;
79 }
80
81
82 void
registerLastDepart()83 SUMORouteHandler::registerLastDepart() {
84 // register only non public transport to parse all public transport lines in advance
85 if (myVehicleParameter->line == "" && myVehicleParameter->departProcedure == DEPART_GIVEN) {
86 myLastDepart = myVehicleParameter->depart;
87 if (myFirstDepart == -1) {
88 myFirstDepart = myLastDepart;
89 }
90 }
91 // else: we don't know when this vehicle will depart. keep the previous known depart time
92 }
93
94
95 void
myStartElement(int element,const SUMOSAXAttributes & attrs)96 SUMORouteHandler::myStartElement(int element,
97 const SUMOSAXAttributes& attrs) {
98 switch (element) {
99 case SUMO_TAG_VEHICLE:
100 delete myVehicleParameter;
101 myVehicleParameter = SUMOVehicleParserHelper::parseVehicleAttributes(attrs);
102 break;
103 case SUMO_TAG_PERSON:
104 delete myVehicleParameter;
105 myVehicleParameter = SUMOVehicleParserHelper::parseVehicleAttributes(attrs, false, false, true);
106 addPerson(attrs);
107 break;
108 case SUMO_TAG_CONTAINER:
109 delete myVehicleParameter;
110 myVehicleParameter = SUMOVehicleParserHelper::parseVehicleAttributes(attrs);
111 addContainer(attrs);
112 break;
113 case SUMO_TAG_FLOW:
114 delete myVehicleParameter;
115 myVehicleParameter = SUMOVehicleParserHelper::parseFlowAttributes(attrs, myBeginDefault, myEndDefault);
116 break;
117 case SUMO_TAG_PERSONFLOW:
118 delete myVehicleParameter;
119 myVehicleParameter = SUMOVehicleParserHelper::parseFlowAttributes(attrs, myBeginDefault, myEndDefault, true);
120 break;
121 case SUMO_TAG_VTYPE:
122 // XXX: Where is this deleted? Delegated to subclasses?! MSRouteHandler takes care of this, in case of RORouteHandler this is not obvious. Consider introduction of a shared_ptr
123 myCurrentVType = SUMOVehicleParserHelper::beginVTypeParsing(attrs, getFileName());
124 break;
125 case SUMO_TAG_VTYPE_DISTRIBUTION:
126 openVehicleTypeDistribution(attrs);
127 break;
128 case SUMO_TAG_ROUTE:
129 openRoute(attrs);
130 break;
131 case SUMO_TAG_ROUTE_DISTRIBUTION:
132 openRouteDistribution(attrs);
133 break;
134 case SUMO_TAG_STOP:
135 addStop(attrs);
136 break;
137 case SUMO_TAG_TRIP: {
138 myVehicleParameter = SUMOVehicleParserHelper::parseVehicleAttributes(attrs, true);
139 if (myVehicleParameter->id == "") {
140 WRITE_WARNING("Omitting trip ids is deprecated!");
141 myVehicleParameter->id = myIdSupplier.getNext();
142 }
143 myVehicleParameter->parametersSet |= VEHPARS_FORCE_REROUTE;
144 myActiveRouteID = "!" + myVehicleParameter->id;
145 // open trip
146 openTrip(attrs);
147 break;
148 }
149 case SUMO_TAG_PERSONTRIP:
150 case SUMO_TAG_WALK:
151 if (attrs.hasAttribute(SUMO_ATTR_EDGES) || attrs.hasAttribute(SUMO_ATTR_ROUTE)) {
152 addWalk(attrs);
153 } else {
154 addPersonTrip(attrs);
155 }
156 break;
157 case SUMO_TAG_INTERVAL: {
158 bool ok;
159 myBeginDefault = attrs.getSUMOTimeReporting(SUMO_ATTR_BEGIN, nullptr, ok);
160 myEndDefault = attrs.getSUMOTimeReporting(SUMO_ATTR_END, nullptr, ok);
161 break;
162 }
163 case SUMO_TAG_RIDE:
164 addRide(attrs);
165 break;
166 case SUMO_TAG_TRANSPORT:
167 addTransport(attrs);
168 break;
169 case SUMO_TAG_TRANSHIP:
170 addTranship(attrs);
171 break;
172 case SUMO_TAG_PARAM:
173 addParam(attrs);
174 break;
175 default:
176 // parse embedded car following model information
177 if (myCurrentVType != nullptr) {
178 WRITE_WARNING("Defining car following parameters in a nested element is deprecated in vType '" + myCurrentVType->id + "', use attributes instead!");
179 SUMOVehicleParserHelper::parseVTypeEmbedded(*myCurrentVType, (SumoXMLTag)element, attrs);
180 }
181 break;
182 }
183 }
184
185
186 void
myEndElement(int element)187 SUMORouteHandler::myEndElement(int element) {
188 switch (element) {
189 case SUMO_TAG_ROUTE:
190 closeRoute();
191 break;
192 case SUMO_TAG_VTYPE:
193 closeVType();
194 break;
195 case SUMO_TAG_PERSON:
196 closePerson();
197 delete myVehicleParameter;
198 myVehicleParameter = nullptr;
199 break;
200 case SUMO_TAG_PERSONFLOW:
201 closePersonFlow();
202 delete myVehicleParameter;
203 myVehicleParameter = nullptr;
204 break;
205 case SUMO_TAG_CONTAINER:
206 closeContainer();
207 delete myVehicleParameter;
208 myVehicleParameter = nullptr;
209 break;
210 case SUMO_TAG_VEHICLE:
211 if (myVehicleParameter->repetitionNumber > 0) {
212 myVehicleParameter->repetitionNumber++; // for backwards compatibility
213 // it is a flow, thus no break here
214 FALLTHROUGH;
215 } else {
216 closeVehicle();
217 delete myVehicleParameter;
218 myVehicleParameter = nullptr;
219 break;
220 }
221 case SUMO_TAG_FLOW:
222 closeFlow();
223 break;
224 case SUMO_TAG_TRIP:
225 closeTrip();
226 delete myVehicleParameter;
227 myVehicleParameter = nullptr;
228 myInsertStopEdgesAt = -1;
229 break;
230 case SUMO_TAG_VTYPE_DISTRIBUTION:
231 closeVehicleTypeDistribution();
232 break;
233 case SUMO_TAG_ROUTE_DISTRIBUTION:
234 closeRouteDistribution();
235 break;
236 case SUMO_TAG_INTERVAL:
237 myBeginDefault = string2time(OptionsCont::getOptions().getString("begin"));
238 myEndDefault = string2time(OptionsCont::getOptions().getString("end"));
239 break;
240 default:
241 break;
242 }
243 }
244
245
246 bool
checkStopPos(double & startPos,double & endPos,const double laneLength,const double minLength,const bool friendlyPos)247 SUMORouteHandler::checkStopPos(double& startPos, double& endPos, const double laneLength,
248 const double minLength, const bool friendlyPos) {
249 if (minLength > laneLength) {
250 return false;
251 }
252 if (startPos < 0) {
253 startPos += laneLength;
254 }
255 if (endPos < 0) {
256 endPos += laneLength;
257 }
258 if (endPos < minLength || endPos > laneLength) {
259 if (!friendlyPos) {
260 return false;
261 }
262 if (endPos < minLength) {
263 endPos = minLength;
264 }
265 if (endPos > laneLength) {
266 endPos = laneLength;
267 }
268 }
269 if (startPos < 0 || startPos > endPos - minLength) {
270 if (!friendlyPos) {
271 return false;
272 }
273 if (startPos < 0) {
274 startPos = 0;
275 }
276 if (startPos > endPos - minLength) {
277 startPos = endPos - minLength;
278 }
279 }
280 return true;
281 }
282
283
284 void
addParam(const SUMOSAXAttributes & attrs)285 SUMORouteHandler::addParam(const SUMOSAXAttributes& attrs) {
286 bool ok = true;
287 const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
288 // circumventing empty string test
289 const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
290 if (myVehicleParameter != nullptr) {
291 myVehicleParameter->setParameter(key, val);
292 } else if (myCurrentVType != nullptr) {
293 myCurrentVType->setParameter(key, val);
294 }
295 }
296
297
298 bool
parseStop(SUMOVehicleParameter::Stop & stop,const SUMOSAXAttributes & attrs,std::string errorSuffix,MsgHandler * const errorOutput)299 SUMORouteHandler::parseStop(SUMOVehicleParameter::Stop& stop, const SUMOSAXAttributes& attrs, std::string errorSuffix, MsgHandler* const errorOutput) {
300 stop.parametersSet = 0;
301 if (attrs.hasAttribute(SUMO_ATTR_ENDPOS)) {
302 stop.parametersSet |= STOP_END_SET;
303 }
304 if (attrs.hasAttribute(SUMO_ATTR_STARTPOS)) {
305 stop.parametersSet |= STOP_START_SET;
306 }
307 if (attrs.hasAttribute(SUMO_ATTR_TRIGGERED)) {
308 stop.parametersSet |= STOP_TRIGGER_SET;
309 }
310 if (attrs.hasAttribute(SUMO_ATTR_CONTAINER_TRIGGERED)) {
311 stop.parametersSet |= STOP_CONTAINER_TRIGGER_SET;
312 }
313 if (attrs.hasAttribute(SUMO_ATTR_PARKING)) {
314 stop.parametersSet |= STOP_PARKING_SET;
315 }
316 if (attrs.hasAttribute(SUMO_ATTR_EXPECTED)) {
317 stop.parametersSet |= STOP_EXPECTED_SET;
318 }
319 if (attrs.hasAttribute(SUMO_ATTR_EXPECTED_CONTAINERS)) {
320 stop.parametersSet |= STOP_EXPECTED_CONTAINERS_SET;
321 }
322 if (attrs.hasAttribute(SUMO_ATTR_TRIP_ID)) {
323 stop.parametersSet |= STOP_TRIP_ID_SET;
324 }
325 bool ok = true;
326 stop.busstop = attrs.getOpt<std::string>(SUMO_ATTR_BUS_STOP, nullptr, ok, "");
327 stop.chargingStation = attrs.getOpt<std::string>(SUMO_ATTR_CHARGING_STATION, nullptr, ok, "");
328 stop.containerstop = attrs.getOpt<std::string>(SUMO_ATTR_CONTAINER_STOP, nullptr, ok, "");
329 stop.parkingarea = attrs.getOpt<std::string>(SUMO_ATTR_PARKING_AREA, nullptr, ok, "");
330 if (stop.busstop != "") {
331 errorSuffix = " at '" + stop.busstop + "'" + errorSuffix;
332 } else if (stop.chargingStation != "") {
333 errorSuffix = " at '" + stop.chargingStation + "'" + errorSuffix;
334 } else if (stop.containerstop != "") {
335 errorSuffix = " at '" + stop.containerstop + "'" + errorSuffix;
336 } else if (stop.parkingarea != "") {
337 errorSuffix = " at '" + stop.parkingarea + "'" + errorSuffix;
338 } else {
339 errorSuffix = " on lane '" + stop.lane + "'" + errorSuffix;
340 }
341 // get the standing duration
342 if (!attrs.hasAttribute(SUMO_ATTR_DURATION) && !attrs.hasAttribute(SUMO_ATTR_UNTIL)) {
343 if (attrs.hasAttribute(SUMO_ATTR_CONTAINER_TRIGGERED)) {
344 stop.containerTriggered = attrs.getOpt<bool>(SUMO_ATTR_CONTAINER_TRIGGERED, nullptr, ok, true);
345 stop.triggered = attrs.getOpt<bool>(SUMO_ATTR_TRIGGERED, nullptr, ok, false);
346 } else {
347 stop.triggered = attrs.getOpt<bool>(SUMO_ATTR_TRIGGERED, nullptr, ok, true);
348 stop.containerTriggered = attrs.getOpt<bool>(SUMO_ATTR_CONTAINER_TRIGGERED, nullptr, ok, false);
349 }
350 stop.duration = -1;
351 stop.until = -1;
352 } else {
353 stop.duration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_DURATION, nullptr, ok, -1);
354 stop.until = attrs.getOptSUMOTimeReporting(SUMO_ATTR_UNTIL, nullptr, ok, -1);
355 if (!ok || (stop.duration < 0 && stop.until < 0)) {
356 errorOutput->inform("Invalid duration or end time is given for a stop" + errorSuffix);
357 return false;
358 }
359 stop.triggered = attrs.getOpt<bool>(SUMO_ATTR_TRIGGERED, nullptr, ok, false);
360 stop.containerTriggered = attrs.getOpt<bool>(SUMO_ATTR_CONTAINER_TRIGGERED, nullptr, ok, false);
361 }
362 stop.parking = attrs.getOpt<bool>(SUMO_ATTR_PARKING, nullptr, ok, stop.triggered || stop.containerTriggered || stop.parkingarea != "");
363 if (stop.parkingarea != "" && !stop.parking) {
364 ok = false;
365 }
366 if (!ok) {
367 errorOutput->inform("Invalid bool for 'triggered', 'containerTriggered' or 'parking' for stop" + errorSuffix);
368 return false;
369 }
370
371 // expected persons
372 const std::vector<std::string>& expected = attrs.getOptStringVector(SUMO_ATTR_EXPECTED, nullptr, ok);
373 stop.awaitedPersons.insert(expected.begin(), expected.end());
374 if (stop.awaitedPersons.size() > 0 && (stop.parametersSet & STOP_TRIGGER_SET) == 0) {
375 stop.triggered = true;
376 if ((stop.parametersSet & STOP_PARKING_SET) == 0) {
377 stop.parking = true;
378 }
379 }
380
381 // expected containers
382 const std::vector<std::string>& expectedContainers = attrs.getOptStringVector(SUMO_ATTR_EXPECTED_CONTAINERS, nullptr, ok);
383 stop.awaitedContainers.insert(expectedContainers.begin(), expectedContainers.end());
384 if (stop.awaitedContainers.size() > 0 && (stop.parametersSet & STOP_CONTAINER_TRIGGER_SET) == 0) {
385 stop.containerTriggered = true;
386 if ((stop.parametersSet & STOP_PARKING_SET) == 0) {
387 stop.parking = true;
388 }
389 }
390 // public transport trip id
391 stop.tripId = attrs.getOpt<std::string>(SUMO_ATTR_TRIP_ID, nullptr, ok, "");
392
393 const std::string idx = attrs.getOpt<std::string>(SUMO_ATTR_INDEX, nullptr, ok, "end");
394 if (idx == "end") {
395 stop.index = STOP_INDEX_END;
396 } else if (idx == "fit") {
397 stop.index = STOP_INDEX_FIT;
398 } else {
399 stop.index = attrs.get<int>(SUMO_ATTR_INDEX, nullptr, ok);
400 if (!ok || stop.index < 0) {
401 errorOutput->inform("Invalid 'index' for stop" + errorSuffix);
402 return false;
403 }
404 }
405 return true;
406 }
407
408 /****************************************************************************/
409