Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2008-2024 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 24866 : 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 24866 : const std::string id = attrs.hasAttribute(SUMO_ATTR_ID) ? parseID(attrs, tag) : "";
61 : // check if ID is valid
62 24866 : if (!needID || !id.empty()) {
63 24859 : if (needID && !SUMOXMLDefinitions::isValidVehicleID(id)) {
64 0 : return handleVehicleError(hardFail, nullptr, "Invalid flow id '" + id + "'.");
65 : }
66 : // declare flags
67 24859 : const bool hasPeriod = attrs.hasAttribute(SUMO_ATTR_PERIOD);
68 24859 : const bool hasVPH = attrs.hasAttribute(SUMO_ATTR_VEHSPERHOUR);
69 24859 : const bool hasPPH = attrs.hasAttribute(SUMO_ATTR_PERSONSPERHOUR);
70 24859 : const bool hasCPH = attrs.hasAttribute(SUMO_ATTR_CONTAINERSPERHOUR);
71 24859 : const bool hasPH = attrs.hasAttribute(SUMO_ATTR_PERHOUR);
72 24859 : const bool hasXPH = hasVPH || hasPPH || hasCPH || hasPH;
73 24859 : const bool hasProb = attrs.hasAttribute(SUMO_ATTR_PROB);
74 24859 : const bool hasNumber = attrs.hasAttribute(SUMO_ATTR_NUMBER);
75 24859 : const bool hasBegin = attrs.hasAttribute(SUMO_ATTR_BEGIN);
76 24859 : const bool hasEnd = attrs.hasAttribute(SUMO_ATTR_END);
77 : SumoXMLAttr PERHOUR = SUMO_ATTR_PERHOUR;
78 24859 : if (hasVPH) {
79 : PERHOUR = SUMO_ATTR_VEHSPERHOUR;
80 : }
81 24859 : if (hasPPH) {
82 : PERHOUR = SUMO_ATTR_PERSONSPERHOUR;
83 : }
84 24859 : if (hasCPH) {
85 : PERHOUR = SUMO_ATTR_CONTAINERSPERHOUR;
86 : }
87 24859 : 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 3890 : 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 24852 : 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 24852 : 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 24852 : if (hasPeriod || hasXPH || hasProb) {
117 16380 : 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 8472 : 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 24838 : SUMOVehicleParameter* flowParameter = new SUMOVehicleParameter();
146 : // set tag
147 24838 : flowParameter->tag = tag;
148 : // set id
149 24838 : flowParameter->id = id;
150 24838 : if (tag == SUMO_TAG_PERSONFLOW) {
151 1719 : flowParameter->vtypeid = DEFAULT_PEDTYPE_ID;
152 : }
153 24838 : if (tag == SUMO_TAG_CONTAINERFLOW) {
154 322 : flowParameter->vtypeid = DEFAULT_CONTAINERTYPE_ID;
155 : }
156 : // parse common vehicle attributes
157 : try {
158 24838 : 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 24790 : if (hasPeriod) {
170 8497 : bool ok = true;
171 8497 : const std::string description = attrs.get<std::string>(SUMO_ATTR_PERIOD, id.c_str(), ok);
172 8497 : const std::string distName = description.substr(0, description.find('('));
173 8497 : if (distName == "exp") {
174 : // declare rate
175 : double rate = -1;
176 : // parse rate
177 : try {
178 551 : 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 551 : 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 544 : flowParameter->poissonRate = rate;
191 : poissonFlow = true;
192 : } else {
193 7946 : flowParameter->repetitionOffset = attrs.getSUMOTimeReporting(SUMO_ATTR_PERIOD, id.c_str(), ok);
194 : }
195 8490 : if (!ok) {
196 7 : return handleVehicleError(hardFail, flowParameter);
197 : } else {
198 8490 : flowParameter->parametersSet |= VEHPARS_PERIOD_SET;
199 : }
200 : }
201 : // parse vehicle/person/container/etc per hour
202 24783 : if (hasXPH) {
203 3883 : bool ok = true;
204 3883 : const double vph = attrs.get<double>(PERHOUR, id.c_str(), ok);
205 3883 : if (!ok) {
206 0 : return handleVehicleError(hardFail, flowParameter);
207 3883 : } 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 3883 : flowParameter->repetitionOffset = TIME2STEPS(3600. / vph);
212 : }
213 3883 : flowParameter->parametersSet |= VEHPARS_VPH_SET;
214 : }
215 : }
216 : // parse probability
217 24783 : if (hasProb) {
218 3993 : bool ok = true;
219 3993 : flowParameter->repetitionProbability = attrs.get<double>(SUMO_ATTR_PROB, id.c_str(), ok);
220 3993 : if (!ok) {
221 0 : return handleVehicleError(hardFail, flowParameter);
222 3993 : } 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 3993 : flowParameter->parametersSet |= VEHPARS_PROB_SET;
226 : }
227 : }
228 : // set default begin
229 24783 : flowParameter->depart = beginDefault;
230 : // parse begin
231 24783 : if (hasBegin) {
232 : // first get begin
233 24601 : bool ok = true;
234 24601 : const std::string begin = attrs.get<std::string>(SUMO_ATTR_BEGIN, id.c_str(), ok);
235 24601 : if (!ok) {
236 7 : return handleVehicleError(hardFail, flowParameter);
237 : } else {
238 : // parse begin
239 : std::string errorMsg;
240 49202 : if (!SUMOVehicleParameter::parseDepart(begin, toString(tag), id, flowParameter->depart, flowParameter->departProcedure, errorMsg, "begin")) {
241 14 : return handleVehicleError(hardFail, flowParameter, errorMsg);
242 : }
243 : }
244 : }
245 24776 : 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 24776 : flowParameter->repetitionEnd = endDefault;
250 24776 : if (flowParameter->repetitionEnd < 0) {
251 17196 : flowParameter->repetitionEnd = SUMOTime_MAX;
252 : }
253 : // parse end
254 24776 : if (hasEnd) {
255 22479 : bool ok = true;
256 22479 : flowParameter->repetitionEnd = attrs.getSUMOTimeReporting(SUMO_ATTR_END, id.c_str(), ok);
257 22479 : if (!ok) {
258 0 : return handleVehicleError(hardFail, flowParameter);
259 : } else {
260 22479 : flowParameter->parametersSet |= VEHPARS_END_SET;
261 : }
262 2297 : } else if (flowParameter->departProcedure == DepartDefinition::TRIGGERED) {
263 47 : if (!hasNumber) {
264 0 : return handleVehicleError(hardFail, flowParameter, toString(tag) + " '" + id + "' with triggered begin must define 'number'.");
265 : } else {
266 47 : flowParameter->repetitionEnd = flowParameter->depart;
267 : }
268 2250 : } 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 24776 : 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 24769 : if (hasNumber) {
279 10401 : bool ok = true;
280 10401 : flowParameter->repetitionNumber = attrs.get<int>(SUMO_ATTR_NUMBER, id.c_str(), ok);
281 10401 : if (!ok) {
282 0 : return handleVehicleError(hardFail, flowParameter);
283 : } else {
284 10401 : flowParameter->parametersSet |= VEHPARS_NUMBER_SET;
285 10401 : 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 10393 : if (flowParameter->repetitionNumber < 0) {
292 14 : return handleVehicleError(hardFail, flowParameter, "Negative repetition number in the definition of " + toString(tag) + " '" + id + "'.");
293 : }
294 10386 : if (flowParameter->repetitionOffset < 0 && !hasProb) {
295 8452 : if (poissonFlow) {
296 43 : flowParameter->repetitionEnd = SUMOTime_MAX;
297 : } else {
298 8409 : flowParameter->repetitionOffset = (flowParameter->repetitionEnd - flowParameter->depart) / flowParameter->repetitionNumber;
299 : }
300 : }
301 : }
302 : }
303 : } else {
304 : // interpret repetitionNumber
305 14368 : if (flowParameter->repetitionProbability > 0) {
306 3951 : flowParameter->repetitionNumber = std::numeric_limits<int>::max();
307 : } else {
308 10417 : if (flowParameter->repetitionOffset <= 0) {
309 515 : if (poissonFlow) {
310 : // number is random but flow has a fixed end time
311 501 : flowParameter->repetitionNumber = std::numeric_limits<int>::max();
312 : } else {
313 28 : return handleVehicleError(hardFail, flowParameter, "Invalid repetition rate in the definition of " + toString(tag) + " '" + id + "'.");
314 : }
315 : } else {
316 9902 : if (flowParameter->repetitionEnd == SUMOTime_MAX) {
317 0 : flowParameter->repetitionNumber = std::numeric_limits<int>::max();
318 : } else {
319 9902 : const SUMOTime repLength = flowParameter->repetitionEnd - flowParameter->depart;
320 9902 : flowParameter->repetitionNumber = (int)ceil((double)repLength / (double)flowParameter->repetitionOffset);
321 : }
322 : }
323 : }
324 : }
325 : // all ok, then return flow parameter
326 24748 : return flowParameter;
327 : } else {
328 132 : return handleVehicleError(hardFail, nullptr, toString(tag) + " cannot be created");
329 : }
330 : }
331 :
332 :
333 : SUMOVehicleParameter*
334 472779 : 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 472779 : if (optionalID) {
339 673 : bool ok = true;
340 673 : id = attrs.getOpt<std::string>(SUMO_ATTR_ID, nullptr, ok, "");
341 673 : if (!ok) {
342 0 : return handleVehicleError(hardFail, nullptr);
343 : }
344 : } else {
345 : // parse ID
346 944212 : id = parseID(attrs, (SumoXMLTag)element);
347 : }
348 : // only continue if id is valid, or if is optional
349 472779 : if (optionalID || !id.empty()) {
350 : // declare vehicle parameter
351 472763 : SUMOVehicleParameter* vehicleParameter = new SUMOVehicleParameter();
352 472763 : vehicleParameter->id = id;
353 472763 : if (element == SUMO_TAG_PERSON) {
354 41429 : vehicleParameter->vtypeid = DEFAULT_PEDTYPE_ID;
355 431334 : } else if (element == SUMO_TAG_CONTAINER) {
356 820 : vehicleParameter->vtypeid = DEFAULT_CONTAINERTYPE_ID;
357 : }
358 : // parse common attributes
359 : try {
360 472763 : 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 472489 : if (!skipDepart) {
371 471816 : bool ok = true;
372 471816 : const std::string helper = attrs.get<std::string>(SUMO_ATTR_DEPART, vehicleParameter->id.c_str(), ok);
373 471816 : if (!ok) {
374 40 : return handleVehicleError(hardFail, vehicleParameter);
375 : }
376 : // now parse depart
377 : std::string departErrorMsg;
378 943600 : 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 472465 : vehicleParameter->tag = (SumoXMLTag)element;
384 : // all ok, then return vehicleParameter
385 472465 : return vehicleParameter;
386 : } else {
387 346 : return handleVehicleError(hardFail, nullptr, toString((SumoXMLTag)element) + " cannot be created");
388 : }
389 : }
390 :
391 :
392 : std::string
393 557623 : SUMOVehicleParserHelper::parseID(const SUMOSAXAttributes& attrs, const SumoXMLTag element) {
394 557623 : bool ok = true;
395 : std::string id;
396 : // first check if attrs contain an ID
397 557623 : if (attrs.hasAttribute(SUMO_ATTR_ID)) {
398 557611 : id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
399 557611 : if (SUMOXMLDefinitions::isValidVehicleID(id)) {
400 557603 : 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 497601 : SUMOVehicleParserHelper::parseCommonAttributes(const SUMOSAXAttributes& attrs, SUMOVehicleParameter* ret, SumoXMLTag tag, const bool allowInternalRoutes) {
417 497601 : const std::string element = toString(tag);
418 : //ret->refid = attrs.getStringSecure(SUMO_ATTR_REFID, "");
419 : // parse route information
420 497601 : if (attrs.hasAttribute(SUMO_ATTR_ROUTE)) {
421 167014 : bool ok = true;
422 167014 : std::string routeID = attrs.get<std::string>(SUMO_ATTR_ROUTE, ret->id.c_str(), ok);
423 167014 : 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 167014 : ret->routeid = routeID;
427 167014 : if (ok) {
428 167004 : ret->parametersSet |= VEHPARS_ROUTE_SET; // !!! needed?
429 : } else {
430 20 : handleVehicleError(true, ret);
431 : }
432 : }
433 : // parse type information
434 497591 : if (attrs.hasAttribute(SUMO_ATTR_TYPE)) {
435 214109 : bool ok = true;
436 214109 : ret->vtypeid = attrs.get<std::string>(SUMO_ATTR_TYPE, ret->id.c_str(), ok);
437 214109 : if (ok) {
438 214109 : ret->parametersSet |= VEHPARS_VTYPE_SET; // !!! needed?
439 : } else {
440 0 : handleVehicleError(true, ret);
441 : }
442 : }
443 : // parse line information
444 497591 : if (attrs.hasAttribute(SUMO_ATTR_LINE)) {
445 2924 : bool ok = true;
446 2924 : ret->line = attrs.get<std::string>(SUMO_ATTR_LINE, ret->id.c_str(), ok);
447 2924 : if (ok) {
448 2918 : ret->parametersSet |= VEHPARS_LINE_SET; // !!! needed?
449 : } else {
450 6 : handleVehicleError(true, ret);
451 : }
452 : }
453 : // parse zone information
454 497585 : if (attrs.hasAttribute(SUMO_ATTR_FROM_TAZ)) {
455 26128 : bool ok = true;
456 26128 : ret->fromTaz = attrs.get<std::string>(SUMO_ATTR_FROM_TAZ, ret->id.c_str(), ok);
457 26128 : if (ok) {
458 26128 : ret->parametersSet |= VEHPARS_FROM_TAZ_SET;
459 : } else {
460 0 : handleVehicleError(true, ret);
461 : }
462 : }
463 497585 : if (attrs.hasAttribute(SUMO_ATTR_TO_TAZ)) {
464 26128 : bool ok = true;
465 26128 : ret->toTaz = attrs.get<std::string>(SUMO_ATTR_TO_TAZ, ret->id.c_str(), ok);
466 26128 : if (ok) {
467 26128 : ret->parametersSet |= VEHPARS_TO_TAZ_SET;
468 : } else {
469 0 : handleVehicleError(true, ret);
470 : }
471 : }
472 : // parse reroute information
473 497585 : if (attrs.hasAttribute(SUMO_ATTR_REROUTE)) {
474 3841 : bool ok = true;
475 3841 : if (attrs.get<bool>(SUMO_ATTR_REROUTE, ret->id.c_str(), ok)) {
476 3841 : if (ok) {
477 3841 : ret->parametersSet |= VEHPARS_FORCE_REROUTE;
478 : } else {
479 0 : handleVehicleError(true, ret);
480 : }
481 : }
482 : }
483 : // parse depart lane information
484 497585 : if (attrs.hasAttribute(SUMO_ATTR_DEPARTLANE)) {
485 110254 : bool ok = true;
486 110254 : 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 110254 : if (SUMOVehicleParameter::parseDepartLane(departLaneStr, element, ret->id, lane, dld, error)) {
491 110206 : ret->parametersSet |= VEHPARS_DEPARTLANE_SET;
492 110206 : ret->departLane = lane;
493 110206 : ret->departLaneProcedure = dld;
494 : } else {
495 96 : handleVehicleError(true, ret, error);
496 : }
497 : }
498 : // parse depart position information
499 497537 : if (attrs.hasAttribute(SUMO_ATTR_DEPARTPOS)) {
500 86973 : bool ok = true;
501 86973 : 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 86973 : if (SUMOVehicleParameter::parseDepartPos(departPosStr, element, ret->id, pos, dpd, error)) {
506 86925 : ret->parametersSet |= VEHPARS_DEPARTPOS_SET;
507 86925 : ret->departPos = pos;
508 86925 : ret->departPosProcedure = dpd;
509 : } else {
510 96 : handleVehicleError(true, ret, error);
511 : }
512 : }
513 : // parse lateral depart position information
514 497489 : if (attrs.hasAttribute(SUMO_ATTR_DEPARTPOS_LAT)) {
515 8717 : bool ok = true;
516 8717 : 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 8717 : if (SUMOVehicleParameter::parseDepartPosLat(departPosLatStr, element, ret->id, pos, dpd, error)) {
521 8717 : ret->parametersSet |= VEHPARS_DEPARTPOSLAT_SET;
522 8717 : ret->departPosLat = pos;
523 8717 : ret->departPosLatProcedure = dpd;
524 : } else {
525 0 : handleVehicleError(true, ret, error);
526 : }
527 : }
528 : // parse depart speed information
529 497489 : if (attrs.hasAttribute(SUMO_ATTR_DEPARTSPEED)) {
530 240885 : bool ok = true;
531 240885 : 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 240885 : if (SUMOVehicleParameter::parseDepartSpeed(departSpeed, element, ret->id, speed, dsd, error)) {
536 240837 : ret->parametersSet |= VEHPARS_DEPARTSPEED_SET;
537 240837 : ret->departSpeed = speed;
538 240837 : ret->departSpeedProcedure = dsd;
539 : } else {
540 96 : handleVehicleError(true, ret, error);
541 : }
542 : }
543 : // parse depart edge information
544 497441 : if (attrs.hasAttribute(SUMO_ATTR_DEPARTEDGE)) {
545 151 : bool ok = true;
546 151 : 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 151 : if (SUMOVehicleParameter::parseRouteIndex(departEdgeStr, element, ret->id, SUMO_ATTR_DEPARTEDGE, edgeIndex, rid, error)) {
551 144 : ret->parametersSet |= VEHPARS_DEPARTEDGE_SET;
552 144 : ret->departEdge = edgeIndex;
553 144 : ret->departEdgeProcedure = rid;
554 : } else {
555 14 : handleVehicleError(true, ret, error);
556 : }
557 : }
558 : // parse arrival lane information
559 497434 : if (attrs.hasAttribute(SUMO_ATTR_ARRIVALLANE)) {
560 3162 : bool ok = true;
561 3162 : 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 3162 : if (SUMOVehicleParameter::parseArrivalLane(arrivalLaneStr, element, ret->id, lane, ald, error)) {
566 3114 : ret->parametersSet |= VEHPARS_ARRIVALLANE_SET;
567 3114 : ret->arrivalLane = lane;
568 3114 : ret->arrivalLaneProcedure = ald;
569 : } else {
570 96 : handleVehicleError(true, ret, error);
571 : }
572 : }
573 : // parse arrival position information
574 497386 : if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS)) {
575 8062 : bool ok = true;
576 8062 : 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 8062 : if (SUMOVehicleParameter::parseArrivalPos(arrivalPosStr, element, ret->id, pos, apd, error)) {
581 8014 : ret->parametersSet |= VEHPARS_ARRIVALPOS_SET;
582 8014 : ret->arrivalPos = pos;
583 8014 : ret->arrivalPosProcedure = apd;
584 : } else {
585 96 : handleVehicleError(true, ret, error);
586 : }
587 : }
588 : // parse lateral arrival position information
589 497338 : if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS_LAT)) {
590 1065 : bool ok = true;
591 1065 : 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 1065 : if (SUMOVehicleParameter::parseArrivalPosLat(arrivalPosLatStr, element, ret->id, pos, apd, error)) {
596 1065 : ret->parametersSet |= VEHPARS_ARRIVALPOSLAT_SET;
597 1065 : ret->arrivalPosLat = pos;
598 1065 : ret->arrivalPosLatProcedure = apd;
599 : } else {
600 0 : handleVehicleError(true, ret, error);
601 : }
602 : }
603 : // parse arrival speed information
604 497338 : if (attrs.hasAttribute(SUMO_ATTR_ARRIVALSPEED)) {
605 3792 : bool ok = true;
606 3792 : 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 3792 : if (SUMOVehicleParameter::parseArrivalSpeed(arrivalSpeedStr, element, ret->id, speed, asd, error)) {
611 3744 : ret->parametersSet |= VEHPARS_ARRIVALSPEED_SET;
612 3744 : ret->arrivalSpeed = speed;
613 3744 : ret->arrivalSpeedProcedure = asd;
614 : } else {
615 96 : handleVehicleError(true, ret, error);
616 : }
617 : }
618 : // parse arrival edge information
619 497290 : if (attrs.hasAttribute(SUMO_ATTR_ARRIVALEDGE)) {
620 81 : bool ok = true;
621 81 : 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 81 : if (SUMOVehicleParameter::parseRouteIndex(arrivalEdgeStr, element, ret->id, SUMO_ATTR_ARRIVALEDGE, edgeIndex, rid, error)) {
626 74 : ret->parametersSet |= VEHPARS_ARRIVALEDGE_SET;
627 74 : ret->arrivalEdge = edgeIndex;
628 74 : ret->arrivalEdgeProcedure = rid;
629 : } else {
630 14 : handleVehicleError(true, ret, error);
631 : }
632 : }
633 : // parse color
634 497283 : if (attrs.hasAttribute(SUMO_ATTR_COLOR)) {
635 8677 : bool ok = true;
636 8677 : ret->color = attrs.get<RGBColor>(SUMO_ATTR_COLOR, ret->id.c_str(), ok);
637 8677 : if (ok) {
638 8677 : ret->parametersSet |= VEHPARS_COLOR_SET;
639 : } else {
640 0 : handleVehicleError(true, ret, "Invalid RGBColor format");
641 : }
642 : } else {
643 488606 : ret->color = RGBColor::DEFAULT_COLOR;
644 : }
645 : // parse person number
646 497283 : if (attrs.hasAttribute(SUMO_ATTR_PERSON_NUMBER)) {
647 986 : bool ok = true;
648 986 : int personNumber = attrs.get<int>(SUMO_ATTR_PERSON_NUMBER, ret->id.c_str(), ok);
649 986 : if (!ok) {
650 0 : handleVehicleError(true, ret);
651 986 : } else if (personNumber >= 0) {
652 986 : ret->parametersSet |= VEHPARS_PERSON_NUMBER_SET;
653 986 : 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 497283 : if (attrs.hasAttribute(SUMO_ATTR_CONTAINER_NUMBER)) {
660 980 : bool ok = true;
661 980 : int containerNumber = attrs.get<int>(SUMO_ATTR_CONTAINER_NUMBER, ret->id.c_str(), ok);
662 980 : if (!ok) {
663 0 : handleVehicleError(true, ret);
664 980 : } else if (containerNumber >= 0) {
665 980 : ret->parametersSet |= VEHPARS_CONTAINER_NUMBER_SET;
666 980 : 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 497283 : if (attrs.hasAttribute(SUMO_ATTR_SPEEDFACTOR)) {
673 10661 : bool ok = true;
674 10661 : double speedFactor = attrs.get<double>(SUMO_ATTR_SPEEDFACTOR, ret->id.c_str(), ok);
675 10661 : if (!ok) {
676 0 : handleVehicleError(true, ret);
677 10661 : } else if (speedFactor > 0) {
678 10661 : ret->parametersSet |= VEHPARS_SPEEDFACTOR_SET;
679 10661 : ret->speedFactor = speedFactor;
680 : } else {
681 0 : handleVehicleError(true, ret, toString(SUMO_ATTR_SPEEDFACTOR) + " must be positive");
682 : }
683 : }
684 : // parse insertion checks
685 497283 : if (attrs.hasAttribute(SUMO_ATTR_INSERTIONCHECKS)) {
686 1022 : ret->parametersSet |= VEHPARS_INSERTION_CHECKS_SET;
687 1022 : bool ok = true;
688 1022 : std::string checks = attrs.get<std::string>(SUMO_ATTR_INSERTIONCHECKS, ret->id.c_str(), ok);
689 1022 : if (!ok) {
690 4 : handleVehicleError(true, ret);
691 : } else {
692 : try {
693 1022 : 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 497279 : 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 497279 : ret->modes = 0;
712 497279 : 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 497279 : 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 497279 : if (tag == SUMO_TAG_FLOW && attrs.hasAttribute(SUMO_ATTR_SPEED)) {
735 216 : bool ok = true;
736 216 : double calibratorSpeed = attrs.get<double>(SUMO_ATTR_SPEED, ret->id.c_str(), ok);
737 216 : if (!ok) {
738 0 : handleVehicleError(true, ret);
739 216 : } else if (calibratorSpeed >= 0 || calibratorSpeed == -1) {
740 216 : ret->parametersSet |= VEHPARS_CALIBRATORSPEED_SET;
741 216 : 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 497279 : }
753 :
754 :
755 : SUMOVTypeParameter*
756 60658 : SUMOVehicleParserHelper::beginVTypeParsing(const SUMOSAXAttributes& attrs, const bool hardFail, const std::string& file) {
757 : // first obtain ID
758 60658 : std::string id = parseID(attrs, SUMO_TAG_VTYPE);
759 : // check if ID is valid
760 60658 : if (!id.empty()) {
761 : SUMOVehicleClass vClass = SVC_PASSENGER;
762 60654 : if (attrs.hasAttribute(SUMO_ATTR_VCLASS)) {
763 35626 : vClass = parseVehicleClass(attrs, id);
764 : }
765 : // create vType
766 60654 : SUMOVTypeParameter* vType = new SUMOVTypeParameter(id, vClass);
767 : // parse attributes
768 60654 : if (attrs.hasAttribute(SUMO_ATTR_VCLASS)) {
769 35626 : vType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
770 : }
771 60654 : if (attrs.hasAttribute(SUMO_ATTR_LENGTH)) {
772 37269 : bool ok = true;
773 37269 : const double length = attrs.get<double>(SUMO_ATTR_LENGTH, vType->id.c_str(), ok);
774 37269 : if (!ok) {
775 0 : return handleVehicleTypeError(hardFail, vType);
776 37269 : } else if (length <= 0) {
777 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_LENGTH) + " must be greater than 0");
778 : } else {
779 37269 : vType->length = length;
780 37269 : vType->parametersSet |= VTYPEPARS_LENGTH_SET;
781 : }
782 : }
783 60654 : if (attrs.hasAttribute(SUMO_ATTR_MINGAP)) {
784 35691 : bool ok = true;
785 35691 : const double minGap = attrs.get<double>(SUMO_ATTR_MINGAP, vType->id.c_str(), ok);
786 35691 : if (!ok) {
787 0 : return handleVehicleTypeError(hardFail, vType);
788 35691 : } else if (minGap < 0) {
789 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MINGAP) + " must be equal or greater than 0");
790 : } else {
791 35691 : vType->minGap = minGap;
792 35691 : vType->parametersSet |= VTYPEPARS_MINGAP_SET;
793 : }
794 : }
795 60654 : if (attrs.hasAttribute(SUMO_ATTR_MAXSPEED)) {
796 36808 : bool ok = true;
797 36808 : const double maxSpeed = attrs.get<double>(SUMO_ATTR_MAXSPEED, vType->id.c_str(), ok);
798 36808 : if (!ok) {
799 0 : return handleVehicleTypeError(hardFail, vType);
800 36808 : } else if (maxSpeed <= 0) {
801 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MAXSPEED) + " must be greater than 0");
802 : } else {
803 36808 : vType->maxSpeed = maxSpeed;
804 36808 : vType->parametersSet |= VTYPEPARS_MAXSPEED_SET;
805 : }
806 : }
807 60654 : if (attrs.hasAttribute(SUMO_ATTR_DESIRED_MAXSPEED)) {
808 48 : bool ok = true;
809 48 : const double desiredMaxSpeed = attrs.get<double>(SUMO_ATTR_DESIRED_MAXSPEED, vType->id.c_str(), ok);
810 48 : if (!ok) {
811 0 : return handleVehicleTypeError(hardFail, vType);
812 48 : } else if (desiredMaxSpeed <= 0) {
813 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_DESIRED_MAXSPEED) + " must be greater than 0");
814 : } else {
815 48 : vType->desiredMaxSpeed = desiredMaxSpeed;
816 48 : vType->parametersSet |= VTYPEPARS_DESIRED_MAXSPEED_SET;
817 : }
818 60606 : } else if (attrs.hasAttribute(SUMO_ATTR_MAXSPEED)) {
819 36795 : if (vClass == SVC_PEDESTRIAN) {
820 : // backward compatibility because pedestrian maxSpeed was subject to speedFactor up to 1.14.1
821 25876 : vType->desiredMaxSpeed = vType->maxSpeed;;
822 77624 : vType->maxSpeed = MAX2(vType->maxSpeed, SUMOVTypeParameter::VClassDefaultValues(vClass).maxSpeed);
823 10919 : } else if (vClass == SVC_BICYCLE) {
824 : // backward compatibility because default desired speed did not exist up to 1.14.1
825 192 : vType->desiredMaxSpeed = MAX2(vType->maxSpeed, vType->desiredMaxSpeed);
826 : }
827 : }
828 :
829 60654 : if (attrs.hasAttribute(SUMO_ATTR_SPEEDFACTOR)) {
830 2388 : bool ok = true;
831 2388 : vType->speedFactor.parse(attrs.get<std::string>(SUMO_ATTR_SPEEDFACTOR, vType->id.c_str(), ok), hardFail);
832 2388 : if (!ok) {
833 0 : return handleVehicleTypeError(hardFail, vType);
834 : } else {
835 2388 : vType->parametersSet |= VTYPEPARS_SPEEDFACTOR_SET;
836 : }
837 : }
838 60654 : if (attrs.hasAttribute(SUMO_ATTR_SPEEDDEV)) {
839 2353 : bool ok = true;
840 2353 : const double speedDev = attrs.get<double>(SUMO_ATTR_SPEEDDEV, vType->id.c_str(), ok);
841 2353 : if (!ok) {
842 0 : return handleVehicleTypeError(hardFail, vType);
843 2353 : } else if (speedDev < 0) {
844 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_SPEEDDEV) + " must be equal or greater than 0");
845 : } else {
846 2353 : vType->speedFactor.getParameter()[1] = speedDev;
847 2353 : vType->parametersSet |= VTYPEPARS_SPEEDFACTOR_SET;
848 : }
849 : }
850 : // validate speed distribution
851 60654 : const std::string& error = vType->speedFactor.isValid();
852 60654 : if (error != "") {
853 14 : return handleVehicleTypeError(hardFail, vType, "Invalid speed distribution when parsing vType '" + vType->id + "' (" + error + ")");
854 : }
855 60647 : if (attrs.hasAttribute(SUMO_ATTR_ACTIONSTEPLENGTH)) {
856 220 : bool ok = true;
857 220 : const double actionStepLengthSecs = attrs.get<double>(SUMO_ATTR_ACTIONSTEPLENGTH, vType->id.c_str(), ok);
858 220 : if (!ok) {
859 0 : return handleVehicleTypeError(hardFail, vType);
860 : } else {
861 : // processActionStepLength(...) function includes warnings
862 220 : vType->actionStepLength = processActionStepLength(actionStepLengthSecs);
863 220 : vType->parametersSet |= VTYPEPARS_ACTIONSTEPLENGTH_SET;
864 : }
865 : }
866 60647 : if (attrs.hasAttribute(SUMO_ATTR_EMISSIONCLASS)) {
867 1772 : bool ok = true;
868 1772 : const std::string parsedEmissionClass = attrs.getOpt<std::string>(SUMO_ATTR_EMISSIONCLASS, id.c_str(), ok, "");
869 : // check if emission class is correct
870 : try {
871 1772 : vType->emissionClass = PollutantsInterface::getClassByName(parsedEmissionClass);
872 1772 : vType->parametersSet |= VTYPEPARS_EMISSIONCLASS_SET;
873 0 : } catch (...) {
874 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_EMISSIONCLASS) + " with name '" + parsedEmissionClass + "' doesn't exist.");
875 0 : }
876 : }
877 60647 : if (attrs.hasAttribute(SUMO_ATTR_MASS)) {
878 261 : bool ok = true;
879 261 : const double mass = attrs.get<double>(SUMO_ATTR_MASS, vType->id.c_str(), ok);
880 261 : if (!ok) {
881 0 : return handleVehicleTypeError(hardFail, vType);
882 261 : } else if (mass < 0) {
883 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MASS) + " must be equal or greater than 0");
884 : } else {
885 261 : vType->mass = mass;
886 261 : vType->parametersSet |= VTYPEPARS_MASS_SET;
887 : }
888 : }
889 60647 : if (attrs.hasAttribute(SUMO_ATTR_IMPATIENCE)) {
890 231 : bool ok = true;
891 231 : const std::string impatienceStr = attrs.get<std::string>(SUMO_ATTR_IMPATIENCE, vType->id.c_str(), ok);
892 231 : if (!ok) {
893 0 : return handleVehicleTypeError(hardFail, vType);
894 231 : } else if (impatienceStr == "off") {
895 12 : vType->impatience = -std::numeric_limits<double>::max();
896 : } else {
897 219 : const double impatienceDouble = attrs.get<double>(SUMO_ATTR_IMPATIENCE, vType->id.c_str(), ok);
898 219 : if (!ok) {
899 0 : return handleVehicleTypeError(hardFail, vType);
900 : } else {
901 219 : vType->impatience = impatienceDouble;
902 219 : vType->parametersSet |= VTYPEPARS_IMPATIENCE_SET;
903 : }
904 : }
905 : }
906 60647 : if (attrs.hasAttribute(SUMO_ATTR_WIDTH)) {
907 26731 : bool ok = true;
908 26731 : const double width = attrs.get<double>(SUMO_ATTR_WIDTH, vType->id.c_str(), ok);
909 26731 : if (!ok) {
910 0 : return handleVehicleTypeError(hardFail, vType);
911 26731 : } else if (width <= 0) {
912 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_WIDTH) + " must be greater than 0");
913 : } else {
914 26731 : vType->width = width;
915 26731 : vType->parametersSet |= VTYPEPARS_WIDTH_SET;
916 26731 : if (vClass == SVC_PEDESTRIAN
917 52838 : && OptionsCont::getOptions().exists("pedestrian.striping.stripe-width")
918 78945 : && OptionsCont::getOptions().getString("pedestrian.model") == "striping"
919 82128 : && OptionsCont::getOptions().getFloat("pedestrian.striping.stripe-width") < vType->width) {
920 12 : WRITE_WARNINGF(TL("Pedestrian vType '%' width % is larger than pedestrian.striping.stripe-width and this may cause collisions with vehicles."), id, vType->width);
921 : }
922 : }
923 : }
924 60647 : if (attrs.hasAttribute(SUMO_ATTR_HEIGHT)) {
925 359 : bool ok = true;
926 359 : const double height = attrs.get<double>(SUMO_ATTR_HEIGHT, vType->id.c_str(), ok);
927 359 : if (!ok) {
928 0 : return handleVehicleTypeError(hardFail, vType);
929 359 : } else if (height < 0) {
930 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_HEIGHT) + " must be equal or greater than 0");
931 : } else {
932 359 : vType->height = height;
933 359 : vType->parametersSet |= VTYPEPARS_HEIGHT_SET;
934 : }
935 : }
936 60647 : if (attrs.hasAttribute(SUMO_ATTR_GUISHAPE)) {
937 27140 : vType->shape = parseGuiShape(attrs, vType->id);
938 27140 : if (vType->shape != SUMOVehicleShape::UNKNOWN) {
939 27140 : vType->parametersSet |= VTYPEPARS_SHAPE_SET;
940 : }
941 : }
942 60647 : if (attrs.hasAttribute(SUMO_ATTR_OSGFILE)) {
943 21 : bool ok = true;
944 21 : const std::string osgFile = attrs.get<std::string>(SUMO_ATTR_OSGFILE, vType->id.c_str(), ok);
945 21 : if (!ok) {
946 0 : return handleVehicleTypeError(hardFail, vType);
947 : } else {
948 21 : vType->osgFile = osgFile;
949 21 : vType->parametersSet |= VTYPEPARS_OSGFILE_SET;
950 : }
951 : }
952 60647 : if (attrs.hasAttribute(SUMO_ATTR_IMGFILE)) {
953 25 : bool ok = true;
954 25 : std::string imgFile = attrs.get<std::string>(SUMO_ATTR_IMGFILE, vType->id.c_str(), ok);
955 25 : if (!ok) {
956 0 : return handleVehicleTypeError(hardFail, vType);
957 : } else {
958 : // check relative path
959 25 : if ((imgFile != "") && !FileHelpers::isAbsolute(imgFile)) {
960 46 : imgFile = FileHelpers::getConfigurationRelative(file, imgFile);
961 : }
962 25 : vType->imgFile = imgFile;
963 25 : vType->parametersSet |= VTYPEPARS_IMGFILE_SET;
964 : }
965 : }
966 60647 : if (attrs.hasAttribute(SUMO_ATTR_COLOR)) {
967 22734 : bool ok = true;
968 22734 : const RGBColor color = attrs.get<RGBColor>(SUMO_ATTR_COLOR, vType->id.c_str(), ok);
969 22734 : if (!ok) {
970 8 : return handleVehicleTypeError(hardFail, vType);
971 : } else {
972 22726 : vType->color = color;
973 22726 : vType->parametersSet |= VTYPEPARS_COLOR_SET;
974 : }
975 : } else {
976 37913 : vType->color = RGBColor::YELLOW;
977 : }
978 60639 : if (attrs.hasAttribute(SUMO_ATTR_PROB)) {
979 611 : bool ok = true;
980 611 : const double defaultProbability = attrs.get<double>(SUMO_ATTR_PROB, vType->id.c_str(), ok);
981 611 : if (!ok) {
982 0 : return handleVehicleTypeError(hardFail, vType);
983 611 : } else if (defaultProbability < 0) {
984 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_PROB) + " must be equal or greater than 0");
985 : } else {
986 611 : vType->defaultProbability = defaultProbability;
987 611 : vType->parametersSet |= VTYPEPARS_PROBABILITY_SET;
988 : }
989 : }
990 60639 : if (attrs.hasAttribute(SUMO_ATTR_LANE_CHANGE_MODEL)) {
991 477 : bool ok = true;
992 477 : std::string lcmS = attrs.get<std::string>(SUMO_ATTR_LANE_CHANGE_MODEL, vType->id.c_str(), ok);
993 477 : if (!ok) {
994 0 : return handleVehicleTypeError(hardFail, vType);
995 477 : } else if (lcmS == "JE2013") {
996 0 : WRITE_WARNING(TL("Lane change model 'JE2013' is deprecated. Using default model instead."));
997 : lcmS = "default";
998 : }
999 : if (SUMOXMLDefinitions::LaneChangeModels.hasString(lcmS)) {
1000 472 : vType->lcModel = SUMOXMLDefinitions::LaneChangeModels.get(lcmS);
1001 472 : vType->parametersSet |= VTYPEPARS_LANE_CHANGE_MODEL_SET;
1002 : } else {
1003 15 : return handleVehicleTypeError(hardFail, vType, "Unknown lane change model '" + lcmS + "' when parsing vType '" + vType->id + "'");
1004 : }
1005 : }
1006 60634 : if (attrs.hasAttribute(SUMO_ATTR_CAR_FOLLOW_MODEL)) {
1007 1240 : bool ok = true;
1008 1240 : const std::string cfmValue = attrs.get<std::string>(SUMO_ATTR_CAR_FOLLOW_MODEL, vType->id.c_str(), ok);
1009 1240 : if (!ok) {
1010 0 : return handleVehicleTypeError(hardFail, vType);
1011 : } else if (SUMOXMLDefinitions::CarFollowModels.hasString(cfmValue)) {
1012 1234 : vType->cfModel = SUMOXMLDefinitions::CarFollowModels.get(cfmValue);
1013 1234 : vType->parametersSet |= VTYPEPARS_CAR_FOLLOW_MODEL;
1014 : } else {
1015 18 : return handleVehicleTypeError(hardFail, vType, "Unknown car following model '" + cfmValue + "' when parsing vType '" + vType->id + "'");
1016 : }
1017 : }
1018 60628 : if (attrs.hasAttribute(SUMO_ATTR_PERSON_CAPACITY)) {
1019 347 : bool ok = true;
1020 347 : const int personCapacity = attrs.get<int>(SUMO_ATTR_PERSON_CAPACITY, vType->id.c_str(), ok);
1021 347 : if (!ok) {
1022 0 : return handleVehicleTypeError(hardFail, vType);
1023 347 : } else if (personCapacity < 0) {
1024 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_PERSON_CAPACITY) + " must be equal or greater than 0");
1025 : } else {
1026 347 : vType->personCapacity = personCapacity;
1027 347 : vType->parametersSet |= VTYPEPARS_PERSON_CAPACITY;
1028 : }
1029 : }
1030 60628 : if (attrs.hasAttribute(SUMO_ATTR_CONTAINER_CAPACITY)) {
1031 346 : bool ok = true;
1032 346 : const int containerCapacity = attrs.get<int>(SUMO_ATTR_CONTAINER_CAPACITY, vType->id.c_str(), ok);
1033 346 : if (!ok) {
1034 0 : return handleVehicleTypeError(hardFail, vType);
1035 346 : } else if (containerCapacity < 0) {
1036 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_CONTAINER_CAPACITY) + " must be equal or greater than 0");
1037 : } else {
1038 346 : vType->containerCapacity = containerCapacity;
1039 346 : vType->parametersSet |= VTYPEPARS_CONTAINER_CAPACITY;
1040 : }
1041 : }
1042 60628 : if (attrs.hasAttribute(SUMO_ATTR_BOARDING_DURATION)) {
1043 101 : bool ok = true;
1044 101 : const SUMOTime boardingDuration = attrs.getSUMOTimeReporting(SUMO_ATTR_BOARDING_DURATION, vType->id.c_str(), ok);
1045 101 : if (!ok) {
1046 0 : return handleVehicleTypeError(hardFail, vType);
1047 101 : } else if (boardingDuration < 0) {
1048 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_BOARDING_DURATION) + " must be equal or greater than 0");
1049 : } else {
1050 101 : vType->boardingDuration = boardingDuration;
1051 101 : vType->parametersSet |= VTYPEPARS_BOARDING_DURATION;
1052 : }
1053 : }
1054 60628 : if (attrs.hasAttribute(SUMO_ATTR_LOADING_DURATION)) {
1055 49 : bool ok = true;
1056 49 : const SUMOTime loadingDuration = attrs.getSUMOTimeReporting(SUMO_ATTR_LOADING_DURATION, vType->id.c_str(), ok);
1057 49 : if (!ok) {
1058 0 : return handleVehicleTypeError(hardFail, vType);
1059 49 : } else if (loadingDuration < 0) {
1060 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_LOADING_DURATION) + " must be equal or greater than 0");
1061 : } else {
1062 49 : vType->loadingDuration = loadingDuration;
1063 49 : vType->parametersSet |= VTYPEPARS_LOADING_DURATION;
1064 : }
1065 : }
1066 60628 : if (attrs.hasAttribute(SUMO_ATTR_SCALE)) {
1067 32 : bool ok = true;
1068 32 : const double scale = attrs.get<double>(SUMO_ATTR_SCALE, id.c_str(), ok);
1069 32 : if (!ok) {
1070 0 : return handleVehicleTypeError(hardFail, vType);
1071 32 : } else if (scale < 0) {
1072 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_SCALE) + " may be not be negative");
1073 : } else {
1074 32 : vType->scale = scale;
1075 32 : vType->parametersSet |= VTYPEPARS_SCALE_SET;
1076 : }
1077 : }
1078 60628 : if (attrs.hasAttribute(SUMO_ATTR_TIME_TO_TELEPORT)) {
1079 13 : bool ok = true;
1080 13 : const SUMOTime ttt = attrs.getSUMOTimeReporting(SUMO_ATTR_TIME_TO_TELEPORT, vType->id.c_str(), ok);
1081 13 : if (!ok) {
1082 0 : return handleVehicleTypeError(hardFail, vType);
1083 : } else {
1084 13 : vType->timeToTeleport = ttt;
1085 13 : vType->parametersSet |= VTYPEPARS_TTT_SET;
1086 : }
1087 : }
1088 60628 : if (attrs.hasAttribute(SUMO_ATTR_TIME_TO_TELEPORT_BIDI)) {
1089 5 : bool ok = true;
1090 5 : const SUMOTime tttb = attrs.getSUMOTimeReporting(SUMO_ATTR_TIME_TO_TELEPORT_BIDI, vType->id.c_str(), ok);
1091 5 : if (!ok) {
1092 0 : return handleVehicleTypeError(hardFail, vType);
1093 : } else {
1094 5 : vType->timeToTeleportBidi = tttb;
1095 5 : vType->parametersSet |= VTYPEPARS_TTT_BIDI_SET;
1096 : }
1097 : }
1098 60628 : if (attrs.hasAttribute(SUMO_ATTR_SPEEDFACTOR_PREMATURE)) {
1099 63 : bool ok = true;
1100 63 : const double sfp = attrs.get<double>(SUMO_ATTR_SPEEDFACTOR_PREMATURE, id.c_str(), ok);
1101 63 : if (!ok) {
1102 0 : return handleVehicleTypeError(hardFail, vType);
1103 : } else {
1104 63 : vType->speedFactorPremature = sfp;
1105 63 : vType->parametersSet |= VTYPEPARS_SPEEDFACTOR_PREMATURE_SET;
1106 : }
1107 : }
1108 60628 : if (attrs.hasAttribute(SUMO_ATTR_BOARDING_FACTOR)) {
1109 8 : bool ok = true;
1110 8 : const double bf = attrs.get<double>(SUMO_ATTR_BOARDING_FACTOR, id.c_str(), ok);
1111 8 : if (!ok) {
1112 0 : return handleVehicleTypeError(hardFail, vType);
1113 8 : } else if (bf < 0) {
1114 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_BOARDING_FACTOR) + " must be equal or greater than 0");
1115 : } else {
1116 8 : vType->boardingFactor = bf;
1117 8 : vType->parametersSet |= VTYPEPARS_BOARDING_FACTOR_SET;
1118 : }
1119 : }
1120 60628 : if (attrs.hasAttribute(SUMO_ATTR_MAXSPEED_LAT)) {
1121 73 : bool ok = true;
1122 73 : const double maxSpeedLat = attrs.get<double>(SUMO_ATTR_MAXSPEED_LAT, vType->id.c_str(), ok);
1123 73 : if (!ok) {
1124 0 : return handleVehicleTypeError(hardFail, vType);
1125 73 : } else if (maxSpeedLat <= 0) {
1126 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MAXSPEED_LAT) + " must be greater than 0");
1127 : } else {
1128 73 : vType->maxSpeedLat = maxSpeedLat;
1129 73 : vType->parametersSet |= VTYPEPARS_MAXSPEED_LAT_SET;
1130 : }
1131 : }
1132 60628 : if (attrs.hasAttribute(SUMO_ATTR_MINGAP_LAT)) {
1133 575 : bool ok = true;
1134 575 : const double minGapLat = attrs.get<double>(SUMO_ATTR_MINGAP_LAT, vType->id.c_str(), ok);
1135 575 : if (!ok) {
1136 0 : return handleVehicleTypeError(hardFail, vType);
1137 575 : } else if (minGapLat < 0) {
1138 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MINGAP_LAT) + " must be equal or greater than 0");
1139 : } else {
1140 575 : vType->minGapLat = minGapLat;
1141 575 : vType->parametersSet |= VTYPEPARS_MINGAP_LAT_SET;
1142 : }
1143 : }
1144 60628 : if (attrs.hasAttribute(SUMO_ATTR_LATALIGNMENT)) {
1145 1704 : bool ok = true;
1146 1704 : const std::string alignS = attrs.get<std::string>(SUMO_ATTR_LATALIGNMENT, vType->id.c_str(), ok);
1147 1704 : if (!ok) {
1148 0 : return handleVehicleTypeError(hardFail, vType);
1149 : } else {
1150 : double lao;
1151 : LatAlignmentDefinition lad;
1152 1704 : if (SUMOVTypeParameter::parseLatAlignment(alignS, lao, lad)) {
1153 1704 : vType->latAlignmentOffset = lao;
1154 1704 : vType->latAlignmentProcedure = lad;
1155 1704 : vType->parametersSet |= VTYPEPARS_LATALIGNMENT_SET;
1156 : } else {
1157 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)");
1158 : }
1159 : }
1160 : }
1161 60628 : if (attrs.hasAttribute(SUMO_ATTR_MANEUVER_ANGLE_TIMES)) {
1162 5 : bool ok = true;
1163 5 : const std::string angleTimesS = attrs.get<std::string>(SUMO_ATTR_MANEUVER_ANGLE_TIMES, vType->id.c_str(), ok);
1164 5 : if (!ok) {
1165 0 : return handleVehicleTypeError(hardFail, vType);
1166 10 : } else if (parseAngleTimesMap(vType, angleTimesS)) {
1167 5 : vType->parametersSet |= VTYPEPARS_MANEUVER_ANGLE_TIMES_SET;
1168 : } else {
1169 0 : return handleVehicleTypeError(hardFail, vType, "Invalid manoeuver angle times map for vType '" + vType->id + "'");
1170 : }
1171 : }
1172 60628 : if (attrs.hasAttribute(SUMO_ATTR_PARKING_BADGES)) {
1173 7 : bool ok = true;
1174 7 : std::vector<std::string> badges = attrs.get<std::vector<std::string>>(SUMO_ATTR_PARKING_BADGES, vType->id.c_str(), ok);
1175 7 : if (!ok) {
1176 0 : return handleVehicleTypeError(hardFail, vType);
1177 : } else {
1178 7 : vType->parametersSet |= VTYPEPARS_PARKING_BADGES_SET;
1179 7 : vType->parkingBadges = badges;
1180 : }
1181 7 : }
1182 : // try to parse Car Following Model params
1183 60628 : if (!parseCFMParams(vType, vType->cfModel, attrs, false)) {
1184 0 : return handleVehicleTypeError(hardFail, vType, "Invalid parsing embedded VType");
1185 : }
1186 : // try to parse Lane Change Model params
1187 60628 : if (!parseLCParams(vType, vType->lcModel, attrs)) {
1188 0 : return handleVehicleTypeError(hardFail, vType, "Invalid Lane Change Model Parameters");
1189 : }
1190 : // try to Junction Model params
1191 60628 : if (!parseJMParams(vType, attrs)) {
1192 26 : return handleVehicleTypeError(hardFail, vType, "Invalid Junction Model Parameters");
1193 : }
1194 : // all ok, then return vType
1195 : return vType;
1196 : } else {
1197 34 : return handleVehicleTypeError(hardFail, nullptr, "VType cannot be created");
1198 : }
1199 : }
1200 :
1201 :
1202 : bool
1203 5 : SUMOVehicleParserHelper::parseAngleTimesMap(SUMOVTypeParameter* vtype, const std::string atm) {
1204 15 : StringTokenizer st(atm, ",");
1205 : std::map<int, std::pair<SUMOTime, SUMOTime>> angleTimesMap;
1206 : int tripletCount = 0;
1207 30 : while (st.hasNext()) {
1208 25 : StringTokenizer pos(st.next());
1209 25 : if (pos.size() != 3) {
1210 0 : WRITE_ERRORF(TL("maneuverAngleTimes format for vType '%' % contains an invalid triplet."), vtype->id, atm);
1211 0 : return false;
1212 : } else {
1213 : try {
1214 25 : const int angle = StringUtils::toInt(pos.next());
1215 25 : const SUMOTime t1 = string2time(pos.next());
1216 25 : const SUMOTime t2 = string2time(pos.next());
1217 25 : angleTimesMap[angle] = std::make_pair(t1, t2);
1218 0 : } catch (...) {
1219 0 : WRITE_ERRORF(TL("Triplet '%' for vType '%' maneuverAngleTimes cannot be parsed as 'int double double'"), st.get(tripletCount), vtype->id);
1220 : return false;
1221 0 : }
1222 25 : tripletCount++;
1223 : }
1224 25 : }
1225 5 : if (angleTimesMap.size() > 0) {
1226 : vtype->myManoeuverAngleTimes.clear();
1227 30 : for (const auto& angleTime : angleTimesMap) {
1228 : vtype->myManoeuverAngleTimes.insert(angleTime);
1229 : }
1230 : angleTimesMap.clear();
1231 5 : return true;
1232 : } else {
1233 : return false;
1234 : }
1235 5 : }
1236 :
1237 :
1238 : bool
1239 60644 : SUMOVehicleParserHelper::parseCFMParams(SUMOVTypeParameter* into, const SumoXMLTag element, const SUMOSAXAttributes& attrs, const bool nestedCFM) {
1240 60644 : const CFAttrMap& allowedCFM = getAllowedCFModelAttrs();
1241 : CFAttrMap::const_iterator cf_it = allowedCFM.find(element);
1242 : // check if given CFM is allowed
1243 60644 : if (cf_it == allowedCFM.end()) {
1244 0 : if (SUMOXMLDefinitions::Tags.has((int)element)) {
1245 0 : WRITE_ERRORF(TL("Unknown car-following model % when parsing vType '%'"), toString(element), into->id);
1246 : } else {
1247 0 : WRITE_ERRORF(TL("Unknown car-following model when parsing vType '%'"), into->id);
1248 : }
1249 0 : return false;
1250 : }
1251 : // check if we're parsing a nested CFM
1252 60644 : if (nestedCFM) {
1253 16 : into->cfModel = cf_it->first;
1254 16 : into->parametersSet |= VTYPEPARS_CAR_FOLLOW_MODEL;
1255 : }
1256 : // set CFM values
1257 615132 : for (const auto& it : cf_it->second) {
1258 554488 : if (attrs.hasAttribute(it)) {
1259 : // first obtain CFM attribute in string format
1260 44650 : bool ok = true;
1261 44650 : std::string parsedCFMAttribute = attrs.get<std::string>(it, into->id.c_str(), ok);
1262 : // check CFM Attribute
1263 44650 : if (!ok) {
1264 : return false;
1265 44650 : } else if (it == SUMO_ATTR_TRAIN_TYPE) {
1266 : // check if train value is valid
1267 223 : if (!SUMOXMLDefinitions::TrainTypes.hasString(parsedCFMAttribute)) {
1268 0 : WRITE_ERROR("Invalid train type '" + parsedCFMAttribute + "' used in Car-Following-Attribute " + toString(it));
1269 0 : return false;
1270 : }
1271 : // add parsedCFMAttribute to cfParameter
1272 223 : into->cfParameter[it] = parsedCFMAttribute;
1273 44427 : } else if (it == SUMO_ATTR_SPEED_TABLE || it == SUMO_ATTR_TRACTION_TABLE || it == SUMO_ATTR_RESISTANCE_TABLE) {
1274 24 : into->cfParameter[it] = parsedCFMAttribute;
1275 44403 : } else if (it == SUMO_ATTR_CF_IDM_STEPPING) {
1276 : // declare a int in wich save CFM int attribute
1277 : double CFMDoubleAttribute = -1;
1278 : try {
1279 : // obtain CFM attribute in int format
1280 6 : CFMDoubleAttribute = StringUtils::toDouble(parsedCFMAttribute);
1281 0 : } catch (...) {
1282 0 : WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Cannot be parsed to float"), toString(it));
1283 : return false;
1284 0 : }
1285 6 : if (CFMDoubleAttribute <= 0) {
1286 0 : WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Must be greater than 0"), toString(it));
1287 0 : return false;
1288 : }
1289 : // add parsedCFMAttribute to cfParameter
1290 6 : into->cfParameter[it] = parsedCFMAttribute;
1291 : } else {
1292 : // declare a double in wich save CFM float attribute
1293 : double CFMDoubleAttribute = -1;
1294 : try {
1295 : // obtain CFM attribute in double format
1296 44397 : CFMDoubleAttribute = StringUtils::toDouble(parsedCFMAttribute);
1297 0 : } catch (...) {
1298 0 : WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Cannot be parsed to float"), toString(it));
1299 : return false;
1300 0 : }
1301 : // check attributes of type "positiveFloatType" (> 0)
1302 44397 : switch (it) {
1303 20758 : case SUMO_ATTR_ACCEL:
1304 : case SUMO_ATTR_DECEL:
1305 : case SUMO_ATTR_APPARENTDECEL:
1306 : case SUMO_ATTR_EMERGENCYDECEL:
1307 : case SUMO_ATTR_TAU:
1308 20758 : if (CFMDoubleAttribute <= 0) {
1309 0 : WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Must be greater than 0"), toString(it));
1310 0 : return false;
1311 : }
1312 : break;
1313 : default:
1314 : break;
1315 : }
1316 : // check attributes restricted to [0-1]
1317 44397 : switch (it) {
1318 23035 : case SUMO_ATTR_SIGMA:
1319 23035 : if ((CFMDoubleAttribute < 0) || (CFMDoubleAttribute > 1)) {
1320 0 : WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Only values between [0-1] are allowed"), toString(it));
1321 0 : return false;
1322 : }
1323 : break;
1324 : default:
1325 : break;
1326 : }
1327 : // add parsedCFMAttribute to cfParameter
1328 44397 : into->cfParameter[it] = parsedCFMAttribute;
1329 : }
1330 : }
1331 : }
1332 : // all CFM successfully parsed, then return true
1333 : return true;
1334 : }
1335 :
1336 :
1337 : const SUMOVehicleParserHelper::CFAttrMap&
1338 60644 : SUMOVehicleParserHelper::getAllowedCFModelAttrs() {
1339 : // init on first use
1340 60644 : if (allowedCFModelAttrs.size() == 0) {
1341 : std::set<SumoXMLAttr> genericParams;
1342 24650 : genericParams.insert(SUMO_ATTR_TAU);
1343 24650 : genericParams.insert(SUMO_ATTR_ACCEL);
1344 24650 : genericParams.insert(SUMO_ATTR_DECEL);
1345 24650 : genericParams.insert(SUMO_ATTR_APPARENTDECEL);
1346 24650 : genericParams.insert(SUMO_ATTR_EMERGENCYDECEL);
1347 24650 : genericParams.insert(SUMO_ATTR_COLLISION_MINGAP_FACTOR);
1348 24650 : genericParams.insert(SUMO_ATTR_STARTUP_DELAY);
1349 : // Krauss
1350 : std::set<SumoXMLAttr> kraussParams(genericParams);
1351 24650 : kraussParams.insert(SUMO_ATTR_SIGMA);
1352 24650 : kraussParams.insert(SUMO_ATTR_SIGMA_STEP);
1353 24650 : allowedCFModelAttrs[SUMO_TAG_CF_KRAUSS] = kraussParams;
1354 24650 : allowedCFModelAttrs[SUMO_TAG_CF_KRAUSS_ORIG1] = kraussParams;
1355 49300 : allowedCFModelAttrs[SUMO_TAG_CF_KRAUSS_PLUS_SLOPE] = kraussParams;
1356 : std::set<SumoXMLAttr> allParams(kraussParams);
1357 : // KraussX
1358 : std::set<SumoXMLAttr> kraussXParams(kraussParams);
1359 24650 : kraussXParams.insert(SUMO_ATTR_TMP1);
1360 24650 : kraussXParams.insert(SUMO_ATTR_TMP2);
1361 24650 : kraussXParams.insert(SUMO_ATTR_TMP3);
1362 24650 : kraussXParams.insert(SUMO_ATTR_TMP4);
1363 24650 : kraussXParams.insert(SUMO_ATTR_TMP5);
1364 49300 : allowedCFModelAttrs[SUMO_TAG_CF_KRAUSSX] = kraussXParams;
1365 24650 : allParams.insert(kraussXParams.begin(), kraussXParams.end());
1366 : // SmartSK
1367 : std::set<SumoXMLAttr> smartSKParams(genericParams);
1368 24650 : smartSKParams.insert(SUMO_ATTR_SIGMA);
1369 24650 : smartSKParams.insert(SUMO_ATTR_TMP1);
1370 24650 : smartSKParams.insert(SUMO_ATTR_TMP2);
1371 24650 : smartSKParams.insert(SUMO_ATTR_TMP3);
1372 24650 : smartSKParams.insert(SUMO_ATTR_TMP4);
1373 24650 : smartSKParams.insert(SUMO_ATTR_TMP5);
1374 49300 : allowedCFModelAttrs[SUMO_TAG_CF_SMART_SK] = smartSKParams;
1375 24650 : allParams.insert(smartSKParams.begin(), smartSKParams.end());
1376 : // Daniel
1377 : std::set<SumoXMLAttr> daniel1Params(genericParams);
1378 24650 : daniel1Params.insert(SUMO_ATTR_SIGMA);
1379 24650 : daniel1Params.insert(SUMO_ATTR_TMP1);
1380 24650 : daniel1Params.insert(SUMO_ATTR_TMP2);
1381 24650 : daniel1Params.insert(SUMO_ATTR_TMP3);
1382 24650 : daniel1Params.insert(SUMO_ATTR_TMP4);
1383 24650 : daniel1Params.insert(SUMO_ATTR_TMP5);
1384 49300 : allowedCFModelAttrs[SUMO_TAG_CF_DANIEL1] = daniel1Params;
1385 24650 : allParams.insert(daniel1Params.begin(), daniel1Params.end());
1386 : // Peter Wagner
1387 : std::set<SumoXMLAttr> pwagParams(genericParams);
1388 24650 : pwagParams.insert(SUMO_ATTR_SIGMA);
1389 24650 : pwagParams.insert(SUMO_ATTR_CF_PWAGNER2009_TAULAST);
1390 24650 : pwagParams.insert(SUMO_ATTR_CF_PWAGNER2009_APPROB);
1391 49300 : allowedCFModelAttrs[SUMO_TAG_CF_PWAGNER2009] = pwagParams;
1392 24650 : allParams.insert(pwagParams.begin(), pwagParams.end());
1393 : // IDM params
1394 : std::set<SumoXMLAttr> idmParams(genericParams);
1395 24650 : idmParams.insert(SUMO_ATTR_CF_IDM_DELTA);
1396 24650 : idmParams.insert(SUMO_ATTR_CF_IDM_STEPPING);
1397 49300 : allowedCFModelAttrs[SUMO_TAG_CF_IDM] = idmParams;
1398 24650 : allParams.insert(idmParams.begin(), idmParams.end());
1399 : // EIDM
1400 : std::set<SumoXMLAttr> eidmParams(genericParams);
1401 24650 : eidmParams.insert(SUMO_ATTR_CF_IDM_DELTA);
1402 24650 : eidmParams.insert(SUMO_ATTR_CF_IDM_STEPPING);
1403 24650 : eidmParams.insert(SUMO_ATTR_CF_EIDM_T_LOOK_AHEAD);
1404 24650 : eidmParams.insert(SUMO_ATTR_CF_EIDM_T_PERSISTENCE_DRIVE);
1405 24650 : eidmParams.insert(SUMO_ATTR_CF_EIDM_T_REACTION);
1406 24650 : eidmParams.insert(SUMO_ATTR_CF_EIDM_T_PERSISTENCE_ESTIMATE);
1407 24650 : eidmParams.insert(SUMO_ATTR_CF_EIDM_C_COOLNESS);
1408 24650 : eidmParams.insert(SUMO_ATTR_CF_EIDM_SIG_LEADER);
1409 24650 : eidmParams.insert(SUMO_ATTR_CF_EIDM_SIG_GAP);
1410 24650 : eidmParams.insert(SUMO_ATTR_CF_EIDM_SIG_ERROR);
1411 24650 : eidmParams.insert(SUMO_ATTR_CF_EIDM_JERK_MAX);
1412 24650 : eidmParams.insert(SUMO_ATTR_CF_EIDM_EPSILON_ACC);
1413 24650 : eidmParams.insert(SUMO_ATTR_CF_EIDM_T_ACC_MAX);
1414 24650 : eidmParams.insert(SUMO_ATTR_CF_EIDM_M_FLATNESS);
1415 24650 : eidmParams.insert(SUMO_ATTR_CF_EIDM_M_BEGIN);
1416 24650 : eidmParams.insert(SUMO_ATTR_CF_EIDM_USEVEHDYNAMICS);
1417 24650 : eidmParams.insert(SUMO_ATTR_CF_EIDM_MAX_VEH_PREVIEW);
1418 49300 : allowedCFModelAttrs[SUMO_TAG_CF_EIDM] = eidmParams;
1419 24650 : allParams.insert(eidmParams.begin(), eidmParams.end());
1420 : // IDMM
1421 : std::set<SumoXMLAttr> idmmParams(genericParams);
1422 24650 : idmmParams.insert(SUMO_ATTR_CF_IDMM_ADAPT_FACTOR);
1423 24650 : idmmParams.insert(SUMO_ATTR_CF_IDMM_ADAPT_TIME);
1424 24650 : idmmParams.insert(SUMO_ATTR_CF_IDM_STEPPING);
1425 49300 : allowedCFModelAttrs[SUMO_TAG_CF_IDMM] = idmmParams;
1426 24650 : allParams.insert(idmmParams.begin(), idmmParams.end());
1427 : // Bieker
1428 : std::set<SumoXMLAttr> bkernerParams(genericParams);
1429 24650 : bkernerParams.insert(SUMO_ATTR_K);
1430 24650 : bkernerParams.insert(SUMO_ATTR_CF_KERNER_PHI);
1431 49300 : allowedCFModelAttrs[SUMO_TAG_CF_BKERNER] = bkernerParams;
1432 24650 : allParams.insert(bkernerParams.begin(), bkernerParams.end());
1433 : // Wiedemann
1434 : std::set<SumoXMLAttr> wiedemannParams(genericParams);
1435 24650 : wiedemannParams.insert(SUMO_ATTR_CF_WIEDEMANN_SECURITY);
1436 24650 : wiedemannParams.insert(SUMO_ATTR_CF_WIEDEMANN_ESTIMATION);
1437 49300 : allowedCFModelAttrs[SUMO_TAG_CF_WIEDEMANN] = wiedemannParams;
1438 24650 : allParams.insert(wiedemannParams.begin(), wiedemannParams.end());
1439 : // W99
1440 : std::set<SumoXMLAttr> w99Params(genericParams);
1441 24650 : w99Params.insert(SUMO_ATTR_CF_W99_CC1);
1442 24650 : w99Params.insert(SUMO_ATTR_CF_W99_CC2);
1443 24650 : w99Params.insert(SUMO_ATTR_CF_W99_CC3);
1444 24650 : w99Params.insert(SUMO_ATTR_CF_W99_CC4);
1445 24650 : w99Params.insert(SUMO_ATTR_CF_W99_CC5);
1446 24650 : w99Params.insert(SUMO_ATTR_CF_W99_CC6);
1447 24650 : w99Params.insert(SUMO_ATTR_CF_W99_CC7);
1448 24650 : w99Params.insert(SUMO_ATTR_CF_W99_CC8);
1449 24650 : w99Params.insert(SUMO_ATTR_CF_W99_CC9);
1450 49300 : allowedCFModelAttrs[SUMO_TAG_CF_W99] = w99Params;
1451 24650 : allParams.insert(w99Params.begin(), w99Params.end());
1452 : // Rail
1453 : std::set<SumoXMLAttr> railParams(genericParams);
1454 24650 : railParams.insert(SUMO_ATTR_TRAIN_TYPE);
1455 24650 : railParams.insert(SUMO_ATTR_SPEED_TABLE);
1456 24650 : railParams.insert(SUMO_ATTR_TRACTION_TABLE);
1457 24650 : railParams.insert(SUMO_ATTR_RESISTANCE_TABLE);
1458 24650 : railParams.insert(SUMO_ATTR_MASSFACTOR);
1459 24650 : railParams.insert(SUMO_ATTR_MAXPOWER);
1460 24650 : railParams.insert(SUMO_ATTR_MAXTRACTION);
1461 24650 : railParams.insert(SUMO_ATTR_RESISTANCE_COEFFICIENT_CONSTANT);
1462 24650 : railParams.insert(SUMO_ATTR_RESISTANCE_COEFFICIENT_LINEAR);
1463 24650 : railParams.insert(SUMO_ATTR_RESISTANCE_COEFFICIENT_QUADRATIC);
1464 49300 : allowedCFModelAttrs[SUMO_TAG_CF_RAIL] = railParams;
1465 24650 : allParams.insert(railParams.begin(), railParams.end());
1466 : // ACC
1467 : std::set<SumoXMLAttr> ACCParams(genericParams);
1468 24650 : ACCParams.insert(SUMO_ATTR_SC_GAIN);
1469 24650 : ACCParams.insert(SUMO_ATTR_GCC_GAIN_SPEED);
1470 24650 : ACCParams.insert(SUMO_ATTR_GCC_GAIN_SPACE);
1471 24650 : ACCParams.insert(SUMO_ATTR_GC_GAIN_SPEED);
1472 24650 : ACCParams.insert(SUMO_ATTR_GC_GAIN_SPACE);
1473 24650 : ACCParams.insert(SUMO_ATTR_CA_GAIN_SPEED);
1474 24650 : ACCParams.insert(SUMO_ATTR_CA_GAIN_SPACE);
1475 24650 : ACCParams.insert(SUMO_ATTR_CA_OVERRIDE);
1476 24650 : ACCParams.insert(SUMO_ATTR_APPLYDRIVERSTATE);
1477 49300 : allowedCFModelAttrs[SUMO_TAG_CF_ACC] = ACCParams;
1478 24650 : allParams.insert(ACCParams.begin(), ACCParams.end());
1479 : // CACC
1480 : std::set<SumoXMLAttr> CACCParams(genericParams);
1481 24650 : CACCParams.insert(SUMO_ATTR_SC_GAIN_CACC);
1482 24650 : CACCParams.insert(SUMO_ATTR_GCC_GAIN_GAP_CACC);
1483 24650 : CACCParams.insert(SUMO_ATTR_GCC_GAIN_GAP_DOT_CACC);
1484 24650 : CACCParams.insert(SUMO_ATTR_GC_GAIN_GAP_CACC);
1485 24650 : CACCParams.insert(SUMO_ATTR_GC_GAIN_GAP_DOT_CACC);
1486 24650 : CACCParams.insert(SUMO_ATTR_CA_GAIN_GAP_CACC);
1487 24650 : CACCParams.insert(SUMO_ATTR_CA_GAIN_GAP_DOT_CACC);
1488 24650 : CACCParams.insert(SUMO_ATTR_GCC_GAIN_SPEED);
1489 24650 : CACCParams.insert(SUMO_ATTR_GCC_GAIN_SPACE);
1490 24650 : CACCParams.insert(SUMO_ATTR_GC_GAIN_SPEED);
1491 24650 : CACCParams.insert(SUMO_ATTR_GC_GAIN_SPACE);
1492 24650 : CACCParams.insert(SUMO_ATTR_CA_GAIN_SPEED);
1493 24650 : CACCParams.insert(SUMO_ATTR_CA_GAIN_SPACE);
1494 24650 : CACCParams.insert(SUMO_ATTR_CA_OVERRIDE);
1495 24650 : CACCParams.insert(SUMO_ATTR_HEADWAY_TIME_CACC_TO_ACC);
1496 24650 : CACCParams.insert(SUMO_ATTR_APPLYDRIVERSTATE);
1497 24650 : CACCParams.insert(SUMO_ATTR_SC_MIN_GAP);
1498 49300 : allowedCFModelAttrs[SUMO_TAG_CF_CACC] = CACCParams;
1499 24650 : allParams.insert(CACCParams.begin(), CACCParams.end());
1500 : // CC
1501 : std::set<SumoXMLAttr> ccParams(genericParams);
1502 24650 : ccParams.insert(SUMO_ATTR_CF_CC_C1);
1503 24650 : ccParams.insert(SUMO_ATTR_CF_CC_CCDECEL);
1504 24650 : ccParams.insert(SUMO_ATTR_CF_CC_CONSTSPACING);
1505 24650 : ccParams.insert(SUMO_ATTR_CF_CC_KP);
1506 24650 : ccParams.insert(SUMO_ATTR_CF_CC_LAMBDA);
1507 24650 : ccParams.insert(SUMO_ATTR_CF_CC_OMEGAN);
1508 24650 : ccParams.insert(SUMO_ATTR_CF_CC_TAU);
1509 24650 : ccParams.insert(SUMO_ATTR_CF_CC_XI);
1510 24650 : ccParams.insert(SUMO_ATTR_CF_CC_LANES_COUNT);
1511 24650 : ccParams.insert(SUMO_ATTR_CF_CC_CCACCEL);
1512 24650 : ccParams.insert(SUMO_ATTR_CF_CC_PLOEG_KP);
1513 24650 : ccParams.insert(SUMO_ATTR_CF_CC_PLOEG_KD);
1514 24650 : ccParams.insert(SUMO_ATTR_CF_CC_PLOEG_H);
1515 24650 : ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_KA);
1516 24650 : ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_KV);
1517 24650 : ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_KP);
1518 24650 : ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_D);
1519 24650 : ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_H);
1520 49300 : allowedCFModelAttrs[SUMO_TAG_CF_CC] = ccParams;
1521 24650 : allParams.insert(ccParams.begin(), ccParams.end());
1522 : // last element
1523 49300 : allowedCFModelAttrs[SUMO_TAG_NOTHING] = allParams;
1524 : }
1525 60644 : return allowedCFModelAttrs;
1526 : }
1527 :
1528 :
1529 : bool
1530 60628 : SUMOVehicleParserHelper::parseLCParams(SUMOVTypeParameter* into, LaneChangeModel model, const SUMOSAXAttributes& attrs) {
1531 60628 : if (allowedLCModelAttrs.size() == 0) {
1532 : // lc2013
1533 : std::set<SumoXMLAttr> lc2013Params;
1534 24650 : lc2013Params.insert(SUMO_ATTR_LCA_STRATEGIC_PARAM);
1535 24650 : lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_PARAM);
1536 24650 : lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_PARAM);
1537 24650 : lc2013Params.insert(SUMO_ATTR_LCA_KEEPRIGHT_PARAM);
1538 24650 : lc2013Params.insert(SUMO_ATTR_LCA_OPPOSITE_PARAM);
1539 24650 : lc2013Params.insert(SUMO_ATTR_LCA_LOOKAHEADLEFT);
1540 24650 : lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAINRIGHT);
1541 24650 : lc2013Params.insert(SUMO_ATTR_LCA_MAXSPEEDLATSTANDING);
1542 24650 : lc2013Params.insert(SUMO_ATTR_LCA_MAXSPEEDLATFACTOR);
1543 24650 : lc2013Params.insert(SUMO_ATTR_LCA_MAXDISTLATSTANDING);
1544 24650 : lc2013Params.insert(SUMO_ATTR_LCA_ASSERTIVE);
1545 24650 : lc2013Params.insert(SUMO_ATTR_LCA_STRATEGIC_LOOKAHEAD);
1546 24650 : lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD);
1547 24650 : lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_REMAIN_TIME);
1548 24650 : lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_ROUNDABOUT);
1549 24650 : lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_SPEED);
1550 24650 : lc2013Params.insert(SUMO_ATTR_LCA_OVERTAKE_RIGHT);
1551 24650 : lc2013Params.insert(SUMO_ATTR_LCA_SIGMA);
1552 24650 : lc2013Params.insert(SUMO_ATTR_LCA_KEEPRIGHT_ACCEPTANCE_TIME);
1553 24650 : lc2013Params.insert(SUMO_ATTR_LCA_OVERTAKE_DELTASPEED_FACTOR);
1554 24650 : lc2013Params.insert(SUMO_ATTR_LCA_CONTRIGHT);
1555 24650 : lc2013Params.insert(SUMO_ATTR_LCA_EXPERIMENTAL1);
1556 49300 : allowedLCModelAttrs[LaneChangeModel::LC2013] = lc2013Params;
1557 : // sl2015 (extension of lc2013)
1558 : std::set<SumoXMLAttr> sl2015Params = lc2013Params;
1559 24650 : sl2015Params.insert(SUMO_ATTR_LCA_PUSHY);
1560 24650 : sl2015Params.insert(SUMO_ATTR_LCA_PUSHYGAP);
1561 24650 : sl2015Params.insert(SUMO_ATTR_LCA_SUBLANE_PARAM);
1562 24650 : sl2015Params.insert(SUMO_ATTR_LCA_IMPATIENCE);
1563 24650 : sl2015Params.insert(SUMO_ATTR_LCA_TIME_TO_IMPATIENCE);
1564 24650 : sl2015Params.insert(SUMO_ATTR_LCA_ACCEL_LAT);
1565 24650 : sl2015Params.insert(SUMO_ATTR_LCA_TURN_ALIGNMENT_DISTANCE);
1566 24650 : sl2015Params.insert(SUMO_ATTR_LCA_LANE_DISCIPLINE);
1567 49300 : allowedLCModelAttrs[LaneChangeModel::SL2015] = sl2015Params;
1568 : // DK2008
1569 : std::set<SumoXMLAttr> noParams;
1570 24650 : allowedLCModelAttrs[LaneChangeModel::DK2008] = noParams;
1571 : // default model may be either LC2013 or SL2015
1572 : // we allow both sets (sl2015 is a superset of lc2013Params)
1573 49300 : allowedLCModelAttrs[LaneChangeModel::DEFAULT] = sl2015Params;
1574 : }
1575 60628 : std::set<SumoXMLAttr> allowed = allowedLCModelAttrs[model];
1576 : // iterate over LCM attributes
1577 1878678 : for (const auto& it : allowed) {
1578 1818050 : if (attrs.hasAttribute(it)) {
1579 : // first obtain CFM attribute in string format
1580 4002 : bool ok = true;
1581 4002 : std::string parsedLCMAttribute = attrs.get<std::string>(it, into->id.c_str(), ok);
1582 4002 : if (!ok) {
1583 : return false;
1584 : }
1585 : // declare a double in wich save CFM attribute
1586 : double LCMAttribute = -1;
1587 : try {
1588 : // obtain CFM attribute in double format
1589 4002 : LCMAttribute = StringUtils::toDouble(parsedLCMAttribute);
1590 0 : } catch (...) {
1591 0 : WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Cannot be parsed to float"), toString(it));
1592 : return false;
1593 0 : }
1594 : // check attributes of type "nonNegativeFloatType" (>= 0)
1595 4002 : switch (it) {
1596 1437 : case SUMO_ATTR_LCA_PUSHYGAP:
1597 : case SUMO_ATTR_LCA_MAXSPEEDLATSTANDING:
1598 : case SUMO_ATTR_LCA_IMPATIENCE:
1599 : case SUMO_ATTR_LCA_OVERTAKE_RIGHT:
1600 : case SUMO_ATTR_LCA_ASSERTIVE:
1601 : case SUMO_ATTR_LCA_LOOKAHEADLEFT:
1602 : case SUMO_ATTR_LCA_SPEEDGAINRIGHT:
1603 : case SUMO_ATTR_LCA_TURN_ALIGNMENT_DISTANCE:
1604 : case SUMO_ATTR_LCA_TIME_TO_IMPATIENCE:
1605 : case SUMO_ATTR_LCA_LANE_DISCIPLINE:
1606 : case SUMO_ATTR_LCA_SIGMA:
1607 1437 : if (LCMAttribute < 0) {
1608 0 : WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Must be equal or greater than 0"), toString(it));
1609 0 : return false;
1610 : }
1611 : break;
1612 : default:
1613 : break;
1614 : }
1615 : // check attributes of type "positiveFloatType" (> 0)
1616 4002 : switch (it) {
1617 10 : case SUMO_ATTR_LCA_ACCEL_LAT:
1618 10 : if (LCMAttribute <= 0) {
1619 0 : WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Must be greater than 0"), toString(it));
1620 0 : return false;
1621 : }
1622 : break;
1623 : default:
1624 : break;
1625 : }
1626 : // check limits of attributes
1627 4002 : switch (it) {
1628 90 : case SUMO_ATTR_LCA_OVERTAKE_DELTASPEED_FACTOR:
1629 90 : if (LCMAttribute < -1 || LCMAttribute > 1) {
1630 0 : WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Must be between -1 and 1"), toString(it));
1631 0 : return false;
1632 : }
1633 : break;
1634 : default:
1635 : break;
1636 : }
1637 : // add parsedLCMAttribute to cfParameter
1638 4002 : into->lcParameter[it] = parsedLCMAttribute;
1639 : }
1640 : }
1641 : // all LCM parsed ok, then return true
1642 : return true;
1643 : }
1644 :
1645 :
1646 : bool
1647 60628 : SUMOVehicleParserHelper::parseJMParams(SUMOVTypeParameter* into, const SUMOSAXAttributes& attrs) {
1648 1030676 : for (const auto& it : SUMOVTypeParameter::AllowedJMAttrs) {
1649 970048 : if (attrs.hasAttribute(it)) {
1650 : // first obtain CFM attribute in string format
1651 1024 : bool ok = true;
1652 1024 : std::string parsedJMAttribute = attrs.get<std::string>(it, into->id.c_str(), ok);
1653 1024 : if (!ok) {
1654 : return false;
1655 : }
1656 : // declare a double in wich save CFM attribute
1657 : double JMAttribute = -1;
1658 : try {
1659 : // obtain CFM attribute in double format
1660 1024 : JMAttribute = StringUtils::toDouble(parsedJMAttribute);
1661 0 : } catch (...) {
1662 0 : WRITE_ERRORF(TL("Invalid Junction-Model Attribute %. Cannot be parsed to float"), toString(it));
1663 : return false;
1664 0 : }
1665 : // now continue checking other properties (-1 is the default value)
1666 1024 : if (JMAttribute != -1) {
1667 : // special case for sigma minor
1668 1006 : if (it == SUMO_ATTR_JM_SIGMA_MINOR) {
1669 : // check attributes sigma minor
1670 126 : if ((JMAttribute < 0) || (JMAttribute > 1)) {
1671 0 : WRITE_ERRORF(TL("Invalid Junction-Model Attribute %. Only values between [0-1] are allowed"), toString(it));
1672 0 : return false;
1673 : }
1674 : } else {
1675 : // check attributes of type "nonNegativeFloatType" (>= 0)
1676 880 : if (JMAttribute < 0) {
1677 0 : WRITE_ERRORF(TL("Invalid Junction-Model Attribute %. Must be equal or greater than 0"), toString(it));
1678 0 : return false;
1679 : }
1680 : }
1681 : // add parsedJMAttribute to cfParameter
1682 1006 : into->jmParameter[it] = parsedJMAttribute;
1683 : }
1684 : }
1685 : }
1686 : // all JM parameters successfully parsed, then return true
1687 : return true;
1688 : }
1689 :
1690 :
1691 : SUMOVehicleClass
1692 35626 : SUMOVehicleParserHelper::parseVehicleClass(const SUMOSAXAttributes& attrs, const std::string& id) {
1693 : SUMOVehicleClass vclass = SVC_IGNORING;
1694 35626 : bool ok = true;
1695 35626 : std::string vclassS = attrs.getOpt<std::string>(SUMO_ATTR_VCLASS, id.c_str(), ok, "");
1696 35626 : if (vclassS == "") {
1697 : return vclass;
1698 : }
1699 : try {
1700 35602 : const SUMOVehicleClass result = getVehicleClassID(vclassS);
1701 35594 : const std::string& realName = SumoVehicleClassStrings.getString(result);
1702 35594 : if (realName != vclassS) {
1703 12 : WRITE_WARNING("The vehicle class '" + vclassS + "' for " + attrs.getObjectType() + " '" + id + "' is deprecated, use '" + realName + "' instead.");
1704 : }
1705 : return result;
1706 8 : } catch (...) {
1707 24 : WRITE_ERRORF(TL("The vehicle class '%' for % '%' is not known."), vclassS, attrs.getObjectType(), id);
1708 8 : }
1709 : return vclass;
1710 : }
1711 :
1712 :
1713 : SUMOVehicleShape
1714 27140 : SUMOVehicleParserHelper::parseGuiShape(const SUMOSAXAttributes& attrs, const std::string& id) {
1715 27140 : bool ok = true;
1716 54280 : std::string vclassS = attrs.getOpt<std::string>(SUMO_ATTR_GUISHAPE, id.c_str(), ok, "");
1717 : if (SumoVehicleShapeStrings.hasString(vclassS)) {
1718 27140 : const SUMOVehicleShape result = SumoVehicleShapeStrings.get(vclassS);
1719 27140 : const std::string& realName = SumoVehicleShapeStrings.getString(result);
1720 27140 : if (realName != vclassS) {
1721 0 : WRITE_WARNING("The shape '" + vclassS + "' for " + attrs.getObjectType() + " '" + id + "' is deprecated, use '" + realName + "' instead.");
1722 : }
1723 27140 : return result;
1724 : } else {
1725 0 : WRITE_ERRORF(TL("The shape '%' for % '%' is not known."), vclassS, attrs.getObjectType(), id);
1726 0 : return SUMOVehicleShape::UNKNOWN;
1727 : }
1728 : }
1729 :
1730 :
1731 : double
1732 31764 : SUMOVehicleParserHelper::parseWalkPos(SumoXMLAttr attr, const bool hardFail, const std::string& id, double maxPos, const std::string& val, SumoRNG* rng) {
1733 : double result;
1734 : std::string error;
1735 31764 : ArrivalPosDefinition proc = ArrivalPosDefinition::DEFAULT;
1736 : // only supports 'random' and 'max'
1737 63528 : if (!SUMOVehicleParameter::parseArrivalPos(val, toString(SUMO_TAG_WALK), id, result, proc, error)) {
1738 0 : handleVehicleError(hardFail, nullptr, error);
1739 : }
1740 31764 : if (proc == ArrivalPosDefinition::RANDOM) {
1741 888 : result = RandHelper::rand(maxPos, rng);
1742 30876 : } else if (proc == ArrivalPosDefinition::CENTER) {
1743 0 : result = maxPos / 2.;
1744 30876 : } else if (proc == ArrivalPosDefinition::MAX) {
1745 0 : result = maxPos;
1746 : }
1747 63528 : return SUMOVehicleParameter::interpretEdgePos(result, maxPos, attr, id);
1748 : }
1749 :
1750 :
1751 : SUMOTime
1752 300134 : SUMOVehicleParserHelper::processActionStepLength(double given) {
1753 300134 : const std::string defaultError = "The parameter action-step-length must be a non-negative multiple of the simulation step-length. ";
1754 300134 : SUMOTime result = TIME2STEPS(given);
1755 300134 : if (result <= 0) {
1756 42757 : if (result < 0) {
1757 36 : WRITE_WARNING(defaultError + "Ignoring given value (=" + toString(STEPS2TIME(result)) + " s.)");
1758 : }
1759 42757 : result = DELTA_T;
1760 257377 : } else if (result % DELTA_T != 0) {
1761 25 : result = (SUMOTime)((double)DELTA_T * floor(double(result) / double(DELTA_T)));
1762 : result = MAX2(DELTA_T, result);
1763 25 : if (fabs(given * 1000. - double(result)) > NUMERICAL_EPS) {
1764 100 : WRITE_WARNING(defaultError + "Parsing given value (" + toString(given) + " s.) to the adjusted value " + toString(STEPS2TIME(result)) + " s.");
1765 : }
1766 : }
1767 300134 : return result;
1768 : }
1769 :
1770 :
1771 : bool
1772 185459 : SUMOVehicleParserHelper::isInternalRouteID(const std::string& id) {
1773 185459 : return id.substr(0, 1) == "!";
1774 : }
1775 :
1776 :
1777 : int
1778 17444 : SUMOVehicleParserHelper::parseCarWalkTransfer(const OptionsCont& oc, const bool hasTaxi) {
1779 : int carWalk = 0;
1780 52332 : for (const std::string& opt : oc.getStringVector("persontrip.transfer.car-walk")) {
1781 17444 : if (opt == "parkingAreas") {
1782 17244 : carWalk |= ModeChangeOptions::PARKING_AREAS;
1783 200 : } else if (opt == "ptStops") {
1784 150 : carWalk |= ModeChangeOptions::PT_STOPS;
1785 50 : } else if (opt == "allJunctions") {
1786 50 : carWalk |= ModeChangeOptions::ALL_JUNCTIONS;
1787 : } else {
1788 0 : WRITE_ERRORF(TL("Invalid transfer option '%'. Must be one of 'parkingAreas', 'ptStops' and 'allJunctions'"), opt);
1789 : }
1790 : }
1791 17444 : const StringVector taxiDropoff = oc.getStringVector("persontrip.transfer.taxi-walk");
1792 34888 : const StringVector taxiPickup = oc.getStringVector("persontrip.transfer.walk-taxi");
1793 17444 : if (taxiDropoff.empty() && hasTaxi) {
1794 87 : carWalk |= ModeChangeOptions::TAXI_DROPOFF_ANYWHERE;
1795 : } else {
1796 17465 : for (const std::string& opt : taxiDropoff) {
1797 108 : if (opt == "parkingAreas") {
1798 0 : carWalk |= ModeChangeOptions::TAXI_DROPOFF_PARKING_AREAS;
1799 108 : } else if (opt == "ptStops") {
1800 76 : carWalk |= ModeChangeOptions::TAXI_DROPOFF_PT;
1801 32 : } else if (opt == "allJunctions") {
1802 32 : carWalk |= ModeChangeOptions::TAXI_DROPOFF_ANYWHERE;
1803 : } else {
1804 0 : WRITE_ERRORF(TL("Invalid transfer option '%'. Must be one of 'parkingAreas', 'ptStops' and 'allJunctions'"), opt);
1805 : }
1806 : }
1807 : }
1808 17444 : if (taxiPickup.empty() && hasTaxi) {
1809 81 : carWalk |= ModeChangeOptions::TAXI_PICKUP_ANYWHERE;
1810 : } else {
1811 17483 : for (const std::string& opt : taxiPickup) {
1812 120 : if (opt == "parkingAreas") {
1813 0 : carWalk |= ModeChangeOptions::TAXI_PICKUP_PARKING_AREAS;
1814 120 : } else if (opt == "ptStops") {
1815 88 : carWalk |= ModeChangeOptions::TAXI_PICKUP_PT;
1816 32 : } else if (opt == "allJunctions") {
1817 32 : carWalk |= ModeChangeOptions::TAXI_PICKUP_ANYWHERE;
1818 : } else {
1819 0 : WRITE_ERRORF(TL("Invalid transfer option '%'. Must be one of 'parkingAreas', 'ptStops' and 'allJunctions'"), opt);
1820 : }
1821 : }
1822 : }
1823 17444 : return carWalk;
1824 17444 : }
1825 :
1826 :
1827 : SUMOVehicleParameter*
1828 432 : SUMOVehicleParserHelper::handleVehicleError(const bool hardFail, SUMOVehicleParameter* vehicleParameter, const std::string message) {
1829 432 : if (vehicleParameter) {
1830 388 : delete vehicleParameter;
1831 : }
1832 432 : if (hardFail) {
1833 864 : throw ProcessError(message);
1834 0 : } else if (message.size() > 0) {
1835 0 : WRITE_ERROR(message);
1836 : }
1837 0 : return nullptr;
1838 : }
1839 :
1840 :
1841 : SUMOVTypeParameter*
1842 30 : SUMOVehicleParserHelper::handleVehicleTypeError(const bool hardFail, SUMOVTypeParameter* vehicleTypeParameter, const std::string message) {
1843 30 : if (vehicleTypeParameter) {
1844 26 : delete vehicleTypeParameter;
1845 : }
1846 30 : if (hardFail) {
1847 60 : throw ProcessError(message);
1848 0 : } else if (message.size() > 0) {
1849 0 : WRITE_ERROR(message);
1850 : }
1851 0 : return nullptr;
1852 : }
1853 :
1854 : /****************************************************************************/
|