Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2008-2025 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file 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 23226 : 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 23226 : const std::string id = attrs.hasAttribute(SUMO_ATTR_ID) ? parseID(attrs, tag) : "";
61 : // check if ID is valid
62 23226 : if (!needID || !id.empty()) {
63 23219 : if (needID && !SUMOXMLDefinitions::isValidVehicleID(id)) {
64 0 : return handleVehicleError(hardFail, nullptr, "Invalid flow id '" + id + "'.");
65 : }
66 : // declare flags
67 23219 : const bool hasPeriod = attrs.hasAttribute(SUMO_ATTR_PERIOD);
68 23219 : const bool hasVPH = attrs.hasAttribute(SUMO_ATTR_VEHSPERHOUR);
69 23219 : const bool hasPPH = attrs.hasAttribute(SUMO_ATTR_PERSONSPERHOUR);
70 23219 : const bool hasCPH = attrs.hasAttribute(SUMO_ATTR_CONTAINERSPERHOUR);
71 23219 : const bool hasPH = attrs.hasAttribute(SUMO_ATTR_PERHOUR);
72 23219 : const bool hasXPH = hasVPH || hasPPH || hasCPH || hasPH;
73 23219 : const bool hasProb = attrs.hasAttribute(SUMO_ATTR_PROB);
74 23219 : const bool hasNumber = attrs.hasAttribute(SUMO_ATTR_NUMBER);
75 23219 : const bool hasBegin = attrs.hasAttribute(SUMO_ATTR_BEGIN);
76 23219 : const bool hasEnd = attrs.hasAttribute(SUMO_ATTR_END);
77 : SumoXMLAttr PERHOUR = SUMO_ATTR_PERHOUR;
78 23219 : if (hasVPH) {
79 : PERHOUR = SUMO_ATTR_VEHSPERHOUR;
80 : }
81 23219 : if (hasPPH) {
82 : PERHOUR = SUMO_ATTR_PERSONSPERHOUR;
83 : }
84 23219 : if (hasCPH) {
85 : PERHOUR = SUMO_ATTR_CONTAINERSPERHOUR;
86 : }
87 23219 : 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 4284 : 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 23212 : 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 23212 : 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 23212 : if (hasPeriod || hasXPH || hasProb) {
117 18543 : 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 4669 : 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 23198 : SUMOVehicleParameter* flowParameter = new SUMOVehicleParameter();
146 : // set tag
147 23198 : flowParameter->tag = tag;
148 : // set id
149 23198 : flowParameter->id = id;
150 23198 : if (tag == SUMO_TAG_PERSONFLOW) {
151 1927 : flowParameter->vtypeid = DEFAULT_PEDTYPE_ID;
152 : }
153 23198 : if (tag == SUMO_TAG_CONTAINERFLOW) {
154 365 : flowParameter->vtypeid = DEFAULT_CONTAINERTYPE_ID;
155 : }
156 : // parse common vehicle attributes
157 : try {
158 23198 : 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 23150 : if (hasPeriod) {
170 9857 : bool ok = true;
171 9857 : const std::string description = attrs.get<std::string>(SUMO_ATTR_PERIOD, id.c_str(), ok);
172 9857 : const std::string distName = description.substr(0, description.find('('));
173 9857 : if (distName == "exp") {
174 : // declare rate
175 : double rate = -1;
176 : // parse rate
177 : try {
178 721 : 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 721 : 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 714 : flowParameter->poissonRate = rate;
191 : poissonFlow = true;
192 : } else {
193 9136 : flowParameter->repetitionOffset = attrs.getSUMOTimeReporting(SUMO_ATTR_PERIOD, id.c_str(), ok);
194 : }
195 9850 : if (!ok) {
196 7 : return handleVehicleError(hardFail, flowParameter);
197 : } else {
198 9850 : flowParameter->parametersSet |= VEHPARS_PERIOD_SET;
199 : }
200 : }
201 : // parse vehicle/person/container/etc per hour
202 23143 : if (hasXPH) {
203 4277 : bool ok = true;
204 4277 : const double vph = attrs.get<double>(PERHOUR, id.c_str(), ok);
205 4277 : if (!ok) {
206 0 : return handleVehicleError(hardFail, flowParameter);
207 4277 : } 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 4277 : flowParameter->repetitionOffset = TIME2STEPS(3600. / vph);
212 : }
213 4277 : flowParameter->parametersSet |= VEHPARS_VPH_SET;
214 : }
215 : }
216 : // parse probability
217 23143 : if (hasProb) {
218 4402 : bool ok = true;
219 4402 : flowParameter->repetitionProbability = attrs.get<double>(SUMO_ATTR_PROB, id.c_str(), ok);
220 4402 : if (!ok) {
221 0 : return handleVehicleError(hardFail, flowParameter);
222 4402 : } 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 4402 : flowParameter->parametersSet |= VEHPARS_PROB_SET;
226 : }
227 : }
228 : // set default begin
229 23143 : flowParameter->depart = beginDefault;
230 : // parse begin
231 23143 : if (hasBegin) {
232 : // first get begin
233 22930 : bool ok = true;
234 22930 : const std::string begin = attrs.get<std::string>(SUMO_ATTR_BEGIN, id.c_str(), ok);
235 22930 : if (!ok) {
236 7 : return handleVehicleError(hardFail, flowParameter);
237 : } else {
238 : // parse begin
239 : std::string errorMsg;
240 45860 : if (!SUMOVehicleParameter::parseDepart(begin, toString(tag), id, flowParameter->depart, flowParameter->departProcedure, errorMsg, "begin")) {
241 14 : return handleVehicleError(hardFail, flowParameter, errorMsg);
242 : }
243 : }
244 : }
245 23136 : 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 23136 : flowParameter->repetitionEnd = endDefault;
250 23136 : if (flowParameter->repetitionEnd < 0) {
251 13807 : flowParameter->repetitionEnd = SUMOTime_MAX;
252 : }
253 : // parse end
254 23136 : if (hasEnd) {
255 20614 : bool ok = true;
256 20614 : flowParameter->repetitionEnd = attrs.getSUMOTimeReporting(SUMO_ATTR_END, id.c_str(), ok);
257 20614 : if (!ok) {
258 0 : return handleVehicleError(hardFail, flowParameter);
259 : } else {
260 20614 : flowParameter->parametersSet |= VEHPARS_END_SET;
261 : }
262 2522 : } 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 2475 : } 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 23136 : 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 23129 : if (hasNumber) {
279 6821 : bool ok = true;
280 6821 : flowParameter->repetitionNumber = attrs.get<int>(SUMO_ATTR_NUMBER, id.c_str(), ok);
281 6821 : if (!ok) {
282 0 : return handleVehicleError(hardFail, flowParameter);
283 : } else {
284 6821 : flowParameter->parametersSet |= VEHPARS_NUMBER_SET;
285 6821 : 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 6813 : if (flowParameter->repetitionNumber < 0) {
292 14 : return handleVehicleError(hardFail, flowParameter, "Negative repetition number in the definition of " + toString(tag) + " '" + id + "'.");
293 : }
294 6806 : if (flowParameter->repetitionOffset < 0 && !hasProb) {
295 4649 : if (poissonFlow) {
296 43 : flowParameter->repetitionEnd = SUMOTime_MAX;
297 : } else {
298 4606 : flowParameter->repetitionOffset = (flowParameter->repetitionEnd - flowParameter->depart) / flowParameter->repetitionNumber;
299 : }
300 : }
301 : }
302 : }
303 : } else {
304 : // interpret repetitionNumber
305 16308 : if (flowParameter->repetitionProbability > 0) {
306 4360 : flowParameter->repetitionNumber = std::numeric_limits<int>::max();
307 : } else {
308 11948 : if (flowParameter->repetitionOffset <= 0) {
309 685 : if (poissonFlow) {
310 : // number is random but flow has a fixed end time
311 671 : 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 11263 : if (flowParameter->repetitionEnd == SUMOTime_MAX) {
317 0 : flowParameter->repetitionNumber = std::numeric_limits<int>::max();
318 : } else {
319 11263 : const SUMOTime repLength = flowParameter->repetitionEnd - flowParameter->depart;
320 11263 : flowParameter->repetitionNumber = (int)ceil((double)repLength / (double)flowParameter->repetitionOffset);
321 : }
322 : }
323 : }
324 : }
325 : // all ok, then return flow parameter
326 23108 : return flowParameter;
327 : } else {
328 132 : return handleVehicleError(hardFail, nullptr, toString(tag) + " cannot be created");
329 : }
330 : }
331 :
332 :
333 : SUMOVehicleParameter*
334 637708 : 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 637708 : if (optionalID) {
339 682 : bool ok = true;
340 682 : id = attrs.getOpt<std::string>(SUMO_ATTR_ID, nullptr, ok, "");
341 682 : if (!ok) {
342 0 : return handleVehicleError(hardFail, nullptr);
343 : }
344 : } else {
345 : // parse ID
346 1274052 : id = parseID(attrs, (SumoXMLTag)element);
347 : }
348 : // only continue if id is valid, or if is optional
349 637708 : if (optionalID || !id.empty()) {
350 : // declare vehicle parameter
351 637692 : SUMOVehicleParameter* vehicleParameter = new SUMOVehicleParameter();
352 637692 : vehicleParameter->id = id;
353 637692 : if (element == SUMO_TAG_PERSON) {
354 43718 : vehicleParameter->vtypeid = DEFAULT_PEDTYPE_ID;
355 593974 : } else if (element == SUMO_TAG_CONTAINER) {
356 865 : vehicleParameter->vtypeid = DEFAULT_CONTAINERTYPE_ID;
357 : }
358 : // parse common attributes
359 : try {
360 637692 : 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 637418 : if (!skipDepart) {
371 636736 : bool ok = true;
372 636736 : const std::string helper = attrs.get<std::string>(SUMO_ATTR_DEPART, vehicleParameter->id.c_str(), ok);
373 636736 : if (!ok) {
374 40 : return handleVehicleError(hardFail, vehicleParameter);
375 : }
376 : // now parse depart
377 : std::string departErrorMsg;
378 1273440 : 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 637394 : vehicleParameter->tag = (SumoXMLTag)element;
384 : // all ok, then return vehicleParameter
385 637394 : return vehicleParameter;
386 : } else {
387 346 : return handleVehicleError(hardFail, nullptr, toString((SumoXMLTag)element) + " cannot be created");
388 : }
389 : }
390 :
391 :
392 : std::string
393 722776 : SUMOVehicleParserHelper::parseID(const SUMOSAXAttributes& attrs, const SumoXMLTag element) {
394 722776 : bool ok = true;
395 : std::string id;
396 : // first check if attrs contain an ID
397 722776 : if (attrs.hasAttribute(SUMO_ATTR_ID)) {
398 722764 : id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
399 722764 : if (SUMOXMLDefinitions::isValidVehicleID(id)) {
400 722756 : 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 660890 : SUMOVehicleParserHelper::parseCommonAttributes(const SUMOSAXAttributes& attrs, SUMOVehicleParameter* ret, SumoXMLTag tag, const bool allowInternalRoutes) {
417 660890 : const std::string element = toString(tag);
418 : //ret->refid = attrs.getStringSecure(SUMO_ATTR_REFID, "");
419 : // parse route information
420 660890 : if (attrs.hasAttribute(SUMO_ATTR_ROUTE)) {
421 165686 : bool ok = true;
422 165686 : std::string routeID = attrs.get<std::string>(SUMO_ATTR_ROUTE, ret->id.c_str(), ok);
423 165686 : 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 165686 : ret->routeid = routeID;
427 165686 : if (ok) {
428 165676 : ret->parametersSet |= VEHPARS_ROUTE_SET; // !!! needed?
429 : } else {
430 20 : handleVehicleError(true, ret);
431 : }
432 : }
433 : // parse type information
434 660880 : if (attrs.hasAttribute(SUMO_ATTR_TYPE)) {
435 218418 : bool ok = true;
436 218418 : ret->vtypeid = attrs.get<std::string>(SUMO_ATTR_TYPE, ret->id.c_str(), ok);
437 218418 : if (ok) {
438 218418 : ret->parametersSet |= VEHPARS_VTYPE_SET; // !!! needed?
439 : } else {
440 0 : handleVehicleError(true, ret);
441 : }
442 : }
443 : // parse line information
444 660880 : if (attrs.hasAttribute(SUMO_ATTR_LINE)) {
445 3265 : bool ok = true;
446 3265 : ret->line = attrs.get<std::string>(SUMO_ATTR_LINE, ret->id.c_str(), ok);
447 3265 : if (ok) {
448 3259 : ret->parametersSet |= VEHPARS_LINE_SET; // !!! needed?
449 : } else {
450 6 : handleVehicleError(true, ret);
451 : }
452 : }
453 : // parse zone information
454 660874 : if (attrs.hasAttribute(SUMO_ATTR_FROM_TAZ)) {
455 21585 : bool ok = true;
456 21585 : ret->fromTaz = attrs.get<std::string>(SUMO_ATTR_FROM_TAZ, ret->id.c_str(), ok);
457 21585 : if (ok) {
458 21585 : ret->parametersSet |= VEHPARS_FROM_TAZ_SET;
459 : } else {
460 0 : handleVehicleError(true, ret);
461 : }
462 : }
463 660874 : if (attrs.hasAttribute(SUMO_ATTR_TO_TAZ)) {
464 21585 : bool ok = true;
465 21585 : ret->toTaz = attrs.get<std::string>(SUMO_ATTR_TO_TAZ, ret->id.c_str(), ok);
466 21585 : if (ok) {
467 21585 : ret->parametersSet |= VEHPARS_TO_TAZ_SET;
468 : } else {
469 0 : handleVehicleError(true, ret);
470 : }
471 : }
472 : // parse reroute information
473 660874 : if (attrs.hasAttribute(SUMO_ATTR_REROUTE)) {
474 4480 : bool ok = true;
475 4480 : if (attrs.get<bool>(SUMO_ATTR_REROUTE, ret->id.c_str(), ok)) {
476 4480 : if (ok) {
477 4480 : ret->parametersSet |= VEHPARS_FORCE_REROUTE;
478 : } else {
479 0 : handleVehicleError(true, ret);
480 : }
481 : }
482 : }
483 : // parse depart lane information
484 660874 : if (attrs.hasAttribute(SUMO_ATTR_DEPARTLANE)) {
485 111379 : bool ok = true;
486 111379 : 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 111379 : if (SUMOVehicleParameter::parseDepartLane(departLaneStr, element, ret->id, lane, dld, error)) {
491 111331 : ret->parametersSet |= VEHPARS_DEPARTLANE_SET;
492 111331 : ret->departLane = lane;
493 111331 : ret->departLaneProcedure = dld;
494 : } else {
495 96 : handleVehicleError(true, ret, error);
496 : }
497 : }
498 : // parse depart position information
499 660826 : if (attrs.hasAttribute(SUMO_ATTR_DEPARTPOS)) {
500 89907 : bool ok = true;
501 89907 : 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 89907 : if (SUMOVehicleParameter::parseDepartPos(departPosStr, element, ret->id, pos, dpd, error)) {
506 89859 : ret->parametersSet |= VEHPARS_DEPARTPOS_SET;
507 89859 : ret->departPos = pos;
508 89859 : ret->departPosProcedure = dpd;
509 : } else {
510 96 : handleVehicleError(true, ret, error);
511 : }
512 : }
513 : // parse lateral depart position information
514 660778 : if (attrs.hasAttribute(SUMO_ATTR_DEPARTPOS_LAT)) {
515 8715 : bool ok = true;
516 8715 : 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 8715 : if (SUMOVehicleParameter::parseDepartPosLat(departPosLatStr, element, ret->id, pos, dpd, error)) {
521 8715 : ret->parametersSet |= VEHPARS_DEPARTPOSLAT_SET;
522 8715 : ret->departPosLat = pos;
523 8715 : ret->departPosLatProcedure = dpd;
524 : } else {
525 0 : handleVehicleError(true, ret, error);
526 : }
527 : }
528 : // parse depart speed information
529 660778 : if (attrs.hasAttribute(SUMO_ATTR_DEPARTSPEED)) {
530 242417 : bool ok = true;
531 242417 : 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 242417 : if (SUMOVehicleParameter::parseDepartSpeed(departSpeed, element, ret->id, speed, dsd, error)) {
536 242369 : ret->parametersSet |= VEHPARS_DEPARTSPEED_SET;
537 242369 : ret->departSpeed = speed;
538 242369 : ret->departSpeedProcedure = dsd;
539 : } else {
540 96 : handleVehicleError(true, ret, error);
541 : }
542 : }
543 : // parse depart edge information
544 660730 : if (attrs.hasAttribute(SUMO_ATTR_DEPARTEDGE)) {
545 262 : bool ok = true;
546 262 : 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 262 : if (SUMOVehicleParameter::parseRouteIndex(departEdgeStr, element, ret->id, SUMO_ATTR_DEPARTEDGE, edgeIndex, rid, error)) {
551 255 : ret->parametersSet |= VEHPARS_DEPARTEDGE_SET;
552 255 : ret->departEdge = edgeIndex;
553 255 : ret->departEdgeProcedure = rid;
554 : } else {
555 14 : handleVehicleError(true, ret, error);
556 : }
557 : }
558 : // parse arrival lane information
559 660723 : if (attrs.hasAttribute(SUMO_ATTR_ARRIVALLANE)) {
560 3263 : bool ok = true;
561 3263 : 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 3263 : if (SUMOVehicleParameter::parseArrivalLane(arrivalLaneStr, element, ret->id, lane, ald, error)) {
566 3215 : ret->parametersSet |= VEHPARS_ARRIVALLANE_SET;
567 3215 : ret->arrivalLane = lane;
568 3215 : ret->arrivalLaneProcedure = ald;
569 : } else {
570 96 : handleVehicleError(true, ret, error);
571 : }
572 : }
573 : // parse arrival position information
574 660675 : if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS)) {
575 8292 : bool ok = true;
576 8292 : 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 8292 : if (SUMOVehicleParameter::parseArrivalPos(arrivalPosStr, element, ret->id, pos, apd, error)) {
581 8244 : ret->parametersSet |= VEHPARS_ARRIVALPOS_SET;
582 8244 : ret->arrivalPos = pos;
583 8244 : ret->arrivalPosProcedure = apd;
584 : } else {
585 96 : handleVehicleError(true, ret, error);
586 : }
587 : }
588 : // parse lateral arrival position information
589 660627 : if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS_LAT)) {
590 1069 : bool ok = true;
591 1069 : 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 1069 : if (SUMOVehicleParameter::parseArrivalPosLat(arrivalPosLatStr, element, ret->id, pos, apd, error)) {
596 1069 : ret->parametersSet |= VEHPARS_ARRIVALPOSLAT_SET;
597 1069 : ret->arrivalPosLat = pos;
598 1069 : ret->arrivalPosLatProcedure = apd;
599 : } else {
600 0 : handleVehicleError(true, ret, error);
601 : }
602 : }
603 : // parse arrival speed information
604 660627 : 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 660579 : if (attrs.hasAttribute(SUMO_ATTR_ARRIVALEDGE)) {
620 90 : bool ok = true;
621 90 : 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 90 : if (SUMOVehicleParameter::parseRouteIndex(arrivalEdgeStr, element, ret->id, SUMO_ATTR_ARRIVALEDGE, edgeIndex, rid, error)) {
626 83 : ret->parametersSet |= VEHPARS_ARRIVALEDGE_SET;
627 83 : ret->arrivalEdge = edgeIndex;
628 83 : ret->arrivalEdgeProcedure = rid;
629 : } else {
630 14 : handleVehicleError(true, ret, error);
631 : }
632 : }
633 : // parse color
634 660572 : if (attrs.hasAttribute(SUMO_ATTR_COLOR)) {
635 9677 : bool ok = true;
636 9677 : ret->color = attrs.get<RGBColor>(SUMO_ATTR_COLOR, ret->id.c_str(), ok);
637 9677 : if (ok) {
638 9677 : ret->parametersSet |= VEHPARS_COLOR_SET;
639 : } else {
640 0 : handleVehicleError(true, ret, "Invalid RGBColor format");
641 : }
642 : } else {
643 650895 : ret->color = RGBColor::DEFAULT_COLOR;
644 : }
645 : // parse person number
646 660572 : if (attrs.hasAttribute(SUMO_ATTR_PERSON_NUMBER)) {
647 984 : bool ok = true;
648 984 : int personNumber = attrs.get<int>(SUMO_ATTR_PERSON_NUMBER, ret->id.c_str(), ok);
649 984 : if (!ok) {
650 0 : handleVehicleError(true, ret);
651 984 : } else if (personNumber >= 0) {
652 984 : ret->parametersSet |= VEHPARS_PERSON_NUMBER_SET;
653 984 : 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 660572 : if (attrs.hasAttribute(SUMO_ATTR_CONTAINER_NUMBER)) {
660 978 : bool ok = true;
661 978 : int containerNumber = attrs.get<int>(SUMO_ATTR_CONTAINER_NUMBER, ret->id.c_str(), ok);
662 978 : if (!ok) {
663 0 : handleVehicleError(true, ret);
664 978 : } else if (containerNumber >= 0) {
665 978 : ret->parametersSet |= VEHPARS_CONTAINER_NUMBER_SET;
666 978 : 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 660572 : if (attrs.hasAttribute(SUMO_ATTR_SPEEDFACTOR)) {
673 11801 : bool ok = true;
674 11801 : double speedFactor = attrs.get<double>(SUMO_ATTR_SPEEDFACTOR, ret->id.c_str(), ok);
675 11801 : if (!ok) {
676 0 : handleVehicleError(true, ret);
677 11801 : } else if (speedFactor > 0) {
678 11801 : ret->parametersSet |= VEHPARS_SPEEDFACTOR_SET;
679 11801 : ret->speedFactor = speedFactor;
680 : } else {
681 0 : handleVehicleError(true, ret, toString(SUMO_ATTR_SPEEDFACTOR) + " must be positive");
682 : }
683 : }
684 : // parse insertion checks
685 660572 : if (attrs.hasAttribute(SUMO_ATTR_INSERTIONCHECKS)) {
686 1009 : ret->parametersSet |= VEHPARS_INSERTION_CHECKS_SET;
687 1009 : bool ok = true;
688 1009 : std::string checks = attrs.get<std::string>(SUMO_ATTR_INSERTIONCHECKS, ret->id.c_str(), ok);
689 1009 : if (!ok) {
690 4 : handleVehicleError(true, ret);
691 : } else {
692 : try {
693 1009 : 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 660568 : 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 660568 : ret->modes = 0;
712 660568 : 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 660568 : 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 660568 : if (tag == SUMO_TAG_FLOW && attrs.hasAttribute(SUMO_ATTR_SPEED)) {
735 221 : bool ok = true;
736 221 : double calibratorSpeed = attrs.get<double>(SUMO_ATTR_SPEED, ret->id.c_str(), ok);
737 221 : if (!ok) {
738 0 : handleVehicleError(true, ret);
739 221 : } else if (calibratorSpeed >= 0 || calibratorSpeed == -1) {
740 221 : ret->parametersSet |= VEHPARS_CALIBRATORSPEED_SET;
741 221 : 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 660568 : }
753 :
754 :
755 : SUMOVTypeParameter*
756 62531 : SUMOVehicleParserHelper::beginVTypeParsing(const SUMOSAXAttributes& attrs, const bool hardFail, const std::string& file) {
757 : // first obtain ID
758 62531 : std::string id = parseID(attrs, SUMO_TAG_VTYPE);
759 : // check if ID is valid
760 62531 : if (!id.empty()) {
761 : SUMOVehicleClass vClass = SVC_PASSENGER;
762 62527 : if (attrs.hasAttribute(SUMO_ATTR_VCLASS)) {
763 36691 : vClass = parseVehicleClass(attrs, id);
764 : }
765 : // create vType
766 62527 : SUMOVTypeParameter* vType = new SUMOVTypeParameter(id, vClass);
767 : // parse attributes
768 62527 : if (attrs.hasAttribute(SUMO_ATTR_VCLASS)) {
769 36691 : vType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
770 : }
771 62527 : if (attrs.hasAttribute(SUMO_ATTR_LENGTH)) {
772 37879 : bool ok = true;
773 37879 : const double length = attrs.get<double>(SUMO_ATTR_LENGTH, vType->id.c_str(), ok);
774 37879 : if (!ok) {
775 0 : return handleVehicleTypeError(hardFail, vType);
776 37879 : } else if (length <= 0) {
777 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_LENGTH) + " must be greater than 0");
778 : } else {
779 37879 : vType->length = length;
780 37879 : vType->parametersSet |= VTYPEPARS_LENGTH_SET;
781 : }
782 : }
783 62527 : if (attrs.hasAttribute(SUMO_ATTR_MINGAP)) {
784 35851 : bool ok = true;
785 35851 : const double minGap = attrs.get<double>(SUMO_ATTR_MINGAP, vType->id.c_str(), ok);
786 35851 : if (!ok) {
787 0 : return handleVehicleTypeError(hardFail, vType);
788 35851 : } else if (minGap < 0) {
789 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MINGAP) + " must be equal or greater than 0");
790 : } else {
791 35851 : vType->minGap = minGap;
792 35851 : vType->parametersSet |= VTYPEPARS_MINGAP_SET;
793 : }
794 : }
795 62527 : if (attrs.hasAttribute(SUMO_ATTR_MAXSPEED)) {
796 37085 : bool ok = true;
797 37085 : const double maxSpeed = attrs.get<double>(SUMO_ATTR_MAXSPEED, vType->id.c_str(), ok);
798 37085 : if (!ok) {
799 0 : return handleVehicleTypeError(hardFail, vType);
800 37085 : } else if (maxSpeed <= 0) {
801 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MAXSPEED) + " must be greater than 0");
802 : } else {
803 37085 : vType->maxSpeed = maxSpeed;
804 37085 : vType->parametersSet |= VTYPEPARS_MAXSPEED_SET;
805 : }
806 : }
807 62527 : if (attrs.hasAttribute(SUMO_ATTR_DESIRED_MAXSPEED)) {
808 88 : bool ok = true;
809 88 : const double desiredMaxSpeed = attrs.get<double>(SUMO_ATTR_DESIRED_MAXSPEED, vType->id.c_str(), ok);
810 88 : if (!ok) {
811 0 : return handleVehicleTypeError(hardFail, vType);
812 88 : } else if (desiredMaxSpeed <= 0) {
813 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_DESIRED_MAXSPEED) + " must be greater than 0");
814 : } else {
815 88 : vType->desiredMaxSpeed = desiredMaxSpeed;
816 88 : vType->parametersSet |= VTYPEPARS_DESIRED_MAXSPEED_SET;
817 : }
818 62439 : } else if (attrs.hasAttribute(SUMO_ATTR_MAXSPEED)) {
819 37064 : if (vClass == SVC_PEDESTRIAN) {
820 : // backward compatibility because pedestrian maxSpeed was subject to speedFactor up to 1.14.1
821 25878 : vType->desiredMaxSpeed = vType->maxSpeed;;
822 77630 : vType->maxSpeed = MAX2(vType->maxSpeed, SUMOVTypeParameter::VClassDefaultValues(vClass).maxSpeed);
823 11186 : } 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 62527 : if (attrs.hasAttribute(SUMO_ATTR_SPEEDFACTOR)) {
830 2451 : bool ok = true;
831 2451 : vType->speedFactor.parse(attrs.get<std::string>(SUMO_ATTR_SPEEDFACTOR, vType->id.c_str(), ok), hardFail);
832 2451 : if (!ok) {
833 0 : return handleVehicleTypeError(hardFail, vType);
834 : } else {
835 2451 : vType->parametersSet |= VTYPEPARS_SPEEDFACTOR_SET;
836 : }
837 : }
838 62527 : if (attrs.hasAttribute(SUMO_ATTR_SPEEDDEV)) {
839 2606 : bool ok = true;
840 2606 : const double speedDev = attrs.get<double>(SUMO_ATTR_SPEEDDEV, vType->id.c_str(), ok);
841 2606 : if (!ok) {
842 0 : return handleVehicleTypeError(hardFail, vType);
843 2606 : } else if (speedDev < 0) {
844 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_SPEEDDEV) + " must be equal or greater than 0");
845 : } else {
846 2606 : vType->speedFactor.setParameter(1, speedDev);
847 2606 : vType->parametersSet |= VTYPEPARS_SPEEDFACTOR_SET;
848 : }
849 : }
850 : // validate speed distribution
851 62527 : const std::string& error = vType->speedFactor.isValid();
852 62527 : if (error != "") {
853 14 : return handleVehicleTypeError(hardFail, vType, "Invalid speed distribution when parsing vType '" + vType->id + "' (" + error + ")");
854 : }
855 62520 : if (attrs.hasAttribute(SUMO_ATTR_ACTIONSTEPLENGTH)) {
856 226 : bool ok = true;
857 226 : const double actionStepLengthSecs = attrs.get<double>(SUMO_ATTR_ACTIONSTEPLENGTH, vType->id.c_str(), ok);
858 226 : if (!ok) {
859 0 : return handleVehicleTypeError(hardFail, vType);
860 : } else {
861 : // processActionStepLength(...) function includes warnings
862 226 : vType->actionStepLength = processActionStepLength(actionStepLengthSecs);
863 226 : vType->parametersSet |= VTYPEPARS_ACTIONSTEPLENGTH_SET;
864 : }
865 : }
866 62520 : if (attrs.hasAttribute(SUMO_ATTR_EMISSIONCLASS)) {
867 1849 : bool ok = true;
868 1849 : 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 1849 : vType->emissionClass = PollutantsInterface::getClassByName(parsedEmissionClass);
872 1849 : 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 62520 : if (attrs.hasAttribute(SUMO_ATTR_MASS)) {
878 304 : bool ok = true;
879 304 : const double mass = attrs.get<double>(SUMO_ATTR_MASS, vType->id.c_str(), ok);
880 304 : if (!ok) {
881 0 : return handleVehicleTypeError(hardFail, vType);
882 304 : } else if (mass < 0) {
883 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_MASS) + " must be equal or greater than 0");
884 : } else {
885 304 : vType->mass = mass;
886 304 : vType->parametersSet |= VTYPEPARS_MASS_SET;
887 : }
888 : }
889 62520 : if (attrs.hasAttribute(SUMO_ATTR_IMPATIENCE)) {
890 243 : bool ok = true;
891 243 : const std::string impatienceStr = attrs.get<std::string>(SUMO_ATTR_IMPATIENCE, vType->id.c_str(), ok);
892 243 : if (!ok) {
893 0 : return handleVehicleTypeError(hardFail, vType);
894 243 : } else if (impatienceStr == "off") {
895 12 : vType->impatience = -std::numeric_limits<double>::max();
896 : } else {
897 231 : const double impatienceDouble = attrs.get<double>(SUMO_ATTR_IMPATIENCE, vType->id.c_str(), ok);
898 231 : if (!ok) {
899 0 : return handleVehicleTypeError(hardFail, vType);
900 : } else {
901 231 : vType->impatience = impatienceDouble;
902 231 : vType->parametersSet |= VTYPEPARS_IMPATIENCE_SET;
903 : }
904 : }
905 : }
906 62520 : if (attrs.hasAttribute(SUMO_ATTR_WIDTH)) {
907 26755 : bool ok = true;
908 26755 : const double width = attrs.get<double>(SUMO_ATTR_WIDTH, vType->id.c_str(), ok);
909 26755 : if (!ok) {
910 0 : return handleVehicleTypeError(hardFail, vType);
911 26755 : } else if (width <= 0) {
912 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_WIDTH) + " must be greater than 0");
913 : } else {
914 26755 : vType->width = width;
915 26755 : vType->parametersSet |= VTYPEPARS_WIDTH_SET;
916 26755 : if (vClass == SVC_PEDESTRIAN
917 52862 : && OptionsCont::getOptions().exists("pedestrian.striping.stripe-width")
918 78969 : && OptionsCont::getOptions().getString("pedestrian.model") == "striping"
919 82152 : && 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 62520 : 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 62520 : if (attrs.hasAttribute(SUMO_ATTR_GUISHAPE)) {
937 27193 : vType->shape = parseGuiShape(attrs, vType->id);
938 27193 : if (vType->shape != SUMOVehicleShape::UNKNOWN) {
939 27193 : vType->parametersSet |= VTYPEPARS_SHAPE_SET;
940 : }
941 : }
942 62520 : 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 62520 : if (attrs.hasAttribute(SUMO_ATTR_IMGFILE)) {
953 28 : bool ok = true;
954 28 : std::string imgFile = attrs.get<std::string>(SUMO_ATTR_IMGFILE, vType->id.c_str(), ok);
955 28 : if (!ok) {
956 0 : return handleVehicleTypeError(hardFail, vType);
957 : } else {
958 : // check relative path
959 28 : if ((imgFile != "") && !FileHelpers::isAbsolute(imgFile)) {
960 56 : imgFile = FileHelpers::getConfigurationRelative(file, imgFile);
961 : }
962 28 : vType->imgFile = imgFile;
963 28 : vType->parametersSet |= VTYPEPARS_IMGFILE_SET;
964 : }
965 : }
966 62520 : if (attrs.hasAttribute(SUMO_ATTR_COLOR)) {
967 22781 : bool ok = true;
968 22781 : const RGBColor color = attrs.get<RGBColor>(SUMO_ATTR_COLOR, vType->id.c_str(), ok);
969 22781 : if (!ok) {
970 8 : return handleVehicleTypeError(hardFail, vType);
971 : } else {
972 22773 : vType->color = color;
973 22773 : vType->parametersSet |= VTYPEPARS_COLOR_SET;
974 : }
975 : } else {
976 39739 : vType->color = RGBColor::YELLOW;
977 : }
978 62512 : if (attrs.hasAttribute(SUMO_ATTR_PROB)) {
979 615 : bool ok = true;
980 615 : const double defaultProbability = attrs.get<double>(SUMO_ATTR_PROB, vType->id.c_str(), ok);
981 615 : if (!ok) {
982 0 : return handleVehicleTypeError(hardFail, vType);
983 615 : } else if (defaultProbability < 0) {
984 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_PROB) + " must be equal or greater than 0");
985 : } else {
986 615 : vType->defaultProbability = defaultProbability;
987 615 : vType->parametersSet |= VTYPEPARS_PROBABILITY_SET;
988 : }
989 : }
990 62512 : 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 62507 : if (attrs.hasAttribute(SUMO_ATTR_CAR_FOLLOW_MODEL)) {
1007 1289 : bool ok = true;
1008 1289 : const std::string cfmValue = attrs.get<std::string>(SUMO_ATTR_CAR_FOLLOW_MODEL, vType->id.c_str(), ok);
1009 1289 : if (!ok) {
1010 0 : return handleVehicleTypeError(hardFail, vType);
1011 : } else if (SUMOXMLDefinitions::CarFollowModels.hasString(cfmValue)) {
1012 1283 : vType->cfModel = SUMOXMLDefinitions::CarFollowModels.get(cfmValue);
1013 1283 : 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 62501 : if (attrs.hasAttribute(SUMO_ATTR_PERSON_CAPACITY)) {
1019 402 : bool ok = true;
1020 402 : const int personCapacity = attrs.get<int>(SUMO_ATTR_PERSON_CAPACITY, vType->id.c_str(), ok);
1021 402 : if (!ok) {
1022 0 : return handleVehicleTypeError(hardFail, vType);
1023 402 : } 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 402 : vType->personCapacity = personCapacity;
1027 402 : vType->parametersSet |= VTYPEPARS_PERSON_CAPACITY;
1028 : }
1029 : }
1030 62501 : if (attrs.hasAttribute(SUMO_ATTR_CONTAINER_CAPACITY)) {
1031 382 : bool ok = true;
1032 382 : const int containerCapacity = attrs.get<int>(SUMO_ATTR_CONTAINER_CAPACITY, vType->id.c_str(), ok);
1033 382 : if (!ok) {
1034 0 : return handleVehicleTypeError(hardFail, vType);
1035 382 : } 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 382 : vType->containerCapacity = containerCapacity;
1039 382 : vType->parametersSet |= VTYPEPARS_CONTAINER_CAPACITY;
1040 : }
1041 : }
1042 62501 : 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 62501 : if (attrs.hasAttribute(SUMO_ATTR_LOADING_DURATION)) {
1055 72 : bool ok = true;
1056 72 : const SUMOTime loadingDuration = attrs.getSUMOTimeReporting(SUMO_ATTR_LOADING_DURATION, vType->id.c_str(), ok);
1057 72 : if (!ok) {
1058 0 : return handleVehicleTypeError(hardFail, vType);
1059 72 : } 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 72 : vType->loadingDuration = loadingDuration;
1063 72 : vType->parametersSet |= VTYPEPARS_LOADING_DURATION;
1064 : }
1065 : }
1066 62501 : if (attrs.hasAttribute(SUMO_ATTR_SCALE)) {
1067 40 : bool ok = true;
1068 40 : const double scale = attrs.get<double>(SUMO_ATTR_SCALE, id.c_str(), ok);
1069 40 : if (!ok) {
1070 0 : return handleVehicleTypeError(hardFail, vType);
1071 40 : } else if (scale < 0) {
1072 0 : return handleVehicleTypeError(hardFail, vType, toString(SUMO_ATTR_SCALE) + " may be not be negative");
1073 : } else {
1074 40 : vType->scale = scale;
1075 40 : vType->parametersSet |= VTYPEPARS_SCALE_SET;
1076 : }
1077 : }
1078 62501 : 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 62501 : 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 62501 : 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 62501 : 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 62501 : 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 62501 : if (attrs.hasAttribute(SUMO_ATTR_MINGAP_LAT)) {
1133 577 : bool ok = true;
1134 577 : const double minGapLat = attrs.get<double>(SUMO_ATTR_MINGAP_LAT, vType->id.c_str(), ok);
1135 577 : if (!ok) {
1136 0 : return handleVehicleTypeError(hardFail, vType);
1137 577 : } 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 577 : vType->minGapLat = minGapLat;
1141 577 : vType->parametersSet |= VTYPEPARS_MINGAP_LAT_SET;
1142 : }
1143 : }
1144 62501 : if (attrs.hasAttribute(SUMO_ATTR_LATALIGNMENT)) {
1145 1716 : bool ok = true;
1146 1716 : const std::string alignS = attrs.get<std::string>(SUMO_ATTR_LATALIGNMENT, vType->id.c_str(), ok);
1147 1716 : if (!ok) {
1148 0 : return handleVehicleTypeError(hardFail, vType);
1149 : } else {
1150 : double lao;
1151 : LatAlignmentDefinition lad;
1152 1716 : if (SUMOVTypeParameter::parseLatAlignment(alignS, lao, lad)) {
1153 1716 : vType->latAlignmentOffset = lao;
1154 1716 : vType->latAlignmentProcedure = lad;
1155 1716 : 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 62501 : 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 62501 : if (attrs.hasAttribute(SUMO_ATTR_PARKING_BADGES)) {
1173 12 : bool ok = true;
1174 12 : std::vector<std::string> badges = attrs.get<std::vector<std::string>>(SUMO_ATTR_PARKING_BADGES, vType->id.c_str(), ok);
1175 12 : if (!ok) {
1176 0 : return handleVehicleTypeError(hardFail, vType);
1177 : } else {
1178 12 : vType->parametersSet |= VTYPEPARS_PARKING_BADGES_SET;
1179 12 : vType->parkingBadges = badges;
1180 : }
1181 12 : }
1182 : // try to parse Car Following Model params
1183 62501 : 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 62501 : 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 62501 : 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 62517 : SUMOVehicleParserHelper::parseCFMParams(SUMOVTypeParameter* into, const SumoXMLTag element, const SUMOSAXAttributes& attrs, const bool nestedCFM) {
1240 62517 : const CFAttrMap& allowedCFM = getAllowedCFModelAttrs();
1241 : CFAttrMap::const_iterator cf_it = allowedCFM.find(element);
1242 : // check if given CFM is allowed
1243 62517 : 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 62517 : if (nestedCFM) {
1253 16 : into->cfModel = cf_it->first;
1254 16 : into->parametersSet |= VTYPEPARS_CAR_FOLLOW_MODEL;
1255 : }
1256 : // set CFM values
1257 821438 : for (const auto& it : cf_it->second) {
1258 758921 : if (attrs.hasAttribute(it)) {
1259 : // first obtain CFM attribute in string format
1260 45609 : bool ok = true;
1261 45609 : std::string parsedCFMAttribute = attrs.get<std::string>(it, into->id.c_str(), ok);
1262 : // check CFM Attribute
1263 45609 : if (!ok) {
1264 : return false;
1265 45609 : } else if (it == SUMO_ATTR_TRAIN_TYPE) {
1266 : // check if train value is valid
1267 235 : 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 235 : into->cfParameter[it] = parsedCFMAttribute;
1273 45374 : } else if (it == SUMO_ATTR_SPEED_TABLE || it == SUMO_ATTR_TRACTION_TABLE || it == SUMO_ATTR_RESISTANCE_TABLE) {
1274 36 : into->cfParameter[it] = parsedCFMAttribute;
1275 45338 : } 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 45332 : } else if (it == SUMO_ATTR_MAXACCEL_PROFILE || it == SUMO_ATTR_DESACCEL_PROFILE) {
1292 24 : if (validProfile(into, parsedCFMAttribute, it)) {
1293 12 : into->cfParameter[it] = parsedCFMAttribute;
1294 : } else {
1295 0 : WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Cannot be parsed as a vector of <speed accel> pairs"), toString(it));
1296 0 : return false;
1297 : }
1298 : } else {
1299 : // declare a double in wich save CFM float attribute
1300 : double CFMDoubleAttribute = -1;
1301 : try {
1302 : // obtain CFM attribute in double format
1303 45320 : CFMDoubleAttribute = StringUtils::toDouble(parsedCFMAttribute);
1304 0 : } catch (...) {
1305 0 : WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Cannot be parsed to float"), toString(it));
1306 : return false;
1307 0 : }
1308 : // check attributes of type "positiveFloatType" (> 0)
1309 45320 : switch (it) {
1310 21008 : case SUMO_ATTR_ACCEL:
1311 : case SUMO_ATTR_DECEL:
1312 : case SUMO_ATTR_APPARENTDECEL:
1313 : case SUMO_ATTR_EMERGENCYDECEL:
1314 : case SUMO_ATTR_TAU:
1315 21008 : if (CFMDoubleAttribute <= 0) {
1316 0 : WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Must be greater than 0"), toString(it));
1317 0 : return false;
1318 : }
1319 : break;
1320 : default:
1321 : break;
1322 : }
1323 : // check attributes restricted to [0-1]
1324 45320 : switch (it) {
1325 23704 : case SUMO_ATTR_SIGMA:
1326 23704 : if ((CFMDoubleAttribute < 0) || (CFMDoubleAttribute > 1)) {
1327 0 : WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. Only values between [0-1] are allowed"), toString(it));
1328 0 : return false;
1329 : }
1330 : break;
1331 : default:
1332 : break;
1333 : }
1334 : // add parsedCFMAttribute to cfParameter
1335 45320 : into->cfParameter[it] = parsedCFMAttribute;
1336 : }
1337 : }
1338 : }
1339 : // all CFM successfully parsed, then return true
1340 : return true;
1341 : }
1342 :
1343 :
1344 : const SUMOVehicleParserHelper::CFAttrMap&
1345 62517 : SUMOVehicleParserHelper::getAllowedCFModelAttrs() {
1346 : // init on first use
1347 62517 : if (allowedCFModelAttrs.size() == 0) {
1348 : std::set<SumoXMLAttr> genericParams;
1349 25969 : genericParams.insert(SUMO_ATTR_TAU);
1350 25969 : genericParams.insert(SUMO_ATTR_ACCEL);
1351 25969 : genericParams.insert(SUMO_ATTR_DECEL);
1352 25969 : genericParams.insert(SUMO_ATTR_APPARENTDECEL);
1353 25969 : genericParams.insert(SUMO_ATTR_EMERGENCYDECEL);
1354 25969 : genericParams.insert(SUMO_ATTR_SPEED_TABLE);
1355 25969 : genericParams.insert(SUMO_ATTR_MAXACCEL_PROFILE);
1356 25969 : genericParams.insert(SUMO_ATTR_DESACCEL_PROFILE);
1357 25969 : genericParams.insert(SUMO_ATTR_COLLISION_MINGAP_FACTOR);
1358 25969 : genericParams.insert(SUMO_ATTR_STARTUP_DELAY);
1359 : // Krauss
1360 : std::set<SumoXMLAttr> kraussParams(genericParams);
1361 25969 : kraussParams.insert(SUMO_ATTR_SIGMA);
1362 25969 : kraussParams.insert(SUMO_ATTR_SIGMA_STEP);
1363 25969 : allowedCFModelAttrs[SUMO_TAG_CF_KRAUSS] = kraussParams;
1364 25969 : allowedCFModelAttrs[SUMO_TAG_CF_KRAUSS_ORIG1] = kraussParams;
1365 51938 : allowedCFModelAttrs[SUMO_TAG_CF_KRAUSS_PLUS_SLOPE] = kraussParams;
1366 : std::set<SumoXMLAttr> allParams(kraussParams);
1367 : // KraussX
1368 : std::set<SumoXMLAttr> kraussXParams(kraussParams);
1369 25969 : kraussXParams.insert(SUMO_ATTR_TMP1);
1370 25969 : kraussXParams.insert(SUMO_ATTR_TMP2);
1371 25969 : kraussXParams.insert(SUMO_ATTR_TMP3);
1372 25969 : kraussXParams.insert(SUMO_ATTR_TMP4);
1373 25969 : kraussXParams.insert(SUMO_ATTR_TMP5);
1374 51938 : allowedCFModelAttrs[SUMO_TAG_CF_KRAUSSX] = kraussXParams;
1375 25969 : allParams.insert(kraussXParams.begin(), kraussXParams.end());
1376 : // SmartSK
1377 : std::set<SumoXMLAttr> smartSKParams(genericParams);
1378 25969 : smartSKParams.insert(SUMO_ATTR_SIGMA);
1379 25969 : smartSKParams.insert(SUMO_ATTR_TMP1);
1380 25969 : smartSKParams.insert(SUMO_ATTR_TMP2);
1381 25969 : smartSKParams.insert(SUMO_ATTR_TMP3);
1382 25969 : smartSKParams.insert(SUMO_ATTR_TMP4);
1383 25969 : smartSKParams.insert(SUMO_ATTR_TMP5);
1384 51938 : allowedCFModelAttrs[SUMO_TAG_CF_SMART_SK] = smartSKParams;
1385 25969 : allParams.insert(smartSKParams.begin(), smartSKParams.end());
1386 : // Daniel
1387 : std::set<SumoXMLAttr> daniel1Params(genericParams);
1388 25969 : daniel1Params.insert(SUMO_ATTR_SIGMA);
1389 25969 : daniel1Params.insert(SUMO_ATTR_TMP1);
1390 25969 : daniel1Params.insert(SUMO_ATTR_TMP2);
1391 25969 : daniel1Params.insert(SUMO_ATTR_TMP3);
1392 25969 : daniel1Params.insert(SUMO_ATTR_TMP4);
1393 25969 : daniel1Params.insert(SUMO_ATTR_TMP5);
1394 51938 : allowedCFModelAttrs[SUMO_TAG_CF_DANIEL1] = daniel1Params;
1395 25969 : allParams.insert(daniel1Params.begin(), daniel1Params.end());
1396 : // Peter Wagner
1397 : std::set<SumoXMLAttr> pwagParams(genericParams);
1398 25969 : pwagParams.insert(SUMO_ATTR_SIGMA);
1399 25969 : pwagParams.insert(SUMO_ATTR_CF_PWAGNER2009_TAULAST);
1400 25969 : pwagParams.insert(SUMO_ATTR_CF_PWAGNER2009_APPROB);
1401 51938 : allowedCFModelAttrs[SUMO_TAG_CF_PWAGNER2009] = pwagParams;
1402 25969 : allParams.insert(pwagParams.begin(), pwagParams.end());
1403 : // IDM params
1404 : std::set<SumoXMLAttr> idmParams(genericParams);
1405 25969 : idmParams.insert(SUMO_ATTR_CF_IDM_DELTA);
1406 25969 : idmParams.insert(SUMO_ATTR_CF_IDM_STEPPING);
1407 51938 : allowedCFModelAttrs[SUMO_TAG_CF_IDM] = idmParams;
1408 25969 : allParams.insert(idmParams.begin(), idmParams.end());
1409 : // EIDM
1410 : std::set<SumoXMLAttr> eidmParams(genericParams);
1411 25969 : eidmParams.insert(SUMO_ATTR_CF_IDM_DELTA);
1412 25969 : eidmParams.insert(SUMO_ATTR_CF_IDM_STEPPING);
1413 25969 : eidmParams.insert(SUMO_ATTR_CF_EIDM_T_LOOK_AHEAD);
1414 25969 : eidmParams.insert(SUMO_ATTR_CF_EIDM_T_PERSISTENCE_DRIVE);
1415 25969 : eidmParams.insert(SUMO_ATTR_CF_EIDM_T_REACTION);
1416 25969 : eidmParams.insert(SUMO_ATTR_CF_EIDM_T_PERSISTENCE_ESTIMATE);
1417 25969 : eidmParams.insert(SUMO_ATTR_CF_EIDM_C_COOLNESS);
1418 25969 : eidmParams.insert(SUMO_ATTR_CF_EIDM_SIG_LEADER);
1419 25969 : eidmParams.insert(SUMO_ATTR_CF_EIDM_SIG_GAP);
1420 25969 : eidmParams.insert(SUMO_ATTR_CF_EIDM_SIG_ERROR);
1421 25969 : eidmParams.insert(SUMO_ATTR_CF_EIDM_JERK_MAX);
1422 25969 : eidmParams.insert(SUMO_ATTR_CF_EIDM_EPSILON_ACC);
1423 25969 : eidmParams.insert(SUMO_ATTR_CF_EIDM_T_ACC_MAX);
1424 25969 : eidmParams.insert(SUMO_ATTR_CF_EIDM_M_FLATNESS);
1425 25969 : eidmParams.insert(SUMO_ATTR_CF_EIDM_M_BEGIN);
1426 25969 : eidmParams.insert(SUMO_ATTR_CF_EIDM_USEVEHDYNAMICS);
1427 25969 : eidmParams.insert(SUMO_ATTR_CF_EIDM_MAX_VEH_PREVIEW);
1428 51938 : allowedCFModelAttrs[SUMO_TAG_CF_EIDM] = eidmParams;
1429 25969 : allParams.insert(eidmParams.begin(), eidmParams.end());
1430 : // IDMM
1431 : std::set<SumoXMLAttr> idmmParams(genericParams);
1432 25969 : idmmParams.insert(SUMO_ATTR_CF_IDMM_ADAPT_FACTOR);
1433 25969 : idmmParams.insert(SUMO_ATTR_CF_IDMM_ADAPT_TIME);
1434 25969 : idmmParams.insert(SUMO_ATTR_CF_IDM_STEPPING);
1435 51938 : allowedCFModelAttrs[SUMO_TAG_CF_IDMM] = idmmParams;
1436 25969 : allParams.insert(idmmParams.begin(), idmmParams.end());
1437 : // Bieker
1438 : std::set<SumoXMLAttr> bkernerParams(genericParams);
1439 25969 : bkernerParams.insert(SUMO_ATTR_K);
1440 25969 : bkernerParams.insert(SUMO_ATTR_CF_KERNER_PHI);
1441 51938 : allowedCFModelAttrs[SUMO_TAG_CF_BKERNER] = bkernerParams;
1442 25969 : allParams.insert(bkernerParams.begin(), bkernerParams.end());
1443 : // Wiedemann
1444 : std::set<SumoXMLAttr> wiedemannParams(genericParams);
1445 25969 : wiedemannParams.insert(SUMO_ATTR_CF_WIEDEMANN_SECURITY);
1446 25969 : wiedemannParams.insert(SUMO_ATTR_CF_WIEDEMANN_ESTIMATION);
1447 51938 : allowedCFModelAttrs[SUMO_TAG_CF_WIEDEMANN] = wiedemannParams;
1448 25969 : allParams.insert(wiedemannParams.begin(), wiedemannParams.end());
1449 : // W99
1450 : std::set<SumoXMLAttr> w99Params(genericParams);
1451 25969 : w99Params.insert(SUMO_ATTR_CF_W99_CC1);
1452 25969 : w99Params.insert(SUMO_ATTR_CF_W99_CC2);
1453 25969 : w99Params.insert(SUMO_ATTR_CF_W99_CC3);
1454 25969 : w99Params.insert(SUMO_ATTR_CF_W99_CC4);
1455 25969 : w99Params.insert(SUMO_ATTR_CF_W99_CC5);
1456 25969 : w99Params.insert(SUMO_ATTR_CF_W99_CC6);
1457 25969 : w99Params.insert(SUMO_ATTR_CF_W99_CC7);
1458 25969 : w99Params.insert(SUMO_ATTR_CF_W99_CC8);
1459 25969 : w99Params.insert(SUMO_ATTR_CF_W99_CC9);
1460 51938 : allowedCFModelAttrs[SUMO_TAG_CF_W99] = w99Params;
1461 25969 : allParams.insert(w99Params.begin(), w99Params.end());
1462 : // Rail
1463 : std::set<SumoXMLAttr> railParams(genericParams);
1464 25969 : railParams.insert(SUMO_ATTR_TRAIN_TYPE);
1465 25969 : railParams.insert(SUMO_ATTR_TRACTION_TABLE);
1466 25969 : railParams.insert(SUMO_ATTR_RESISTANCE_TABLE);
1467 25969 : railParams.insert(SUMO_ATTR_MASSFACTOR);
1468 25969 : railParams.insert(SUMO_ATTR_MAXPOWER);
1469 25969 : railParams.insert(SUMO_ATTR_MAXTRACTION);
1470 25969 : railParams.insert(SUMO_ATTR_RESISTANCE_COEFFICIENT_CONSTANT);
1471 25969 : railParams.insert(SUMO_ATTR_RESISTANCE_COEFFICIENT_LINEAR);
1472 25969 : railParams.insert(SUMO_ATTR_RESISTANCE_COEFFICIENT_QUADRATIC);
1473 51938 : allowedCFModelAttrs[SUMO_TAG_CF_RAIL] = railParams;
1474 25969 : allParams.insert(railParams.begin(), railParams.end());
1475 : // ACC
1476 : std::set<SumoXMLAttr> ACCParams(genericParams);
1477 25969 : ACCParams.insert(SUMO_ATTR_SC_GAIN);
1478 25969 : ACCParams.insert(SUMO_ATTR_GCC_GAIN_SPEED);
1479 25969 : ACCParams.insert(SUMO_ATTR_GCC_GAIN_SPACE);
1480 25969 : ACCParams.insert(SUMO_ATTR_GC_GAIN_SPEED);
1481 25969 : ACCParams.insert(SUMO_ATTR_GC_GAIN_SPACE);
1482 25969 : ACCParams.insert(SUMO_ATTR_CA_GAIN_SPEED);
1483 25969 : ACCParams.insert(SUMO_ATTR_CA_GAIN_SPACE);
1484 25969 : ACCParams.insert(SUMO_ATTR_CA_OVERRIDE);
1485 25969 : ACCParams.insert(SUMO_ATTR_APPLYDRIVERSTATE);
1486 51938 : allowedCFModelAttrs[SUMO_TAG_CF_ACC] = ACCParams;
1487 25969 : allParams.insert(ACCParams.begin(), ACCParams.end());
1488 : // CACC
1489 : std::set<SumoXMLAttr> CACCParams(genericParams);
1490 25969 : CACCParams.insert(SUMO_ATTR_SC_GAIN_CACC);
1491 25969 : CACCParams.insert(SUMO_ATTR_GCC_GAIN_GAP_CACC);
1492 25969 : CACCParams.insert(SUMO_ATTR_GCC_GAIN_GAP_DOT_CACC);
1493 25969 : CACCParams.insert(SUMO_ATTR_GC_GAIN_GAP_CACC);
1494 25969 : CACCParams.insert(SUMO_ATTR_GC_GAIN_GAP_DOT_CACC);
1495 25969 : CACCParams.insert(SUMO_ATTR_CA_GAIN_GAP_CACC);
1496 25969 : CACCParams.insert(SUMO_ATTR_CA_GAIN_GAP_DOT_CACC);
1497 25969 : CACCParams.insert(SUMO_ATTR_GCC_GAIN_SPEED);
1498 25969 : CACCParams.insert(SUMO_ATTR_GCC_GAIN_SPACE);
1499 25969 : CACCParams.insert(SUMO_ATTR_GC_GAIN_SPEED);
1500 25969 : CACCParams.insert(SUMO_ATTR_GC_GAIN_SPACE);
1501 25969 : CACCParams.insert(SUMO_ATTR_CA_GAIN_SPEED);
1502 25969 : CACCParams.insert(SUMO_ATTR_CA_GAIN_SPACE);
1503 25969 : CACCParams.insert(SUMO_ATTR_CA_OVERRIDE);
1504 25969 : CACCParams.insert(SUMO_ATTR_HEADWAY_TIME_CACC_TO_ACC);
1505 25969 : CACCParams.insert(SUMO_ATTR_APPLYDRIVERSTATE);
1506 25969 : CACCParams.insert(SUMO_ATTR_SC_MIN_GAP);
1507 51938 : allowedCFModelAttrs[SUMO_TAG_CF_CACC] = CACCParams;
1508 25969 : allParams.insert(CACCParams.begin(), CACCParams.end());
1509 : // CC
1510 : std::set<SumoXMLAttr> ccParams(genericParams);
1511 25969 : ccParams.insert(SUMO_ATTR_CF_CC_C1);
1512 25969 : ccParams.insert(SUMO_ATTR_CF_CC_CCDECEL);
1513 25969 : ccParams.insert(SUMO_ATTR_CF_CC_CONSTSPACING);
1514 25969 : ccParams.insert(SUMO_ATTR_CF_CC_KP);
1515 25969 : ccParams.insert(SUMO_ATTR_CF_CC_LAMBDA);
1516 25969 : ccParams.insert(SUMO_ATTR_CF_CC_OMEGAN);
1517 25969 : ccParams.insert(SUMO_ATTR_CF_CC_TAU);
1518 25969 : ccParams.insert(SUMO_ATTR_CF_CC_XI);
1519 25969 : ccParams.insert(SUMO_ATTR_CF_CC_LANES_COUNT);
1520 25969 : ccParams.insert(SUMO_ATTR_CF_CC_CCACCEL);
1521 25969 : ccParams.insert(SUMO_ATTR_CF_CC_PLOEG_KP);
1522 25969 : ccParams.insert(SUMO_ATTR_CF_CC_PLOEG_KD);
1523 25969 : ccParams.insert(SUMO_ATTR_CF_CC_PLOEG_H);
1524 25969 : ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_KA);
1525 25969 : ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_KV);
1526 25969 : ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_KP);
1527 25969 : ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_D);
1528 25969 : ccParams.insert(SUMO_ATTR_CF_CC_FLATBED_H);
1529 51938 : allowedCFModelAttrs[SUMO_TAG_CF_CC] = ccParams;
1530 25969 : allParams.insert(ccParams.begin(), ccParams.end());
1531 : // last element
1532 51938 : allowedCFModelAttrs[SUMO_TAG_NOTHING] = allParams;
1533 : }
1534 62517 : return allowedCFModelAttrs;
1535 : }
1536 :
1537 :
1538 : bool
1539 62501 : SUMOVehicleParserHelper::parseLCParams(SUMOVTypeParameter* into, LaneChangeModel model, const SUMOSAXAttributes& attrs) {
1540 62501 : if (allowedLCModelAttrs.size() == 0) {
1541 : // lc2013
1542 : std::set<SumoXMLAttr> lc2013Params;
1543 25969 : lc2013Params.insert(SUMO_ATTR_LCA_STRATEGIC_PARAM);
1544 25969 : lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_PARAM);
1545 25969 : lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_PARAM);
1546 25969 : lc2013Params.insert(SUMO_ATTR_LCA_KEEPRIGHT_PARAM);
1547 25969 : lc2013Params.insert(SUMO_ATTR_LCA_OPPOSITE_PARAM);
1548 25969 : lc2013Params.insert(SUMO_ATTR_LCA_LOOKAHEADLEFT);
1549 25969 : lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAINRIGHT);
1550 25969 : lc2013Params.insert(SUMO_ATTR_LCA_MAXSPEEDLATSTANDING);
1551 25969 : lc2013Params.insert(SUMO_ATTR_LCA_MAXSPEEDLATFACTOR);
1552 25969 : lc2013Params.insert(SUMO_ATTR_LCA_MAXDISTLATSTANDING);
1553 25969 : lc2013Params.insert(SUMO_ATTR_LCA_ASSERTIVE);
1554 25969 : lc2013Params.insert(SUMO_ATTR_LCA_STRATEGIC_LOOKAHEAD);
1555 25969 : lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD);
1556 25969 : lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_REMAIN_TIME);
1557 25969 : lc2013Params.insert(SUMO_ATTR_LCA_SPEEDGAIN_URGENCY);
1558 25969 : lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_ROUNDABOUT);
1559 25969 : lc2013Params.insert(SUMO_ATTR_LCA_COOPERATIVE_SPEED);
1560 25969 : lc2013Params.insert(SUMO_ATTR_LCA_OVERTAKE_RIGHT);
1561 25969 : lc2013Params.insert(SUMO_ATTR_LCA_SIGMA);
1562 25969 : lc2013Params.insert(SUMO_ATTR_LCA_KEEPRIGHT_ACCEPTANCE_TIME);
1563 25969 : lc2013Params.insert(SUMO_ATTR_LCA_OVERTAKE_DELTASPEED_FACTOR);
1564 25969 : lc2013Params.insert(SUMO_ATTR_LCA_CONTRIGHT);
1565 25969 : lc2013Params.insert(SUMO_ATTR_LCA_EXPERIMENTAL1);
1566 51938 : allowedLCModelAttrs[LaneChangeModel::LC2013] = lc2013Params;
1567 : // sl2015 (extension of lc2013)
1568 : std::set<SumoXMLAttr> sl2015Params = lc2013Params;
1569 25969 : sl2015Params.insert(SUMO_ATTR_LCA_PUSHY);
1570 25969 : sl2015Params.insert(SUMO_ATTR_LCA_PUSHYGAP);
1571 25969 : sl2015Params.insert(SUMO_ATTR_LCA_SUBLANE_PARAM);
1572 25969 : sl2015Params.insert(SUMO_ATTR_LCA_IMPATIENCE);
1573 25969 : sl2015Params.insert(SUMO_ATTR_LCA_TIME_TO_IMPATIENCE);
1574 25969 : sl2015Params.insert(SUMO_ATTR_LCA_ACCEL_LAT);
1575 25969 : sl2015Params.insert(SUMO_ATTR_LCA_TURN_ALIGNMENT_DISTANCE);
1576 25969 : sl2015Params.insert(SUMO_ATTR_LCA_LANE_DISCIPLINE);
1577 51938 : allowedLCModelAttrs[LaneChangeModel::SL2015] = sl2015Params;
1578 : // DK2008
1579 : std::set<SumoXMLAttr> noParams;
1580 25969 : allowedLCModelAttrs[LaneChangeModel::DK2008] = noParams;
1581 : // default model may be either LC2013 or SL2015
1582 : // we allow both sets (sl2015 is a superset of lc2013Params)
1583 51938 : allowedLCModelAttrs[LaneChangeModel::DEFAULT] = sl2015Params;
1584 : }
1585 62501 : std::set<SumoXMLAttr> allowed = allowedLCModelAttrs[model];
1586 : // iterate over LCM attributes
1587 1999233 : for (const auto& it : allowed) {
1588 1936732 : if (attrs.hasAttribute(it)) {
1589 : // first obtain CFM attribute in string format
1590 4061 : bool ok = true;
1591 4061 : std::string parsedLCMAttribute = attrs.get<std::string>(it, into->id.c_str(), ok);
1592 4061 : if (!ok) {
1593 : return false;
1594 : }
1595 : // declare a double in wich save CFM attribute
1596 : double LCMAttribute = -1;
1597 : try {
1598 : // obtain CFM attribute in double format
1599 4061 : LCMAttribute = StringUtils::toDouble(parsedLCMAttribute);
1600 0 : } catch (...) {
1601 0 : WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Cannot be parsed to float"), toString(it));
1602 : return false;
1603 0 : }
1604 : // check attributes of type "nonNegativeFloatType" (>= 0)
1605 4061 : switch (it) {
1606 1448 : case SUMO_ATTR_LCA_PUSHYGAP:
1607 : case SUMO_ATTR_LCA_MAXSPEEDLATSTANDING:
1608 : case SUMO_ATTR_LCA_IMPATIENCE:
1609 : case SUMO_ATTR_LCA_OVERTAKE_RIGHT:
1610 : case SUMO_ATTR_LCA_ASSERTIVE:
1611 : case SUMO_ATTR_LCA_LOOKAHEADLEFT:
1612 : case SUMO_ATTR_LCA_SPEEDGAINRIGHT:
1613 : case SUMO_ATTR_LCA_TURN_ALIGNMENT_DISTANCE:
1614 : case SUMO_ATTR_LCA_TIME_TO_IMPATIENCE:
1615 : case SUMO_ATTR_LCA_LANE_DISCIPLINE:
1616 : case SUMO_ATTR_LCA_SIGMA:
1617 1448 : if (LCMAttribute < 0) {
1618 0 : WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Must be equal or greater than 0"), toString(it));
1619 0 : return false;
1620 : }
1621 : break;
1622 : default:
1623 : break;
1624 : }
1625 : // check attributes of type "positiveFloatType" (> 0)
1626 4061 : switch (it) {
1627 10 : case SUMO_ATTR_LCA_ACCEL_LAT:
1628 10 : if (LCMAttribute <= 0) {
1629 0 : WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Must be greater than 0"), toString(it));
1630 0 : return false;
1631 : }
1632 : break;
1633 : default:
1634 : break;
1635 : }
1636 : // check limits of attributes
1637 4061 : switch (it) {
1638 90 : case SUMO_ATTR_LCA_OVERTAKE_DELTASPEED_FACTOR:
1639 90 : if (LCMAttribute < -1 || LCMAttribute > 1) {
1640 0 : WRITE_ERRORF(TL("Invalid Lane-Change-Model Attribute %. Must be between -1 and 1"), toString(it));
1641 0 : return false;
1642 : }
1643 : break;
1644 : default:
1645 : break;
1646 : }
1647 : // add parsedLCMAttribute to cfParameter
1648 4061 : into->lcParameter[it] = parsedLCMAttribute;
1649 : }
1650 : }
1651 : // all LCM parsed ok, then return true
1652 : return true;
1653 : }
1654 :
1655 :
1656 : bool
1657 62501 : SUMOVehicleParserHelper::parseJMParams(SUMOVTypeParameter* into, const SUMOSAXAttributes& attrs) {
1658 1062517 : for (const auto& it : SUMOVTypeParameter::AllowedJMAttrs) {
1659 1000016 : if (attrs.hasAttribute(it)) {
1660 : // first obtain CFM attribute in string format
1661 1075 : bool ok = true;
1662 1075 : std::string parsedJMAttribute = attrs.get<std::string>(it, into->id.c_str(), ok);
1663 1075 : if (!ok) {
1664 : return false;
1665 : }
1666 : // declare a double in wich save CFM attribute
1667 : double JMAttribute = INVALID_DOUBLE;
1668 : try {
1669 : // obtain CFM attribute in double format
1670 1075 : JMAttribute = StringUtils::toDouble(parsedJMAttribute);
1671 0 : } catch (...) {
1672 0 : WRITE_ERRORF(TL("Invalid Junction-Model Attribute %. Cannot be parsed to float"), toString(it));
1673 : return false;
1674 0 : }
1675 : // now continue checking other properties (-1 is the default value)
1676 1075 : if (JMAttribute != INVALID_DOUBLE) {
1677 : // special case for sigma minor
1678 1075 : if (it == SUMO_ATTR_JM_SIGMA_MINOR) {
1679 : // check attributes sigma minor
1680 126 : if ((JMAttribute < 0) || (JMAttribute > 1)) {
1681 0 : WRITE_ERRORF(TL("Invalid Junction-Model Attribute %. Only values between [0-1] are allowed"), toString(it));
1682 0 : return false;
1683 : }
1684 949 : } else if (JMAttribute < 0
1685 25 : && it != SUMO_ATTR_JM_TIMEGAP_MINOR
1686 18 : && it != SUMO_ATTR_JM_EXTRA_GAP) {
1687 : // attributes with error value
1688 18 : if (JMAttribute != -1 || (it != SUMO_ATTR_JM_DRIVE_AFTER_YELLOW_TIME
1689 : && it != SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME
1690 18 : && it != SUMO_ATTR_JM_IGNORE_KEEPCLEAR_TIME)) {
1691 : // check attributes of type "nonNegativeFloatType" (>= 0)
1692 0 : WRITE_ERRORF(TL("Invalid Junction-Model Attribute %. Must be equal or greater than 0"), toString(it));
1693 0 : return false;
1694 : }
1695 : }
1696 : // add parsedJMAttribute to cfParameter
1697 1075 : into->jmParameter[it] = parsedJMAttribute;
1698 : }
1699 : }
1700 : }
1701 : // all JM parameters successfully parsed, then return true
1702 : return true;
1703 : }
1704 :
1705 :
1706 : SUMOVehicleClass
1707 36691 : SUMOVehicleParserHelper::parseVehicleClass(const SUMOSAXAttributes& attrs, const std::string& id) {
1708 : SUMOVehicleClass vclass = SVC_IGNORING;
1709 36691 : bool ok = true;
1710 36691 : std::string vclassS = attrs.getOpt<std::string>(SUMO_ATTR_VCLASS, id.c_str(), ok, "");
1711 36691 : if (vclassS == "") {
1712 : return vclass;
1713 : }
1714 : try {
1715 36667 : const SUMOVehicleClass result = getVehicleClassID(vclassS);
1716 36659 : const std::string& realName = SumoVehicleClassStrings.getString(result);
1717 36659 : if (realName != vclassS) {
1718 12 : WRITE_WARNING("The vehicle class '" + vclassS + "' for " + attrs.getObjectType() + " '" + id + "' is deprecated, use '" + realName + "' instead.");
1719 : }
1720 : return result;
1721 8 : } catch (...) {
1722 24 : WRITE_ERRORF(TL("The vehicle class '%' for % '%' is not known."), vclassS, attrs.getObjectType(), id);
1723 8 : }
1724 : return vclass;
1725 : }
1726 :
1727 :
1728 : SUMOVehicleShape
1729 27193 : SUMOVehicleParserHelper::parseGuiShape(const SUMOSAXAttributes& attrs, const std::string& id) {
1730 27193 : bool ok = true;
1731 54386 : std::string vclassS = attrs.getOpt<std::string>(SUMO_ATTR_GUISHAPE, id.c_str(), ok, "");
1732 : if (SumoVehicleShapeStrings.hasString(vclassS)) {
1733 27193 : const SUMOVehicleShape result = SumoVehicleShapeStrings.get(vclassS);
1734 27193 : const std::string& realName = SumoVehicleShapeStrings.getString(result);
1735 27193 : if (realName != vclassS) {
1736 0 : WRITE_WARNING("The shape '" + vclassS + "' for " + attrs.getObjectType() + " '" + id + "' is deprecated, use '" + realName + "' instead.");
1737 : }
1738 27193 : return result;
1739 : } else {
1740 0 : WRITE_ERRORF(TL("The shape '%' for % '%' is not known."), vclassS, attrs.getObjectType(), id);
1741 0 : return SUMOVehicleShape::UNKNOWN;
1742 : }
1743 : }
1744 :
1745 :
1746 : double
1747 31983 : SUMOVehicleParserHelper::parseWalkPos(SumoXMLAttr attr, const bool hardFail, const std::string& id, double maxPos, const std::string& val, SumoRNG* rng) {
1748 : double result;
1749 : std::string error;
1750 31983 : ArrivalPosDefinition proc = ArrivalPosDefinition::DEFAULT;
1751 : // only supports 'random' and 'max'
1752 63966 : if (!SUMOVehicleParameter::parseArrivalPos(val, toString(SUMO_TAG_WALK), id, result, proc, error)) {
1753 0 : handleVehicleError(hardFail, nullptr, error);
1754 : }
1755 31983 : if (proc == ArrivalPosDefinition::RANDOM) {
1756 1076 : result = RandHelper::rand(maxPos, rng);
1757 30907 : } else if (proc == ArrivalPosDefinition::CENTER) {
1758 0 : result = maxPos / 2.;
1759 30907 : } else if (proc == ArrivalPosDefinition::MAX) {
1760 0 : result = maxPos;
1761 : }
1762 63966 : return SUMOVehicleParameter::interpretEdgePos(result, maxPos, attr, id);
1763 : }
1764 :
1765 :
1766 : SUMOTime
1767 446095 : SUMOVehicleParserHelper::processActionStepLength(double given) {
1768 446095 : const std::string defaultError = "The parameter action-step-length must be a non-negative multiple of the simulation step-length. ";
1769 446095 : SUMOTime result = TIME2STEPS(given);
1770 446095 : if (result <= 0) {
1771 38536 : if (result < 0) {
1772 36 : WRITE_WARNING(defaultError + "Ignoring given value (=" + toString(STEPS2TIME(result)) + " s.)");
1773 : }
1774 38536 : result = DELTA_T;
1775 407589 : } else if (result % DELTA_T != 0 && OptionsCont::getOptions().exists("step-length")) {
1776 26 : result = (SUMOTime)((double)DELTA_T * floor(double(result) / double(DELTA_T)));
1777 : result = MAX2(DELTA_T, result);
1778 26 : if (fabs(given * 1000. - double(result)) > NUMERICAL_EPS) {
1779 104 : WRITE_WARNING(defaultError + "Parsing given value (" + toString(given) + " s.) to the adjusted value " + toString(STEPS2TIME(result)) + " s.");
1780 : }
1781 : }
1782 446095 : return result;
1783 : }
1784 :
1785 :
1786 : bool
1787 183030 : SUMOVehicleParserHelper::isInternalRouteID(const std::string& id) {
1788 183030 : return id.substr(0, 1) == "!";
1789 : }
1790 :
1791 :
1792 : bool
1793 12 : SUMOVehicleParserHelper::validProfile(SUMOVTypeParameter* vtype, const std::string data, const SumoXMLAttr attr) {
1794 48 : for (std::string value : StringTokenizer(data).getVector()) {
1795 : try {
1796 24 : double v = StringUtils::toDouble(value);
1797 24 : if (v < 0.) {
1798 0 : WRITE_ERRORF(TL("Invalid Car-Following-Model Attribute %. An acceleration profile value cannot be negative"), toString(attr));
1799 0 : return false;
1800 : }
1801 0 : } catch (...) {
1802 0 : WRITE_ERRORF(TL("Entry '%' of % table for vType '%' cannot be parsed as 'double'"), value, toString(attr), vtype->id);
1803 : return false;
1804 0 : }
1805 12 : }
1806 12 : return true;
1807 : }
1808 :
1809 :
1810 : int
1811 13537 : SUMOVehicleParserHelper::parseCarWalkTransfer(const OptionsCont& oc, const bool hasTaxi) {
1812 : int carWalk = 0;
1813 40611 : for (const std::string& opt : oc.getStringVector("persontrip.transfer.car-walk")) {
1814 13537 : if (opt == "parkingAreas") {
1815 13337 : carWalk |= ModeChangeOptions::PARKING_AREAS;
1816 200 : } else if (opt == "ptStops") {
1817 150 : carWalk |= ModeChangeOptions::PT_STOPS;
1818 50 : } else if (opt == "allJunctions") {
1819 50 : carWalk |= ModeChangeOptions::ALL_JUNCTIONS;
1820 : } else {
1821 0 : WRITE_ERRORF(TL("Invalid transfer option '%'. Must be one of 'parkingAreas', 'ptStops' and 'allJunctions'"), opt);
1822 : }
1823 : }
1824 13537 : const StringVector taxiDropoff = oc.getStringVector("persontrip.transfer.taxi-walk");
1825 27074 : const StringVector taxiPickup = oc.getStringVector("persontrip.transfer.walk-taxi");
1826 13537 : if (taxiDropoff.empty() && hasTaxi) {
1827 3444 : carWalk |= ModeChangeOptions::TAXI_DROPOFF_ANYWHERE;
1828 : } else {
1829 10231 : for (const std::string& opt : taxiDropoff) {
1830 138 : if (opt == "parkingAreas") {
1831 14 : carWalk |= ModeChangeOptions::TAXI_DROPOFF_PARKING_AREAS;
1832 124 : } else if (opt == "ptStops") {
1833 80 : carWalk |= ModeChangeOptions::TAXI_DROPOFF_PT;
1834 44 : } else if (opt == "allJunctions") {
1835 44 : carWalk |= ModeChangeOptions::TAXI_DROPOFF_ANYWHERE;
1836 : } else {
1837 0 : WRITE_ERRORF(TL("Invalid transfer option '%'. Must be one of 'parkingAreas', 'ptStops' and 'allJunctions'"), opt);
1838 : }
1839 : }
1840 : }
1841 13537 : if (taxiPickup.empty() && hasTaxi) {
1842 3424 : carWalk |= ModeChangeOptions::TAXI_PICKUP_ANYWHERE;
1843 : } else {
1844 10271 : for (const std::string& opt : taxiPickup) {
1845 158 : if (opt == "parkingAreas") {
1846 14 : carWalk |= ModeChangeOptions::TAXI_PICKUP_PARKING_AREAS;
1847 144 : } else if (opt == "ptStops") {
1848 96 : carWalk |= ModeChangeOptions::TAXI_PICKUP_PT;
1849 48 : } else if (opt == "allJunctions") {
1850 48 : carWalk |= ModeChangeOptions::TAXI_PICKUP_ANYWHERE;
1851 : } else {
1852 0 : WRITE_ERRORF(TL("Invalid transfer option '%'. Must be one of 'parkingAreas', 'ptStops' and 'allJunctions'"), opt);
1853 : }
1854 : }
1855 : }
1856 13537 : return carWalk;
1857 13537 : }
1858 :
1859 :
1860 : SUMOVehicleParameter*
1861 432 : SUMOVehicleParserHelper::handleVehicleError(const bool hardFail, SUMOVehicleParameter* vehicleParameter, const std::string message) {
1862 432 : if (vehicleParameter) {
1863 388 : delete vehicleParameter;
1864 : }
1865 432 : if (hardFail) {
1866 432 : throw ProcessError(message);
1867 0 : } else if (message.size() > 0) {
1868 0 : WRITE_ERROR(message);
1869 : }
1870 0 : return nullptr;
1871 : }
1872 :
1873 :
1874 : SUMOVTypeParameter*
1875 30 : SUMOVehicleParserHelper::handleVehicleTypeError(const bool hardFail, SUMOVTypeParameter* vehicleTypeParameter, const std::string message) {
1876 30 : if (vehicleTypeParameter) {
1877 26 : delete vehicleTypeParameter;
1878 : }
1879 30 : if (hardFail) {
1880 30 : throw ProcessError(message);
1881 0 : } else if (message.size() > 0) {
1882 0 : WRITE_ERROR(message);
1883 : }
1884 0 : return nullptr;
1885 : }
1886 :
1887 : /****************************************************************************/
|