Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-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 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 78736 : SUMORouteHandler::SUMORouteHandler(const std::string& file, const std::string& expectedRoot, const bool hardFail) :
40 : SUMOSAXHandler(file, expectedRoot),
41 78736 : myHardFail(hardFail),
42 78736 : myVehicleParameter(nullptr),
43 78736 : myLastDepart(-1),
44 78736 : myActiveRouteColor(nullptr),
45 78736 : myCurrentCosts(0.),
46 78736 : myCurrentVType(nullptr),
47 236206 : myBeginDefault(OptionsCont::getOptions().exists("begin") ? string2time(OptionsCont::getOptions().getString("begin")) : 0),
48 236206 : myEndDefault(OptionsCont::getOptions().exists("end") ? string2time(OptionsCont::getOptions().getString("end")) : -1),
49 78736 : myFirstDepart(-1),
50 78736 : myInsertStopEdgesAt(-1),
51 157472 : myAllowInternalRoutes(false) {
52 78736 : }
53 :
54 :
55 78290 : SUMORouteHandler::~SUMORouteHandler() {
56 78290 : delete myVehicleParameter;
57 78290 : delete myCurrentVType;
58 78290 : }
59 :
60 :
61 : bool
62 606552 : SUMORouteHandler::checkLastDepart() {
63 606552 : if (myVehicleParameter->departProcedure == DepartDefinition::GIVEN) {
64 605612 : if (myVehicleParameter->depart < myLastDepart) {
65 16 : WRITE_WARNINGF(TL("Route file should be sorted by departure time, ignoring '%'!"), myVehicleParameter->id);
66 8 : return false;
67 : }
68 : }
69 : return true;
70 : }
71 :
72 :
73 : void
74 655455 : SUMORouteHandler::registerLastDepart() {
75 : // register only non public transport to parse all public transport lines in advance
76 655455 : if (myVehicleParameter && myVehicleParameter->line == "" && myVehicleParameter->departProcedure == DepartDefinition::GIVEN) {
77 650109 : myLastDepart = myVehicleParameter->depart;
78 650109 : if (myFirstDepart == -1) {
79 39788 : myFirstDepart = myLastDepart;
80 : }
81 : }
82 : // else: we don't know when this vehicle will depart. keep the previous known depart time
83 655455 : }
84 :
85 :
86 : void
87 11024599 : SUMORouteHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
88 11024599 : myElementStack.push_back(element);
89 11024599 : switch (element) {
90 400975 : case SUMO_TAG_VEHICLE:
91 : case SUMO_TAG_PERSON:
92 : case SUMO_TAG_CONTAINER:
93 : // if myVehicleParameter is nullptr this will do nothing
94 400975 : delete myVehicleParameter;
95 : // we set to nullptr to have a consistent state if the parsing fails
96 400975 : myVehicleParameter = nullptr;
97 400975 : myVehicleParameter = SUMOVehicleParserHelper::parseVehicleAttributes(element, attrs, myHardFail, false, false, myAllowInternalRoutes);
98 400715 : myParamStack.push_back(myVehicleParameter);
99 400715 : if (element != SUMO_TAG_VEHICLE) {
100 45540 : addTransportable(attrs, element == SUMO_TAG_PERSON);
101 : }
102 : break;
103 20142 : case SUMO_TAG_FLOW:
104 : // delete if myVehicleParameter isn't null
105 20142 : if (myVehicleParameter) {
106 0 : delete myVehicleParameter;
107 0 : myVehicleParameter = nullptr;
108 : }
109 : // parse vehicle parameters
110 : // might be called to parse vehicles from additional file in the
111 : // context of quickReload. In this case, rerouter flows must be ignored
112 20142 : if (myElementStack.size() == 1 || myElementStack[myElementStack.size() - 2] != SUMO_TAG_CALIBRATOR) {
113 20142 : myVehicleParameter = SUMOVehicleParserHelper::parseFlowAttributes(SUMO_TAG_FLOW, attrs, myHardFail, true, myBeginDefault, myEndDefault, myAllowInternalRoutes);
114 : }
115 : // check if myVehicleParameter was successfully created
116 20024 : if (myVehicleParameter) {
117 : // check tag
118 20024 : if (myVehicleParameter->routeid.empty()) {
119 : // open a route flow (It could be a flow with embedded route)
120 11755 : openFlow(attrs);
121 : } else {
122 : // open a route flow
123 8269 : openRouteFlow(attrs);
124 : }
125 20024 : myParamStack.push_back(myVehicleParameter);
126 : }
127 : break;
128 2227 : case SUMO_TAG_PERSONFLOW:
129 : case SUMO_TAG_CONTAINERFLOW:
130 : // delete if myVehicleParameter isn't null
131 2227 : if (myVehicleParameter) {
132 0 : delete myVehicleParameter;
133 0 : myVehicleParameter = nullptr;
134 : }
135 : // create a new flow
136 2227 : myVehicleParameter = SUMOVehicleParserHelper::parseFlowAttributes((SumoXMLTag)element, attrs, myHardFail, true, myBeginDefault, myEndDefault, myAllowInternalRoutes);
137 2227 : myParamStack.push_back(myVehicleParameter);
138 2227 : break;
139 62610 : case SUMO_TAG_VTYPE:
140 : // delete if myCurrentVType isn't null
141 62610 : if (myCurrentVType != nullptr) {
142 4 : delete myCurrentVType;
143 4 : myCurrentVType = nullptr;
144 : }
145 : // create a new vType
146 62610 : myCurrentVType = SUMOVehicleParserHelper::beginVTypeParsing(attrs, myHardFail, getFileName());
147 62580 : myParamStack.push_back(myCurrentVType);
148 62580 : break;
149 527 : case SUMO_TAG_VTYPE_DISTRIBUTION:
150 527 : openVehicleTypeDistribution(attrs);
151 527 : break;
152 383980 : case SUMO_TAG_ROUTE:
153 383980 : openRoute(attrs);
154 383928 : break;
155 92347 : case SUMO_TAG_ROUTE_DISTRIBUTION:
156 92347 : openRouteDistribution(attrs);
157 92347 : break;
158 38641 : case SUMO_TAG_STOP:
159 38641 : myParamStack.push_back(addStop(attrs));
160 38523 : break;
161 235609 : case SUMO_TAG_TRIP: {
162 : // delete if myVehicleParameter isn't null
163 235609 : if (myVehicleParameter) {
164 0 : delete myVehicleParameter;
165 0 : myVehicleParameter = nullptr;
166 : }
167 : // parse vehicle parameters
168 235609 : myVehicleParameter = SUMOVehicleParserHelper::parseVehicleAttributes(element, attrs, myHardFail, false, false, myAllowInternalRoutes);
169 : // check if myVehicleParameter was successfully created
170 235555 : if (myVehicleParameter) {
171 235555 : myVehicleParameter->parametersSet |= VEHPARS_FORCE_REROUTE;
172 235555 : myActiveRouteID = "!" + myVehicleParameter->id;
173 : // open trip
174 235555 : openTrip(attrs);
175 235555 : myParamStack.push_back(myVehicleParameter);
176 : }
177 : break;
178 : }
179 4368 : case SUMO_TAG_PERSONTRIP:
180 4368 : addPersonTrip(attrs);
181 4351 : break;
182 39685 : case SUMO_TAG_WALK:
183 39685 : addWalk(attrs);
184 39663 : break;
185 19 : case SUMO_TAG_INTERVAL: {
186 : bool ok;
187 19 : myBeginDefault = attrs.getSUMOTimeReporting(SUMO_ATTR_BEGIN, nullptr, ok);
188 19 : myEndDefault = attrs.getSUMOTimeReporting(SUMO_ATTR_END, nullptr, ok);
189 : break;
190 : }
191 4924 : case SUMO_TAG_RIDE:
192 4924 : addRide(attrs);
193 4894 : break;
194 1870 : case SUMO_TAG_TRANSPORT:
195 1870 : addTransport(attrs);
196 1855 : break;
197 1579 : case SUMO_TAG_TRANSHIP:
198 1579 : addTranship(attrs);
199 1579 : break;
200 55177 : case SUMO_TAG_PARAM:
201 55177 : addParam(attrs);
202 55177 : break;
203 9679919 : default:
204 : // parse embedded car following model information
205 9679919 : if (myCurrentVType != nullptr) {
206 32 : WRITE_WARNINGF(TL("Defining car-following parameters in a nested element is deprecated in vType '%', use attributes instead!"), myCurrentVType->id);
207 16 : if (!SUMOVehicleParserHelper::parseCFMParams(myCurrentVType, (SumoXMLTag)element, attrs, true)) {
208 0 : if (myHardFail) {
209 0 : throw ProcessError(TL("Invalid parsing embedded VType"));
210 : } else {
211 0 : WRITE_ERROR(TL("Invalid parsing embedded VType"));
212 : }
213 : }
214 : }
215 : break;
216 : }
217 11023883 : }
218 :
219 :
220 : void
221 11017257 : SUMORouteHandler::myEndElement(int element) {
222 11017257 : switch (element) {
223 38523 : case SUMO_TAG_STOP:
224 : myParamStack.pop_back();
225 : break;
226 383926 : case SUMO_TAG_ROUTE:
227 383926 : closeRoute();
228 383872 : break;
229 62576 : case SUMO_TAG_VTYPE:
230 62576 : closeVType();
231 62552 : delete myCurrentVType;
232 62552 : myCurrentVType = nullptr;
233 : myParamStack.pop_back();
234 : break;
235 43336 : case SUMO_TAG_PERSON:
236 43336 : closePerson();
237 43310 : delete myVehicleParameter;
238 43310 : myVehicleParameter = nullptr;
239 : myParamStack.pop_back();
240 : break;
241 1895 : case SUMO_TAG_PERSONFLOW:
242 1895 : closePersonFlow();
243 1883 : delete myVehicleParameter;
244 1883 : myVehicleParameter = nullptr;
245 : myParamStack.pop_back();
246 : break;
247 2092 : case SUMO_TAG_CONTAINER:
248 2092 : closeContainer();
249 2084 : delete myVehicleParameter;
250 2084 : myVehicleParameter = nullptr;
251 : myParamStack.pop_back();
252 : break;
253 329 : case SUMO_TAG_CONTAINERFLOW:
254 329 : closeContainerFlow();
255 329 : delete myVehicleParameter;
256 329 : myVehicleParameter = nullptr;
257 : myParamStack.pop_back();
258 : break;
259 355026 : case SUMO_TAG_VEHICLE:
260 355026 : if (myVehicleParameter == nullptr) {
261 : break;
262 : }
263 355026 : if (myVehicleParameter->repetitionNumber > 0) {
264 0 : myVehicleParameter->repetitionNumber++; // for backwards compatibility
265 : // it is a flow, thus no break here
266 : FALLTHROUGH;
267 : } else {
268 355026 : closeVehicle();
269 354940 : delete myVehicleParameter;
270 354940 : myVehicleParameter = nullptr;
271 : myParamStack.pop_back();
272 : break;
273 : }
274 : case SUMO_TAG_FLOW:
275 20020 : if (myVehicleParameter) {
276 20020 : closeFlow();
277 20013 : delete myVehicleParameter;
278 : myParamStack.pop_back();
279 : }
280 20013 : myVehicleParameter = nullptr;
281 20013 : myInsertStopEdgesAt = -1;
282 20013 : break;
283 235509 : case SUMO_TAG_TRIP:
284 235509 : closeTrip();
285 235496 : delete myVehicleParameter;
286 235496 : myVehicleParameter = nullptr;
287 : myParamStack.pop_back();
288 235496 : myInsertStopEdgesAt = -1;
289 235496 : break;
290 524 : case SUMO_TAG_VTYPE_DISTRIBUTION:
291 524 : closeVehicleTypeDistribution();
292 524 : break;
293 92317 : case SUMO_TAG_ROUTE_DISTRIBUTION:
294 92317 : closeRouteDistribution();
295 92317 : break;
296 52338 : case SUMO_TAG_PERSONTRIP:
297 : case SUMO_TAG_RIDE:
298 : case SUMO_TAG_TRANSPORT:
299 : case SUMO_TAG_TRANSHIP:
300 : case SUMO_TAG_WALK:
301 52338 : if (myParamStack.size() == 2) {
302 : myParamStack.pop_back();
303 : }
304 : break;
305 19 : case SUMO_TAG_INTERVAL:
306 19 : myBeginDefault = string2time(OptionsCont::getOptions().getString("begin"));
307 19 : myEndDefault = string2time(OptionsCont::getOptions().getString("end"));
308 19 : break;
309 : default:
310 : break;
311 : }
312 : myElementStack.pop_back();
313 11017027 : }
314 :
315 :
316 : SUMORouteHandler::StopPos
317 97986 : SUMORouteHandler::checkStopPos(double& startPos, double& endPos, const double laneLength, const double minLength, const bool friendlyPos) {
318 97986 : if (minLength > laneLength) {
319 : return STOPPOS_INVALID_LANELENGTH;
320 : }
321 97986 : if (startPos < 0) {
322 137 : startPos += laneLength;
323 : }
324 97986 : if (endPos < 0) {
325 1930 : endPos += laneLength;
326 : }
327 97986 : if ((endPos < minLength) || (endPos > laneLength)) {
328 112 : if (!friendlyPos) {
329 : return STOPPOS_INVALID_ENDPOS;
330 : }
331 107 : if (endPos < minLength) {
332 3 : endPos = minLength;
333 : }
334 107 : if (endPos > laneLength) {
335 104 : endPos = laneLength;
336 : }
337 : }
338 97981 : if ((startPos < 0) || (startPos > (endPos - minLength))) {
339 37 : if (!friendlyPos) {
340 : return STOPPOS_INVALID_STARTPOS;
341 : }
342 37 : if (startPos < 0) {
343 13 : startPos = 0;
344 : }
345 37 : if (startPos > (endPos - minLength)) {
346 24 : startPos = endPos - minLength;
347 : }
348 : }
349 : return STOPPOS_VALID;
350 : }
351 :
352 :
353 : bool
354 0 : SUMORouteHandler::isStopPosValid(const double startPos, const double endPos, const double laneLength, const double minLength, const bool friendlyPos) {
355 : // declare dummy start and end positions
356 0 : double dummyStartPos = startPos;
357 0 : double dummyEndPos = endPos;
358 : // return checkStopPos
359 0 : return (checkStopPos(dummyStartPos, dummyEndPos, laneLength, minLength, friendlyPos) == STOPPOS_VALID);
360 : }
361 :
362 :
363 : SUMOTime
364 96620 : SUMORouteHandler::getFirstDepart() const {
365 96620 : return myFirstDepart;
366 : }
367 :
368 :
369 : SUMOTime
370 3222460 : SUMORouteHandler::getLastDepart() const {
371 3222460 : return myLastDepart;
372 : }
373 :
374 :
375 : void
376 55177 : SUMORouteHandler::addParam(const SUMOSAXAttributes& attrs) {
377 55177 : bool ok = true;
378 55177 : const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
379 : // only continue if key isn't empty
380 55177 : if (ok && (key.size() > 0)) {
381 : // circumventing empty string test
382 55177 : 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 46933 : if ((myVehicleParameter != nullptr || myCurrentVType != nullptr)
385 61324 : && (key == "device.toc.file" || key == "device.ssm.file")) {
386 786 : val = FileHelpers::checkForRelativity(val, getFileName());
387 : }
388 : // add parameter in current created element
389 55177 : if (!myParamStack.empty()) {
390 14391 : myParamStack.back()->setParameter(key, val);
391 : }
392 : }
393 55177 : }
394 :
395 :
396 : bool
397 38625 : SUMORouteHandler::parseStop(SUMOVehicleParameter::Stop& stop, const SUMOSAXAttributes& attrs, std::string errorSuffix, MsgHandler* const errorOutput) {
398 38625 : stop.parametersSet = 0;
399 38625 : if (attrs.hasAttribute(SUMO_ATTR_ARRIVAL)) {
400 398 : stop.parametersSet |= STOP_ARRIVAL_SET;
401 : }
402 38625 : if (attrs.hasAttribute(SUMO_ATTR_DURATION)) {
403 20692 : stop.parametersSet |= STOP_DURATION_SET;
404 : }
405 38625 : if (attrs.hasAttribute(SUMO_ATTR_UNTIL)) {
406 18833 : stop.parametersSet |= STOP_UNTIL_SET;
407 : }
408 38625 : if (attrs.hasAttribute(SUMO_ATTR_STARTED)) {
409 6541 : stop.parametersSet |= STOP_STARTED_SET;
410 : }
411 38625 : if (attrs.hasAttribute(SUMO_ATTR_ENDED)) {
412 6049 : stop.parametersSet |= STOP_ENDED_SET;
413 : }
414 38625 : if (attrs.hasAttribute(SUMO_ATTR_EXTENSION)) {
415 464 : stop.parametersSet |= STOP_EXTENSION_SET;
416 : }
417 38625 : if (attrs.hasAttribute(SUMO_ATTR_ENDPOS)) {
418 8641 : stop.parametersSet |= STOP_END_SET;
419 : }
420 38625 : if (attrs.hasAttribute(SUMO_ATTR_STARTPOS)) {
421 1540 : stop.parametersSet |= STOP_START_SET;
422 : }
423 38625 : if (attrs.hasAttribute(SUMO_ATTR_POSITION_LAT)) {
424 125 : stop.parametersSet |= STOP_POSLAT_SET;
425 : }
426 38625 : if (attrs.hasAttribute(SUMO_ATTR_TRIGGERED)) {
427 1479 : stop.parametersSet |= STOP_TRIGGER_SET;
428 : }
429 : // legacy attribute
430 38625 : if (attrs.hasAttribute(SUMO_ATTR_CONTAINER_TRIGGERED)) {
431 56 : stop.parametersSet |= STOP_TRIGGER_SET;
432 : }
433 38625 : if (attrs.hasAttribute(SUMO_ATTR_PARKING)) {
434 914 : stop.parametersSet |= STOP_PARKING_SET;
435 : }
436 38625 : if (attrs.hasAttribute(SUMO_ATTR_EXPECTED)) {
437 242 : stop.parametersSet |= STOP_EXPECTED_SET;
438 : }
439 38625 : if (attrs.hasAttribute(SUMO_ATTR_PERMITTED)) {
440 344 : stop.parametersSet |= STOP_PERMITTED_SET;
441 : }
442 38625 : if (attrs.hasAttribute(SUMO_ATTR_EXPECTED_CONTAINERS)) {
443 77 : stop.parametersSet |= STOP_EXPECTED_CONTAINERS_SET;
444 : }
445 38625 : if (attrs.hasAttribute(SUMO_ATTR_TRIP_ID)) {
446 432 : stop.parametersSet |= STOP_TRIP_ID_SET;
447 : }
448 38625 : if (attrs.hasAttribute(SUMO_ATTR_SPLIT)) {
449 356 : stop.parametersSet |= STOP_SPLIT_SET;
450 : }
451 38625 : if (attrs.hasAttribute(SUMO_ATTR_JOIN)) {
452 116 : stop.parametersSet |= STOP_JOIN_SET;
453 : }
454 38625 : if (attrs.hasAttribute(SUMO_ATTR_LINE)) {
455 387 : stop.parametersSet |= STOP_LINE_SET;
456 : }
457 38625 : if (attrs.hasAttribute(SUMO_ATTR_SPEED)) {
458 670 : stop.parametersSet |= STOP_SPEED_SET;
459 : }
460 38625 : if (attrs.hasAttribute(SUMO_ATTR_ONDEMAND)) {
461 171 : stop.parametersSet |= STOP_ONDEMAND_SET;
462 : }
463 38625 : if (attrs.hasAttribute(SUMO_ATTR_PRIORITY)) {
464 237 : stop.parametersSet |= STOP_PRIORITY_SET;
465 : }
466 38625 : if (attrs.hasAttribute(SUMO_ATTR_JUMP)) {
467 545 : stop.parametersSet |= STOP_JUMP_SET;
468 : }
469 38625 : if (attrs.hasAttribute(SUMO_ATTR_JUMP_UNTIL)) {
470 7 : stop.parametersSet |= STOP_JUMP_UNTIL_SET;
471 : }
472 38625 : bool ok = true;
473 77250 : stop.busstop = attrs.getOpt<std::string>(SUMO_ATTR_BUS_STOP, nullptr, ok, "");
474 38625 : stop.busstop = attrs.getOpt<std::string>(SUMO_ATTR_TRAIN_STOP, nullptr, ok, stop.busstop);
475 38625 : stop.chargingStation = attrs.getOpt<std::string>(SUMO_ATTR_CHARGING_STATION, nullptr, ok, "");
476 38625 : stop.overheadWireSegment = attrs.getOpt<std::string>(SUMO_ATTR_OVERHEAD_WIRE_SEGMENT, nullptr, ok, "");
477 38625 : stop.containerstop = attrs.getOpt<std::string>(SUMO_ATTR_CONTAINER_STOP, nullptr, ok, "");
478 77250 : stop.parkingarea = attrs.getOpt<std::string>(SUMO_ATTR_PARKING_AREA, nullptr, ok, "");
479 38625 : if (stop.busstop != "") {
480 31146 : errorSuffix = " at '" + stop.busstop + "'" + errorSuffix;
481 28243 : } else if (stop.chargingStation != "") {
482 3378 : errorSuffix = " at '" + stop.chargingStation + "'" + errorSuffix;
483 27117 : } else if (stop.overheadWireSegment != "") {
484 0 : errorSuffix = " at '" + stop.overheadWireSegment + "'" + errorSuffix;
485 27117 : } else if (stop.containerstop != "") {
486 1908 : errorSuffix = " at '" + stop.containerstop + "'" + errorSuffix;
487 26481 : } else if (stop.parkingarea != "") {
488 45882 : errorSuffix = " at '" + stop.parkingarea + "'" + errorSuffix;
489 11187 : } else if (attrs.hasAttribute(SUMO_ATTR_LANE)) {
490 28452 : errorSuffix = " on lane '" + attrs.get<std::string>(SUMO_ATTR_LANE, nullptr, ok) + "'" + errorSuffix;
491 1703 : } else if (attrs.hasAttribute(SUMO_ATTR_EDGE)) {
492 4809 : errorSuffix = " on edge '" + attrs.get<std::string>(SUMO_ATTR_EDGE, nullptr, ok) + "'" + errorSuffix;
493 : } else {
494 200 : errorSuffix = " at undefined location" + errorSuffix;
495 : }
496 : // speed for counting as stopped
497 38625 : stop.speed = attrs.getOpt<double>(SUMO_ATTR_SPEED, nullptr, ok, 0);
498 38625 : if (stop.speed < 0) {
499 12 : errorOutput->inform(TLF("Speed cannot be negative for stop%.", errorSuffix));
500 6 : return false;
501 : }
502 :
503 : // get the standing duration
504 38619 : bool expectTrigger = !attrs.hasAttribute(SUMO_ATTR_DURATION) && !attrs.hasAttribute(SUMO_ATTR_UNTIL) && !attrs.hasAttribute(SUMO_ATTR_SPEED);
505 38619 : std::vector<std::string> triggers = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_TRIGGERED, nullptr, ok);
506 : // legacy
507 38619 : if (attrs.getOpt<bool>(SUMO_ATTR_CONTAINER_TRIGGERED, nullptr, ok, false)) {
508 112 : triggers.push_back(toString(SUMO_TAG_CONTAINER));
509 : }
510 38619 : SUMOVehicleParameter::parseStopTriggers(triggers, expectTrigger, stop);
511 38619 : stop.arrival = attrs.getOptSUMOTimeReporting(SUMO_ATTR_ARRIVAL, nullptr, ok, -1);
512 38619 : stop.duration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_DURATION, nullptr, ok, -1);
513 38619 : stop.until = attrs.getOptSUMOTimeReporting(SUMO_ATTR_UNTIL, nullptr, ok, -1);
514 38619 : if (!expectTrigger && (!ok || (stop.duration < 0 && stop.until < 0 && stop.speed == 0))) {
515 36 : errorOutput->inform(TLF("Invalid duration or end time is given for a stop%.", errorSuffix));
516 12 : return false;
517 : }
518 38607 : if (triggers.size() > 0 && stop.speed > 0) {
519 27 : errorOutput->inform(TLF("Triggers and waypoints cannot be combined%.", errorSuffix));
520 9 : return false;
521 : }
522 38598 : stop.extension = attrs.getOptSUMOTimeReporting(SUMO_ATTR_EXTENSION, nullptr, ok, -1);
523 38598 : const bool defaultParking = (stop.triggered || stop.containerTriggered || stop.parkingarea != "");
524 38598 : stop.parking = attrs.getOpt<ParkingType>(SUMO_ATTR_PARKING, nullptr, ok, defaultParking ? ParkingType::OFFROAD : ParkingType::ONROAD);
525 38598 : if ((stop.parkingarea != "") && (stop.parking == ParkingType::ONROAD)) {
526 21 : WRITE_WARNINGF(TL("Stop at parkingArea overrides attribute 'parking' for stop%."), errorSuffix);
527 7 : stop.parking = ParkingType::OFFROAD;
528 : }
529 :
530 : // expected persons
531 38598 : const std::vector<std::string>& expected = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_EXPECTED, nullptr, ok);
532 : stop.awaitedPersons.insert(expected.begin(), expected.end());
533 38598 : if (stop.awaitedPersons.size() > 0) {
534 242 : stop.triggered = true;
535 242 : if ((stop.parametersSet & STOP_PARKING_SET) == 0) {
536 123 : stop.parking = ParkingType::OFFROAD;
537 : }
538 : }
539 :
540 : // permitted transportables
541 38598 : const std::vector<std::string>& permitted = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_PERMITTED, nullptr, ok);
542 : stop.permitted.insert(permitted.begin(), permitted.end());
543 :
544 : // expected containers
545 38598 : const std::vector<std::string>& expectedContainers = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_EXPECTED_CONTAINERS, nullptr, ok);
546 : stop.awaitedContainers.insert(expectedContainers.begin(), expectedContainers.end());
547 38598 : if (stop.awaitedContainers.size() > 0) {
548 77 : stop.containerTriggered = true;
549 77 : if ((stop.parametersSet & STOP_PARKING_SET) == 0) {
550 67 : stop.parking = ParkingType::OFFROAD;
551 : }
552 : }
553 : // public transport trip id
554 38598 : stop.tripId = attrs.getOpt<std::string>(SUMO_ATTR_TRIP_ID, nullptr, ok, "");
555 38598 : stop.split = attrs.getOpt<std::string>(SUMO_ATTR_SPLIT, nullptr, ok, "");
556 38598 : stop.join = attrs.getOpt<std::string>(SUMO_ATTR_JOIN, nullptr, ok, "");
557 38598 : stop.line = attrs.getOpt<std::string>(SUMO_ATTR_LINE, nullptr, ok, "");
558 :
559 38598 : const std::string idx = attrs.getOpt<std::string>(SUMO_ATTR_INDEX, nullptr, ok, "end");
560 38598 : if (idx == "end") {
561 38375 : stop.index = STOP_INDEX_END;
562 223 : } else if (idx == "fit") {
563 14 : stop.index = STOP_INDEX_FIT;
564 : } else {
565 209 : stop.index = attrs.get<int>(SUMO_ATTR_INDEX, nullptr, ok);
566 209 : if (!ok || stop.index < 0) {
567 18 : errorOutput->inform(TLF("Invalid 'index' for stop%.", errorSuffix));
568 6 : return false;
569 : }
570 : }
571 38592 : stop.started = attrs.getOptSUMOTimeReporting(SUMO_ATTR_STARTED, nullptr, ok, -1);
572 38592 : stop.ended = attrs.getOptSUMOTimeReporting(SUMO_ATTR_ENDED, nullptr, ok, -1);
573 38592 : stop.posLat = attrs.getOpt<double>(SUMO_ATTR_POSITION_LAT, nullptr, ok, INVALID_DOUBLE);
574 38592 : stop.actType = attrs.getOpt<std::string>(SUMO_ATTR_ACTTYPE, nullptr, ok, "");
575 38592 : stop.onDemand = attrs.getOpt<bool>(SUMO_ATTR_ONDEMAND, nullptr, ok, false);
576 38592 : stop.priority = attrs.getOpt<double>(SUMO_ATTR_PRIORITY, nullptr, ok, -1);
577 38592 : stop.jump = attrs.getOptSUMOTimeReporting(SUMO_ATTR_JUMP, nullptr, ok, -1);
578 38592 : stop.jumpUntil = attrs.getOptSUMOTimeReporting(SUMO_ATTR_JUMP_UNTIL, nullptr, ok, -1);
579 38592 : stop.collision = attrs.getOpt<bool>(SUMO_ATTR_COLLISION, nullptr, ok, false);
580 38592 : return true;
581 38619 : }
582 :
583 :
584 : /****************************************************************************/
|