Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2007-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 SUMOSAXAttributes.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @date Fri, 30 Mar 2007
19 : ///
20 : // Encapsulated SAX-Attributes
21 : /****************************************************************************/
22 : #include <config.h>
23 :
24 : #include <string>
25 : #include <iostream>
26 : #include <sstream>
27 : #include <utils/common/MsgHandler.h>
28 : #include <utils/common/RGBColor.h>
29 : #include <utils/common/StringTokenizer.h>
30 : #include <utils/common/StringUtils.h>
31 : #include <utils/geom/Boundary.h>
32 : #include <utils/geom/PositionVector.h>
33 : #include "SUMOSAXAttributes.h"
34 :
35 :
36 : // ===========================================================================
37 : // static members
38 : // ===========================================================================
39 : const std::string SUMOSAXAttributes::ENCODING = " encoding=\"UTF-8\"";
40 :
41 :
42 : // ===========================================================================
43 : // method definitions
44 : // ===========================================================================
45 15760949 : SUMOSAXAttributes::SUMOSAXAttributes(const std::string& objectType):
46 15760949 : myObjectType(objectType) {}
47 :
48 :
49 : const std::string invalid_return<std::string>::value = "";
50 : template<>
51 32551896 : std::string SUMOSAXAttributes::fromString(const std::string& value) const {
52 32551896 : if (value == "") {
53 682 : throw EmptyData();
54 : }
55 32551214 : return value;
56 : }
57 :
58 :
59 : SUMOTime
60 607531 : SUMOSAXAttributes::getSUMOTimeReporting(int attr, const char* objectid,
61 : bool& ok, bool report) const {
62 : try {
63 607531 : bool isPresent = true;
64 607531 : const std::string& val = getString(attr, &isPresent);
65 607531 : if (!isPresent) {
66 13 : if (report) {
67 50 : emitUngivenError(getName(attr), objectid);
68 : }
69 13 : ok = false;
70 13 : return -1;
71 : }
72 607518 : return string2time(val);
73 24 : } catch (EmptyData&) {
74 12 : if (report) {
75 24 : emitEmptyError(getName(attr), objectid);
76 : }
77 24 : } catch (ProcessError&) {
78 12 : if (report) {
79 24 : emitFormatError(getName(attr), "is not a valid time value", objectid);
80 : }
81 12 : }
82 24 : ok = false;
83 24 : return -1;
84 : }
85 :
86 :
87 : SUMOTime
88 559 : SUMOSAXAttributes::getPeriod(const char* objectid, bool& ok, bool report) const {
89 : int attr = SUMO_ATTR_PERIOD;
90 : try {
91 559 : bool isPresent = true;
92 559 : const std::string& val = getString(attr, &isPresent);
93 559 : if (!isPresent) {
94 : // try 'freq' as alias for 'period'
95 : attr = SUMO_ATTR_FREQUENCY;
96 534 : isPresent = true;
97 534 : const std::string& valFreq = getString(attr, &isPresent);
98 534 : if (!isPresent) {
99 534 : if (report) {
100 0 : emitUngivenError(getName(SUMO_ATTR_PERIOD), objectid);
101 : }
102 534 : ok = false;
103 534 : return -1;
104 : }
105 0 : return string2time(valFreq);
106 : }
107 25 : return string2time(val);
108 0 : } catch (EmptyData&) {
109 0 : if (report) {
110 0 : emitEmptyError(getName(attr), objectid);
111 : }
112 0 : } catch (ProcessError&) {
113 0 : if (report) {
114 0 : emitFormatError(getName(attr), "is not a valid time value", objectid);
115 : }
116 0 : }
117 0 : ok = false;
118 0 : return -1;
119 : }
120 :
121 :
122 : SUMOTime
123 5150277 : SUMOSAXAttributes::getOptSUMOTimeReporting(int attr, const char* objectid,
124 : bool& ok, SUMOTime defaultValue, bool report) const {
125 : try {
126 5150277 : bool isPresent = true;
127 5150277 : const std::string& val = getString(attr, &isPresent);
128 5150277 : if (!isPresent) {
129 : return defaultValue;
130 : }
131 78870 : return string2time(val);
132 36 : } catch (EmptyData&) {
133 0 : if (report) {
134 0 : emitEmptyError(getName(attr), objectid);
135 : }
136 36 : } catch (ProcessError&) {
137 36 : if (report) {
138 72 : emitFormatError(getName(attr), "is not a valid time value", objectid);
139 : }
140 36 : }
141 36 : ok = false;
142 36 : return -1;
143 : }
144 :
145 :
146 : SUMOTime
147 109468 : SUMOSAXAttributes::getOptOffsetReporting(int attr, const char* objectid,
148 : bool& ok, SUMOTime defaultValue, bool report) const {
149 : try {
150 109468 : bool isPresent = true;
151 109468 : const std::string& val = getString(attr, &isPresent);
152 109468 : if (!isPresent) {
153 : return defaultValue;
154 : }
155 109360 : if (val == "begin") {
156 : return SUMOTime_MAX;
157 : } else {
158 109357 : return string2time(val);
159 : }
160 0 : } catch (EmptyData&) {
161 0 : if (report) {
162 0 : emitEmptyError(getName(attr), objectid);
163 : }
164 0 : } catch (ProcessError&) {
165 0 : if (report) {
166 0 : emitFormatError(getName(attr), "is not a valid time value", objectid);
167 : }
168 0 : }
169 0 : ok = false;
170 0 : return -1;
171 : }
172 :
173 :
174 : SUMOTime
175 48043 : SUMOSAXAttributes::getOptPeriod(const char* objectid, bool& ok, SUMOTime defaultValue, bool report) const {
176 : int attr = SUMO_ATTR_PERIOD;
177 : try {
178 48043 : bool isPresent = true;
179 48043 : const std::string& val = getString(attr, &isPresent);
180 48043 : if (!isPresent) {
181 : // try 'freq' as alias for 'period'
182 : attr = SUMO_ATTR_FREQUENCY;
183 25658 : isPresent = true;
184 25658 : const std::string& valFreq = getString(attr, &isPresent);
185 25658 : if (!isPresent) {
186 : return defaultValue;
187 : }
188 7805 : return string2time(valFreq);
189 : }
190 22385 : return string2time(val);
191 40 : } catch (EmptyData&) {
192 20 : if (report) {
193 40 : emitEmptyError(getName(attr), objectid);
194 : }
195 40 : } catch (ProcessError&) {
196 20 : if (report) {
197 40 : emitFormatError(getName(attr), "is not a valid time value", objectid);
198 : }
199 20 : }
200 40 : ok = false;
201 40 : return -1;
202 : }
203 :
204 :
205 : void
206 292 : SUMOSAXAttributes::emitUngivenError(const std::string& attrname, const char* objectid) const {
207 292 : std::ostringstream oss;
208 292 : oss << "Attribute '" << attrname << "' is missing in definition of ";
209 292 : if (objectid == nullptr || objectid[0] == 0) {
210 : oss << "a " << myObjectType;
211 : } else {
212 160 : oss << myObjectType << " '" << objectid << "'";
213 : }
214 292 : oss << ".";
215 292 : WRITE_ERROR(oss.str());
216 292 : }
217 :
218 :
219 : void
220 549 : SUMOSAXAttributes::emitEmptyError(const std::string& attrname, const char* objectid) const {
221 549 : std::ostringstream oss;
222 549 : oss << "Attribute '" << attrname << "' in definition of ";
223 549 : if (objectid == nullptr || objectid[0] == 0) {
224 : oss << "a " << myObjectType;
225 : } else {
226 392 : oss << myObjectType << " '" << objectid << "'";
227 : }
228 549 : oss << " is empty.";
229 549 : WRITE_ERROR(oss.str());
230 549 : }
231 :
232 :
233 : void
234 302 : SUMOSAXAttributes::emitFormatError(const std::string& attrname, const std::string& type, const char* objectid) const {
235 302 : std::ostringstream oss;
236 302 : oss << "Attribute '" << attrname << "' in definition of ";
237 302 : if (objectid == nullptr || objectid[0] == 0) {
238 : oss << "a " << myObjectType;
239 : } else {
240 282 : oss << myObjectType << " '" << objectid << "'";
241 : }
242 302 : oss << " " << type << ".";
243 302 : WRITE_ERROR(oss.str());
244 302 : }
245 :
246 :
247 : const int invalid_return<int>::value = -1;
248 : template<>
249 11398973 : int SUMOSAXAttributes::fromString(const std::string& value) const {
250 11398973 : return StringUtils::toInt(value);
251 : }
252 :
253 :
254 : const long long int invalid_return<long long int>::value = -1;
255 : template<>
256 1001054 : long long int SUMOSAXAttributes::fromString(const std::string& value) const {
257 1001054 : return StringUtils::toLong(value);
258 : }
259 :
260 :
261 : const double invalid_return<double>::value = -1;
262 : template<>
263 8203841 : double SUMOSAXAttributes::fromString(const std::string& value) const {
264 8203841 : return StringUtils::toDouble(value);
265 : }
266 :
267 :
268 : const bool invalid_return<bool>::value = false;
269 : template<>
270 853151 : bool SUMOSAXAttributes::fromString(const std::string& value) const {
271 853151 : return StringUtils::toBool(value);
272 : }
273 :
274 :
275 : const RGBColor invalid_return<RGBColor>::value = RGBColor();
276 : template<>
277 68831 : RGBColor SUMOSAXAttributes::fromString(const std::string& value) const {
278 137654 : return RGBColor::parseColor(value);
279 : }
280 :
281 :
282 : const Position invalid_return<Position>::value = Position();
283 : template<>
284 1282 : Position SUMOSAXAttributes::fromString(const std::string& value) const {
285 1282 : StringTokenizer st(value);
286 : // check StringTokenizer
287 1282 : while (st.hasNext()) {
288 : // obtain position
289 2564 : StringTokenizer pos(st.next(), ",");
290 : // check that position has X-Y or X-Y-Z
291 1282 : if ((pos.size() != 2) && (pos.size() != 3)) {
292 0 : throw FormatException("is not a valid position");
293 : }
294 : // obtain x and y
295 1282 : double x = StringUtils::toDouble(pos.next());
296 1282 : double y = StringUtils::toDouble(pos.next());
297 : // check if return a X-Y or a X-Y-Z Position
298 1282 : if (pos.size() == 2) {
299 : return Position(x, y);
300 : } else {
301 : // obtain z
302 0 : double z = StringUtils::toDouble(pos.next());
303 : return Position(x, y, z);
304 : }
305 1282 : }
306 : // empty positions aren't allowed
307 0 : throw FormatException("is not a valid position");
308 1282 : }
309 :
310 :
311 : const PositionVector invalid_return<PositionVector>::value = PositionVector();
312 : template<>
313 2837738 : PositionVector SUMOSAXAttributes::fromString(const std::string& value) const {
314 2837738 : StringTokenizer st(value);
315 2837738 : PositionVector shape;
316 13485912 : while (st.hasNext()) {
317 21296564 : StringTokenizer pos(st.next(), ",");
318 10648282 : if (pos.size() != 2 && pos.size() != 3) {
319 84 : throw FormatException("is not a valid list of positions");
320 : }
321 10648240 : double x = StringUtils::toDouble(pos.next());
322 10648196 : double y = StringUtils::toDouble(pos.next());
323 10648174 : if (pos.size() == 2) {
324 10619529 : shape.push_back(Position(x, y));
325 : } else {
326 28645 : double z = StringUtils::toDouble(pos.next());
327 28645 : shape.push_back(Position(x, y, z));
328 : }
329 10648282 : }
330 2837630 : return shape;
331 2837846 : }
332 :
333 :
334 : const Boundary invalid_return<Boundary>::value = Boundary();
335 : template<>
336 89124 : Boundary SUMOSAXAttributes::fromString(const std::string& value) const {
337 267372 : StringTokenizer st(value, ",");
338 89124 : if (st.size() != 4) {
339 0 : throw FormatException("is not a valid boundary");
340 : }
341 89124 : const double xmin = StringUtils::toDouble(st.next());
342 89124 : const double ymin = StringUtils::toDouble(st.next());
343 89124 : const double xmax = StringUtils::toDouble(st.next());
344 89124 : const double ymax = StringUtils::toDouble(st.next());
345 178248 : return Boundary(xmin, ymin, xmax, ymax);
346 89124 : }
347 :
348 :
349 : const SumoXMLEdgeFunc invalid_return<SumoXMLEdgeFunc>::value = SumoXMLEdgeFunc::NORMAL;
350 : template<>
351 1247029 : SumoXMLEdgeFunc SUMOSAXAttributes::fromString(const std::string& value) const {
352 : if (SUMOXMLDefinitions::EdgeFunctions.hasString(value)) {
353 1247019 : return SUMOXMLDefinitions::EdgeFunctions.get(value);
354 : }
355 20 : throw FormatException("is not a valid edge function");
356 : }
357 :
358 :
359 : const SumoXMLNodeType invalid_return<SumoXMLNodeType>::value = SumoXMLNodeType::UNKNOWN;
360 : template<>
361 643229 : SumoXMLNodeType SUMOSAXAttributes::fromString(const std::string& value) const {
362 : if (SUMOXMLDefinitions::NodeTypes.hasString(value)) {
363 643199 : return SUMOXMLDefinitions::NodeTypes.get(value);
364 : }
365 60 : throw FormatException("is not a valid node type");
366 : }
367 :
368 :
369 : const RightOfWay invalid_return<RightOfWay>::value = RightOfWay::DEFAULT;
370 : template<>
371 4 : RightOfWay SUMOSAXAttributes::fromString(const std::string& value) const {
372 : if (SUMOXMLDefinitions::RightOfWayValues.hasString(value)) {
373 4 : return SUMOXMLDefinitions::RightOfWayValues.get(value);
374 : }
375 0 : throw FormatException("is not a valid right of way value");
376 : }
377 :
378 :
379 : const FringeType invalid_return<FringeType>::value = FringeType::DEFAULT;
380 : template<>
381 235 : FringeType SUMOSAXAttributes::fromString(const std::string& value) const {
382 : if (SUMOXMLDefinitions::FringeTypeValues.hasString(value)) {
383 235 : return SUMOXMLDefinitions::FringeTypeValues.get(value);
384 : }
385 0 : throw FormatException("is not a valid fringe type");
386 : }
387 :
388 :
389 : const RoundaboutType invalid_return<RoundaboutType>::value = RoundaboutType::DEFAULT;
390 : template<>
391 1 : RoundaboutType SUMOSAXAttributes::fromString(const std::string& value) const {
392 : if (SUMOXMLDefinitions::RoundaboutTypeValues.hasString(value)) {
393 1 : return SUMOXMLDefinitions::RoundaboutTypeValues.get(value);
394 : }
395 0 : throw FormatException("is not a valid roundabout type");
396 : }
397 :
398 :
399 : const ParkingType invalid_return<ParkingType>::value = ParkingType::ONROAD;
400 : template<>
401 913 : ParkingType SUMOSAXAttributes::fromString(const std::string& value) const {
402 913 : if (value == toString(ParkingType::OPPORTUNISTIC)) {
403 : return ParkingType::OPPORTUNISTIC;
404 : } else {
405 913 : return StringUtils::toBool(value) ? ParkingType::OFFROAD : ParkingType::ONROAD;
406 : }
407 : }
408 :
409 :
410 : const std::vector<std::string> invalid_return<std::vector<std::string> >::value = std::vector<std::string>();
411 : template<>
412 12265 : std::vector<std::string> SUMOSAXAttributes::fromString(const std::string& value) const {
413 24530 : const std::vector<std::string>& ret = StringTokenizer(value).getVector();
414 12265 : if (ret.empty()) {
415 356 : throw EmptyData();
416 : }
417 23818 : return ret;
418 12265 : }
419 :
420 :
421 : const std::vector<int> invalid_return<std::vector<int> >::value = std::vector<int>();
422 : template<>
423 252 : std::vector<int> SUMOSAXAttributes::fromString(const std::string& value) const {
424 504 : const std::vector<std::string>& tmp = StringTokenizer(value).getVector();
425 252 : if (tmp.empty()) {
426 0 : throw EmptyData();
427 : }
428 : std::vector<int> ret;
429 639 : for (const std::string& s : tmp) {
430 387 : ret.push_back(StringUtils::toInt(s));
431 : }
432 252 : return ret;
433 252 : }
434 :
435 :
436 : const std::vector<double> invalid_return<std::vector<double> >::value = std::vector<double>();
437 : template<>
438 903 : std::vector<double> SUMOSAXAttributes::fromString(const std::string& value) const {
439 1806 : const std::vector<std::string>& tmp = StringTokenizer(value).getVector();
440 903 : if (tmp.empty()) {
441 0 : throw EmptyData();
442 : }
443 : std::vector<double> ret;
444 66415 : for (const std::string& s : tmp) {
445 65512 : ret.push_back(StringUtils::toDouble(s));
446 : }
447 903 : return ret;
448 903 : }
449 :
450 : /****************************************************************************/
|