Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2002-2024 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file RONetHandler.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Christian Roessel
18 : /// @author Michael Behrisch
19 : /// @author Yun-Pang Floetteroed
20 : /// @date Sept 2002
21 : ///
22 : // The handler for SUMO-Networks
23 : /****************************************************************************/
24 : #include <config.h>
25 :
26 : #include <string>
27 : #include <utils/common/MsgHandler.h>
28 : #include <utils/common/StringTokenizer.h>
29 : #include <utils/common/UtilExceptions.h>
30 : #include <utils/common/ToString.h>
31 : #include <utils/common/StringUtils.h>
32 : #include <utils/geom/PositionVector.h>
33 : #include <utils/geom/GeoConvHelper.h>
34 : #include <utils/vehicle/SUMORouteHandler.h>
35 : #include <utils/xml/SUMOSAXHandler.h>
36 : #include <utils/xml/SUMOXMLDefinitions.h>
37 : #include "ROEdge.h"
38 : #include "ROLane.h"
39 : #include "RONode.h"
40 : #include "RONet.h"
41 : #include "RONetHandler.h"
42 : #include "ROAbstractEdgeBuilder.h"
43 :
44 :
45 : // ===========================================================================
46 : // method definitions
47 : // ===========================================================================
48 5053 : RONetHandler::RONetHandler(RONet& net, ROAbstractEdgeBuilder& eb, const bool ignoreInternal, const double minorPenalty, double tlsPenalty) :
49 : SUMOSAXHandler("sumo-network"),
50 5053 : myNet(net),
51 : myNetworkVersion(0, 0),
52 5053 : myEdgeBuilder(eb), myIgnoreInternal(ignoreInternal),
53 5053 : myCurrentName(), myCurrentEdge(nullptr), myCurrentStoppingPlace(nullptr),
54 5053 : myMinorPenalty(minorPenalty),
55 10106 : myTLSPenalty(tlsPenalty)
56 5053 : {}
57 :
58 :
59 10106 : RONetHandler::~RONetHandler() {}
60 :
61 :
62 : void
63 1531740 : RONetHandler::myStartElement(int element,
64 : const SUMOSAXAttributes& attrs) {
65 1531740 : switch (element) {
66 5053 : case SUMO_TAG_LOCATION:
67 5053 : setLocation(attrs);
68 5053 : break;
69 5053 : case SUMO_TAG_NET: {
70 : bool ok;
71 5053 : myNetworkVersion = StringUtils::toVersion(attrs.get<std::string>(SUMO_ATTR_VERSION, nullptr, ok, false));
72 : break;
73 : }
74 308979 : case SUMO_TAG_EDGE:
75 : // in the first step, we do need the name to allocate the edge
76 : // in the second, we need it to know to which edge we have to add
77 : // the following edges to
78 308979 : parseEdge(attrs);
79 308955 : break;
80 352490 : case SUMO_TAG_LANE:
81 352490 : parseLane(attrs);
82 352490 : break;
83 97460 : case SUMO_TAG_JUNCTION:
84 97460 : parseJunction(attrs);
85 97460 : break;
86 451753 : case SUMO_TAG_CONNECTION:
87 451753 : parseConnection(attrs);
88 451117 : break;
89 1796 : case SUMO_TAG_BUS_STOP:
90 : case SUMO_TAG_TRAIN_STOP:
91 : case SUMO_TAG_CONTAINER_STOP:
92 : case SUMO_TAG_PARKING_AREA:
93 : case SUMO_TAG_CHARGING_STATION:
94 : case SUMO_TAG_OVERHEAD_WIRE_SEGMENT:
95 1796 : parseStoppingPlace(attrs, (SumoXMLTag)element);
96 1796 : break;
97 1604 : case SUMO_TAG_ACCESS:
98 1604 : parseAccess(attrs);
99 1604 : break;
100 313 : case SUMO_TAG_TAZ:
101 313 : parseDistrict(attrs);
102 313 : break;
103 116 : case SUMO_TAG_TAZSOURCE:
104 116 : parseDistrictEdge(attrs, true);
105 116 : break;
106 117 : case SUMO_TAG_TAZSINK:
107 117 : parseDistrictEdge(attrs, false);
108 117 : break;
109 1763 : case SUMO_TAG_TYPE: {
110 1763 : bool ok = true;
111 3526 : myCurrentTypeID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
112 : break;
113 : }
114 1 : case SUMO_TAG_RESTRICTION: {
115 1 : bool ok = true;
116 2 : const SUMOVehicleClass svc = getVehicleClassID(attrs.get<std::string>(SUMO_ATTR_VCLASS, myCurrentTypeID.c_str(), ok));
117 1 : const double speed = attrs.get<double>(SUMO_ATTR_SPEED, myCurrentTypeID.c_str(), ok);
118 1 : if (ok) {
119 1 : myNet.addRestriction(myCurrentTypeID, svc, speed);
120 : }
121 : break;
122 : }
123 103788 : case SUMO_TAG_PARAM:
124 103788 : addParam(attrs);
125 103788 : break;
126 : default:
127 : break;
128 : }
129 1531080 : }
130 :
131 :
132 : void
133 1529550 : RONetHandler::myEndElement(int element) {
134 1529550 : switch (element) {
135 3883 : case SUMO_TAG_NET:
136 : // build junction graph
137 4039 : for (std::set<std::string>::const_iterator it = myUnseenNodeIDs.begin(); it != myUnseenNodeIDs.end(); ++it) {
138 468 : WRITE_ERRORF(TL("Unknown node '%'."), *it);
139 : }
140 : break;
141 : default:
142 : break;
143 : }
144 1529550 : }
145 :
146 :
147 : void
148 103788 : RONetHandler::addParam(const SUMOSAXAttributes& attrs) {
149 103788 : bool ok = true;
150 103788 : const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
151 : // circumventing empty string test
152 103788 : const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
153 : // add parameter in current created element, or in myLoadedParameterised
154 103788 : if (myCurrentEdge != nullptr) {
155 103788 : myCurrentEdge->setParameter(key, val);
156 : }
157 103788 : }
158 :
159 :
160 : void
161 308979 : RONetHandler::parseEdge(const SUMOSAXAttributes& attrs) {
162 : // get the id, report an error if not given or empty...
163 308979 : bool ok = true;
164 308979 : myCurrentName = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
165 308979 : if (!ok) {
166 24 : throw ProcessError();
167 : }
168 308955 : const SumoXMLEdgeFunc func = attrs.getOpt<SumoXMLEdgeFunc>(SUMO_ATTR_FUNCTION, myCurrentName.c_str(), ok, SumoXMLEdgeFunc::NORMAL);
169 308955 : if (!ok) {
170 108 : return;
171 : }
172 : // get the edge
173 : std::string from;
174 : std::string to;
175 : int priority;
176 308943 : myCurrentEdge = nullptr;
177 308943 : if (func == SumoXMLEdgeFunc::INTERNAL || func == SumoXMLEdgeFunc::CROSSING || func == SumoXMLEdgeFunc::WALKINGAREA) {
178 : assert(myCurrentName[0] == ':');
179 392908 : const std::string junctionID = SUMOXMLDefinitions::getJunctionIDFromInternalEdge(myCurrentName);
180 : from = junctionID;
181 : to = junctionID;
182 : priority = -1;
183 196454 : } else {
184 224978 : from = attrs.get<std::string>(SUMO_ATTR_FROM, myCurrentName.c_str(), ok);
185 224978 : to = attrs.get<std::string>(SUMO_ATTR_TO, myCurrentName.c_str(), ok);
186 112489 : priority = attrs.get<int>(SUMO_ATTR_PRIORITY, myCurrentName.c_str(), ok);
187 112489 : if (!ok) {
188 : return;
189 : }
190 : }
191 308847 : RONode* fromNode = myNet.getNode(from);
192 258275 : if (fromNode == nullptr) {
193 : myUnseenNodeIDs.insert(from);
194 50572 : fromNode = new RONode(from);
195 50572 : myNet.addNode(fromNode);
196 : }
197 308847 : RONode* toNode = myNet.getNode(to);
198 285546 : if (toNode == nullptr) {
199 : myUnseenNodeIDs.insert(to);
200 23301 : toNode = new RONode(to);
201 23301 : myNet.addNode(toNode);
202 : }
203 : // build the edge
204 308847 : myCurrentEdge = myEdgeBuilder.buildEdge(myCurrentName, fromNode, toNode, priority);
205 : // set the type
206 617694 : myCurrentEdge->setRestrictions(myNet.getRestrictions(attrs.getOpt<std::string>(SUMO_ATTR_TYPE, myCurrentName.c_str(), ok, "")));
207 308847 : myCurrentEdge->setFunction(func);
208 :
209 308847 : if (myNet.addEdge(myCurrentEdge)) {
210 308823 : fromNode->addOutgoing(myCurrentEdge);
211 308823 : toNode->addIncoming(myCurrentEdge);
212 617646 : const std::string bidi = attrs.getOpt<std::string>(SUMO_ATTR_BIDI, myCurrentName.c_str(), ok, "");
213 308823 : if (bidi != "") {
214 11680 : myBidiEdges[myCurrentEdge] = bidi;
215 : }
216 : } else {
217 24 : myCurrentEdge = nullptr;
218 : }
219 : }
220 :
221 :
222 : void
223 352490 : RONetHandler::parseLane(const SUMOSAXAttributes& attrs) {
224 352490 : if (myCurrentEdge == nullptr) {
225 : // was an internal edge to skip or an error occurred
226 564 : return;
227 : }
228 352238 : bool ok = true;
229 : // get the id, report an error if not given or empty...
230 352238 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
231 352238 : if (!ok) {
232 : return;
233 : }
234 : // get the speed
235 352190 : double maxSpeed = attrs.get<double>(SUMO_ATTR_SPEED, id.c_str(), ok);
236 352190 : double length = attrs.get<double>(SUMO_ATTR_LENGTH, id.c_str(), ok);
237 352190 : std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, id.c_str(), ok, "");
238 704380 : std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, id.c_str(), ok, "");
239 352190 : const PositionVector shape = attrs.get<PositionVector>(SUMO_ATTR_SHAPE, id.c_str(), ok);
240 352190 : if (!ok) {
241 : return;
242 : }
243 351974 : if (shape.size() < 2) {
244 144 : WRITE_ERRORF(TL("Ignoring lane '%' with broken shape."), id);
245 48 : return;
246 : }
247 : // get the length
248 : // get the vehicle classes
249 351926 : SVCPermissions permissions = parseVehicleClasses(allow, disallow, myNetworkVersion);
250 351926 : if (permissions != SVCAll) {
251 248797 : myNet.setPermissionsFound();
252 : }
253 : // add when both values are valid
254 351926 : if (maxSpeed > 0 && length > 0 && id.length() > 0) {
255 351926 : myCurrentEdge->addLane(new ROLane(id, myCurrentEdge, length, maxSpeed, permissions, shape));
256 : } else {
257 0 : WRITE_WARNING("Ignoring lane '" + id + "' with speed " + toString(maxSpeed) + " and length " + toString(length));
258 : }
259 352190 : }
260 :
261 :
262 : void
263 97460 : RONetHandler::parseJunction(const SUMOSAXAttributes& attrs) {
264 97460 : bool ok = true;
265 : // get the id, report an error if not given or empty...
266 97460 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
267 97460 : const SumoXMLNodeType type = attrs.get<SumoXMLNodeType>(SUMO_ATTR_TYPE, id.c_str(), ok);
268 97460 : if (type == SumoXMLNodeType::INTERNAL) {
269 : return;
270 : }
271 : myUnseenNodeIDs.erase(id);
272 : // get the position of the node
273 72849 : const double x = attrs.get<double>(SUMO_ATTR_X, id.c_str(), ok);
274 72849 : const double y = attrs.get<double>(SUMO_ATTR_Y, id.c_str(), ok);
275 72849 : const double z = attrs.getOpt<double>(SUMO_ATTR_Z, id.c_str(), ok, 0.);
276 72849 : if (!ok) {
277 : return;
278 : }
279 72759 : RONode* n = myNet.getNode(id);
280 72559 : if (n == nullptr) {
281 600 : WRITE_WARNINGF(TL("Skipping isolated junction '%'."), id);
282 : } else {
283 72559 : n->setPosition(Position(x, y, z));
284 : }
285 : }
286 :
287 :
288 : void
289 451753 : RONetHandler::parseConnection(const SUMOSAXAttributes& attrs) {
290 451753 : bool ok = true;
291 451753 : std::string fromID = attrs.get<std::string>(SUMO_ATTR_FROM, nullptr, ok);
292 451753 : std::string toID = attrs.get<std::string>(SUMO_ATTR_TO, nullptr, ok);
293 451753 : const int fromLane = attrs.get<int>(SUMO_ATTR_FROM_LANE, nullptr, ok);
294 451753 : const int toLane = attrs.get<int>(SUMO_ATTR_TO_LANE, nullptr, ok);
295 451753 : std::string dir = attrs.get<std::string>(SUMO_ATTR_DIR, nullptr, ok);
296 452389 : std::string viaID = attrs.getOpt<std::string>(SUMO_ATTR_VIA, nullptr, ok, "");
297 452389 : std::string tlID = attrs.getOpt<std::string>(SUMO_ATTR_TLID, nullptr, ok, "");
298 451753 : ROEdge* from = myNet.getEdge(fromID);
299 : ROEdge* to = myNet.getEdge(toID);
300 451753 : if (from == nullptr) {
301 552 : throw ProcessError(TLF("unknown from-edge '%' in connection", fromID));
302 : }
303 451615 : if (to == nullptr) {
304 552 : throw ProcessError(TLF("unknown to-edge '%' in connection", toID));
305 : }
306 451477 : if ((int)from->getLanes().size() <= fromLane) {
307 360 : throw ProcessError("invalid fromLane '" + toString(fromLane) + "' in connection from '" + fromID + "'.");
308 : }
309 451297 : if ((int)to->getLanes().size() <= toLane) {
310 360 : throw ProcessError("invalid toLane '" + toString(toLane) + "' in connection to '" + toID + "'.");
311 : }
312 878113 : if (myIgnoreInternal || viaID == "") {
313 302109 : from->getLanes()[fromLane]->addOutgoingLane(to->getLanes()[toLane]);
314 906327 : from->addSuccessor(to, nullptr, dir);
315 302109 : if (to->isCrossing()) {
316 12120 : to->setTimePenalty(myTLSPenalty);
317 : }
318 : } else {
319 447024 : ROEdge* const via = myNet.getEdge(SUMOXMLDefinitions::getEdgeIDFromLane(viaID));
320 149008 : if (via == nullptr) {
321 0 : throw ProcessError(TLF("unknown via-edge '%' in connection", viaID));
322 : }
323 149008 : from->getLanes()[fromLane]->addOutgoingLane(to->getLanes()[toLane], via);
324 298016 : from->addSuccessor(to, via, dir);
325 298016 : via->addSuccessor(to, nullptr, dir);
326 149644 : LinkState state = SUMOXMLDefinitions::LinkStates.get(attrs.get<std::string>(SUMO_ATTR_STATE, nullptr, ok));
327 149008 : if (state == LINKSTATE_MINOR || state == LINKSTATE_EQUAL || state == LINKSTATE_STOP || state == LINKSTATE_ALLWAY_STOP) {
328 84348 : via->setTimePenalty(myMinorPenalty);
329 : }
330 149008 : if (tlID != "") {
331 14156 : via->setTimePenalty(myTLSPenalty);
332 14156 : if (to->isCrossing()) {
333 : to->setTimePenalty(myTLSPenalty);
334 : }
335 : }
336 : }
337 451117 : }
338 :
339 :
340 : void
341 1796 : RONetHandler::parseStoppingPlace(const SUMOSAXAttributes& attrs, const SumoXMLTag element) {
342 1796 : bool ok = true;
343 1796 : myCurrentStoppingPlace = new SUMOVehicleParameter::Stop();
344 : // get the id, throw if not given or empty...
345 1796 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, toString(element).c_str(), ok);
346 : // get the lane
347 3592 : myCurrentStoppingPlace->lane = attrs.get<std::string>(SUMO_ATTR_LANE, toString(element).c_str(), ok);
348 1796 : if (!ok) {
349 0 : throw ProcessError();
350 : }
351 1796 : const ROEdge* edge = myNet.getEdgeForLaneID(myCurrentStoppingPlace->lane);
352 1796 : if (edge == nullptr) {
353 0 : throw InvalidArgument("Unknown lane '" + myCurrentStoppingPlace->lane + "' for " + toString(element) + " '" + id + "'.");
354 : }
355 : // get the positions
356 1796 : myCurrentStoppingPlace->startPos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, id.c_str(), ok, 0.);
357 1796 : myCurrentStoppingPlace->endPos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok, edge->getLength());
358 1796 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
359 1796 : if (!ok || (SUMORouteHandler::checkStopPos(myCurrentStoppingPlace->startPos, myCurrentStoppingPlace->endPos, edge->getLength(), POSITION_EPS, friendlyPos) != SUMORouteHandler::StopPos::STOPPOS_VALID)) {
360 0 : throw InvalidArgument("Invalid position for " + toString(element) + " '" + id + "'.");
361 : }
362 : // this is a hack: the busstop attribute is meant to hold the id within the simulation context but this is not used within the router context
363 3592 : myCurrentStoppingPlace->busstop = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok, "");
364 : // this is a hack: the actType is not used when using this to encode a stopping place
365 1796 : myCurrentStoppingPlace->actType = toString(element);
366 1796 : myNet.addStoppingPlace(id, element, myCurrentStoppingPlace);
367 1796 : }
368 :
369 :
370 : void
371 1604 : RONetHandler::parseAccess(const SUMOSAXAttributes& attrs) {
372 1604 : bool ok = true;
373 1604 : const std::string lane = attrs.get<std::string>(SUMO_ATTR_LANE, "access", ok);
374 1604 : const ROEdge* edge = myNet.getEdgeForLaneID(lane);
375 1604 : if (edge == nullptr) {
376 0 : throw InvalidArgument("Unknown lane '" + lane + "' for access.");
377 : }
378 1604 : if ((edge->getPermissions() & SVC_PEDESTRIAN) == 0) {
379 0 : WRITE_WARNINGF(TL("Ignoring invalid access from non-pedestrian edge '%'."), edge->getID());
380 : return;
381 : }
382 3208 : const bool random = attrs.getOpt<std::string>(SUMO_ATTR_POSITION, "access", ok) == "random";
383 1604 : double pos = random ? edge->getLength() / 2. : attrs.getOpt<double>(SUMO_ATTR_POSITION, "access", ok, 0.);
384 1604 : double length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, "access", ok, -1);
385 1604 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, "access", ok, false);
386 1604 : if (!ok || (SUMORouteHandler::checkStopPos(pos, pos, edge->getLength(), 0., friendlyPos) != SUMORouteHandler::StopPos::STOPPOS_VALID)) {
387 0 : throw InvalidArgument("Invalid position " + toString(pos) + " for access on lane '" + lane + "'.");
388 : }
389 1604 : if (!ok) {
390 0 : throw ProcessError();
391 : }
392 1604 : if (length < 0) {
393 568 : const Position accPos = myNet.getLane(lane)->geometryPositionAtOffset(pos);
394 568 : const double stopCenter = (myCurrentStoppingPlace->startPos + myCurrentStoppingPlace->endPos) / 2;
395 568 : const Position stopPos = myNet.getLane(myCurrentStoppingPlace->lane)->geometryPositionAtOffset(stopCenter);
396 568 : length = accPos.distanceTo(stopPos);
397 : }
398 3208 : myCurrentStoppingPlace->accessPos.push_back(std::make_tuple(lane, pos, length));
399 : }
400 :
401 :
402 : void
403 313 : RONetHandler::parseDistrict(const SUMOSAXAttributes& attrs) {
404 313 : myCurrentEdge = nullptr;
405 313 : bool ok = true;
406 313 : myCurrentName = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
407 313 : if (!ok) {
408 0 : return;
409 : }
410 313 : ROEdge* const sink = myEdgeBuilder.buildEdge(myCurrentName + "-sink", nullptr, nullptr, 0);
411 313 : ROEdge* const source = myEdgeBuilder.buildEdge(myCurrentName + "-source", nullptr, nullptr, 0);
412 313 : myNet.addDistrict(myCurrentName, source, sink);
413 313 : if (attrs.hasAttribute(SUMO_ATTR_EDGES)) {
414 184 : const std::vector<std::string>& desc = attrs.get<std::vector<std::string> >(SUMO_ATTR_EDGES, myCurrentName.c_str(), ok);
415 611 : for (const std::string& eID : desc) {
416 1281 : myNet.addDistrictEdge(myCurrentName, eID, true);
417 1281 : myNet.addDistrictEdge(myCurrentName, eID, false);
418 : }
419 184 : }
420 : }
421 :
422 :
423 : void
424 233 : RONetHandler::parseDistrictEdge(const SUMOSAXAttributes& attrs, bool isSource) {
425 233 : bool ok = true;
426 233 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, myCurrentName.c_str(), ok);
427 699 : myNet.addDistrictEdge(myCurrentName, id, isSource);
428 233 : }
429 :
430 : void
431 5053 : RONetHandler::setLocation(const SUMOSAXAttributes& attrs) {
432 5053 : bool ok = true;
433 5053 : PositionVector s = attrs.get<PositionVector>(SUMO_ATTR_NET_OFFSET, nullptr, ok);
434 5053 : Boundary convBoundary = attrs.get<Boundary>(SUMO_ATTR_CONV_BOUNDARY, nullptr, ok);
435 5053 : Boundary origBoundary = attrs.get<Boundary>(SUMO_ATTR_ORIG_BOUNDARY, nullptr, ok);
436 5053 : std::string proj = attrs.get<std::string>(SUMO_ATTR_ORIG_PROJ, nullptr, ok);
437 5053 : if (ok) {
438 5053 : Position networkOffset = s[0];
439 5053 : GeoConvHelper::init(proj, networkOffset, origBoundary, convBoundary);
440 : }
441 5053 : }
442 :
443 :
444 : /****************************************************************************/
|