Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file CommonHandler.cpp
15 : /// @author Pablo Alvarez Lopez
16 : /// @date Dec 2024
17 : ///
18 : // Collection of functions used in handlers
19 : /****************************************************************************/
20 : #include <config.h>
21 :
22 : #include <utils/common/MsgHandler.h>
23 : #include <utils/common/StringUtils.h>
24 : #include <utils/xml/XMLSubSys.h>
25 :
26 : #include "CommonHandler.h"
27 :
28 :
29 : // ===========================================================================
30 : // method definitions
31 : // ===========================================================================
32 :
33 0 : CommonHandler::CommonHandler(const std::string& filename) :
34 0 : myFilename(filename) {
35 0 : }
36 :
37 :
38 0 : CommonHandler::~CommonHandler() {}
39 :
40 :
41 : bool
42 0 : CommonHandler::isErrorCreatingElement() const {
43 0 : return myErrorCreatingElement;
44 : }
45 :
46 :
47 : void
48 0 : CommonHandler::parseParameters(const SUMOSAXAttributes& attrs) {
49 : // declare Ok Flag
50 0 : bool parsedOk = true;
51 : // get key
52 0 : const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, parsedOk);
53 : // get SumoBaseObject parent
54 0 : CommonXMLStructure::SumoBaseObject* SumoBaseObjectParent = myCommonXMLStructure.getCurrentSumoBaseObject()->getParentSumoBaseObject();
55 : // check parent
56 0 : if ((SumoBaseObjectParent == nullptr) || (SumoBaseObjectParent->getTag() == SUMO_TAG_ROOTFILE)) {
57 0 : writeError(TL("Parameters must be defined within an object"));
58 0 : } else if (SumoBaseObjectParent->getTag() == SUMO_TAG_PARAM) {
59 0 : writeError(TL("Parameters cannot be defined within another parameter."));
60 0 : } else if ((SumoBaseObjectParent->getTag() != SUMO_TAG_ERROR) && parsedOk) {
61 : // get tag str
62 0 : const std::string parentTagStr = toString(SumoBaseObjectParent->getTag());
63 : // circumventing empty string value
64 0 : const std::string value = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
65 : // show warnings if values are invalid
66 0 : if (key.empty()) {
67 0 : writeError(TLF("Error parsing key from % generic parameter. Key cannot be empty", parentTagStr));
68 0 : } else if (!SUMOXMLDefinitions::isValidParameterKey(key)) {
69 0 : writeError(TLF("Error parsing key from % generic parameter. Key contains invalid characters", parentTagStr));
70 : } else {
71 : // insert parameter in SumoBaseObjectParent
72 0 : SumoBaseObjectParent->addParameter(key, value);
73 : }
74 : }
75 0 : }
76 :
77 :
78 : CommonXMLStructure::SumoBaseObject*
79 0 : CommonHandler::getEmbeddedRoute(const CommonXMLStructure::SumoBaseObject* sumoBaseObject) const {
80 : // locate route in childrens
81 0 : for (const auto& embeddedRoute : sumoBaseObject->getSumoBaseObjectChildren()) {
82 0 : if ((embeddedRoute->getTag() == SUMO_TAG_ROUTE) && (!embeddedRoute->hasStringAttribute(SUMO_ATTR_ID))) {
83 0 : return embeddedRoute;
84 : }
85 : }
86 : return nullptr;
87 : }
88 :
89 :
90 : void
91 0 : CommonHandler::checkParsedParent(const SumoXMLTag currentTag, const std::vector<SumoXMLTag>& parentTags, bool& ok) {
92 0 : if (parentTags.size() > 0) {
93 : std::string tagsStr;
94 0 : for (auto it = parentTags.begin(); it != parentTags.end(); it++) {
95 0 : tagsStr.append(toString(*it));
96 0 : if ((it + 1) != parentTags.end()) {
97 0 : if ((it + 2) != parentTags.end()) {
98 0 : tagsStr.append(", ");
99 : } else {
100 0 : tagsStr.append(" or ");
101 : }
102 : }
103 : }
104 : // obtain parent
105 0 : CommonXMLStructure::SumoBaseObject* const parent = myCommonXMLStructure.getCurrentSumoBaseObject()->getParentSumoBaseObject();
106 0 : if (parent == nullptr) {
107 0 : ok = writeError(TLF("'%' must be defined within the definition of a %.", toString(currentTag), tagsStr));
108 0 : } else if ((parent->getTag() != SUMO_TAG_ERROR) && std::find(parentTags.begin(), parentTags.end(), parent->getTag()) == parentTags.end()) {
109 0 : if (parent->hasStringAttribute(SUMO_ATTR_ID)) {
110 0 : ok = writeError(TLF("'%' must be defined within the definition of a '%' (found % '%').", toString(currentTag), tagsStr,
111 : toString(parent->getTag()), parent->getStringAttribute(SUMO_ATTR_ID)));
112 : } else {
113 0 : ok = writeError(TLF("'%' must be defined within the definition of a '%' (found %).", toString(currentTag), tagsStr,
114 : toString(parent->getTag())));
115 : }
116 : }
117 : }
118 0 : }
119 :
120 :
121 : bool
122 0 : CommonHandler::checkListOfVehicleTypes(const SumoXMLTag tag, const std::string& id, const std::vector<std::string>& vTypeIDs) {
123 0 : for (const auto& vTypeID : vTypeIDs) {
124 0 : if (!SUMOXMLDefinitions::isValidTypeID(vTypeID)) {
125 0 : return writeError(TLF("Could not build % with ID '%' in netedit; '%' ist not a valid vType ID.", toString(tag), id, vTypeID));
126 : }
127 : }
128 : return true;
129 : }
130 :
131 :
132 : bool
133 0 : CommonHandler::checkWithinDistribution(CommonXMLStructure::SumoBaseObject* obj) {
134 0 : if (obj->getParentSumoBaseObject() == nullptr) {
135 : return false;
136 0 : } else if (obj->getParentSumoBaseObject()->getTag() == SUMO_TAG_ROUTE_DISTRIBUTION) {
137 : return true;
138 0 : } else if (obj->getParentSumoBaseObject()->getTag() == SUMO_TAG_VTYPE_DISTRIBUTION) {
139 : return true;
140 : } else {
141 : return false;
142 : }
143 : }
144 :
145 :
146 : bool
147 0 : CommonHandler::checkVehicleParents(CommonXMLStructure::SumoBaseObject* obj) {
148 0 : if (obj == nullptr) {
149 : return false;
150 0 : } else if (!obj->hasStringAttribute(SUMO_ATTR_ID)) {
151 : return false;
152 : } else {
153 0 : SumoXMLTag tag = obj->getTag();
154 0 : const std::string id = obj->getStringAttribute(SUMO_ATTR_ID);
155 0 : const bool hasRoute = obj->hasStringAttribute(SUMO_ATTR_ROUTE);
156 0 : const bool hasEmbeddedRoute = (getEmbeddedRoute(obj) != nullptr);
157 0 : const bool overEdges = obj->hasStringAttribute(SUMO_ATTR_FROM) && obj->hasStringAttribute(SUMO_ATTR_TO);
158 0 : const bool overJunctions = obj->hasStringAttribute(SUMO_ATTR_FROM_JUNCTION) && obj->hasStringAttribute(SUMO_ATTR_TO_JUNCTION);
159 0 : const bool overTAZs = obj->hasStringAttribute(SUMO_ATTR_FROM_TAZ) && obj->hasStringAttribute(SUMO_ATTR_TO_TAZ);
160 0 : if (hasRoute && hasEmbeddedRoute) {
161 0 : return writeError(TLF("Could not build % with ID '%' in netedit; Cannot have an external route and an embedded route in the same definition.", toString(tag), id));
162 : }
163 0 : if ((overEdges + overJunctions + overTAZs) > 1) {
164 0 : return writeError(TLF("Could not build % with ID '%' in netedit; Cannot have multiple from-to attributes.", toString(tag), id));
165 : }
166 0 : if ((hasRoute + hasEmbeddedRoute + overEdges + overJunctions + overTAZs) > 1) {
167 0 : return writeError(TLF("Could not build % with ID '%' in netedit; Cannot have from-to attributes and route attributes in the same definition.", toString(tag), id));
168 : }
169 0 : if ((hasRoute + hasEmbeddedRoute + overEdges + overJunctions + overTAZs) == 0) {
170 0 : return writeError(TLF("Could not build % with ID '%' in netedit; Requires either a route or an embedded route or a from-to attribute (Edges, junctions or TAZs).", toString(tag), id));
171 : }
172 : return true;
173 : }
174 : }
175 :
176 :
177 : bool
178 0 : CommonHandler::checkPersonPlanParents(CommonXMLStructure::SumoBaseObject* obj) {
179 0 : const auto parent = obj->getParentSumoBaseObject();
180 0 : if (parent == nullptr) {
181 : return false;
182 0 : } else if (!parent->wasCreated()) {
183 : return false;
184 0 : } else if ((parent->getTag() == SUMO_TAG_PERSON) || (parent->getTag() == SUMO_TAG_PERSONFLOW)) {
185 0 : return true;
186 : } else {
187 : return false;
188 : }
189 : }
190 :
191 :
192 : bool
193 0 : CommonHandler::checkContainerPlanParents(CommonXMLStructure::SumoBaseObject* obj) {
194 0 : const auto parent = obj->getParentSumoBaseObject();
195 0 : if (parent == nullptr) {
196 : return false;
197 0 : } else if (!parent->wasCreated()) {
198 : return false;
199 0 : } else if ((parent->getTag() == SUMO_TAG_CONTAINER) || (parent->getTag() == SUMO_TAG_CONTAINERFLOW)) {
200 0 : return true;
201 : } else {
202 : return false;
203 : }
204 : }
205 :
206 :
207 : bool
208 0 : CommonHandler::checkStopParents(CommonXMLStructure::SumoBaseObject* obj) {
209 0 : const auto parent = obj->getParentSumoBaseObject();
210 0 : if (parent == nullptr) {
211 : return false;
212 0 : } else if (!parent->wasCreated()) {
213 : return false;
214 0 : } else if ((parent->getTag() == SUMO_TAG_ROUTE) || (parent->getTag() == SUMO_TAG_TRIP) ||
215 0 : (parent->getTag() == SUMO_TAG_VEHICLE) || (parent->getTag() == SUMO_TAG_FLOW) ||
216 0 : (parent->getTag() == SUMO_TAG_PERSON) || (parent->getTag() == SUMO_TAG_PERSONFLOW) ||
217 0 : (parent->getTag() == SUMO_TAG_CONTAINER) || (parent->getTag() == SUMO_TAG_CONTAINERFLOW)) {
218 0 : return true;
219 : } else {
220 : return false;
221 : }
222 : }
223 :
224 :
225 : bool
226 0 : CommonHandler::checkNegative(const SumoXMLTag tag, const std::string& id, const SumoXMLAttr attribute, const int value, const bool canBeZero) {
227 0 : if (canBeZero) {
228 0 : if (value < 0) {
229 0 : return writeError(TLF("Could not build % with ID '%' in netedit; Attribute % cannot be negative.", toString(tag), id, toString(attribute)));
230 : } else {
231 : return true;
232 : }
233 : } else {
234 0 : if (value <= 0) {
235 0 : return writeError(TLF("Could not build % with ID '%' in netedit; Attribute % must be greather than zero.", toString(tag), id, toString(attribute)));
236 : } else {
237 : return true;
238 : }
239 : }
240 : }
241 :
242 :
243 : bool
244 0 : CommonHandler::checkNegative(const SumoXMLTag tag, const std::string& id, const SumoXMLAttr attribute, const double value, const bool canBeZero) {
245 0 : if (canBeZero) {
246 0 : if (value < 0) {
247 0 : return writeError(TLF("Could not build % with ID '%' in netedit; Attribute % cannot be negative (%).", toString(tag), id, toString(attribute), toString(value)));
248 : } else {
249 : return true;
250 : }
251 : } else {
252 0 : if (value <= 0) {
253 0 : return writeError(TLF("Could not build % with ID '%' in netedit; Attribute % must be greather than zero (%).", toString(tag), id, toString(attribute), toString(value)));
254 : } else {
255 : return true;
256 : }
257 : }
258 : }
259 :
260 :
261 : bool
262 0 : CommonHandler::checkNegative(const SumoXMLTag tag, const std::string& id, const SumoXMLAttr attribute, const SUMOTime value, const bool canBeZero) {
263 0 : if (canBeZero) {
264 0 : if (value < 0) {
265 0 : return writeError(TLF("Could not build % with ID '%' in netedit; Attribute % cannot be negative (%).", toString(tag), id, toString(attribute), time2string(value)));
266 : } else {
267 : return true;
268 : }
269 : } else {
270 0 : if (value <= 0) {
271 0 : return writeError(TLF("Could not build % with ID '%' in netedit; Attribute % must be greather than zero (%).", toString(tag), id, toString(attribute), time2string(value)));
272 : } else {
273 : return true;
274 : }
275 : }
276 : }
277 :
278 :
279 : bool
280 0 : CommonHandler::checkFileName(const SumoXMLTag tag, const std::string& id, const SumoXMLAttr attribute, const std::string& value) {
281 0 : if (SUMOXMLDefinitions::isValidFilename(value)) {
282 : return true;
283 : } else {
284 0 : return writeError(TLF("Could not build % with ID '%' in netedit; % is invalid % ()", toString(tag), id, toString(attribute), value));
285 : }
286 : }
287 :
288 :
289 : bool
290 0 : CommonHandler::checkValidAdditionalID(const SumoXMLTag tag, const std::string& value) {
291 0 : if (value.empty()) {
292 0 : return writeError(TLF("Could not build %; ID cannot be empty", toString(tag)));
293 0 : } else if (!SUMOXMLDefinitions::isValidVehicleID(value)) {
294 0 : return writeError(TLF("Could not build % with ID '%' in netedit; ID contains invalid characters.", toString(tag), value));
295 : } else {
296 : return true;
297 : }
298 : }
299 :
300 :
301 : bool
302 0 : CommonHandler::checkValidDetectorID(const SumoXMLTag tag, const std::string& value) {
303 0 : if (value.empty()) {
304 0 : return writeError(TLF("Could not build %; ID cannot be empty", toString(tag)));
305 0 : } else if (!SUMOXMLDefinitions::isValidDetectorID(value)) {
306 0 : return writeError(TLF("Could not build % with ID '%' in netedit; detector ID contains invalid characters.", toString(tag), value));
307 : } else {
308 : return true;
309 : }
310 : }
311 :
312 :
313 : bool
314 0 : CommonHandler::checkValidDemandElementID(const SumoXMLTag tag, const std::string& value) {
315 0 : if (value.empty()) {
316 0 : return writeError(TLF("Could not build %; ID cannot be empty", toString(tag)));
317 0 : } else if (!SUMOXMLDefinitions::isValidVehicleID(value)) {
318 0 : return writeError(TLF("Could not build % with ID '%' in netedit; ID contains invalid characters.", toString(tag), value));
319 : } else {
320 : return true;
321 : }
322 : }
323 :
324 :
325 : void
326 0 : CommonHandler::writeWarningOverwritting(const SumoXMLTag tag, const std::string& id) {
327 0 : WRITE_WARNING(TLF("Overwritting % with ID '%'", toString(tag), id));
328 0 : }
329 :
330 :
331 : bool
332 0 : CommonHandler::writeWarningDuplicated(const SumoXMLTag tag, const std::string& id, const SumoXMLTag checkedTag) {
333 0 : return writeError(TLF("Could not build % with ID '%' in netedit; Found another % with the same ID.", toString(tag), id, toString(checkedTag)));
334 : }
335 :
336 :
337 : bool
338 0 : CommonHandler::writeError(const std::string& error) {
339 0 : WRITE_ERROR(error);
340 0 : myErrorCreatingElement = true;
341 0 : return false;
342 : }
343 :
344 :
345 : bool
346 0 : CommonHandler::writeErrorInvalidPosition(const SumoXMLTag tag, const std::string& id) {
347 0 : return writeError(TLF("Could not build % with ID '%' in netedit; Invalid position over lane.", toString(tag), id));
348 : }
349 :
350 :
351 : bool
352 0 : CommonHandler::writeErrorEmptyEdges(const SumoXMLTag tag, const std::string& id) {
353 0 : return writeError(TLF("Could not build % with ID '%' in netedit; List of edges cannot be empty.", toString(tag), id));
354 : }
355 :
356 :
357 : bool
358 0 : CommonHandler::writeErrorInvalidLanes(const SumoXMLTag tag, const std::string& id) {
359 0 : return writeError(TLF("Could not build % with ID '%' in netedit; List of lanes isn't valid.", toString(tag), id));
360 : }
361 :
362 :
363 : bool
364 0 : CommonHandler::writeErrorInvalidParent(const SumoXMLTag tag, const std::string& id, const SumoXMLTag parentTag, const std::string& parentID) {
365 0 : return writeError(TLF("Could not build % with ID '%' in netedit; % parent with ID '%' doesn't exist.", toString(tag), id, toString(parentTag), parentID));
366 : }
367 :
368 :
369 : bool
370 0 : CommonHandler::writeErrorInvalidParent(const SumoXMLTag tag, const SumoXMLTag parentTag, const std::string& parentID) {
371 0 : return writeError(TLF("Could not build % in netedit; % parent with ID '%' doesn't exist.", toString(tag), toString(parentTag), parentID));
372 : }
373 :
374 :
375 : bool
376 0 : CommonHandler::writeErrorInvalidParent(const SumoXMLTag tag, const SumoXMLTag parentTag) {
377 0 : return writeError(TLF("Could not build % in netedit; % parent doesn't exist.", toString(tag), toString(parentTag)));
378 : }
379 :
380 : /****************************************************************************/
|