Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2008-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 SUMOVehicleParserHelper.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Axel Wegener
18 : /// @author Michael Behrisch
19 : /// @author Laura Bieker
20 : /// @author Mirko Barthauer
21 : /// @date Mon, 07.04.2008
22 : ///
23 : // Helper methods for parsing vehicle attributes
24 : /****************************************************************************/
25 : #include <config.h>
26 :
27 : #include <utils/common/FileHelpers.h>
28 : #include <utils/common/MsgHandler.h>
29 : #include <utils/common/RandHelper.h>
30 : #include <utils/common/StringTokenizer.h>
31 : #include <utils/common/StringUtils.h>
32 : #include <utils/common/ToString.h>
33 : #include <utils/common/UtilExceptions.h>
34 : #include <utils/options/OptionsCont.h>
35 : #include <utils/emissions/PollutantsInterface.h>
36 : #include <utils/router/IntermodalNetwork.h>
37 : #include <utils/vehicle/SUMOVTypeParameter.h>
38 : #include <utils/vehicle/SUMOVehicleParameter.h>
39 : #include <utils/xml/SUMOSAXAttributes.h>
40 :
41 : #include "SUMOVehicleParserHelper.h"
42 :
43 :
44 : // ===========================================================================
45 : // static members
46 : // ===========================================================================
47 :
48 : SUMOVehicleParserHelper::CFAttrMap SUMOVehicleParserHelper::allowedCFModelAttrs;
49 : SUMOVehicleParserHelper::LCAttrMap SUMOVehicleParserHelper::allowedLCModelAttrs;
50 :
51 :
52 : // ===========================================================================
53 : // method definitions
54 : // ===========================================================================
55 :
56 : SUMOVehicleParameter*
57 24976 : SUMOVehicleParserHelper::parseFlowAttributes(SumoXMLTag tag, const SUMOSAXAttributes& attrs, const bool hardFail, const bool needID,
58 : const SUMOTime beginDefault, const SUMOTime endDefault, const bool allowInternalRoutes) {
59 : // first parse ID
60 24976 : const std::string id = attrs.hasAttribute(SUMO_ATTR_ID) ? parseID(attrs, tag) : "";
61 : // check if ID is valid
62 24976 : if (!needID || !id.empty()) {
63 24969 : if (needID && !SUMOXMLDefinitions::isValidVehicleID(id)) {
64 0 : return handleVehicleError(hardFail, nullptr, "Invalid flow id '" + id + "'.");
65 : }
66 : // declare flags
67 24969 : const bool hasPeriod = attrs.hasAttribute(SUMO_ATTR_PERIOD);
68 24969 : const bool hasVPH = attrs.hasAttribute(SUMO_ATTR_VEHSPERHOUR);
69 24969 : const bool hasPPH = attrs.hasAttribute(SUMO_ATTR_PERSONSPERHOUR);
70 24969 : const bool hasCPH = attrs.hasAttribute(SUMO_ATTR_CONTAINERSPERHOUR);
71 24969 : const bool hasPH = attrs.hasAttribute(SUMO_ATTR_PERHOUR);
72 24969 : const bool hasXPH = hasVPH || hasPPH || hasCPH || hasPH;
73 24969 : const bool hasProb = attrs.hasAttribute(SUMO_ATTR_PROB);
74 24969 : const bool hasNumber = attrs.hasAttribute(SUMO_ATTR_NUMBER);
75 24969 : const bool hasBegin = attrs.hasAttribute(SUMO_ATTR_BEGIN);
76 24969 : const bool hasEnd = attrs.hasAttribute(SUMO_ATTR_END);
77 : SumoXMLAttr PERHOUR = SUMO_ATTR_PERHOUR;
78 24969 : if (hasVPH) {
79 : PERHOUR = SUMO_ATTR_VEHSPERHOUR;
80 : }
81 24969 : if (hasPPH) {
82 : PERHOUR = SUMO_ATTR_PERSONSPERHOUR;
83 : }
84 24969 : if (hasCPH) {
85 : PERHOUR = SUMO_ATTR_CONTAINERSPERHOUR;
86 : }
87 24969 : if (hasXPH && !(hasVPH ^ hasPPH ^ hasCPH ^ hasPH)) {
88 0 : return handleVehicleError(hardFail, nullptr,
89 0 : "At most one of '" + attrs.getName(SUMO_ATTR_PERHOUR) +
90 0 : "', '" + attrs.getName(SUMO_ATTR_VEHSPERHOUR) +
91 0 : "', '" + attrs.getName(SUMO_ATTR_PERSONSPERHOUR) +
92 0 : "' and '" + attrs.getName(SUMO_ATTR_CONTAINERSPERHOUR) +
93 0 : "' has to be given in the definition of " + toString(tag) + " '" + id + "'.");
94 : }
95 4093 : if (hasPeriod && hasXPH) {
96 7 : return handleVehicleError(hardFail, nullptr,
97 14 : "At most one of '" + attrs.getName(SUMO_ATTR_PERIOD) +
98 21 : "' and '" + attrs.getName(PERHOUR) +
99 : "' has to be given in the definition of "
100 14 : + toString(tag) + " '" + id + "'.");
101 : }
102 24962 : if (hasPeriod && hasProb) {
103 0 : return handleVehicleError(hardFail, nullptr,
104 0 : "At most one of '" + attrs.getName(SUMO_ATTR_PERIOD) +
105 0 : "' and '" + attrs.getName(SUMO_ATTR_PROB) +
106 : "' has to be given in the definition of "
107 0 : + toString(tag) + " '" + id + "'.");
108 : }
109 24962 : if (hasProb && hasXPH) {
110 0 : return handleVehicleError(hardFail, nullptr,
111 0 : "At most one of '" + attrs.getName(SUMO_ATTR_PROB) +
112 0 : "' and '" + attrs.getName(PERHOUR) +
113 : "' has to be given in the definition of "
114 0 : + toString(tag) + " '" + id + "'.");
115 : }
116 24962 : if (hasPeriod || hasXPH || hasProb) {
117 19981 : if (hasEnd && hasNumber) {
118 7 : return handleVehicleError(hardFail, nullptr,
119 14 : "If '" + attrs.getName(SUMO_ATTR_PERIOD) +
120 21 : "', '" + attrs.getName(SUMO_ATTR_VEHSPERHOUR) +
121 21 : "', '" + attrs.getName(SUMO_ATTR_PERSONSPERHOUR) +
122 21 : "', '" + attrs.getName(SUMO_ATTR_CONTAINERSPERHOUR) +
123 21 : "', '" + attrs.getName(SUMO_ATTR_PERHOUR) +
124 21 : "' or '" + attrs.getName(SUMO_ATTR_PROB) +
125 21 : "' are given at most one of '" + attrs.getName(SUMO_ATTR_END) +
126 21 : "' and '" + attrs.getName(SUMO_ATTR_NUMBER) +
127 : "' are allowed in "
128 14 : + toString(tag) + " '" + id + "'.");
129 : }
130 : } else {
131 4981 : if (!hasNumber) {
132 7 : return handleVehicleError(hardFail, nullptr,
133 14 : "At least one of '" + attrs.getName(SUMO_ATTR_PERIOD) +
134 21 : "', '" + attrs.getName(SUMO_ATTR_VEHSPERHOUR) +
135 21 : "', '" + attrs.getName(SUMO_ATTR_PERSONSPERHOUR) +
136 21 : "', '" + attrs.getName(SUMO_ATTR_CONTAINERSPERHOUR) +
137 21 : "', '" + attrs.getName(SUMO_ATTR_PERHOUR) +
138 21 : "', '" + attrs.getName(SUMO_ATTR_PROB) +
139 21 : "', and '" + attrs.getName(SUMO_ATTR_NUMBER) +
140 : "' is needed in "
141 14 : + toString(tag) + " '" + id + "'.");
142 : }
143 : }
144 : // declare flow
145 24948 : SUMOVehicleParameter* flowParameter = new SUMOVehicleParameter();
146 : // set tag
147 24948 : flowParameter->tag = tag;
148 : // set id
149 24948 : flowParameter->id = id;
150 24948 : if (tag == SUMO_TAG_PERSONFLOW) {
151 1989 : flowParameter->vtypeid = DEFAULT_PEDTYPE_ID;
152 : }
153 24948 : if (tag == SUMO_TAG_CONTAINERFLOW) {
154 333 : flowParameter->vtypeid = DEFAULT_CONTAINERTYPE_ID;
155 : }
156 : // parse common vehicle attributes
157 : try {
158 24948 : parseCommonAttributes(attrs, flowParameter, tag, allowInternalRoutes);
159 48 : } catch (ProcessError& attributeError) {
160 : // check if continue handling another vehicles or stop handling
161 48 : if (hardFail) {
162 96 : throw ProcessError(attributeError.what());
163 : } else {
164 : return nullptr;
165 : }
166 48 : }
167 : // parse period
168 : bool poissonFlow = false;
169 24900 : if (hasPeriod) {
170 11199 : bool ok = true;
171 11199 : const std::string description = attrs.get<std::string>(SUMO_ATTR_PERIOD, id.c_str(), ok);
172 11199 : const std::string distName = description.substr(0, description.find('('));
173 11199 : if (distName == "exp") {
174 : // declare rate
175 : double rate = -1;
176 : // parse rate
177 : try {
178 936 : rate = StringUtils::toDouble(description.substr(distName.size() + 1, description.size() - distName.size() - 2));
179 0 : } catch (ProcessError& attributeError) {
180 : // check if continue handling another vehicles or stop handling
181 0 : if (hardFail) {
182 0 : throw ProcessError(attributeError.what());
183 : } else {
184 : return nullptr;
185 : }
186 0 : }
187 936 : if (rate <= 0) {
188 14 : return handleVehicleError(hardFail, flowParameter, "Invalid rate parameter for exponentially distributed period in the definition of " + toString(tag) + " '" + id + "'.");
189 : }
190 929 : flowParameter->poissonRate = rate;
191 : poissonFlow = true;
192 : } else {
193 10263 : flowParameter->repetitionOffset = attrs.getSUMOTimeReporting(SUMO_ATTR_PERIOD, id.c_str(), ok);
194 : }
195 11192 : if (!ok) {
196 7 : return handleVehicleError(hardFail, flowParameter);
197 : } else {
198 11192 : flowParameter->parametersSet |= VEHPARS_PERIOD_SET;
199 : }
200 : }
201 : // parse vehicle/person/container/etc per hour
202 24893 : if (hasXPH) {
203 4086 : bool ok = true;
204 4086 : const double vph = attrs.get<double>(PERHOUR, id.c_str(), ok);
205 4086 : if (!ok) {
206 0 : return handleVehicleError(hardFail, flowParameter);
207 4086 : } else if (vph <= 0) {
208 0 : return handleVehicleError(hardFail, flowParameter, "Invalid repetition rate in the definition of " + toString(tag) + " '" + id + "'.");
209 : } else {
210 : if (vph != 0) {
211 4086 : flowParameter->repetitionOffset = TIME2STEPS(3600. / vph);
212 : }
213 4086 : flowParameter->parametersSet |= VEHPARS_VPH_SET;
214 : }
215 : }
216 : // parse probability
217 24893 : if (hasProb) {
218 4689 : bool ok = true;
219 4689 : flowParameter->repetitionProbability = attrs.get<double>(SUMO_ATTR_PROB, id.c_str(), ok);
220 4689 : if (!ok) {
221 0 : return handleVehicleError(hardFail, flowParameter);
222 4689 : } else if (flowParameter->repetitionProbability <= 0 || flowParameter->repetitionProbability > 1) {
223 0 : return handleVehicleError(hardFail, flowParameter, "Invalid repetition probability in the definition of " + toString(tag) + " '" + id + "'.");
224 : } else {
225 4689 : flowParameter->parametersSet |= VEHPARS_PROB_SET;
226 : }
227 : }
228 : // set default begin
229 24893 : flowParameter->depart = beginDefault;
230 : // parse begin
231 24893 : if (hasBegin) {
232 : // first get begin
233 24674 : bool ok = true;
234 24674 : const std::string begin = attrs.get<std::string>(SUMO_ATTR_BEGIN, id.c_str(), ok);
235 24674 : if (!ok) {
236 7 : return handleVehicleError(hardFail, flowParameter);
237 : } else {
238 : // parse begin
239 : std::string errorMsg;
240 49348 : if (!SUMOVehicleParameter::parseDepart(begin, toString(tag), id, flowParameter->depart, flowParameter->departProcedure, errorMsg, "begin")) {
241 14 : return handleVehicleError(hardFail, flowParameter, errorMsg);
242 : }
243 : }
244 : }
245 24886 : if (flowParameter->depart < 0) {
246 0 : return handleVehicleError(hardFail, flowParameter, "Negative begin time in the definition of " + toString(tag) + " '" + id + "'.");
247 : }
248 : // set default end
249 24886 : flowParameter->repetitionEnd = endDefault;
250 24886 : if (flowParameter->repetitionEnd < 0) {
251 19068 : flowParameter->repetitionEnd = SUMOTime_MAX;
252 : }
253 : // parse end
254 24886 : if (hasEnd) {
255 21880 : bool ok = true;
256 21880 : flowParameter->repetitionEnd = attrs.getSUMOTimeReporting(SUMO_ATTR_END, id.c_str(), ok);
257 21880 : if (!ok) {
258 0 : return handleVehicleError(hardFail, flowParameter);
259 : } else {
260 21880 : flowParameter->parametersSet |= VEHPARS_END_SET;
261 : }
262 3006 : } else if (flowParameter->departProcedure == DepartDefinition::TRIGGERED) {
263 55 : if (!hasNumber) {
264 0 : return handleVehicleError(hardFail, flowParameter, toString(tag) + " '" + id + "' with triggered begin must define 'number'.");
265 : } else {
266 55 : flowParameter->repetitionEnd = flowParameter->depart;
267 : }
268 2951 : } else if ((endDefault == SUMOTime_MAX || endDefault < 0) && (!hasNumber || (!hasProb && !hasPeriod && !hasXPH))) {
269 156 : WRITE_WARNINGF(TL("Undefined end for % '%', defaulting to 24hour duration."), toString(tag), id);
270 52 : flowParameter->repetitionEnd = flowParameter->depart + TIME2STEPS(24 * 3600);
271 : }
272 24886 : if (flowParameter->repetitionEnd < flowParameter->depart) {
273 7 : std::string flow = toString(tag);
274 7 : flow[0] = (char)::toupper((char)flow[0]);
275 21 : return handleVehicleError(hardFail, flowParameter, flow + " '" + id + "' ends before its begin time.");
276 : }
277 : // parse number
278 24879 : if (hasNumber) {
279 7617 : bool ok = true;
280 7617 : flowParameter->repetitionNumber = attrs.get<long long int>(SUMO_ATTR_NUMBER, id.c_str(), ok);
281 7617 : if (!ok) {
282 0 : return handleVehicleError(hardFail, flowParameter);
283 : } else {
284 7617 : flowParameter->parametersSet |= VEHPARS_NUMBER_SET;
285 7617 : if (flowParameter->repetitionNumber == 0) {
286 8 : std::string flow = toString(tag);
287 8 : flow[0] = (char)::toupper((char)flow[0]);
288 16 : WRITE_WARNING(flow + " '" + id + "' has no instances; will skip it.");
289 8 : flowParameter->repetitionEnd = flowParameter->depart;
290 : } else {
291 7609 : if (flowParameter->repetitionNumber < 0) {
292 14 : return handleVehicleError(hardFail, flowParameter, "Negative repetition number in the definition of " + toString(tag) + " '" + id + "'.");
293 : }
294 7602 : if (flowParameter->repetitionOffset < 0 && !hasProb) {
295 5057 : if (poissonFlow) {
296 139 : flowParameter->repetitionEnd = SUMOTime_MAX;
297 : } else {
298 4918 : flowParameter->repetitionOffset = (flowParameter->repetitionEnd - flowParameter->depart) / flowParameter->repetitionNumber;
299 : }
300 : }
301 : }
302 : }
303 : } else {
304 : // interpret repetitionNumber
305 17262 : if (flowParameter->repetitionProbability > 0) {
306 4647 : flowParameter->repetitionNumber = std::numeric_limits<long long int>::max();
307 : } else {
308 12615 : if (flowParameter->repetitionOffset <= 0) {
309 804 : if (poissonFlow) {
310 : // number is random but flow has a fixed end time
311 790 : flowParameter->repetitionNumber = std::numeric_limits<long long int>::max();
312 : } else {
313 28 : return handleVehicleError(hardFail, flowParameter, "Invalid repetition rate in the definition of " + toString(tag) + " '" + id + "'.");
314 : }
315 : } else {
316 11811 : if (flowParameter->repetitionEnd == SUMOTime_MAX) {
317 0 : flowParameter->repetitionNumber = std::numeric_limits<long long int>::max();
318 : } else {
319 11811 : const SUMOTime repLength = flowParameter->repetitionEnd - flowParameter->depart;
320 11811 : flowParameter->repetitionNumber = (long long int)ceil((double)repLength / (double)flowParameter->repetitionOffset);
321 : }
322 : }
323 : }
324 : }
325 : // all ok, then return flow parameter
326 24858 : return flowParameter;
327 : } else {
328 132 : return handleVehicleError(hardFail, nullptr, toString(tag) + " cannot be created");
329 : }
330 : }
331 :
332 :
333 : SUMOVehicleParameter*
334 642668 : SUMOVehicleParserHelper::parseVehicleAttributes(int element, const SUMOSAXAttributes& attrs, const bool hardFail, const bool optionalID, const bool skipDepart, const bool allowInternalRoutes) {
335 : // declare vehicle ID
336 : std::string id;
337 : // for certain vehicles, ID can be optional
338 642668 : if (optionalID) {
339 696 : bool ok = true;
340 696 : id = attrs.getOpt<std::string>(SUMO_ATTR_ID, nullptr, ok, "");
341 696 : if (!ok) {
342 0 : return handleVehicleError(hardFail, nullptr);
343 : }
344 : } else {
345 : // parse ID
346 1283944 : id = parseID(attrs, (SumoXMLTag)element);
347 : }
348 : // only continue if id is valid, or if is optional
349 642668 : if (optionalID || !id.empty()) {
350 : // declare vehicle parameter
351 642652 : SUMOVehicleParameter* vehicleParameter = new SUMOVehicleParameter();
352 642652 : vehicleParameter->id = id;
353 642652 : if (element == SUMO_TAG_PERSON) {
354 44983 : vehicleParameter->vtypeid = DEFAULT_PEDTYPE_ID;
355 597669 : } else if (element == SUMO_TAG_CONTAINER) {
356 2113 : vehicleParameter->vtypeid = DEFAULT_CONTAINERTYPE_ID;
357 : }
358 : // parse common attributes
359 : try {
360 642652 : parseCommonAttributes(attrs, vehicleParameter, (SumoXMLTag)element, allowInternalRoutes);
361 274 : } catch (ProcessError& attributeError) {
362 : // check if continue handling another vehicles or stop handling
363 274 : if (hardFail) {
364 548 : throw ProcessError(attributeError.what());
365 : } else {
366 : return nullptr;
367 : }
368 274 : }
369 : // check depart
370 642378 : if (!skipDepart) {
371 641682 : bool ok = true;
372 641682 : const std::string helper = attrs.get<std::string>(SUMO_ATTR_DEPART, vehicleParameter->id.c_str(), ok);
373 641682 : if (!ok) {
374 40 : return handleVehicleError(hardFail, vehicleParameter);
375 : }
376 : // now parse depart
377 : std::string departErrorMsg;
378 1283332 : if (!SUMOVehicleParameter::parseDepart(helper, "vehicle", vehicleParameter->id, vehicleParameter->depart, vehicleParameter->departProcedure, departErrorMsg)) {
379 16 : return handleVehicleError(hardFail, vehicleParameter, departErrorMsg);
380 : }
381 : }
382 : // set tag
383 642354 : vehicleParameter->tag = (SumoXMLTag)element;
384 : // all ok, then return vehicleParameter
385 642354 : return vehicleParameter;
386 : } else {
387 346 : return handleVehicleError(hardFail, nullptr, toString((SumoXMLTag)element) + " cannot be created");
388 : }
389 : }
390 :
391 :
392 : std::string
393 731255 : SUMOVehicleParserHelper::parseID(const SUMOSAXAttributes& attrs, const SumoXMLTag element) {
394 731255 : bool ok = true;
395 : std::string id;
396 : // first check if attrs contain an ID
397 731255 : if (attrs.hasAttribute(SUMO_ATTR_ID)) {
398 731243 : id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
399 731243 : if (SUMOXMLDefinitions::isValidVehicleID(id)) {
400 731235 : return id;
401 8 : } else if (id.empty()) {
402 : // add extra information for empty IDs
403 24 : WRITE_ERRORF(TL("Invalid % id '%'."), toString(element), id);
404 : } else {
405 0 : WRITE_ERRORF(TL("Invalid % id '%'. Contains invalid characters."), toString(element), id);
406 : }
407 : } else {
408 36 : WRITE_ERROR("Attribute '" + toString(SUMO_ATTR_ID) + "' is missing in definition of " + toString(element));
409 : }
410 : // return empty (invalid) ID
411 20 : return "";
412 : }
413 :
414 :
415 : void
416 667600 : SUMOVehicleParserHelper::parseCommonAttributes(const SUMOSAXAttributes& attrs, SUMOVehicleParameter* ret, SumoXMLTag tag, const bool allowInternalRoutes) {
417 667600 : const std::string element = toString(tag);
418 : //ret->refid = attrs.getStringSecure(SUMO_ATTR_REFID, "");
419 : // parse route information
420 667600 : if (attrs.hasAttribute(SUMO_ATTR_ROUTE)) {
421 167783 : bool ok = true;
422 167783 : std::string routeID = attrs.get<std::string>(SUMO_ATTR_ROUTE, ret->id.c_str(), ok);
423 167783 : if (!allowInternalRoutes && isInternalRouteID(routeID)) {
424 0 : WRITE_WARNINGF(TL("Internal routes receive an ID starting with '!' and must not be referenced in other vehicle or flow definitions. Please remove all references to route '%' in case it is internal."), routeID);
425 : }
426 167783 : ret->routeid = routeID;
427 167783 : if (ok) {
428 167773 : ret->parametersSet |= VEHPARS_ROUTE_SET; // !!! needed?
429 : } else {
430 20 : handleVehicleError(true, ret);
431 : }
432 : }
433 : // parse type information
434 667590 : if (attrs.hasAttribute(SUMO_ATTR_TYPE)) {
435 220568 : bool ok = true;
436 220568 : ret->vtypeid = attrs.get<std::string>(SUMO_ATTR_TYPE, ret->id.c_str(), ok);
437 220568 : if (ok) {
438 220568 : ret->parametersSet |= VEHPARS_VTYPE_SET; // !!! needed?
439 : } else {
440 0 : handleVehicleError(true, ret);
441 : }
442 : }
443 : // parse line information
444 667590 : if (attrs.hasAttribute(SUMO_ATTR_LINE)) {
445 3327 : bool ok = true;
446 3327 : ret->line = attrs.get<std::string>(SUMO_ATTR_LINE, ret->id.c_str(), ok);
447 3327 : if (ok) {
448 3321 : ret->parametersSet |= VEHPARS_LINE_SET; // !!! needed?
449 : } else {
450 6 : handleVehicleError(true, ret);
451 : }
452 : }
453 : // parse zone information
454 667584 : if (attrs.hasAttribute(SUMO_ATTR_FROM_TAZ)) {
455 21507 : bool ok = true;
456 21507 : ret->fromTaz = attrs.get<std::string>(SUMO_ATTR_FROM_TAZ, ret->id.c_str(), ok);
457 21507 : if (ok) {
458 21507 : ret->parametersSet |= VEHPARS_FROM_TAZ_SET;
459 : } else {
460 0 : handleVehicleError(true, ret);
461 : }
462 : }
463 667584 : if (attrs.hasAttribute(SUMO_ATTR_TO_TAZ)) {
464 21513 : bool ok = true;
465 21513 : ret->toTaz = attrs.get<std::string>(SUMO_ATTR_TO_TAZ, ret->id.c_str(), ok);
466 21513 : if (ok) {
467 21513 : ret->parametersSet |= VEHPARS_TO_TAZ_SET;
468 : } else {
469 0 : handleVehicleError(true, ret);
470 : }
471 : }
472 : // parse reroute information
473 667584 : if (attrs.hasAttribute(SUMO_ATTR_REROUTE)) {
474 3685 : bool ok = true;
475 3685 : if (attrs.get<bool>(SUMO_ATTR_REROUTE, ret->id.c_str(), ok)) {
476 3685 : if (ok) {
477 3685 : ret->parametersSet |= VEHPARS_FORCE_REROUTE;
478 : } else {
479 0 : handleVehicleError(true, ret);
480 : }
481 : }
482 : }
483 : // parse depart lane information
484 667584 : if (attrs.hasAttribute(SUMO_ATTR_DEPARTLANE)) {
485 111954 : bool ok = true;
486 111954 : const std::string departLaneStr = attrs.get<std::string>(SUMO_ATTR_DEPARTLANE, ret->id.c_str(), ok);
487 : int lane;
488 : DepartLaneDefinition dld;
489 : std::string error;
490 111954 : if (SUMOVehicleParameter::parseDepartLane(departLaneStr, element, ret->id, lane, dld, error)) {
491 111906 : ret->parametersSet |= VEHPARS_DEPARTLANE_SET;
492 111906 : ret->departLane = lane;
493 111906 : ret->departLaneProcedure = dld;
494 : } else {
495 96 : handleVehicleError(true, ret, error);
496 : }
497 : }
498 : // parse depart position information
499 667536 : if (attrs.hasAttribute(SUMO_ATTR_DEPARTPOS)) {
500 91634 : bool ok = true;
501 91634 : const std::string departPosStr = attrs.get<std::string>(SUMO_ATTR_DEPARTPOS, ret->id.c_str(), ok);
502 : double pos;
503 : DepartPosDefinition dpd;
504 : std::string error;
505 91634 : if (SUMOVehicleParameter::parseDepartPos(departPosStr, element, ret->id, pos, dpd, error)) {
506 91586 : ret->parametersSet |= VEHPARS_DEPARTPOS_SET;
507 91586 : ret->departPos = pos;
508 91586 : ret->departPosProcedure = dpd;
509 : } else {
510 96 : handleVehicleError(true, ret, error);
511 : }
512 : }
513 : // parse lateral depart position information
514 667488 : if (attrs.hasAttribute(SUMO_ATTR_DEPARTPOS_LAT)) {
515 8699 : bool ok = true;
516 8699 : const std::string departPosLatStr = attrs.get<std::string>(SUMO_ATTR_DEPARTPOS_LAT, ret->id.c_str(), ok);
517 : double pos;
518 : DepartPosLatDefinition dpd;
519 : std::string error;
520 8699 : if (SUMOVehicleParameter::parseDepartPosLat(departPosLatStr, element, ret->id, pos, dpd, error)) {
521 8699 : ret->parametersSet |= VEHPARS_DEPARTPOSLAT_SET;
522 8699 : ret->departPosLat = pos;
523 8699 : ret->departPosLatProcedure = dpd;
524 : } else {
525 0 : handleVehicleError(true, ret, error);
526 : }
527 : }
528 : // parse depart speed information
529 667488 : if (attrs.hasAttribute(SUMO_ATTR_DEPARTSPEED)) {
530 243722 : bool ok = true;
531 243722 : const std::string departSpeed = attrs.get<std::string>(SUMO_ATTR_DEPARTSPEED, ret->id.c_str(), ok);
532 : double speed;
533 : DepartSpeedDefinition dsd;
534 : std::string error;
535 243722 : if (SUMOVehicleParameter::parseDepartSpeed(departSpeed, element, ret->id, speed, dsd, error)) {
536 243674 : ret->parametersSet |= VEHPARS_DEPARTSPEED_SET;
537 243674 : ret->departSpeed = speed;
538 243674 : ret->departSpeedProcedure = dsd;
539 : } else {
540 96 : handleVehicleError(true, ret, error);
541 : }
542 : }
543 : // parse depart edge information
544 667440 : if (attrs.hasAttribute(SUMO_ATTR_DEPARTEDGE)) {
545 296 : bool ok = true;
546 296 : const std::string departEdgeStr = attrs.get<std::string>(SUMO_ATTR_DEPARTEDGE, ret->id.c_str(), ok);
547 : int edgeIndex;
548 : RouteIndexDefinition rid;
549 : std::string error;
550 296 : if (SUMOVehicleParameter::parseRouteIndex(departEdgeStr, element, ret->id, SUMO_ATTR_DEPARTEDGE, edgeIndex, rid, error)) {
551 289 : ret->parametersSet |= VEHPARS_DEPARTEDGE_SET;
552 289 : ret->departEdge = edgeIndex;
553 289 : ret->departEdgeProcedure = rid;
554 : } else {
555 14 : handleVehicleError(true, ret, error);
556 : }
557 : }
558 : // parse arrival lane information
559 667433 : if (attrs.hasAttribute(SUMO_ATTR_ARRIVALLANE)) {
560 3280 : bool ok = true;
561 3280 : const std::string arrivalLaneStr = attrs.get<std::string>(SUMO_ATTR_ARRIVALLANE, ret->id.c_str(), ok);
562 : int lane;
563 : ArrivalLaneDefinition ald;
564 : std::string error;
565 3280 : if (SUMOVehicleParameter::parseArrivalLane(arrivalLaneStr, element, ret->id, lane, ald, error)) {
566 3232 : ret->parametersSet |= VEHPARS_ARRIVALLANE_SET;
567 3232 : ret->arrivalLane = lane;
568 3232 : ret->arrivalLaneProcedure = ald;
569 : } else {
570 96 : handleVehicleError(true, ret, error);
571 : }
572 : }
573 : // parse arrival position information
574 667385 : if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS)) {
575 8333 : bool ok = true;
576 8333 : const std::string arrivalPosStr = attrs.get<std::string>(SUMO_ATTR_ARRIVALPOS, ret->id.c_str(), ok);
577 : double pos;
578 : ArrivalPosDefinition apd;
579 : std::string error;
580 8333 : if (SUMOVehicleParameter::parseArrivalPos(arrivalPosStr, element, ret->id, pos, apd, error)) {
581 8285 : ret->parametersSet |= VEHPARS_ARRIVALPOS_SET;
582 8285 : ret->arrivalPos = pos;
583 8285 : ret->arrivalPosProcedure = apd;
584 : } else {
585 96 : handleVehicleError(true, ret, error);
586 : }
587 : }
588 : // parse lateral arrival position information
589 667337 : if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS_LAT)) {
590 1072 : bool ok = true;
591 1072 : const std::string arrivalPosLatStr = attrs.get<std::string>(SUMO_ATTR_ARRIVALPOS_LAT, ret->id.c_str(), ok);
592 : double pos;
593 : ArrivalPosLatDefinition apd;
594 : std::string error;
595 1072 : if (SUMOVehicleParameter::parseArrivalPosLat(arrivalPosLatStr, element, ret->id, pos, apd, error)) {
596 1072 : ret->parametersSet |= VEHPARS_ARRIVALPOSLAT_SET;
597 1072 : ret->arrivalPosLat = pos;
598 1072 : ret->arrivalPosLatProcedure = apd;
599 : } else {
600 0 : handleVehicleError(true, ret, error);
601 : }
602 : }
603 : // parse arrival speed information
604 667337 : if (attrs.hasAttribute(SUMO_ATTR_ARRIVALSPEED)) {
605 3793 : bool ok = true;
606 3793 : std::string arrivalSpeedStr = attrs.get<std::string>(SUMO_ATTR_ARRIVALSPEED, ret->id.c_str(), ok);
607 : double speed;
608 : ArrivalSpeedDefinition asd;
609 : std::string error;
610 3793 : if (SUMOVehicleParameter::parseArrivalSpeed(arrivalSpeedStr, element, ret->id, speed, asd, error)) {
611 3745 : ret->parametersSet |= VEHPARS_ARRIVALSPEED_SET;
612 3745 : ret->arrivalSpeed = speed;
613 3745 : ret->arrivalSpeedProcedure = asd;
614 : } else {
615 96 : handleVehicleError(true, ret, error);
616 : }
617 : }
618 : // parse arrival edge information
619 667289 : if (attrs.hasAttribute(SUMO_ATTR_ARRIVALEDGE)) {
620 105 : bool ok = true;
621 105 : std::string arrivalEdgeStr = attrs.get<std::string>(SUMO_ATTR_ARRIVALEDGE, ret->id.c_str(), ok);
622 : int edgeIndex;
623 : RouteIndexDefinition rid;
624 : std::string error;
625 105 : if (SUMOVehicleParameter::parseRouteIndex(arrivalEdgeStr, element, ret->id, SUMO_ATTR_ARRIVALEDGE, edgeIndex, rid, error)) {
626 98 : ret->parametersSet |= VEHPARS_ARRIVALEDGE_SET;
627 98 : ret->arrivalEdge = edgeIndex;
628 98 : ret->arrivalEdgeProcedure = rid;
629 : } else {
630 14 : handleVehicleError(true, ret, error);
631 : }
632 : }
633 : // parse color
634 667282 : if (attrs.hasAttribute(SUMO_ATTR_COLOR)) {
635 10111 : bool ok = true;
636 10111 : ret->color = attrs.get<RGBColor>(SUMO_ATTR_COLOR, ret->id.c_str(), ok);
637 10111 : if (ok) {
638 10111 : ret->parametersSet |= VEHPARS_COLOR_SET;
639 : } else {
640 0 : handleVehicleError(true, ret, "Invalid RGBColor format");
641 : }
642 : } else {
643 657171 : ret->color = RGBColor::DEFAULT_COLOR;
644 : }
645 : // parse person number
646 667282 : if (attrs.hasAttribute(SUMO_ATTR_PERSON_NUMBER)) {
647 982 : bool ok = true;
648 982 : int personNumber = attrs.get<int>(SUMO_ATTR_PERSON_NUMBER, ret->id.c_str(), ok);
649 982 : if (!ok) {
650 0 : handleVehicleError(true, ret);
651 982 : } else if (personNumber >= 0) {
652 982 : ret->parametersSet |= VEHPARS_PERSON_NUMBER_SET;
653 982 : ret->personNumber = personNumber;
654 : } else {
655 0 : handleVehicleError(true, ret, toString(SUMO_ATTR_PERSON_NUMBER) + " cannot be negative");
656 : }
657 : }
658 : // parse container number
659 667282 : if (attrs.hasAttribute(SUMO_ATTR_CONTAINER_NUMBER)) {
660 976 : bool ok = true;
661 976 : int containerNumber = attrs.get<int>(SUMO_ATTR_CONTAINER_NUMBER, ret->id.c_str(), ok);
662 976 : if (!ok) {
663 0 : handleVehicleError(true, ret);
664 976 : } else if (containerNumber >= 0) {
665 976 : ret->parametersSet |= VEHPARS_CONTAINER_NUMBER_SET;
666 976 : ret->containerNumber = containerNumber;
667 : } else {
668 0 : handleVehicleError(true, ret, toString(SUMO_ATTR_CONTAINER_NUMBER) + " cannot be negative");
669 : }
670 : }
671 : // parse individual speedFactor
672 667282 : if (attrs.hasAttribute(SUMO_ATTR_SPEEDFACTOR)) {
673 11379 : bool ok = true;
674 11379 : double speedFactor = attrs.get<double>(SUMO_ATTR_SPEEDFACTOR, ret->id.c_str(), ok);
675 11379 : if (!ok) {
676 0 : handleVehicleError(true, ret);
677 11379 : } else if (speedFactor > 0) {
678 11379 : ret->parametersSet |= VEHPARS_SPEEDFACTOR_SET;
679 11379 : ret->speedFactor = speedFactor;
680 : } else {
681 0 : handleVehicleError(true, ret, toString(SUMO_ATTR_SPEEDFACTOR) + " must be positive");
682 : }
683 : }
684 : // parse insertion checks
685 667282 : if (attrs.hasAttribute(SUMO_ATTR_INSERTIONCHECKS)) {
686 1007 : ret->parametersSet |= VEHPARS_INSERTION_CHECKS_SET;
687 1007 : bool ok = true;
688 1007 : std::string checks = attrs.get<std::string>(SUMO_ATTR_INSERTIONCHECKS, ret->id.c_str(), ok);
689 1007 : if (!ok) {
690 4 : handleVehicleError(true, ret);
691 : } else {
692 : try {
693 1007 : ret->insertionChecks = SUMOVehicleParameter::parseInsertionChecks(checks);
694 4 : } catch (InvalidArgument& e) {
695 4 : handleVehicleError(true, ret, e.what());
696 4 : }
697 : }
698 : }
699 : // parse parking access rights
700 667278 : if (attrs.hasAttribute(SUMO_ATTR_PARKING_BADGES)) {
701 7 : bool ok = true;
702 7 : std::vector<std::string> badges = attrs.get<std::vector<std::string>>(SUMO_ATTR_PARKING_BADGES, ret->id.c_str(), ok);
703 7 : if (!ok) {
704 0 : handleVehicleError(true, ret);
705 : } else {
706 7 : ret->parametersSet |= VEHPARS_PARKING_BADGES_SET;
707 7 : ret->parkingBadges = badges;
708 : }
709 7 : }
710 : // parse modes (transportables only)
711 667278 : ret->modes = 0;
712 667278 : if (attrs.hasAttribute(SUMO_ATTR_MODES)) {
713 4 : bool ok = true;
714 4 : const std::string modeString = attrs.get<std::string>(SUMO_ATTR_MODES, ret->id.c_str(), ok);
715 4 : if (!ok) {
716 0 : handleVehicleError(true, ret);
717 : } else {
718 : std::string errorMsg;
719 8 : if (!SUMOVehicleParameter::parsePersonModes(modeString, toString(tag), ret->id, ret->modes, errorMsg)) {
720 0 : handleVehicleError(true, ret, errorMsg);
721 : }
722 : }
723 : }
724 : // parse usable vehicle types (transportables only)
725 667278 : if (attrs.hasAttribute(SUMO_ATTR_VTYPES)) {
726 0 : bool ok = true;
727 0 : ret->vTypes = attrs.get<std::string>(SUMO_ATTR_VTYPES, ret->id.c_str(), ok);
728 0 : if (!ok) {
729 0 : handleVehicleError(true, ret);
730 : }
731 : }
732 : // parse speed (only used by calibrators flow)
733 : // also used by vehicle in saved state but this is parsed elsewhere
734 667278 : if (tag == SUMO_TAG_FLOW && attrs.hasAttribute(SUMO_ATTR_SPEED)) {
735 223 : bool ok = true;
736 223 : double calibratorSpeed = attrs.get<double>(SUMO_ATTR_SPEED, ret->id.c_str(), ok);
737 223 : if (!ok) {
738 0 : handleVehicleError(true, ret);
739 223 : } else if (calibratorSpeed >= 0 || calibratorSpeed == -1) {
740 223 : ret->parametersSet |= VEHPARS_CALIBRATORSPEED_SET;
741 223 : ret->calibratorSpeed = calibratorSpeed;
742 : } else {
743 322 : handleVehicleError(true, ret, toString(SUMO_ATTR_SPEED) + " may not be negative");
744 : }
745 : }
746 : /*/ parse via
747 : if (attrs.hasAttribute(SUMO_ATTR_VIA)) {
748 : ret->setParameter |= VEHPARS_VIA_SET;
749 : SUMOSAXAttributes::parseStringVector(attrs.get<std::string>(SUMO_ATTR_VIA, ret->id.c_str(), ok), ret->via);
750 : }
751 : */
752 667278 : }
753 :
754 :
755 : SUMOVTypeParameter*
756 64314 : SUMOVehicleParserHelper::beginVTypeParsing(const SUMOSAXAttributes& attrs, const bool hardFail, const std::string& file, const SUMOVTypeParameter* const base) {
757 64314 : const std::string id = (attrs.hasAttribute(SUMO_ATTR_ID) || base == nullptr) ? parseID(attrs, SUMO_TAG_VTYPE) : "";
758 64314 : if (!id.empty()) {
759 : // create vType
760 64310 : SUMOVehicleClass vClass = base == nullptr ? SVC_PASSENGER : base->vehicleClass;
761 64310 : if (attrs.hasAttribute(SUMO_ATTR_VCLASS)) {
762 37138 : vClass = parseVehicleClass(attrs, id);
763 : }
764 : SUMOVTypeParameter* vType;
765 64310 : if (base == nullptr) {
766 64260 : vType = new SUMOVTypeParameter(id, vClass);
767 : } else {
768 50 : vType = new SUMOVTypeParameter(*base);
769 50 : vType->id = id;
770 50 : vType->vehicleClass = vClass;
771 : }
772 : // parse attributes
773 64310 : if (attrs.hasAttribute(SUMO_ATTR_VCLASS)) {
774 37138 : vType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
775 : }
776 64310 : if (attrs.hasAttribute(SUMO_ATTR_LENGTH)) {
777 38319 : bool ok = true;
778 38319 : const double length = attrs.get<double>(SUMO_ATTR_LENGTH, vType->id.c_str(), ok);
779 38319 : if (!ok) {
780 0 : return handleVehicleTypeError(hardFail, vType);
781 38319 : } else if (length <= 0) {
782 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_LENGTH) + " must be greater than 0");
783 : } else {
784 38319 : vType->length = length;
785 38319 : vType->parametersSet |= VTYPEPARS_LENGTH_SET;
786 : }
787 : }
788 64310 : if (attrs.hasAttribute(SUMO_ATTR_MINGAP)) {
789 36116 : bool ok = true;
790 36116 : const double minGap = attrs.get<double>(SUMO_ATTR_MINGAP, vType->id.c_str(), ok);
791 36116 : if (!ok) {
792 0 : return handleVehicleTypeError(hardFail, vType);
793 36116 : } else if (minGap < 0) {
794 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MINGAP) + " must be equal or greater than 0");
795 : } else {
796 36116 : vType->minGap = minGap;
797 36116 : vType->parametersSet |= VTYPEPARS_MINGAP_SET;
798 : }
799 : }
800 64310 : if (attrs.hasAttribute(SUMO_ATTR_MAXSPEED)) {
801 37494 : bool ok = true;
802 37494 : const double maxSpeed = attrs.get<double>(SUMO_ATTR_MAXSPEED, vType->id.c_str(), ok);
803 37494 : if (!ok) {
804 0 : return handleVehicleTypeError(hardFail, vType);
805 37494 : } else if (maxSpeed <= 0) {
806 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MAXSPEED) + " must be greater than 0");
807 : } else {
808 37494 : vType->maxSpeed = maxSpeed;
809 37494 : vType->parametersSet |= VTYPEPARS_MAXSPEED_SET;
810 : }
811 : }
812 64310 : if (attrs.hasAttribute(SUMO_ATTR_DESIRED_MAXSPEED)) {
813 87 : bool ok = true;
814 87 : const double desiredMaxSpeed = attrs.get<double>(SUMO_ATTR_DESIRED_MAXSPEED, vType->id.c_str(), ok);
815 87 : if (!ok) {
816 0 : return handleVehicleTypeError(hardFail, vType);
817 87 : } else if (desiredMaxSpeed <= 0) {
818 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_DESIRED_MAXSPEED) + " must be greater than 0");
819 : } else {
820 87 : vType->desiredMaxSpeed = desiredMaxSpeed;
821 87 : vType->parametersSet |= VTYPEPARS_DESIRED_MAXSPEED_SET;
822 : }
823 64223 : } else if (attrs.hasAttribute(SUMO_ATTR_MAXSPEED)) {
824 37473 : if (vClass == SVC_PEDESTRIAN) {
825 : // backward compatibility because pedestrian maxSpeed was subject to speedFactor up to 1.14.1
826 25880 : vType->desiredMaxSpeed = vType->maxSpeed;;
827 77636 : vType->maxSpeed = MAX2(vType->maxSpeed, SUMOVTypeParameter::VClassDefaultValues(vClass).maxSpeed);
828 11593 : } else if (vClass == SVC_BICYCLE) {
829 : // backward compatibility because default desired speed did not exist up to 1.14.1
830 192 : vType->desiredMaxSpeed = MAX2(vType->maxSpeed, vType->desiredMaxSpeed);
831 : }
832 : }
833 :
834 64310 : if (attrs.hasAttribute(SUMO_ATTR_SPEEDFACTOR)) {
835 2501 : bool ok = true;
836 2501 : vType->speedFactor.parse(attrs.get<std::string>(SUMO_ATTR_SPEEDFACTOR, vType->id.c_str(), ok), hardFail);
837 2501 : if (!ok) {
838 0 : return handleVehicleTypeError(hardFail, vType);
839 : } else {
840 2501 : vType->parametersSet |= VTYPEPARS_SPEEDFACTOR_SET;
841 : }
842 : }
843 64310 : if (attrs.hasAttribute(SUMO_ATTR_SPEEDDEV)) {
844 2673 : bool ok = true;
845 2673 : const double speedDev = attrs.get<double>(SUMO_ATTR_SPEEDDEV, vType->id.c_str(), ok);
846 2673 : if (!ok) {
847 0 : return handleVehicleTypeError(hardFail, vType);
848 2673 : } else if (speedDev < 0) {
849 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_SPEEDDEV) + " must be equal or greater than 0");
850 : } else {
851 2673 : vType->speedFactor.setParameter(1, speedDev);
852 2673 : vType->parametersSet |= VTYPEPARS_SPEEDFACTOR_SET;
853 : }
854 : }
855 : // validate speed distribution
856 64310 : const std::string& error = vType->speedFactor.isValid();
857 64310 : if (error != "") {
858 14 : return handleVehicleTypeError(hardFail, vType, "Invalid speed distribution when parsing vType '" + vType->id + "' (" + error + ")");
859 : }
860 64303 : if (attrs.hasAttribute(SUMO_ATTR_ACTIONSTEPLENGTH)) {
861 226 : bool ok = true;
862 226 : const double actionStepLengthSecs = attrs.get<double>(SUMO_ATTR_ACTIONSTEPLENGTH, vType->id.c_str(), ok);
863 226 : if (!ok) {
864 0 : return handleVehicleTypeError(hardFail, vType);
865 : } else {
866 : // processActionStepLength(...) function includes warnings
867 226 : vType->actionStepLength = processActionStepLength(actionStepLengthSecs);
868 226 : vType->parametersSet |= VTYPEPARS_ACTIONSTEPLENGTH_SET;
869 : }
870 : }
871 64303 : if (attrs.hasAttribute(SUMO_ATTR_EMISSIONCLASS)) {
872 1876 : bool ok = true;
873 1876 : const std::string parsedEmissionClass = attrs.getOpt<std::string>(SUMO_ATTR_EMISSIONCLASS, id.c_str(), ok, "");
874 : // check if emission class is correct
875 : try {
876 1876 : vType->emissionClass = PollutantsInterface::getClassByName(parsedEmissionClass);
877 1876 : vType->parametersSet |= VTYPEPARS_EMISSIONCLASS_SET;
878 0 : } catch (...) {
879 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_EMISSIONCLASS) + " with name '" + parsedEmissionClass + "' doesn't exist.");
880 0 : }
881 : }
882 64303 : if (attrs.hasAttribute(SUMO_ATTR_MASS)) {
883 341 : bool ok = true;
884 341 : const double mass = attrs.get<double>(SUMO_ATTR_MASS, vType->id.c_str(), ok);
885 341 : if (!ok) {
886 0 : return handleVehicleTypeError(hardFail, vType);
887 341 : } else if (mass < 0) {
888 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MASS) + " must be equal or greater than 0");
889 : } else {
890 341 : vType->mass = mass;
891 341 : vType->parametersSet |= VTYPEPARS_MASS_SET;
892 : }
893 : }
894 64303 : if (attrs.hasAttribute(SUMO_ATTR_IMPATIENCE)) {
895 247 : bool ok = true;
896 247 : const std::string impatienceStr = attrs.get<std::string>(SUMO_ATTR_IMPATIENCE, vType->id.c_str(), ok);
897 247 : if (!ok) {
898 0 : return handleVehicleTypeError(hardFail, vType);
899 247 : } else if (impatienceStr == "off") {
900 12 : vType->impatience = -std::numeric_limits<double>::max();
901 : } else {
902 235 : const double impatienceDouble = attrs.get<double>(SUMO_ATTR_IMPATIENCE, vType->id.c_str(), ok);
903 235 : if (!ok) {
904 0 : return handleVehicleTypeError(hardFail, vType);
905 : } else {
906 235 : vType->impatience = impatienceDouble;
907 235 : vType->parametersSet |= VTYPEPARS_IMPATIENCE_SET;
908 : }
909 : }
910 : }
911 64303 : if (attrs.hasAttribute(SUMO_ATTR_WIDTH)) {
912 26761 : bool ok = true;
913 26761 : const double width = attrs.get<double>(SUMO_ATTR_WIDTH, vType->id.c_str(), ok);
914 26761 : if (!ok) {
915 0 : return handleVehicleTypeError(hardFail, vType);
916 26761 : } else if (width <= 0) {
917 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_WIDTH) + " must be greater than 0");
918 : } else {
919 26761 : vType->width = width;
920 26761 : vType->parametersSet |= VTYPEPARS_WIDTH_SET;
921 26761 : if (vClass == SVC_PEDESTRIAN
922 52868 : && OptionsCont::getOptions().exists("pedestrian.striping.stripe-width")
923 78975 : && OptionsCont::getOptions().getString("pedestrian.model") == "striping"
924 82156 : && OptionsCont::getOptions().getFloat("pedestrian.striping.stripe-width") < vType->width) {
925 12 : WRITE_WARNINGF(TL("Pedestrian vType '%' width % is larger than pedestrian.striping.stripe-width and this may cause collisions with vehicles."), id, vType->width);
926 : }
927 : }
928 : }
929 64303 : if (attrs.hasAttribute(SUMO_ATTR_HEIGHT)) {
930 357 : bool ok = true;
931 357 : const double height = attrs.get<double>(SUMO_ATTR_HEIGHT, vType->id.c_str(), ok);
932 357 : if (!ok) {
933 0 : return handleVehicleTypeError(hardFail, vType);
934 357 : } else if (height < 0) {
935 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_HEIGHT) + " must be equal or greater than 0");
936 : } else {
937 357 : vType->height = height;
938 357 : vType->parametersSet |= VTYPEPARS_HEIGHT_SET;
939 : }
940 : }
941 64303 : if (attrs.hasAttribute(SUMO_ATTR_GUISHAPE)) {
942 27191 : vType->shape = parseGuiShape(attrs, vType->id);
943 27191 : if (vType->shape != SUMOVehicleShape::UNKNOWN) {
944 27191 : vType->parametersSet |= VTYPEPARS_SHAPE_SET;
945 : }
946 : }
947 64303 : if (attrs.hasAttribute(SUMO_ATTR_OSGFILE)) {
948 21 : bool ok = true;
949 21 : const std::string osgFile = attrs.get<std::string>(SUMO_ATTR_OSGFILE, vType->id.c_str(), ok);
950 21 : if (!ok) {
951 0 : return handleVehicleTypeError(hardFail, vType);
952 : } else {
953 21 : vType->osgFile = osgFile;
954 21 : vType->parametersSet |= VTYPEPARS_OSGFILE_SET;
955 : }
956 : }
957 64303 : if (attrs.hasAttribute(SUMO_ATTR_IMGFILE)) {
958 28 : bool ok = true;
959 28 : std::string imgFile = attrs.get<std::string>(SUMO_ATTR_IMGFILE, vType->id.c_str(), ok);
960 28 : if (!ok) {
961 0 : return handleVehicleTypeError(hardFail, vType);
962 : } else {
963 : // check relative path
964 28 : if ((imgFile != "") && !FileHelpers::isAbsolute(imgFile)) {
965 56 : imgFile = FileHelpers::getConfigurationRelative(file, imgFile);
966 : }
967 28 : vType->imgFile = imgFile;
968 28 : vType->parametersSet |= VTYPEPARS_IMGFILE_SET;
969 : }
970 : }
971 64303 : if (attrs.hasAttribute(SUMO_ATTR_COLOR)) {
972 22824 : bool ok = true;
973 22824 : const RGBColor color = attrs.get<RGBColor>(SUMO_ATTR_COLOR, vType->id.c_str(), ok);
974 22824 : if (!ok) {
975 8 : return handleVehicleTypeError(hardFail, vType);
976 : } else {
977 22816 : vType->color = color;
978 22816 : vType->parametersSet |= VTYPEPARS_COLOR_SET;
979 : }
980 : } else {
981 41479 : vType->color = RGBColor::YELLOW;
982 : }
983 64295 : if (attrs.hasAttribute(SUMO_ATTR_PROB)) {
984 705 : bool ok = true;
985 705 : const double defaultProbability = attrs.get<double>(SUMO_ATTR_PROB, vType->id.c_str(), ok);
986 705 : if (!ok) {
987 0 : return handleVehicleTypeError(hardFail, vType);
988 705 : } else if (defaultProbability < 0) {
989 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_PROB) + " must be equal or greater than 0");
990 : } else {
991 705 : vType->defaultProbability = defaultProbability;
992 705 : vType->parametersSet |= VTYPEPARS_PROBABILITY_SET;
993 : }
994 : }
995 64295 : if (attrs.hasAttribute(SUMO_ATTR_LANE_CHANGE_MODEL)) {
996 476 : bool ok = true;
997 476 : std::string lcmS = attrs.get<std::string>(SUMO_ATTR_LANE_CHANGE_MODEL, vType->id.c_str(), ok);
998 476 : if (!ok) {
999 0 : return handleVehicleTypeError(hardFail, vType);
1000 476 : } else if (lcmS == "JE2013") {
1001 0 : WRITE_WARNING(TL("Lane change model 'JE2013' is deprecated. Using default model instead."));
1002 : lcmS = "default";
1003 : }
1004 : if (SUMOXMLDefinitions::LaneChangeModels.hasString(lcmS)) {
1005 471 : vType->lcModel = SUMOXMLDefinitions::LaneChangeModels.get(lcmS);
1006 471 : vType->parametersSet |= VTYPEPARS_LANE_CHANGE_MODEL_SET;
1007 : } else {
1008 15 : return handleVehicleTypeError(hardFail, vType, "Unknown lane change model '" + lcmS + "' when parsing vType '" + vType->id + "'");
1009 : }
1010 : }
1011 64290 : if (attrs.hasAttribute(SUMO_ATTR_CAR_FOLLOW_MODEL)) {
1012 1336 : bool ok = true;
1013 1336 : const std::string cfmValue = attrs.get<std::string>(SUMO_ATTR_CAR_FOLLOW_MODEL, vType->id.c_str(), ok);
1014 1336 : if (!ok) {
1015 0 : return handleVehicleTypeError(hardFail, vType);
1016 : } else if (SUMOXMLDefinitions::CarFollowModels.hasString(cfmValue)) {
1017 1330 : vType->cfModel = SUMOXMLDefinitions::CarFollowModels.get(cfmValue);
1018 1330 : vType->parametersSet |= VTYPEPARS_CAR_FOLLOW_MODEL;
1019 : } else {
1020 18 : return handleVehicleTypeError(hardFail, vType, "Unknown car following model '" + cfmValue + "' when parsing vType '" + vType->id + "'");
1021 : }
1022 : }
1023 64284 : if (attrs.hasAttribute(SUMO_ATTR_PERSON_CAPACITY)) {
1024 411 : bool ok = true;
1025 411 : const int personCapacity = attrs.get<int>(SUMO_ATTR_PERSON_CAPACITY, vType->id.c_str(), ok);
1026 411 : if (!ok) {
1027 0 : return handleVehicleTypeError(hardFail, vType);
1028 411 : } else if (personCapacity < 0) {
1029 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_PERSON_CAPACITY) + " must be equal or greater than 0");
1030 : } else {
1031 411 : vType->personCapacity = personCapacity;
1032 411 : vType->parametersSet |= VTYPEPARS_PERSON_CAPACITY;
1033 : }
1034 : }
1035 64284 : if (attrs.hasAttribute(SUMO_ATTR_CONTAINER_CAPACITY)) {
1036 381 : bool ok = true;
1037 381 : const int containerCapacity = attrs.get<int>(SUMO_ATTR_CONTAINER_CAPACITY, vType->id.c_str(), ok);
1038 381 : if (!ok) {
1039 0 : return handleVehicleTypeError(hardFail, vType);
1040 381 : } else if (containerCapacity < 0) {
1041 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_CONTAINER_CAPACITY) + " must be equal or greater than 0");
1042 : } else {
1043 381 : vType->containerCapacity = containerCapacity;
1044 381 : vType->parametersSet |= VTYPEPARS_CONTAINER_CAPACITY;
1045 : }
1046 : }
1047 64284 : if (attrs.hasAttribute(SUMO_ATTR_BOARDING_DURATION)) {
1048 122 : bool ok = true;
1049 122 : const SUMOTime boardingDuration = attrs.getSUMOTimeReporting(SUMO_ATTR_BOARDING_DURATION, vType->id.c_str(), ok);
1050 122 : if (!ok) {
1051 0 : return handleVehicleTypeError(hardFail, vType);
1052 122 : } else if (boardingDuration < 0) {
1053 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_BOARDING_DURATION) + " must be equal or greater than 0");
1054 : } else {
1055 122 : vType->boardingDuration = boardingDuration;
1056 122 : vType->parametersSet |= VTYPEPARS_BOARDING_DURATION;
1057 : }
1058 : }
1059 64284 : if (attrs.hasAttribute(SUMO_ATTR_LOADING_DURATION)) {
1060 84 : bool ok = true;
1061 84 : const SUMOTime loadingDuration = attrs.getSUMOTimeReporting(SUMO_ATTR_LOADING_DURATION, vType->id.c_str(), ok);
1062 84 : if (!ok) {
1063 0 : return handleVehicleTypeError(hardFail, vType);
1064 84 : } else if (loadingDuration < 0) {
1065 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_LOADING_DURATION) + " must be equal or greater than 0");
1066 : } else {
1067 84 : vType->loadingDuration = loadingDuration;
1068 84 : vType->parametersSet |= VTYPEPARS_LOADING_DURATION;
1069 : }
1070 : }
1071 64284 : if (attrs.hasAttribute(SUMO_ATTR_SCALE)) {
1072 40 : bool ok = true;
1073 40 : const double scale = attrs.get<double>(SUMO_ATTR_SCALE, id.c_str(), ok);
1074 40 : if (!ok) {
1075 0 : return handleVehicleTypeError(hardFail, vType);
1076 40 : } else if (scale < 0) {
1077 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_SCALE) + " may be not be negative");
1078 : } else {
1079 40 : vType->scale = scale;
1080 40 : vType->parametersSet |= VTYPEPARS_SCALE_SET;
1081 : }
1082 : }
1083 64284 : if (attrs.hasAttribute(SUMO_ATTR_TIME_TO_TELEPORT)) {
1084 25 : bool ok = true;
1085 25 : const SUMOTime ttt = attrs.getSUMOTimeReporting(SUMO_ATTR_TIME_TO_TELEPORT, vType->id.c_str(), ok);
1086 25 : if (!ok) {
1087 0 : return handleVehicleTypeError(hardFail, vType);
1088 : } else {
1089 25 : vType->timeToTeleport = ttt;
1090 25 : vType->parametersSet |= VTYPEPARS_TTT_SET;
1091 : }
1092 : }
1093 64284 : if (attrs.hasAttribute(SUMO_ATTR_TIME_TO_TELEPORT_BIDI)) {
1094 5 : bool ok = true;
1095 5 : const SUMOTime tttb = attrs.getSUMOTimeReporting(SUMO_ATTR_TIME_TO_TELEPORT_BIDI, vType->id.c_str(), ok);
1096 5 : if (!ok) {
1097 0 : return handleVehicleTypeError(hardFail, vType);
1098 : } else {
1099 5 : vType->timeToTeleportBidi = tttb;
1100 5 : vType->parametersSet |= VTYPEPARS_TTT_BIDI_SET;
1101 : }
1102 : }
1103 64284 : if (attrs.hasAttribute(SUMO_ATTR_SPEEDFACTOR_PREMATURE)) {
1104 63 : bool ok = true;
1105 63 : const double sfp = attrs.get<double>(SUMO_ATTR_SPEEDFACTOR_PREMATURE, id.c_str(), ok);
1106 63 : if (!ok) {
1107 0 : return handleVehicleTypeError(hardFail, vType);
1108 : } else {
1109 63 : vType->speedFactorPremature = sfp;
1110 63 : vType->parametersSet |= VTYPEPARS_SPEEDFACTOR_PREMATURE_SET;
1111 : }
1112 : }
1113 64284 : if (attrs.hasAttribute(SUMO_ATTR_BOARDING_FACTOR)) {
1114 8 : bool ok = true;
1115 8 : const double bf = attrs.get<double>(SUMO_ATTR_BOARDING_FACTOR, id.c_str(), ok);
1116 8 : if (!ok) {
1117 0 : return handleVehicleTypeError(hardFail, vType);
1118 8 : } else if (bf < 0) {
1119 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_BOARDING_FACTOR) + " must be equal or greater than 0");
1120 : } else {
1121 8 : vType->boardingFactor = bf;
1122 8 : vType->parametersSet |= VTYPEPARS_BOARDING_FACTOR_SET;
1123 : }
1124 : }
1125 64284 : if (attrs.hasAttribute(SUMO_ATTR_MAXSPEED_LAT)) {
1126 72 : bool ok = true;
1127 72 : const double maxSpeedLat = attrs.get<double>(SUMO_ATTR_MAXSPEED_LAT, vType->id.c_str(), ok);
1128 72 : if (!ok) {
1129 0 : return handleVehicleTypeError(hardFail, vType);
1130 72 : } else if (maxSpeedLat <= 0) {
1131 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MAXSPEED_LAT) + " must be greater than 0");
1132 : } else {
1133 72 : vType->maxSpeedLat = maxSpeedLat;
1134 72 : vType->parametersSet |= VTYPEPARS_MAXSPEED_LAT_SET;
1135 : }
1136 : }
1137 64284 : if (attrs.hasAttribute(SUMO_ATTR_MINGAP_LAT)) {
1138 573 : bool ok = true;
1139 573 : const double minGapLat = attrs.get<double>(SUMO_ATTR_MINGAP_LAT, vType->id.c_str(), ok);
1140 573 : if (!ok) {
1141 0 : return handleVehicleTypeError(hardFail, vType);
1142 573 : } else if (minGapLat < 0) {
1143 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MINGAP_LAT) + " must be equal or greater than 0");
1144 : } else {
1145 573 : vType->minGapLat = minGapLat;
1146 573 : vType->parametersSet |= VTYPEPARS_MINGAP_LAT_SET;
1147 : }
1148 : }
1149 64284 : if (attrs.hasAttribute(SUMO_ATTR_LATALIGNMENT)) {
1150 1704 : bool ok = true;
1151 1704 : const std::string alignS = attrs.get<std::string>(SUMO_ATTR_LATALIGNMENT, vType->id.c_str(), ok);
1152 1704 : if (!ok) {
1153 0 : return handleVehicleTypeError(hardFail, vType);
1154 : } else {
1155 : double lao;
1156 : LatAlignmentDefinition lad;
1157 1704 : if (SUMOVTypeParameter::parseLatAlignment(alignS, lao, lad)) {
1158 1704 : vType->latAlignmentOffset = lao;
1159 1704 : vType->latAlignmentProcedure = lad;
1160 1704 : vType->parametersSet |= VTYPEPARS_LATALIGNMENT_SET;
1161 : } else {
1162 0 : return handleVehicleTypeError(hardFail, vType, "Unknown lateral alignment '" + alignS + "' when parsing vType '" + vType->id + "';\n must be one of (\"right\", \"center\", \"arbitrary\", \"nice\", \"compact\", \"left\" or a float)");
1163 : }
1164 : }
1165 : }
1166 64284 : if (attrs.hasAttribute(SUMO_ATTR_MANEUVER_ANGLE_TIMES)) {
1167 5 : bool ok = true;
1168 5 : const std::string angleTimesS = attrs.get<std::string>(SUMO_ATTR_MANEUVER_ANGLE_TIMES, vType->id.c_str(), ok);
1169 5 : if (!ok) {
1170 0 : return handleVehicleTypeError(hardFail, vType);
1171 10 : } else if (parseAngleTimesMap(vType, angleTimesS)) {
1172 5 : vType->parametersSet |= VTYPEPARS_MANEUVER_ANGLE_TIMES_SET;
1173 : } else {
1174 0 : return handleVehicleTypeError(hardFail, vType, "Invalid manoeuver angle times map for vType '" + vType->id + "'");
1175 : }
1176 : }
1177 64284 : if (attrs.hasAttribute(SUMO_ATTR_PARKING_BADGES)) {
1178 12 : bool ok = true;
1179 12 : std::vector<std::string> badges = attrs.get<std::vector<std::string>>(SUMO_ATTR_PARKING_BADGES, vType->id.c_str(), ok);
1180 12 : if (!ok) {
1181 0 : return handleVehicleTypeError(hardFail, vType);
1182 : } else {
1183 12 : vType->parametersSet |= VTYPEPARS_PARKING_BADGES_SET;
1184 12 : vType->parkingBadges = badges;
1185 : }
1186 12 : }
1187 : // try to parse Car Following Model params
1188 64284 : if (!parseCFMParams(vType, vType->cfModel, attrs, false)) {
1189 0 : return handleVehicleTypeError(hardFail, vType, "Invalid parsing embedded VType");
1190 : }
1191 : // try to parse Lane Change Model params
1192 64284 : if (!parseLCParams(vType, vType->lcModel, attrs)) {
1193 0 : return handleVehicleTypeError(hardFail, vType, "Invalid Lane Change Model Parameters");
1194 : }
1195 : // try to Junction Model params
1196 64284 : if (!parseJMParams(vType, attrs)) {
1197 26 : return handleVehicleTypeError(hardFail, vType, "Invalid Junction Model Parameters");
1198 : }
1199 : // all ok, then return vType
1200 : return vType;
1201 4 : } else if (base != nullptr) {
1202 : return const_cast<SUMOVTypeParameter*>(base);
1203 : } else {
1204 34 : return handleVehicleTypeError(hardFail, nullptr, "VType cannot be created");
1205 : }
1206 : }
1207 :
1208 :
1209 : bool
1210 5 : SUMOVehicleParserHelper::parseAngleTimesMap(SUMOVTypeParameter* vtype, const std::string atm) {
1211 15 : StringTokenizer st(atm, ",");
1212 : std::map<int, std::pair<SUMOTime, SUMOTime>> angleTimesMap;
1213 : int tripletCount = 0;
1214 30 : while (st.hasNext()) {
1215 25 : StringTokenizer pos(st.next());
1216 25 : if (pos.size() != 3) {
1217 0 : WRITE_ERRORF(TL("maneuverAngleTimes format for vType '%' % contains an invalid triplet."), vtype->id, atm);
1218 0 : return false;
1219 : } else {
1220 : try {
1221 25 : const int angle = StringUtils::toInt(pos.next());
1222 25 : const SUMOTime t1 = string2time(pos.next());
1223 25 : const SUMOTime t2 = string2time(pos.next());
1224 25 : angleTimesMap[angle] = std::make_pair(t1, t2);
1225 0 : } catch (...) {
1226 0 : WRITE_ERRORF(TL("Triplet '%' for vType '%' maneuverAngleTimes cannot be parsed as 'int double double'"), st.get(tripletCount), vtype->id);
1227 : return false;
1228 0 : }
1229 25 : tripletCount++;
1230 : }
1231 25 : }
1232 5 : if (angleTimesMap.size() > 0) {
1233 : vtype->myManoeuverAngleTimes.clear();
1234 30 : for (const auto& angleTime : angleTimesMap) {
1235 : vtype->myManoeuverAngleTimes.insert(angleTime);
1236 : }
1237 : angleTimesMap.clear();
1238 5 : return true;
1239 : } else {
1240 : return false;
1241 : }
1242 5 : }
1243 :
1244 :
1245 : bool
1246 64300 : SUMOVehicleParserHelper::parseCFMParams(SUMOVTypeParameter* into, const SumoXMLTag element, const SUMOSAXAttributes& attrs, const bool nestedCFM) {
1247 64300 : const CFAttrMap& allowedCFM = getAllowedCFModelAttrs();
1248 : CFAttrMap::const_iterator cf_it = allowedCFM.find(element);
1249 : // check if given CFM is allowed
1250 64300 : if (cf_it == allowedCFM.end()) {
1251 0 : if (SUMOXMLDefinitions::Tags.has((int)element)) {
1252 0 : WRITE_ERRORF(TL("Unknown car-following model % when parsing vType '%'"), toString(element), into->id);
1253 : } else {
1254 0 : WRITE_ERRORF(TL("Unknown car-following model when parsing vType '%'"), into->id);
1255 : }
1256 0 : return false;
1257 : }
1258 : // check if we're parsing a nested CFM
1259 64300 : if (nestedCFM) {
1260 16 : into->cfModel = cf_it->first;
1261 16 : into->parametersSet |= VTYPEPARS_CAR_FOLLOW_MODEL;
1262 : }
1263 : // set CFM values
1264 847283 : for (const auto& it : cf_it->second) {
1265 782983 : if (attrs.hasAttribute(it)) {
1266 : // first obtain CFM attribute in string format
1267 47360 : bool ok = true;
1268 47360 : std::string parsedCFMAttribute = attrs.get<std::string>(it, into->id.c_str(), ok);
1269 : // check CFM Attribute
1270 47360 : if (!ok) {
1271 : return false;
1272 47360 : } else if (it == SUMO_ATTR_TRAIN_TYPE) {
1273 : // check if train value is valid
1274 271 : if (!SUMOXMLDefinitions::TrainTypes.hasString(parsedCFMAttribute)) {
1275 0 : WRITE_ERROR("Invalid train type '" + parsedCFMAttribute + "' used in Car-Following-Attribute " + toString(it));
1276 0 : return false;
1277 : }
1278 : // add parsedCFMAttribute to cfParameter
1279 271 : into->cfParameter[it] = parsedCFMAttribute;
1280 47089 : } else if (it == SUMO_ATTR_SPEED_TABLE || it == SUMO_ATTR_TRACTION_TABLE || it == SUMO_ATTR_RESISTANCE_TABLE) {
1281 52 : into->cfParameter[it] = parsedCFMAttribute;
1282 47037 : } else if (it == SUMO_ATTR_CF_IDM_STEPPING) {
1283 : // declare a int in wich save CFM int attribute
1284 : double CFMDoubleAttribute = -1;
1285 : try {
1286 : // obtain CFM attribute in int format
1287 6 : CFMDoubleAttribute = StringUtils::toDouble(parsedCFMAttribute);
1288 0 : } catch (...) {
1289 0 : WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Cannot be parsed to float"), toString(it));
1290 : return false;
1291 0 : }
1292 6 : if (CFMDoubleAttribute <= 0) {
1293 0 : WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Must be greater than 0"), toString(it));
1294 0 : return false;
1295 : }
1296 : // add parsedCFMAttribute to cfParameter
1297 6 : into->cfParameter[it] = parsedCFMAttribute;
1298 47031 : } else if (it == SUMO_ATTR_MAXACCEL_PROFILE || it == SUMO_ATTR_DESACCEL_PROFILE) {
1299 32 : if (validProfile(into, parsedCFMAttribute, it)) {
1300 16 : into->cfParameter[it] = parsedCFMAttribute;
1301 : } else {
1302 0 : WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Cannot be parsed as a vector of <speed accel> pairs"), toString(it));
1303 0 : return false;
1304 : }
1305 : } else {
1306 : // declare a double in wich save CFM float attribute
1307 : double CFMDoubleAttribute = -1;
1308 : try {
1309 : // obtain CFM attribute in double format
1310 47015 : CFMDoubleAttribute = StringUtils::toDouble(parsedCFMAttribute);
1311 0 : } catch (...) {
1312 0 : WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Cannot be parsed to float"), toString(it));
1313 : return false;
1314 0 : }
1315 : // check attributes of type "positiveFloatType" (> 0)
1316 47015 : switch (it) {
1317 21610 : case SUMO_ATTR_ACCEL:
1318 : case SUMO_ATTR_DECEL:
1319 : case SUMO_ATTR_APPARENTDECEL:
1320 : case SUMO_ATTR_EMERGENCYDECEL:
1321 : case SUMO_ATTR_TAU:
1322 21610 : if (CFMDoubleAttribute <= 0) {
1323 0 : WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Must be greater than 0"), toString(it));
1324 0 : return false;
1325 : }
1326 : break;
1327 : default:
1328 : break;
1329 : }
1330 : // check attributes restricted to [0-1]
1331 47015 : switch (it) {
1332 24763 : case SUMO_ATTR_SIGMA:
1333 24763 : if ((CFMDoubleAttribute < 0) || (CFMDoubleAttribute > 1)) {
1334 0 : WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Only values between [0-1] are allowed"), toString(it));
1335 0 : return false;
1336 : }
1337 : break;
1338 : default:
1339 : break;
1340 : }
1341 : // add parsedCFMAttribute to cfParameter
1342 47015 : into->cfParameter[it] = parsedCFMAttribute;
1343 : }
1344 : }
1345 : }
1346 : // all CFM successfully parsed, then return true
1347 : return true;
1348 : }
1349 :
1350 :
1351 : const SUMOVehicleParserHelper::CFAttrMap&
1352 64300 : SUMOVehicleParserHelper::getAllowedCFModelAttrs() {
1353 : // init on first use
1354 64300 : if (allowedCFModelAttrs.size() == 0) {
1355 : std::set<SumoXMLAttr> genericParams;
1356 27432 : genericParams.insert(SUMO_ATTR_TAU);
1357 27432 : genericParams.insert(SUMO_ATTR_ACCEL);
1358 27432 : genericParams.insert(SUMO_ATTR_DECEL);
1359 27432 : genericParams.insert(SUMO_ATTR_APPARENTDECEL);
1360 27432 : genericParams.insert(SUMO_ATTR_EMERGENCYDECEL);
1361 27432 : genericParams.insert(SUMO_ATTR_SPEED_TABLE);
1362 27432 : genericParams.insert(SUMO_ATTR_MAXACCEL_PROFILE);
1363 27432 : genericParams.insert(SUMO_ATTR_DESACCEL_PROFILE);
1364 27432 : genericParams.insert(SUMO_ATTR_COLLISION_MINGAP_FACTOR);
1365 27432 : genericParams.insert(SUMO_ATTR_STARTUP_DELAY);
1366 : // Krauss
1367 : std::set<SumoXMLAttr> kraussParams(genericParams);
1368 27432 : kraussParams.insert(SUMO_ATTR_SIGMA);
1369 27432 : kraussParams.insert(SUMO_ATTR_SIGMA_STEP);
1370 27432 : allowedCFModelAttrs[SUMO_TAG_CF_KRAUSS] = kraussParams;
1371 27432 : allowedCFModelAttrs[SUMO_TAG_CF_KRAUSS_ORIG1] = kraussParams;
1372 54864 : allowedCFModelAttrs[SUMO_TAG_CF_KRAUSS_PLUS_SLOPE] = kraussParams;
1373 : std::set<SumoXMLAttr> allParams(kraussParams);
1374 : // KraussX
1375 : std::set<SumoXMLAttr> kraussXParams(kraussParams);
1376 27432 : kraussXParams.insert(SUMO_ATTR_TMP1);
1377 27432 : kraussXParams.insert(SUMO_ATTR_TMP2);
1378 27432 : kraussXParams.insert(SUMO_ATTR_TMP3);
1379 27432 : kraussXParams.insert(SUMO_ATTR_TMP4);
1380 27432 : kraussXParams.insert(SUMO_ATTR_TMP5);
1381 54864 : allowedCFModelAttrs[SUMO_TAG_CF_KRAUSSX] = kraussXParams;
1382 27432 : allParams.insert(kraussXParams.begin(), kraussXParams.end());
1383 : // SmartSK
1384 : std::set<SumoXMLAttr> smartSKParams(genericParams);
1385 27432 : smartSKParams.insert(SUMO_ATTR_SIGMA);
1386 27432 : smartSKParams.insert(SUMO_ATTR_TMP1);
1387 27432 : smartSKParams.insert(SUMO_ATTR_TMP2);
1388 27432 : smartSKParams.insert(SUMO_ATTR_TMP3);
1389 27432 : smartSKParams.insert(SUMO_ATTR_TMP4);
1390 27432 : smartSKParams.insert(SUMO_ATTR_TMP5);
1391 54864 : allowedCFModelAttrs[SUMO_TAG_CF_SMART_SK] = smartSKParams;
1392 27432 : allParams.insert(smartSKParams.begin(), smartSKParams.end());
1393 : // Daniel
1394 : std::set<SumoXMLAttr> daniel1Params(genericParams);
1395 27432 : daniel1Params.insert(SUMO_ATTR_SIGMA);
1396 27432 : daniel1Params.insert(SUMO_ATTR_TMP1);
1397 27432 : daniel1Params.insert(SUMO_ATTR_TMP2);
1398 27432 : daniel1Params.insert(SUMO_ATTR_TMP3);
1399 27432 : daniel1Params.insert(SUMO_ATTR_TMP4);
1400 27432 : daniel1Params.insert(SUMO_ATTR_TMP5);
1401 54864 : allowedCFModelAttrs[SUMO_TAG_CF_DANIEL1] = daniel1Params;
1402 27432 : allParams.insert(daniel1Params.begin(), daniel1Params.end());
1403 : // Peter Wagner
1404 : std::set<SumoXMLAttr> pwagParams(genericParams);
1405 27432 : pwagParams.insert(SUMO_ATTR_SIGMA);
1406 27432 : pwagParams.insert(SUMO_ATTR_CF_PWAGNER2009_TAULAST);
1407 27432 : pwagParams.insert(SUMO_ATTR_CF_PWAGNER2009_APPROB);
1408 54864 : allowedCFModelAttrs[SUMO_TAG_CF_PWAGNER2009] = pwagParams;
1409 27432 : allParams.insert(pwagParams.begin(), pwagParams.end());
1410 : // IDM params
1411 : std::set<SumoXMLAttr> idmParams(genericParams);
1412 27432 : idmParams.insert(SUMO_ATTR_CF_IDM_DELTA);
1413 27432 : idmParams.insert(SUMO_ATTR_CF_IDM_STEPPING);
1414 54864 : allowedCFModelAttrs[SUMO_TAG_CF_IDM] = idmParams;
1415 27432 : allParams.insert(idmParams.begin(), idmParams.end());
1416 : // EIDM
1417 : std::set<SumoXMLAttr> eidmParams(genericParams);
1418 27432 : eidmParams.insert(SUMO_ATTR_CF_IDM_DELTA);
1419 27432 : eidmParams.insert(SUMO_ATTR_CF_IDM_STEPPING);
1420 27432 : eidmParams.insert(SUMO_ATTR_CF_EIDM_T_LOOK_AHEAD);
1421 27432 : eidmParams.insert(SUMO_ATTR_CF_EIDM_T_PERSISTENCE_DRIVE);
1422 27432 : eidmParams.insert(SUMO_ATTR_CF_EIDM_T_REACTION);
1423 27432 : eidmParams.insert(SUMO_ATTR_CF_EIDM_T_PERSISTENCE_ESTIMATE);
1424 27432 : eidmParams.insert(SUMO_ATTR_CF_EIDM_C_COOLNESS);
1425 27432 : eidmParams.insert(SUMO_ATTR_CF_EIDM_SIG_LEADER);
1426 27432 : eidmParams.insert(SUMO_ATTR_CF_EIDM_SIG_GAP);
1427 27432 : eidmParams.insert(SUMO_ATTR_CF_EIDM_SIG_ERROR);
1428 27432 : eidmParams.insert(SUMO_ATTR_CF_EIDM_JERK_MAX);
1429 27432 : eidmParams.insert(SUMO_ATTR_CF_EIDM_EPSILON_ACC);
1430 27432 : eidmParams.insert(SUMO_ATTR_CF_EIDM_T_ACC_MAX);
1431 27432 : eidmParams.insert(SUMO_ATTR_CF_EIDM_M_FLATNESS);
1432 27432 : eidmParams.insert(SUMO_ATTR_CF_EIDM_M_BEGIN);
1433 27432 : eidmParams.insert(SUMO_ATTR_CF_EIDM_USEVEHDYNAMICS);
1434 27432 : eidmParams.insert(SUMO_ATTR_CF_EIDM_MAX_VEH_PREVIEW);
1435 54864 : allowedCFModelAttrs[SUMO_TAG_CF_EIDM] = eidmParams;
1436 27432 : allParams.insert(eidmParams.begin(), eidmParams.end());
1437 : // IDMM
1438 : std::set<SumoXMLAttr> idmmParams(genericParams);
1439 27432 : idmmParams.insert(SUMO_ATTR_CF_IDMM_ADAPT_FACTOR);
1440 27432 : idmmParams.insert(SUMO_ATTR_CF_IDMM_ADAPT_TIME);
1441 27432 : idmmParams.insert(SUMO_ATTR_CF_IDM_STEPPING);
1442 54864 : allowedCFModelAttrs[SUMO_TAG_CF_IDMM] = idmmParams;
1443 27432 : allParams.insert(idmmParams.begin(), idmmParams.end());
1444 : // Bieker
1445 : std::set<SumoXMLAttr> bkernerParams(genericParams);
1446 27432 : bkernerParams.insert(SUMO_ATTR_K);
1447 27432 : bkernerParams.insert(SUMO_ATTR_CF_KERNER_PHI);
1448 54864 : allowedCFModelAttrs[SUMO_TAG_CF_BKERNER] = bkernerParams;
1449 27432 : allParams.insert(bkernerParams.begin(), bkernerParams.end());
1450 : // Wiedemann
1451 : std::set<SumoXMLAttr> wiedemannParams(genericParams);
1452 27432 : wiedemannParams.insert(SUMO_ATTR_CF_WIEDEMANN_SECURITY);
1453 27432 : wiedemannParams.insert(SUMO_ATTR_CF_WIEDEMANN_ESTIMATION);
1454 54864 : allowedCFModelAttrs[SUMO_TAG_CF_WIEDEMANN] = wiedemannParams;
1455 27432 : allParams.insert(wiedemannParams.begin(), wiedemannParams.end());
1456 : // W99
1457 : std::set<SumoXMLAttr> w99Params(genericParams);
1458 27432 : w99Params.insert(SUMO_ATTR_CF_W99_CC1);
1459 27432 : w99Params.insert(SUMO_ATTR_CF_W99_CC2);
1460 27432 : w99Params.insert(SUMO_ATTR_CF_W99_CC3);
1461 27432 : w99Params.insert(SUMO_ATTR_CF_W99_CC4);
1462 27432 : w99Params.insert(SUMO_ATTR_CF_W99_CC5);
1463 27432 : w99Params.insert(SUMO_ATTR_CF_W99_CC6);
1464 27432 : w99Params.insert(SUMO_ATTR_CF_W99_CC7);
1465 27432 : w99Params.insert(SUMO_ATTR_CF_W99_CC8);
1466 27432 : w99Params.insert(SUMO_ATTR_CF_W99_CC9);
1467 54864 : allowedCFModelAttrs[SUMO_TAG_CF_W99] = w99Params;
1468 27432 : allParams.insert(w99Params.begin(), w99Params.end());
1469 : // Rail
1470 : std::set<SumoXMLAttr> railParams(genericParams);
1471 27432 : railParams.insert(SUMO_ATTR_TRAIN_TYPE);
1472 27432 : railParams.insert(SUMO_ATTR_TRACTION_TABLE);
1473 27432 : railParams.insert(SUMO_ATTR_RESISTANCE_TABLE);
1474 27432 : railParams.insert(SUMO_ATTR_MASSFACTOR);
1475 27432 : railParams.insert(SUMO_ATTR_MAXPOWER);
1476 27432 : railParams.insert(SUMO_ATTR_MAXTRACTION);
1477 27432 : railParams.insert(SUMO_ATTR_RESISTANCE_COEFFICIENT_CONSTANT);
1478 27432 : railParams.insert(SUMO_ATTR_RESISTANCE_COEFFICIENT_LINEAR);
1479 27432 : railParams.insert(SUMO_ATTR_RESISTANCE_COEFFICIENT_QUADRATIC);
1480 27432 : railParams.insert(SUMO_ATTR_CURVE_RESISTANCE);
1481 27432 : railParams.insert(SUMO_ATTR_CURVE_INTEGRATION);
1482 27432 : railParams.insert(SUMO_ATTR_ROECKL_SHARP_RADIUS);
1483 27432 : railParams.insert(SUMO_ATTR_ROECKL_NUMERATOR);
1484 27432 : railParams.insert(SUMO_ATTR_ROECKL_NUMERATOR_SHARP);
1485 27432 : railParams.insert(SUMO_ATTR_ROECKL_OFFSET);
1486 27432 : railParams.insert(SUMO_ATTR_ROECKL_OFFSET_SHARP);
1487 54864 : allowedCFModelAttrs[SUMO_TAG_CF_RAIL] = railParams;
1488 27432 : allParams.insert(railParams.begin(), railParams.end());
1489 : // ACC
1490 : std::set<SumoXMLAttr> ACCParams(genericParams);
1491 27432 : ACCParams.insert(SUMO_ATTR_SC_GAIN);
1492 27432 : ACCParams.insert(SUMO_ATTR_GCC_GAIN_SPEED);
1493 27432 : ACCParams.insert(SUMO_ATTR_GCC_GAIN_SPACE);
1494 27432 : ACCParams.insert(SUMO_ATTR_GC_GAIN_SPEED);
1495 27432 : ACCParams.insert(SUMO_ATTR_GC_GAIN_SPACE);
1496 27432 : ACCParams.insert(SUMO_ATTR_CA_GAIN_SPEED);
1497 27432 : ACCParams.insert(SUMO_ATTR_CA_GAIN_SPACE);
1498 27432 : ACCParams.insert(SUMO_ATTR_CA_OVERRIDE);
1499 27432 : ACCParams.insert(SUMO_ATTR_APPLYDRIVERSTATE);
1500 54864 : allowedCFModelAttrs[SUMO_TAG_CF_ACC] = ACCParams;
1501 27432 : allParams.insert(ACCParams.begin(), ACCParams.end());
1502 : // CACC
1503 : std::set<SumoXMLAttr> CACCParams(genericParams);
1504 27432 : CACCParams.insert(SUMO_ATTR_SC_GAIN_CACC);
1505 27432 : CACCParams.insert(SUMO_ATTR_GCC_GAIN_GAP_CACC);
1506 27432 : CACCParams.insert(SUMO_ATTR_GCC_GAIN_GAP_DOT_CACC);
1507 27432 : CACCParams.insert(SUMO_ATTR_GC_GAIN_GAP_CACC);
1508 27432 : CACCParams.insert(SUMO_ATTR_GC_GAIN_GAP_DOT_CACC);
1509 27432 : CACCParams.insert(SUMO_ATTR_CA_GAIN_GAP_CACC);
1510 27432 : CACCParams.insert(SUMO_ATTR_CA_GAIN_GAP_DOT_CACC);
1511 27432 : CACCParams.insert(SUMO_ATTR_GCC_GAIN_SPEED);
1512 27432 : CACCParams.insert(SUMO_ATTR_GCC_GAIN_SPACE);
1513 27432 : CACCParams.insert(SUMO_ATTR_GC_GAIN_SPEED);
1514 27432 : CACCParams.insert(SUMO_ATTR_GC_GAIN_SPACE);
1515 27432 : CACCParams.insert(SUMO_ATTR_CA_GAIN_SPEED);
1516 27432 : CACCParams.insert(SUMO_ATTR_CA_GAIN_SPACE);
1517 27432 : CACCParams.insert(SUMO_ATTR_CA_OVERRIDE);
1518 27432 : CACCParams.insert(SUMO_ATTR_HEADWAY_TIME_CACC_TO_ACC);
1519 27432 : CACCParams.insert(SUMO_ATTR_APPLYDRIVERSTATE);
1520 27432 : CACCParams.insert(SUMO_ATTR_SC_MIN_GAP);
1521 54864 : allowedCFModelAttrs[SUMO_TAG_CF_CACC] = CACCParams;
1522 27432 : allParams.insert(CACCParams.begin(), CACCParams.end());
1523 : // CC
1524 : std::set<SumoXMLAttr> ccParams(genericParams);
1525 27432 : ccParams.insert(SUMO_ATTR_CF_CC_C1);
1526 27432 : ccParams.insert(SUMO_ATTR_CF_CC_CCDECEL);
1527 27432 : ccParams.insert(SUMO_ATTR_CF_CC_CONSTSPACING);
1528 27432 : ccParams.insert(SUMO_ATTR_CF_CC_KP);
1529 27432 : ccParams.insert(SUMO_ATTR_CF_CC_LAMBDA);
1530 27432 : ccParams.insert(SUMO_ATTR_CF_CC_OMEGAN);
1531 27432 : ccParams.insert(SUMO_ATTR_CF_CC_TAU);
1532 27432 : ccParams.insert(SUMO_ATTR_CF_CC_XI);
1533 27432 : ccParams.insert(SUMO_ATTR_CF_CC_LANES_COUNT);
1534 27432 : ccParams.insert(SUMO_ATTR_CF_CC_CCACCEL);
1535 27432 : ccParams.insert(SUMO_ATTR_CF_CC_PLOEG_KP);
1536 27432 : ccParams.insert(SUMO_ATTR_CF_CC_PLOEG_KD);
1537 27432 : ccParams.insert(SUMO_ATTR_CF_CC_PLOEG_H);
1538 27432 : ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_KA);
1539 27432 : ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_KV);
1540 27432 : ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_KP);
1541 27432 : ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_D);
1542 27432 : ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_H);
1543 54864 : allowedCFModelAttrs[SUMO_TAG_CF_CC] = ccParams;
1544 27432 : allParams.insert(ccParams.begin(), ccParams.end());
1545 : // last element
1546 54864 : allowedCFModelAttrs[SUMO_TAG_NOTHING] = allParams;
1547 : }
1548 64300 : return allowedCFModelAttrs;
1549 : }
1550 :
1551 :
1552 : bool
1553 64284 : SUMOVehicleParserHelper::parseLCParams(SUMOVTypeParameter* into, LaneChangeModel model, const SUMOSAXAttributes& attrs) {
1554 64284 : if (allowedLCModelAttrs.size() == 0) {
1555 : // lc2013
1556 : std::set<SumoXMLAttr> lc2013Params;
1557 27432 : lc2013Params.insert(SUMO_ATTR_LCA_STRATEGIC_PARAM);
1558 27432 : lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_PARAM);
1559 27432 : lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_PARAM);
1560 27432 : lc2013Params.insert(SUMO_ATTR_LCA_KEEPRIGHT_PARAM);
1561 27432 : lc2013Params.insert(SUMO_ATTR_LCA_OPPOSITE_PARAM);
1562 27432 : lc2013Params.insert(SUMO_ATTR_LCA_LOOKAHEADLEFT);
1563 27432 : lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAINRIGHT);
1564 27432 : lc2013Params.insert(SUMO_ATTR_LCA_MAXSPEEDLATSTANDING);
1565 27432 : lc2013Params.insert(SUMO_ATTR_LCA_MAXSPEEDLATFACTOR);
1566 27432 : lc2013Params.insert(SUMO_ATTR_LCA_MAXDISTLATSTANDING);
1567 27432 : lc2013Params.insert(SUMO_ATTR_LCA_ASSERTIVE);
1568 27432 : lc2013Params.insert(SUMO_ATTR_LCA_STRATEGIC_LOOKAHEAD);
1569 27432 : lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD);
1570 27432 : lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_REMAIN_TIME);
1571 27432 : lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_URGENCY);
1572 27432 : lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_ROUNDABOUT);
1573 27432 : lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_SPEED);
1574 27432 : lc2013Params.insert(SUMO_ATTR_LCA_OVERTAKE_RIGHT);
1575 27432 : lc2013Params.insert(SUMO_ATTR_LCA_SIGMA);
1576 27432 : lc2013Params.insert(SUMO_ATTR_LCA_KEEPRIGHT_ACCEPTANCE_TIME);
1577 27432 : lc2013Params.insert(SUMO_ATTR_LCA_OVERTAKE_DELTASPEED_FACTOR);
1578 27432 : lc2013Params.insert(SUMO_ATTR_LCA_CONTRIGHT);
1579 27432 : lc2013Params.insert(SUMO_ATTR_LCA_EXPERIMENTAL1);
1580 54864 : allowedLCModelAttrs[LaneChangeModel::LC2013] = lc2013Params;
1581 : // sl2015 (extension of lc2013)
1582 : std::set<SumoXMLAttr> sl2015Params = lc2013Params;
1583 27432 : sl2015Params.insert(SUMO_ATTR_LCA_PUSHY);
1584 27432 : sl2015Params.insert(SUMO_ATTR_LCA_PUSHYGAP);
1585 27432 : sl2015Params.insert(SUMO_ATTR_LCA_SUBLANE_PARAM);
1586 27432 : sl2015Params.insert(SUMO_ATTR_LCA_IMPATIENCE);
1587 27432 : sl2015Params.insert(SUMO_ATTR_LCA_TIME_TO_IMPATIENCE);
1588 27432 : sl2015Params.insert(SUMO_ATTR_LCA_ACCEL_LAT);
1589 27432 : sl2015Params.insert(SUMO_ATTR_LCA_TURN_ALIGNMENT_DISTANCE);
1590 27432 : sl2015Params.insert(SUMO_ATTR_LCA_LANE_DISCIPLINE);
1591 54864 : allowedLCModelAttrs[LaneChangeModel::SL2015] = sl2015Params;
1592 : // DK2008
1593 : std::set<SumoXMLAttr> noParams;
1594 27432 : allowedLCModelAttrs[LaneChangeModel::DK2008] = noParams;
1595 : // default model may be either LC2013 or SL2015
1596 : // we allow both sets (sl2015 is a superset of lc2013Params)
1597 54864 : allowedLCModelAttrs[LaneChangeModel::DEFAULT] = sl2015Params;
1598 : }
1599 64284 : std::set<SumoXMLAttr> allowed = allowedLCModelAttrs[model];
1600 : // iterate over LCM attributes
1601 2056289 : for (const auto& it : allowed) {
1602 1992005 : if (attrs.hasAttribute(it)) {
1603 : // first obtain CFM attribute in string format
1604 4056 : bool ok = true;
1605 4056 : std::string parsedLCMAttribute = attrs.get<std::string>(it, into->id.c_str(), ok);
1606 4056 : if (!ok) {
1607 : return false;
1608 : }
1609 : // declare a double in wich save CFM attribute
1610 : double LCMAttribute = -1;
1611 : try {
1612 : // obtain CFM attribute in double format
1613 4056 : LCMAttribute = StringUtils::toDouble(parsedLCMAttribute);
1614 0 : } catch (...) {
1615 0 : WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Cannot be parsed to float"), toString(it));
1616 : return false;
1617 0 : }
1618 : // check attributes of type "nonNegativeFloatType" (>= 0)
1619 4056 : switch (it) {
1620 1446 : case SUMO_ATTR_LCA_PUSHYGAP:
1621 : case SUMO_ATTR_LCA_MAXSPEEDLATSTANDING:
1622 : case SUMO_ATTR_LCA_IMPATIENCE:
1623 : case SUMO_ATTR_LCA_OVERTAKE_RIGHT:
1624 : case SUMO_ATTR_LCA_ASSERTIVE:
1625 : case SUMO_ATTR_LCA_LOOKAHEADLEFT:
1626 : case SUMO_ATTR_LCA_SPEEDGAINRIGHT:
1627 : case SUMO_ATTR_LCA_TURN_ALIGNMENT_DISTANCE:
1628 : case SUMO_ATTR_LCA_TIME_TO_IMPATIENCE:
1629 : case SUMO_ATTR_LCA_LANE_DISCIPLINE:
1630 : case SUMO_ATTR_LCA_SIGMA:
1631 1446 : if (LCMAttribute < 0) {
1632 0 : WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Must be equal or greater than 0"), toString(it));
1633 0 : return false;
1634 : }
1635 : break;
1636 : default:
1637 : break;
1638 : }
1639 : // check attributes of type "positiveFloatType" (> 0)
1640 4056 : switch (it) {
1641 10 : case SUMO_ATTR_LCA_ACCEL_LAT:
1642 10 : if (LCMAttribute <= 0) {
1643 0 : WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Must be greater than 0"), toString(it));
1644 0 : return false;
1645 : }
1646 : break;
1647 : default:
1648 : break;
1649 : }
1650 : // check limits of attributes
1651 4056 : switch (it) {
1652 90 : case SUMO_ATTR_LCA_OVERTAKE_DELTASPEED_FACTOR:
1653 90 : if (LCMAttribute < -1 || LCMAttribute > 1) {
1654 0 : WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Must be between -1 and 1"), toString(it));
1655 0 : return false;
1656 : }
1657 : break;
1658 : default:
1659 : break;
1660 : }
1661 : // add parsedLCMAttribute to cfParameter
1662 4056 : into->lcParameter[it] = parsedLCMAttribute;
1663 : }
1664 : }
1665 : // all LCM parsed ok, then return true
1666 : return true;
1667 : }
1668 :
1669 :
1670 : bool
1671 64284 : SUMOVehicleParserHelper::parseJMParams(SUMOVTypeParameter* into, const SUMOSAXAttributes& attrs) {
1672 1092828 : for (const auto& it : SUMOVTypeParameter::AllowedJMAttrs) {
1673 1028544 : if (attrs.hasAttribute(it)) {
1674 : // first obtain CFM attribute in string format
1675 1081 : bool ok = true;
1676 1081 : std::string parsedJMAttribute = attrs.get<std::string>(it, into->id.c_str(), ok);
1677 1081 : if (!ok) {
1678 : return false;
1679 : }
1680 : // declare a double in wich save CFM attribute
1681 : double JMAttribute = INVALID_DOUBLE;
1682 : try {
1683 : // obtain CFM attribute in double format
1684 1081 : JMAttribute = StringUtils::toDouble(parsedJMAttribute);
1685 0 : } catch (...) {
1686 0 : WRITE_ERRORF(TL("Invalid Junction-Model Attribute %. Cannot be parsed to float"), toString(it));
1687 : return false;
1688 0 : }
1689 : // now continue checking other properties (-1 is the default value)
1690 1081 : if (JMAttribute != INVALID_DOUBLE) {
1691 : // special case for sigma minor
1692 1081 : if (it == SUMO_ATTR_JM_SIGMA_MINOR) {
1693 : // check attributes sigma minor
1694 126 : if ((JMAttribute < 0) || (JMAttribute > 1)) {
1695 0 : WRITE_ERRORF(TL("Invalid Junction-Model Attribute %. Only values between [0-1] are allowed"), toString(it));
1696 0 : return false;
1697 : }
1698 955 : } else if (JMAttribute < 0
1699 25 : && it != SUMO_ATTR_JM_TIMEGAP_MINOR
1700 18 : && it != SUMO_ATTR_JM_EXTRA_GAP) {
1701 : // attributes with error value
1702 18 : if (JMAttribute != -1 || (it != SUMO_ATTR_JM_DRIVE_AFTER_YELLOW_TIME
1703 : && it != SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME
1704 18 : && it != SUMO_ATTR_JM_IGNORE_KEEPCLEAR_TIME)) {
1705 : // check attributes of type "nonNegativeFloatType" (>= 0)
1706 0 : WRITE_ERRORF(TL("Invalid Junction-Model Attribute %. Must be equal or greater than 0"), toString(it));
1707 0 : return false;
1708 : }
1709 : }
1710 : // add parsedJMAttribute to cfParameter
1711 1081 : into->jmParameter[it] = parsedJMAttribute;
1712 : }
1713 : }
1714 : }
1715 : // all JM parameters successfully parsed, then return true
1716 : return true;
1717 : }
1718 :
1719 :
1720 : SUMOVehicleClass
1721 37138 : SUMOVehicleParserHelper::parseVehicleClass(const SUMOSAXAttributes& attrs, const std::string& id) {
1722 : SUMOVehicleClass vclass = SVC_IGNORING;
1723 37138 : bool ok = true;
1724 37138 : std::string vclassS = attrs.getOpt<std::string>(SUMO_ATTR_VCLASS, id.c_str(), ok, "");
1725 37138 : if (vclassS == "") {
1726 : return vclass;
1727 : }
1728 : try {
1729 37114 : const SUMOVehicleClass result = getVehicleClassID(vclassS);
1730 37106 : const std::string& realName = SumoVehicleClassStrings.getString(result);
1731 37106 : if (realName != vclassS) {
1732 12 : WRITE_WARNING("The vehicle class '" + vclassS + "' for " + attrs.getObjectType() + " '" + id + "' is deprecated, use '" + realName + "' instead.");
1733 : }
1734 : return result;
1735 8 : } catch (...) {
1736 24 : WRITE_ERRORF(TL("The vehicle class '%' for % '%' is not known."), vclassS, attrs.getObjectType(), id);
1737 8 : }
1738 : return vclass;
1739 : }
1740 :
1741 :
1742 : SUMOVehicleShape
1743 27191 : SUMOVehicleParserHelper::parseGuiShape(const SUMOSAXAttributes& attrs, const std::string& id) {
1744 27191 : bool ok = true;
1745 54382 : std::string vclassS = attrs.getOpt<std::string>(SUMO_ATTR_GUISHAPE, id.c_str(), ok, "");
1746 : if (SumoVehicleShapeStrings.hasString(vclassS)) {
1747 27191 : const SUMOVehicleShape result = SumoVehicleShapeStrings.get(vclassS);
1748 27191 : const std::string& realName = SumoVehicleShapeStrings.getString(result);
1749 27191 : if (realName != vclassS) {
1750 0 : WRITE_WARNING("The shape '" + vclassS + "' for " + attrs.getObjectType() + " '" + id + "' is deprecated, use '" + realName + "' instead.");
1751 : }
1752 27191 : return result;
1753 : } else {
1754 0 : WRITE_ERRORF(TL("The shape '%' for % '%' is not known."), vclassS, attrs.getObjectType(), id);
1755 0 : return SUMOVehicleShape::UNKNOWN;
1756 : }
1757 : }
1758 :
1759 :
1760 : double
1761 32005 : SUMOVehicleParserHelper::parseWalkPos(SumoXMLAttr attr, const bool hardFail, const std::string& id, double maxPos, const std::string& val, SumoRNG* rng) {
1762 : double result;
1763 : std::string error;
1764 32005 : ArrivalPosDefinition proc = ArrivalPosDefinition::DEFAULT;
1765 : // only supports 'random' and 'max'
1766 64010 : if (!SUMOVehicleParameter::parseArrivalPos(val, toString(SUMO_TAG_WALK), id, result, proc, error)) {
1767 0 : handleVehicleError(hardFail, nullptr, error);
1768 : }
1769 32005 : if (proc == ArrivalPosDefinition::RANDOM) {
1770 1076 : result = RandHelper::rand(maxPos, rng);
1771 30929 : } else if (proc == ArrivalPosDefinition::CENTER) {
1772 0 : result = maxPos / 2.;
1773 30929 : } else if (proc == ArrivalPosDefinition::MAX) {
1774 0 : result = maxPos;
1775 : }
1776 64010 : return SUMOVehicleParameter::interpretEdgePos(result, maxPos, attr, id);
1777 : }
1778 :
1779 :
1780 : SUMOTime
1781 494655 : SUMOVehicleParserHelper::processActionStepLength(double given) {
1782 494655 : const std::string defaultError = "The parameter action-step-length must be a non-negative multiple of the simulation step-length. ";
1783 494655 : SUMOTime result = TIME2STEPS(given);
1784 494655 : if (result <= 0) {
1785 42293 : if (result < 0) {
1786 36 : WRITE_WARNING(defaultError + "Ignoring given value (=" + toString(STEPS2TIME(result)) + " s.)");
1787 : }
1788 42293 : result = DELTA_T;
1789 452391 : } else if (result % DELTA_T != 0 && OptionsCont::getOptions().exists("step-length")) {
1790 25 : result = (SUMOTime)((double)DELTA_T * floor(double(result) / double(DELTA_T)));
1791 : result = MAX2(DELTA_T, result);
1792 25 : if (fabs(given * 1000. - double(result)) > NUMERICAL_EPS) {
1793 100 : WRITE_WARNING(defaultError + "Parsing given value (" + toString(given) + " s.) to the adjusted value " + toString(STEPS2TIME(result)) + " s.");
1794 : }
1795 : }
1796 494655 : return result;
1797 : }
1798 :
1799 :
1800 : bool
1801 185767 : SUMOVehicleParserHelper::isInternalRouteID(const std::string& id) {
1802 185767 : return id.substr(0, 1) == "!";
1803 : }
1804 :
1805 :
1806 : bool
1807 16 : SUMOVehicleParserHelper::validProfile(SUMOVTypeParameter* vtype, const std::string data, const SumoXMLAttr attr) {
1808 68 : for (std::string value : StringTokenizer(data).getVector()) {
1809 : try {
1810 36 : double v = StringUtils::toDouble(value);
1811 36 : if (v < 0.) {
1812 0 : WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. An acceleration profile value cannot be negative"), toString(attr));
1813 0 : return false;
1814 : }
1815 0 : } catch (...) {
1816 0 : WRITE_ERRORF(TL("Entry '%' of % table for vType '%' cannot be parsed as 'double'"), value, toString(attr), vtype->id);
1817 : return false;
1818 0 : }
1819 16 : }
1820 16 : return true;
1821 : }
1822 :
1823 :
1824 : int
1825 14431 : SUMOVehicleParserHelper::parseCarWalkTransfer(const OptionsCont& oc, const bool hasTaxi) {
1826 : int carWalk = 0;
1827 43293 : for (const std::string& opt : oc.getStringVector("persontrip.transfer.car-walk")) {
1828 14431 : if (opt == "parkingAreas") {
1829 14231 : carWalk |= ModeChangeOptions::PARKING_AREAS;
1830 200 : } else if (opt == "ptStops") {
1831 150 : carWalk |= ModeChangeOptions::PT_STOPS;
1832 50 : } else if (opt == "allJunctions") {
1833 50 : carWalk |= ModeChangeOptions::ALL_JUNCTIONS;
1834 : } else {
1835 0 : WRITE_ERRORF(TL("Invalid transfer option '%'. Must be one of 'parkingAreas', 'ptStops' and 'allJunctions'"), opt);
1836 : }
1837 : }
1838 14431 : const StringVector taxiDropoff = oc.getStringVector("persontrip.transfer.taxi-walk");
1839 28862 : const StringVector taxiPickup = oc.getStringVector("persontrip.transfer.walk-taxi");
1840 14431 : if (taxiDropoff.empty() && hasTaxi) {
1841 3683 : carWalk |= ModeChangeOptions::TAXI_DROPOFF_ANYWHERE;
1842 : } else {
1843 10960 : for (const std::string& opt : taxiDropoff) {
1844 212 : if (opt == "parkingAreas") {
1845 14 : carWalk |= ModeChangeOptions::TAXI_DROPOFF_PARKING_AREAS;
1846 198 : } else if (opt == "ptStops") {
1847 152 : carWalk |= ModeChangeOptions::TAXI_DROPOFF_PT;
1848 46 : } else if (opt == "allJunctions") {
1849 46 : carWalk |= ModeChangeOptions::TAXI_DROPOFF_ANYWHERE;
1850 : } else {
1851 0 : WRITE_ERRORF(TL("Invalid transfer option '%'. Must be one of 'parkingAreas', 'ptStops' and 'allJunctions'"), opt);
1852 : }
1853 : }
1854 : }
1855 14431 : if (taxiPickup.empty() && hasTaxi) {
1856 3659 : carWalk |= ModeChangeOptions::TAXI_PICKUP_ANYWHERE;
1857 : } else {
1858 11008 : for (const std::string& opt : taxiPickup) {
1859 236 : if (opt == "parkingAreas") {
1860 14 : carWalk |= ModeChangeOptions::TAXI_PICKUP_PARKING_AREAS;
1861 222 : } else if (opt == "ptStops") {
1862 172 : carWalk |= ModeChangeOptions::TAXI_PICKUP_PT;
1863 50 : } else if (opt == "allJunctions") {
1864 50 : carWalk |= ModeChangeOptions::TAXI_PICKUP_ANYWHERE;
1865 : } else {
1866 0 : WRITE_ERRORF(TL("Invalid transfer option '%'. Must be one of 'parkingAreas', 'ptStops' and 'allJunctions'"), opt);
1867 : }
1868 : }
1869 : }
1870 14431 : return carWalk;
1871 14431 : }
1872 :
1873 :
1874 : SUMOVehicleParameter*
1875 432 : SUMOVehicleParserHelper::handleVehicleError(const bool hardFail, SUMOVehicleParameter* vehicleParameter, const std::string message) {
1876 432 : if (vehicleParameter) {
1877 388 : delete vehicleParameter;
1878 : }
1879 432 : if (hardFail) {
1880 432 : throw ProcessError(message);
1881 0 : } else if (message.size() > 0) {
1882 0 : WRITE_ERROR(message);
1883 : }
1884 0 : return nullptr;
1885 : }
1886 :
1887 :
1888 : SUMOVTypeParameter*
1889 30 : SUMOVehicleParserHelper::handleVehicleTypeError(const bool hardFail, SUMOVTypeParameter* vehicleTypeParameter, const std::string message) {
1890 30 : if (vehicleTypeParameter) {
1891 26 : delete vehicleTypeParameter;
1892 : }
1893 30 : if (hardFail) {
1894 30 : throw ProcessError(message);
1895 0 : } else if (message.size() > 0) {
1896 0 : WRITE_ERROR(message);
1897 : }
1898 0 : return nullptr;
1899 : }
1900 :
1901 : /****************************************************************************/
|