Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-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 SUMORouteHandler.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Sascha Krieg
18 : /// @author Michael Behrisch
19 : /// @date Mon, 9 Jul 2001
20 : ///
21 : // Parser for routes during their loading
22 : /****************************************************************************/
23 : #include <config.h>
24 :
25 : #include <utils/common/MsgHandler.h>
26 : #include <utils/common/FileHelpers.h>
27 : #include <utils/options/OptionsCont.h>
28 : #include <utils/vehicle/SUMOVTypeParameter.h>
29 : #include <utils/vehicle/SUMOVehicleParserHelper.h>
30 : #include <utils/xml/XMLSubSys.h>
31 :
32 : #include "SUMORouteHandler.h"
33 :
34 :
35 : // ===========================================================================
36 : // method definitions
37 : // ===========================================================================
38 :
39 83449 : SUMORouteHandler::SUMORouteHandler(const std::string& file, const std::string& expectedRoot, const bool hardFail) :
40 : SUMOSAXHandler(file, expectedRoot),
41 83449 : myHardFail(hardFail),
42 83449 : myVehicleParameter(nullptr),
43 83449 : myLastDepart(-1),
44 83449 : myActiveRouteColor(nullptr),
45 83449 : myCurrentCosts(0.),
46 83449 : myCurrentVType(nullptr),
47 83449 : myCurrentVTypeProbability(-1),
48 250345 : myBeginDefault(OptionsCont::getOptions().exists("begin") ? string2time(OptionsCont::getOptions().getString("begin")) : 0),
49 250345 : myEndDefault(OptionsCont::getOptions().exists("end") ? string2time(OptionsCont::getOptions().getString("end")) : -1),
50 83449 : myFirstDepart(-1),
51 83449 : myInsertStopEdgesAt(-1),
52 166898 : myAllowInternalRoutes(false) {
53 83449 : }
54 :
55 :
56 83005 : SUMORouteHandler::~SUMORouteHandler() {
57 83005 : delete myVehicleParameter;
58 83005 : delete myCurrentVType;
59 83005 : }
60 :
61 :
62 : bool
63 613477 : SUMORouteHandler::checkLastDepart() {
64 613477 : if (myVehicleParameter->departProcedure == DepartDefinition::GIVEN) {
65 612537 : if (myVehicleParameter->depart < myLastDepart) {
66 16 : WRITE_WARNINGF(TL("Route file should be sorted by departure time, ignoring '%'!"), myVehicleParameter->id);
67 8 : return false;
68 : }
69 : }
70 : return true;
71 : }
72 :
73 :
74 : void
75 661980 : SUMORouteHandler::registerLastDepart() {
76 : // register only non public transport to parse all public transport lines in advance
77 661980 : if (myVehicleParameter && myVehicleParameter->line == "" && myVehicleParameter->departProcedure == DepartDefinition::GIVEN) {
78 656122 : myLastDepart = myVehicleParameter->depart;
79 656122 : if (myFirstDepart == -1) {
80 42020 : myFirstDepart = myLastDepart;
81 : }
82 : }
83 : // else: we don't know when this vehicle will depart. keep the previous known depart time
84 661980 : }
85 :
86 :
87 : void
88 11669317 : SUMORouteHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
89 11669317 : myElementStack.push_back(element);
90 11669317 : switch (element) {
91 404395 : case SUMO_TAG_VEHICLE:
92 : case SUMO_TAG_PERSON:
93 : case SUMO_TAG_CONTAINER:
94 : // if myVehicleParameter is nullptr this will do nothing
95 404395 : delete myVehicleParameter;
96 : // we set to nullptr to have a consistent state if the parsing fails
97 404395 : myVehicleParameter = nullptr;
98 404395 : myVehicleParameter = SUMOVehicleParserHelper::parseVehicleAttributes(element, attrs, myHardFail, false, false, myAllowInternalRoutes);
99 404135 : myParamStack.push_back(myVehicleParameter);
100 404135 : if (element != SUMO_TAG_VEHICLE) {
101 47096 : addTransportable(attrs, element == SUMO_TAG_PERSON);
102 : }
103 : break;
104 22314 : case SUMO_TAG_FLOW:
105 : // delete if myVehicleParameter isn't null
106 22314 : if (myVehicleParameter) {
107 0 : delete myVehicleParameter;
108 0 : myVehicleParameter = nullptr;
109 : }
110 : // parse vehicle parameters
111 : // might be called to parse vehicles from additional file in the
112 : // context of quickReload. In this case, rerouter flows must be ignored
113 22314 : if (myElementStack.size() == 1 || myElementStack[myElementStack.size() - 2] != SUMO_TAG_CALIBRATOR) {
114 22314 : myVehicleParameter = SUMOVehicleParserHelper::parseFlowAttributes(SUMO_TAG_FLOW, attrs, myHardFail, true, myBeginDefault, myEndDefault, myAllowInternalRoutes);
115 : }
116 : // check if myVehicleParameter was successfully created
117 22196 : if (myVehicleParameter) {
118 : // check tag
119 22196 : if (myVehicleParameter->routeid.empty()) {
120 : // open a route flow (It could be a flow with embedded route)
121 12754 : openFlow(attrs);
122 : } else {
123 : // open a route flow
124 9442 : openRouteFlow(attrs);
125 : }
126 22196 : myParamStack.push_back(myVehicleParameter);
127 : }
128 : break;
129 2322 : case SUMO_TAG_PERSONFLOW:
130 : case SUMO_TAG_CONTAINERFLOW:
131 : // delete if myVehicleParameter isn't null
132 2322 : if (myVehicleParameter) {
133 0 : delete myVehicleParameter;
134 0 : myVehicleParameter = nullptr;
135 : }
136 : // create a new flow
137 2322 : myVehicleParameter = SUMOVehicleParserHelper::parseFlowAttributes((SumoXMLTag)element, attrs, myHardFail, true, myBeginDefault, myEndDefault, myAllowInternalRoutes);
138 2322 : myParamStack.push_back(myVehicleParameter);
139 2322 : break;
140 64436 : case SUMO_TAG_VTYPE:
141 : // delete if myCurrentVType isn't null
142 64436 : if (myCurrentVType != nullptr) {
143 4 : delete myCurrentVType;
144 4 : myCurrentVType = nullptr;
145 : }
146 : // create a new vType
147 64436 : if (attrs.hasAttribute(SUMO_ATTR_REFID) && !attrs.hasAttribute(SUMO_ATTR_ID)) {
148 122 : bool ok = true;
149 244 : myCurrentVTypeRef = attrs.get<std::string>(SUMO_ATTR_REFID, nullptr, ok);
150 122 : myCurrentVTypeProbability = attrs.getOpt<double>(SUMO_ATTR_PROB, myCurrentVTypeRef.c_str(), ok, -1);
151 : } else {
152 128598 : myCurrentVType = SUMOVehicleParserHelper::beginVTypeParsing(attrs, myHardFail, getFileName(), getVTypeParameter(attrs.getStringSecure(SUMO_ATTR_REFID, "")));
153 : }
154 64406 : myParamStack.push_back(myCurrentVType);
155 64406 : break;
156 619 : case SUMO_TAG_VTYPE_DISTRIBUTION:
157 619 : openVehicleTypeDistribution(attrs);
158 619 : break;
159 387558 : case SUMO_TAG_ROUTE:
160 387558 : openRoute(attrs);
161 387506 : break;
162 92418 : case SUMO_TAG_ROUTE_DISTRIBUTION:
163 92418 : openRouteDistribution(attrs);
164 92418 : break;
165 40955 : case SUMO_TAG_STOP:
166 40955 : myParamStack.push_back(addStop(attrs));
167 40887 : break;
168 236479 : case SUMO_TAG_TRIP: {
169 : // delete if myVehicleParameter isn't null
170 236479 : if (myVehicleParameter) {
171 0 : delete myVehicleParameter;
172 0 : myVehicleParameter = nullptr;
173 : }
174 : // parse vehicle parameters
175 236479 : myVehicleParameter = SUMOVehicleParserHelper::parseVehicleAttributes(element, attrs, myHardFail, false, false, myAllowInternalRoutes);
176 : // check if myVehicleParameter was successfully created
177 236425 : if (myVehicleParameter) {
178 236425 : myVehicleParameter->parametersSet |= VEHPARS_FORCE_REROUTE;
179 236425 : myActiveRouteID = "!" + myVehicleParameter->id;
180 : // open trip
181 236425 : openTrip(attrs);
182 236425 : myParamStack.push_back(myVehicleParameter);
183 : }
184 : break;
185 : }
186 5062 : case SUMO_TAG_PERSONTRIP:
187 5062 : addPersonTrip(attrs);
188 5047 : break;
189 40483 : case SUMO_TAG_WALK:
190 40483 : addWalk(attrs);
191 40463 : break;
192 23 : case SUMO_TAG_INTERVAL: {
193 : bool ok;
194 23 : myBeginDefault = attrs.getSUMOTimeReporting(SUMO_ATTR_BEGIN, nullptr, ok);
195 23 : myEndDefault = attrs.getSUMOTimeReporting(SUMO_ATTR_END, nullptr, ok);
196 : break;
197 : }
198 5523 : case SUMO_TAG_RIDE:
199 5523 : addRide(attrs);
200 5483 : break;
201 1875 : case SUMO_TAG_TRANSPORT:
202 1875 : addTransport(attrs);
203 1859 : break;
204 1584 : case SUMO_TAG_TRANSHIP:
205 1584 : addTranship(attrs);
206 1584 : break;
207 57642 : case SUMO_TAG_PARAM:
208 57642 : addParam(attrs);
209 57642 : break;
210 10305629 : default:
211 : // parse embedded car following model information
212 10305629 : if (myCurrentVType != nullptr) {
213 32 : WRITE_WARNINGF(TL("Defining car-following parameters in a nested element is deprecated in vType '%', use attributes instead!"), myCurrentVType->id);
214 16 : if (!SUMOVehicleParserHelper::parseCFMParams(myCurrentVType, (SumoXMLTag)element, attrs, true)) {
215 0 : if (myHardFail) {
216 0 : throw ProcessError(TL("Invalid parsing embedded VType"));
217 : } else {
218 0 : WRITE_ERROR(TL("Invalid parsing embedded VType"));
219 : }
220 : }
221 : }
222 : break;
223 : }
224 11668644 : }
225 :
226 :
227 : void
228 11661512 : SUMORouteHandler::myEndElement(int element) {
229 11661512 : switch (element) {
230 40887 : case SUMO_TAG_STOP:
231 : myParamStack.pop_back();
232 : break;
233 387506 : case SUMO_TAG_ROUTE:
234 387506 : closeRoute();
235 387452 : break;
236 64402 : case SUMO_TAG_VTYPE:
237 64402 : closeVType();
238 64378 : if (myCurrentVTypeRef.empty()) {
239 64256 : delete myCurrentVType;
240 : }
241 64378 : myCurrentVType = nullptr;
242 64378 : myCurrentVTypeRef = "";
243 64378 : myCurrentVTypeProbability = -1;
244 : myParamStack.pop_back();
245 : break;
246 44899 : case SUMO_TAG_PERSON:
247 44899 : closePerson();
248 44873 : delete myVehicleParameter;
249 44873 : myVehicleParameter = nullptr;
250 : myParamStack.pop_back();
251 : break;
252 1979 : case SUMO_TAG_PERSONFLOW:
253 1979 : closePersonFlow();
254 1967 : delete myVehicleParameter;
255 1967 : myVehicleParameter = nullptr;
256 : myParamStack.pop_back();
257 : break;
258 2095 : case SUMO_TAG_CONTAINER:
259 2095 : closeContainer();
260 2087 : delete myVehicleParameter;
261 2087 : myVehicleParameter = nullptr;
262 : myParamStack.pop_back();
263 : break;
264 331 : case SUMO_TAG_CONTAINERFLOW:
265 331 : closeContainerFlow();
266 331 : delete myVehicleParameter;
267 331 : myVehicleParameter = nullptr;
268 : myParamStack.pop_back();
269 : break;
270 356929 : case SUMO_TAG_VEHICLE:
271 356929 : if (myVehicleParameter == nullptr) {
272 : break;
273 : }
274 356929 : if (myVehicleParameter->repetitionNumber <= 0) {
275 356929 : closeVehicle();
276 356800 : delete myVehicleParameter;
277 356800 : myVehicleParameter = nullptr;
278 : myParamStack.pop_back();
279 : break;
280 : }
281 0 : myVehicleParameter->repetitionNumber++; // for backwards compatibility
282 : // it is a flow, thus no break here
283 : FALLTHROUGH;
284 22196 : case SUMO_TAG_FLOW:
285 22196 : if (myVehicleParameter) {
286 22196 : closeFlow();
287 22189 : delete myVehicleParameter;
288 : myParamStack.pop_back();
289 : }
290 22189 : myVehicleParameter = nullptr;
291 22189 : myInsertStopEdgesAt = -1;
292 22189 : break;
293 236384 : case SUMO_TAG_TRIP:
294 236384 : closeTrip();
295 236367 : delete myVehicleParameter;
296 236367 : myVehicleParameter = nullptr;
297 : myParamStack.pop_back();
298 236367 : myInsertStopEdgesAt = -1;
299 236367 : break;
300 619 : case SUMO_TAG_VTYPE_DISTRIBUTION:
301 619 : closeVehicleTypeDistribution();
302 619 : break;
303 92388 : case SUMO_TAG_ROUTE_DISTRIBUTION:
304 92388 : closeRouteDistribution();
305 92386 : break;
306 54432 : case SUMO_TAG_PERSONTRIP:
307 : case SUMO_TAG_RIDE:
308 : case SUMO_TAG_TRANSPORT:
309 : case SUMO_TAG_TRANSHIP:
310 : case SUMO_TAG_WALK:
311 54432 : if (myParamStack.size() == 2) {
312 : myParamStack.pop_back();
313 : }
314 : break;
315 23 : case SUMO_TAG_INTERVAL:
316 23 : myBeginDefault = string2time(OptionsCont::getOptions().getString("begin"));
317 23 : myEndDefault = string2time(OptionsCont::getOptions().getString("end"));
318 23 : break;
319 : default:
320 : break;
321 : }
322 : myElementStack.pop_back();
323 11661233 : }
324 :
325 :
326 : SUMORouteHandler::StopPos
327 101860 : SUMORouteHandler::checkStopPos(double& startPos, double& endPos, const double laneLength, const double minLength, const bool friendlyPos) {
328 101860 : if (minLength > laneLength) {
329 : return STOPPOS_INVALID_LANELENGTH;
330 : }
331 101860 : if (startPos < 0) {
332 161 : startPos += laneLength;
333 : }
334 101860 : if (endPos < 0) {
335 1512 : endPos += laneLength;
336 : }
337 101860 : if ((endPos < minLength) || (endPos > laneLength)) {
338 113 : if (!friendlyPos) {
339 : return STOPPOS_INVALID_ENDPOS;
340 : }
341 108 : if (endPos < minLength) {
342 3 : endPos = minLength;
343 : }
344 108 : if (endPos > laneLength) {
345 105 : endPos = laneLength;
346 : }
347 : }
348 101855 : if ((startPos < 0) || (startPos > (endPos - minLength))) {
349 37 : if (!friendlyPos) {
350 : return STOPPOS_INVALID_STARTPOS;
351 : }
352 37 : if (startPos < 0) {
353 13 : startPos = 0;
354 : }
355 37 : if (startPos > (endPos - minLength)) {
356 24 : startPos = endPos - minLength;
357 : }
358 : }
359 : return STOPPOS_VALID;
360 : }
361 :
362 :
363 : SUMOTime
364 102336 : SUMORouteHandler::getFirstDepart() const {
365 102336 : return myFirstDepart;
366 : }
367 :
368 :
369 : SUMOTime
370 3274413 : SUMORouteHandler::getLastDepart() const {
371 3274413 : return myLastDepart;
372 : }
373 :
374 :
375 : void
376 57642 : SUMORouteHandler::addParam(const SUMOSAXAttributes& attrs) {
377 57642 : bool ok = true;
378 57642 : const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
379 : // only continue if key isn't empty
380 57642 : if (ok && (key.size() > 0)) {
381 : // circumventing empty string test
382 57642 : std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
383 : // check special params that must be interpreted as relative paths
384 48716 : if ((myVehicleParameter != nullptr || myCurrentVType != nullptr)
385 64198 : && (key == "device.toc.file" || key == "device.ssm.file")) {
386 786 : val = FileHelpers::checkForRelativity(val, getFileName());
387 : }
388 : // add parameter in current created element
389 57642 : if (!myParamStack.empty()) {
390 15482 : if (!myCurrentVTypeRef.empty() && myParamStack.back() == myCurrentVType) {
391 0 : WRITE_WARNINGF(TL("Ignoring param for referenced vType %"), myCurrentVType->id);
392 : } else {
393 15482 : myParamStack.back()->setParameter(key, val);
394 : }
395 : }
396 : }
397 57642 : }
398 :
399 :
400 : bool
401 40939 : SUMORouteHandler::parseStop(SUMOVehicleParameter::Stop& stop, const SUMOSAXAttributes& attrs, std::string errorSuffix, MsgHandler* const errorOutput) {
402 40939 : stop.parametersSet = 0;
403 40939 : if (attrs.hasAttribute(SUMO_ATTR_ARRIVAL)) {
404 415 : stop.parametersSet |= STOP_ARRIVAL_SET;
405 : }
406 40939 : if (attrs.hasAttribute(SUMO_ATTR_DURATION)) {
407 22658 : stop.parametersSet |= STOP_DURATION_SET;
408 : }
409 40939 : if (attrs.hasAttribute(SUMO_ATTR_UNTIL)) {
410 20045 : stop.parametersSet |= STOP_UNTIL_SET;
411 : }
412 40939 : if (attrs.hasAttribute(SUMO_ATTR_STARTED)) {
413 6742 : stop.parametersSet |= STOP_STARTED_SET;
414 : }
415 40939 : if (attrs.hasAttribute(SUMO_ATTR_ENDED)) {
416 6224 : stop.parametersSet |= STOP_ENDED_SET;
417 : }
418 40939 : if (attrs.hasAttribute(SUMO_ATTR_EXTENSION)) {
419 464 : stop.parametersSet |= STOP_EXTENSION_SET;
420 : }
421 40939 : if (attrs.hasAttribute(SUMO_ATTR_ENDPOS)) {
422 9079 : stop.parametersSet |= STOP_END_SET;
423 : }
424 40939 : if (attrs.hasAttribute(SUMO_ATTR_STARTPOS)) {
425 1491 : stop.parametersSet |= STOP_START_SET;
426 : }
427 40939 : if (attrs.hasAttribute(SUMO_ATTR_POSITION_LAT)) {
428 125 : stop.parametersSet |= STOP_POSLAT_SET;
429 : }
430 40939 : if (attrs.hasAttribute(SUMO_ATTR_TRIGGERED)) {
431 1588 : stop.parametersSet |= STOP_TRIGGER_SET;
432 : }
433 : // legacy attribute
434 40939 : if (attrs.hasAttribute(SUMO_ATTR_CONTAINER_TRIGGERED)) {
435 56 : stop.parametersSet |= STOP_TRIGGER_SET;
436 : }
437 40939 : if (attrs.hasAttribute(SUMO_ATTR_PARKING)) {
438 980 : stop.parametersSet |= STOP_PARKING_SET;
439 : }
440 40939 : if (attrs.hasAttribute(SUMO_ATTR_EXPECTED)) {
441 242 : stop.parametersSet |= STOP_EXPECTED_SET;
442 : }
443 40939 : if (attrs.hasAttribute(SUMO_ATTR_PERMITTED)) {
444 369 : stop.parametersSet |= STOP_PERMITTED_SET;
445 : }
446 40939 : if (attrs.hasAttribute(SUMO_ATTR_EXPECTED_CONTAINERS)) {
447 77 : stop.parametersSet |= STOP_EXPECTED_CONTAINERS_SET;
448 : }
449 40939 : if (attrs.hasAttribute(SUMO_ATTR_TRIP_ID)) {
450 432 : stop.parametersSet |= STOP_TRIP_ID_SET;
451 : }
452 40939 : if (attrs.hasAttribute(SUMO_ATTR_SPLIT)) {
453 356 : stop.parametersSet |= STOP_SPLIT_SET;
454 : }
455 40939 : if (attrs.hasAttribute(SUMO_ATTR_JOIN)) {
456 116 : stop.parametersSet |= STOP_JOIN_SET;
457 : }
458 40939 : if (attrs.hasAttribute(SUMO_ATTR_LINE)) {
459 387 : stop.parametersSet |= STOP_LINE_SET;
460 : }
461 40939 : if (attrs.hasAttribute(SUMO_ATTR_SPEED)) {
462 673 : stop.parametersSet |= STOP_SPEED_SET;
463 : }
464 40939 : if (attrs.hasAttribute(SUMO_ATTR_ONDEMAND)) {
465 178 : stop.parametersSet |= STOP_ONDEMAND_SET;
466 : }
467 40939 : if (attrs.hasAttribute(SUMO_ATTR_PRIORITY)) {
468 321 : stop.parametersSet |= STOP_PRIORITY_SET;
469 : }
470 40939 : if (attrs.hasAttribute(SUMO_ATTR_JUMP)) {
471 545 : stop.parametersSet |= STOP_JUMP_SET;
472 : }
473 40939 : if (attrs.hasAttribute(SUMO_ATTR_JUMP_UNTIL)) {
474 7 : stop.parametersSet |= STOP_JUMP_UNTIL_SET;
475 : }
476 40939 : bool ok = true;
477 81878 : stop.busstop = attrs.getOpt<std::string>(SUMO_ATTR_BUS_STOP, nullptr, ok, "");
478 40939 : stop.busstop = attrs.getOpt<std::string>(SUMO_ATTR_TRAIN_STOP, nullptr, ok, stop.busstop);
479 40939 : stop.chargingStation = attrs.getOpt<std::string>(SUMO_ATTR_CHARGING_STATION, nullptr, ok, "");
480 40939 : stop.overheadWireSegment = attrs.getOpt<std::string>(SUMO_ATTR_OVERHEAD_WIRE_SEGMENT, nullptr, ok, "");
481 40939 : stop.containerstop = attrs.getOpt<std::string>(SUMO_ATTR_CONTAINER_STOP, nullptr, ok, "");
482 81878 : stop.parkingarea = attrs.getOpt<std::string>(SUMO_ATTR_PARKING_AREA, nullptr, ok, "");
483 40939 : if (stop.busstop != "") {
484 34698 : errorSuffix = " at '" + stop.busstop + "'" + errorSuffix;
485 29373 : } else if (stop.chargingStation != "") {
486 3624 : errorSuffix = " at '" + stop.chargingStation + "'" + errorSuffix;
487 28165 : } else if (stop.overheadWireSegment != "") {
488 0 : errorSuffix = " at '" + stop.overheadWireSegment + "'" + errorSuffix;
489 28165 : } else if (stop.containerstop != "") {
490 1908 : errorSuffix = " at '" + stop.containerstop + "'" + errorSuffix;
491 27529 : } else if (stop.parkingarea != "") {
492 46674 : errorSuffix = " at '" + stop.parkingarea + "'" + errorSuffix;
493 11971 : } else if (attrs.hasAttribute(SUMO_ATTR_LANE)) {
494 30048 : errorSuffix = " on lane '" + attrs.get<std::string>(SUMO_ATTR_LANE, nullptr, ok) + "'" + errorSuffix;
495 1955 : } else if (attrs.hasAttribute(SUMO_ATTR_EDGE)) {
496 5565 : errorSuffix = " on edge '" + attrs.get<std::string>(SUMO_ATTR_EDGE, nullptr, ok) + "'" + errorSuffix;
497 : } else {
498 200 : errorSuffix = " at undefined location" + errorSuffix;
499 : }
500 : // speed for counting as stopped
501 40939 : stop.speed = attrs.getOpt<double>(SUMO_ATTR_SPEED, nullptr, ok, 0);
502 40939 : if (stop.speed < 0) {
503 12 : errorOutput->inform(TLF("Speed cannot be negative for stop%.", errorSuffix));
504 6 : return false;
505 : }
506 :
507 : // get the standing duration
508 40933 : bool expectTrigger = !attrs.hasAttribute(SUMO_ATTR_DURATION) && !attrs.hasAttribute(SUMO_ATTR_UNTIL) && !attrs.hasAttribute(SUMO_ATTR_SPEED);
509 40933 : std::vector<std::string> triggers = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_TRIGGERED, nullptr, ok);
510 : // legacy
511 40933 : if (attrs.getOpt<bool>(SUMO_ATTR_CONTAINER_TRIGGERED, nullptr, ok, false)) {
512 112 : triggers.push_back(toString(SUMO_TAG_CONTAINER));
513 : }
514 40933 : SUMOVehicleParameter::parseStopTriggers(triggers, expectTrigger, stop);
515 40933 : stop.arrival = attrs.getOptSUMOTimeReporting(SUMO_ATTR_ARRIVAL, nullptr, ok, -1);
516 40933 : stop.duration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_DURATION, nullptr, ok, -1);
517 40933 : stop.until = attrs.getOptSUMOTimeReporting(SUMO_ATTR_UNTIL, nullptr, ok, -1);
518 40933 : if (!expectTrigger && (!ok || (stop.duration < 0 && stop.until < 0 && stop.speed == 0))) {
519 36 : errorOutput->inform(TLF("Invalid duration or end time is given for a stop%.", errorSuffix));
520 12 : return false;
521 : }
522 40921 : if (triggers.size() > 0 && stop.speed > 0) {
523 9 : errorOutput->inform(TLF("Triggers and waypoints cannot be combined%.", errorSuffix));
524 3 : return false;
525 : }
526 40918 : stop.extension = attrs.getOptSUMOTimeReporting(SUMO_ATTR_EXTENSION, nullptr, ok, -1);
527 40918 : const bool defaultParking = (stop.triggered || stop.containerTriggered || stop.parkingarea != "");
528 40918 : stop.parking = attrs.getOpt<ParkingType>(SUMO_ATTR_PARKING, nullptr, ok, defaultParking ? ParkingType::OFFROAD : ParkingType::ONROAD);
529 40918 : if ((stop.parkingarea != "") && (stop.parking == ParkingType::ONROAD)) {
530 21 : WRITE_WARNINGF(TL("Stop at parkingArea overrides attribute 'parking' for stop%."), errorSuffix);
531 7 : stop.parking = ParkingType::OFFROAD;
532 : }
533 :
534 : // expected persons
535 40918 : const std::vector<std::string>& expected = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_EXPECTED, nullptr, ok);
536 : stop.awaitedPersons.insert(expected.begin(), expected.end());
537 40918 : if (stop.awaitedPersons.size() > 0) {
538 242 : stop.triggered = true;
539 242 : if ((stop.parametersSet & STOP_PARKING_SET) == 0) {
540 123 : stop.parking = ParkingType::OFFROAD;
541 : }
542 : }
543 :
544 : // permitted transportables
545 40918 : const std::vector<std::string>& permitted = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_PERMITTED, nullptr, ok);
546 : stop.permitted.insert(permitted.begin(), permitted.end());
547 :
548 : // expected containers
549 40918 : const std::vector<std::string>& expectedContainers = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_EXPECTED_CONTAINERS, nullptr, ok);
550 : stop.awaitedContainers.insert(expectedContainers.begin(), expectedContainers.end());
551 40918 : if (stop.awaitedContainers.size() > 0) {
552 77 : stop.containerTriggered = true;
553 77 : if ((stop.parametersSet & STOP_PARKING_SET) == 0) {
554 67 : stop.parking = ParkingType::OFFROAD;
555 : }
556 : }
557 : // public transport trip id
558 40918 : stop.tripId = attrs.getOpt<std::string>(SUMO_ATTR_TRIP_ID, nullptr, ok, "");
559 40918 : stop.split = attrs.getOpt<std::string>(SUMO_ATTR_SPLIT, nullptr, ok, "");
560 40918 : stop.join = attrs.getOpt<std::string>(SUMO_ATTR_JOIN, nullptr, ok, "");
561 40918 : stop.line = attrs.getOpt<std::string>(SUMO_ATTR_LINE, nullptr, ok, "");
562 :
563 40918 : const std::string idx = attrs.getOpt<std::string>(SUMO_ATTR_INDEX, nullptr, ok, "end");
564 40918 : if (idx == "end") {
565 40685 : stop.index = STOP_INDEX_END;
566 233 : } else if (idx == "fit") {
567 14 : stop.index = STOP_INDEX_FIT;
568 : } else {
569 219 : stop.index = attrs.get<int>(SUMO_ATTR_INDEX, nullptr, ok);
570 219 : if (!ok || stop.index < 0) {
571 18 : errorOutput->inform(TLF("Invalid 'index' for stop%.", errorSuffix));
572 6 : return false;
573 : }
574 : }
575 40912 : stop.started = attrs.getOptSUMOTimeReporting(SUMO_ATTR_STARTED, nullptr, ok, -1);
576 40912 : stop.ended = attrs.getOptSUMOTimeReporting(SUMO_ATTR_ENDED, nullptr, ok, -1);
577 40912 : stop.posLat = attrs.getOpt<double>(SUMO_ATTR_POSITION_LAT, nullptr, ok, INVALID_DOUBLE);
578 40912 : stop.actType = attrs.getOpt<std::string>(SUMO_ATTR_ACTTYPE, nullptr, ok, "");
579 40912 : stop.onDemand = attrs.getOpt<bool>(SUMO_ATTR_ONDEMAND, nullptr, ok, false);
580 40912 : stop.priority = attrs.getOpt<double>(SUMO_ATTR_PRIORITY, nullptr, ok, -1);
581 40912 : stop.jump = attrs.getOptSUMOTimeReporting(SUMO_ATTR_JUMP, nullptr, ok, -1);
582 40912 : stop.jumpUntil = attrs.getOptSUMOTimeReporting(SUMO_ATTR_JUMP_UNTIL, nullptr, ok, -1);
583 40912 : stop.collision = attrs.getOpt<bool>(SUMO_ATTR_COLLISION, nullptr, ok, false);
584 40912 : return true;
585 40933 : }
586 :
587 :
588 : /****************************************************************************/
|