Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2002-2026 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 5032 : RONetHandler::RONetHandler(RONet& net, ROAbstractEdgeBuilder& eb, const bool ignoreInternal, const double minorPenalty, double tlsPenalty, double turnaroundPenalty) :
49 : SUMOSAXHandler("sumo-network"),
50 5032 : myNet(net),
51 : myNetworkVersion(0, 0),
52 5032 : myEdgeBuilder(eb), myIgnoreInternal(ignoreInternal),
53 5032 : myCurrentName(), myCurrentEdge(nullptr), myCurrentStoppingPlace(nullptr),
54 5032 : myMinorPenalty(minorPenalty),
55 5032 : myTLSPenalty(tlsPenalty),
56 10064 : myTurnaroundPenalty(turnaroundPenalty)
57 5032 : {}
58 :
59 :
60 10064 : RONetHandler::~RONetHandler() {}
61 :
62 :
63 : void
64 1709318 : RONetHandler::myStartElement(int element,
65 : const SUMOSAXAttributes& attrs) {
66 1709318 : switch (element) {
67 5032 : case SUMO_TAG_LOCATION:
68 5032 : setLocation(attrs);
69 5032 : break;
70 5032 : case SUMO_TAG_NET: {
71 : bool ok;
72 10064 : myNetworkVersion = StringUtils::toVersion(attrs.get<std::string>(SUMO_ATTR_VERSION, nullptr, ok, false));
73 : break;
74 : }
75 346089 : case SUMO_TAG_EDGE:
76 : // in the first step, we do need the name to allocate the edge
77 : // in the second, we need it to know to which edge we have to add
78 : // the following edges to
79 346089 : parseEdge(attrs);
80 346077 : break;
81 391149 : case SUMO_TAG_LANE:
82 391149 : parseLane(attrs);
83 391149 : break;
84 109700 : case SUMO_TAG_JUNCTION:
85 109700 : parseJunction(attrs);
86 109700 : break;
87 506828 : case SUMO_TAG_CONNECTION:
88 506828 : parseConnection(attrs);
89 506510 : break;
90 2335 : case SUMO_TAG_BUS_STOP:
91 : case SUMO_TAG_TRAIN_STOP:
92 : case SUMO_TAG_CONTAINER_STOP:
93 : case SUMO_TAG_PARKING_AREA:
94 : case SUMO_TAG_CHARGING_STATION:
95 : case SUMO_TAG_OVERHEAD_WIRE_SEGMENT:
96 2335 : parseStoppingPlace(attrs, (SumoXMLTag)element);
97 2335 : break;
98 2219 : case SUMO_TAG_ACCESS:
99 2219 : parseAccess(attrs);
100 2219 : break;
101 427 : case SUMO_TAG_TAZ:
102 427 : parseDistrict(attrs);
103 427 : break;
104 145 : case SUMO_TAG_TAZSOURCE:
105 145 : parseDistrictEdge(attrs, true);
106 145 : break;
107 145 : case SUMO_TAG_TAZSINK:
108 145 : parseDistrictEdge(attrs, false);
109 145 : break;
110 2551 : case SUMO_TAG_TYPE: {
111 2551 : bool ok = true;
112 5102 : myCurrentTypeID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
113 : break;
114 : }
115 21 : case SUMO_TAG_RESTRICTION: {
116 21 : bool ok = true;
117 42 : const SUMOVehicleClass svc = getVehicleClassID(attrs.get<std::string>(SUMO_ATTR_VCLASS, myCurrentTypeID.c_str(), ok));
118 21 : const double speed = attrs.get<double>(SUMO_ATTR_SPEED, myCurrentTypeID.c_str(), ok);
119 21 : if (ok) {
120 21 : myNet.addSpeedRestriction(myCurrentTypeID, svc, speed);
121 : }
122 : break;
123 : }
124 50 : case SUMO_TAG_PREFERENCE: {
125 50 : bool ok = true;
126 50 : const std::string routingType = attrs.get<std::string>(SUMO_ATTR_ROUTINGTYPE, nullptr, ok);
127 50 : const double prio = attrs.get<double>(SUMO_ATTR_PRIORITY, routingType.c_str(), ok);
128 50 : if (prio <= 0) {
129 0 : throw InvalidArgument("In preference for routingType '" + routingType + "', priority must be positve");
130 : }
131 50 : if (attrs.hasAttribute(SUMO_ATTR_VCLASSES)) {
132 10 : StringTokenizer st(attrs.get<std::string>(SUMO_ATTR_VCLASSES, routingType.c_str(), ok));
133 40 : for (std::string className : st.getVector()) {
134 30 : myNet.addPreference(routingType, getVehicleClassID(className), prio);
135 10 : }
136 50 : } else if (!attrs.hasAttribute(SUMO_ATTR_VTYPES)) {
137 : // general preferenze applying to all types and vClasses
138 60 : myNet.addPreference(routingType, "", prio);
139 : }
140 50 : if (attrs.hasAttribute(SUMO_ATTR_VTYPES)) {
141 10 : StringTokenizer st(attrs.get<std::string>(SUMO_ATTR_VTYPES, routingType.c_str(), ok));
142 20 : for (std::string typeName : st.getVector()) {
143 30 : myNet.addPreference(routingType, typeName, prio);
144 10 : }
145 10 : }
146 : break;
147 : }
148 10 : case SUMO_TAG_REROUTER: {
149 10 : bool ok = true;
150 20 : myRerouterID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
151 : break;
152 : }
153 10 : case SUMO_TAG_INTERVAL:
154 10 : if (myRerouterID != "") {
155 10 : bool ok = true;
156 10 : myIntervalBegin = attrs.getOptSUMOTimeReporting(SUMO_ATTR_BEGIN, myRerouterID.c_str(), ok, -1);
157 10 : myIntervalEnd = attrs.getOptSUMOTimeReporting(SUMO_ATTR_END, myRerouterID.c_str(), ok, SUMOTime_MAX);
158 10 : if (myIntervalEnd <= myIntervalBegin) {
159 0 : throw ProcessError(TLF("Invalid rerouter interval from % to %", time2string(myIntervalBegin), time2string(myIntervalEnd)));
160 : }
161 : }
162 : break;
163 5 : case SUMO_TAG_CLOSING_REROUTE: {
164 5 : const std::string& closed_id = attrs.getStringSecure(SUMO_ATTR_ID, "");
165 5 : ROEdge* closedEdge = myNet.getEdge(closed_id);
166 5 : if (closedEdge == nullptr) {
167 0 : throw ProcessError(TLF("rerouter '%': Edge '%' to close is not known.", myRerouterID, closed_id));
168 : }
169 : bool ok;
170 5 : const std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, myRerouterID.c_str(), ok, "", false);
171 5 : const std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, myRerouterID.c_str(), ok, "");
172 5 : RouterProhibition prohibition;
173 5 : prohibition.permissions = parseVehicleClasses(allow, disallow);
174 5 : prohibition.begin = STEPS2TIME(myIntervalBegin);
175 5 : prohibition.end = STEPS2TIME(attrs.getOptSUMOTimeReporting(SUMO_ATTR_UNTIL, nullptr, ok, myIntervalEnd));
176 5 : myNet.addProhibition(closedEdge, prohibition);
177 : break;
178 : }
179 5 : case SUMO_TAG_CLOSING_LANE_REROUTE: {
180 5 : const std::string& closed_id = attrs.getStringSecure(SUMO_ATTR_ID, "");
181 5 : ROLane* closedLane = myNet.getLane(closed_id);
182 5 : if (closedLane == nullptr) {
183 0 : throw ProcessError(TLF("rerouter '%': Lane '%' to close is not known.", myRerouterID, closed_id));
184 : }
185 : bool ok;
186 5 : const std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, myRerouterID.c_str(), ok, "", false);
187 5 : const std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, myRerouterID.c_str(), ok, "");
188 5 : RouterProhibition prohibition;
189 5 : prohibition.permissions = parseVehicleClasses(allow, disallow);
190 5 : prohibition.begin = STEPS2TIME(myIntervalBegin);
191 5 : prohibition.end = STEPS2TIME(attrs.getOptSUMOTimeReporting(SUMO_ATTR_UNTIL, nullptr, ok, myIntervalEnd));
192 5 : myNet.addLaneProhibition(closedLane, prohibition);
193 : break;
194 : }
195 102962 : case SUMO_TAG_PARAM:
196 102962 : addParam(attrs);
197 102962 : break;
198 : default:
199 : break;
200 : }
201 1708988 : }
202 :
203 :
204 : void
205 1708223 : RONetHandler::myEndElement(int element) {
206 1708223 : switch (element) {
207 10 : case SUMO_TAG_REROUTER:
208 10 : myRerouterID = "";
209 : break;
210 4447 : case SUMO_TAG_NET:
211 : // build junction graph
212 4525 : for (std::set<std::string>::const_iterator it = myUnseenNodeIDs.begin(); it != myUnseenNodeIDs.end(); ++it) {
213 234 : WRITE_ERRORF(TL("Unknown node '%'."), *it);
214 : }
215 : break;
216 : default:
217 : break;
218 : }
219 1708223 : }
220 :
221 :
222 : void
223 102962 : RONetHandler::addParam(const SUMOSAXAttributes& attrs) {
224 102962 : bool ok = true;
225 102962 : const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
226 : // circumventing empty string test
227 102962 : const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
228 : // add parameter in current created element, or in myLoadedParameterised
229 102962 : if (myCurrentEdge != nullptr) {
230 102962 : myCurrentEdge->setParameter(key, val);
231 : }
232 102962 : }
233 :
234 :
235 : void
236 346089 : RONetHandler::parseEdge(const SUMOSAXAttributes& attrs) {
237 : // get the id, report an error if not given or empty...
238 346089 : bool ok = true;
239 346089 : myCurrentName = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
240 346089 : if (!ok) {
241 12 : throw ProcessError();
242 : }
243 346077 : const SumoXMLEdgeFunc func = attrs.getOpt<SumoXMLEdgeFunc>(SUMO_ATTR_FUNCTION, myCurrentName.c_str(), ok, SumoXMLEdgeFunc::NORMAL);
244 346077 : if (!ok) {
245 54 : return;
246 : }
247 : // get the edge
248 : std::string from;
249 : std::string to;
250 : int priority;
251 346071 : myCurrentEdge = nullptr;
252 346071 : if (func == SumoXMLEdgeFunc::INTERNAL || func == SumoXMLEdgeFunc::CROSSING || func == SumoXMLEdgeFunc::WALKINGAREA) {
253 : assert(myCurrentName[0] == ':');
254 439562 : const std::string junctionID = SUMOXMLDefinitions::getJunctionIDFromInternalEdge(myCurrentName);
255 : from = junctionID;
256 : to = junctionID;
257 : priority = -1;
258 219781 : } else {
259 252580 : from = attrs.get<std::string>(SUMO_ATTR_FROM, myCurrentName.c_str(), ok);
260 252580 : to = attrs.get<std::string>(SUMO_ATTR_TO, myCurrentName.c_str(), ok);
261 126290 : priority = attrs.get<int>(SUMO_ATTR_PRIORITY, myCurrentName.c_str(), ok);
262 126290 : if (!ok) {
263 : return;
264 : }
265 : }
266 346023 : RONode* fromNode = myNet.getNode(from);
267 290309 : if (fromNode == nullptr) {
268 : myUnseenNodeIDs.insert(from);
269 55714 : fromNode = new RONode(from);
270 55714 : myNet.addNode(fromNode);
271 : }
272 346023 : RONode* toNode = myNet.getNode(to);
273 320555 : if (toNode == nullptr) {
274 : myUnseenNodeIDs.insert(to);
275 25468 : toNode = new RONode(to);
276 25468 : myNet.addNode(toNode);
277 : }
278 346023 : const std::string type = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, myCurrentName.c_str(), ok, "");
279 346023 : const std::string routingType = attrs.getOpt<std::string>(SUMO_ATTR_ROUTINGTYPE, myCurrentName.c_str(), ok, "");
280 : // build the edge
281 346023 : myCurrentEdge = myEdgeBuilder.buildEdge(myCurrentName, fromNode, toNode, priority, type, routingType);
282 : myCurrentEdge->setFunction(func);
283 :
284 346023 : if (myNet.addEdge(myCurrentEdge)) {
285 346011 : fromNode->addOutgoing(myCurrentEdge);
286 346011 : toNode->addIncoming(myCurrentEdge);
287 692022 : const std::string bidi = attrs.getOpt<std::string>(SUMO_ATTR_BIDI, myCurrentName.c_str(), ok, "");
288 346011 : if (bidi != "") {
289 13148 : myBidiEdges[myCurrentEdge] = bidi;
290 : }
291 : } else {
292 12 : myCurrentEdge = nullptr;
293 : }
294 : }
295 :
296 :
297 : void
298 391149 : RONetHandler::parseLane(const SUMOSAXAttributes& attrs) {
299 391149 : if (myCurrentEdge == nullptr) {
300 : // was an internal edge to skip or an error occurred
301 282 : return;
302 : }
303 391023 : bool ok = true;
304 : // get the id, report an error if not given or empty...
305 391023 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
306 391023 : if (!ok) {
307 : return;
308 : }
309 : // get the speed
310 390999 : double maxSpeed = attrs.get<double>(SUMO_ATTR_SPEED, id.c_str(), ok);
311 390999 : double length = attrs.get<double>(SUMO_ATTR_LENGTH, id.c_str(), ok);
312 390999 : std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, id.c_str(), ok, "");
313 781998 : std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, id.c_str(), ok, "");
314 390999 : const PositionVector shape = attrs.get<PositionVector>(SUMO_ATTR_SHAPE, id.c_str(), ok);
315 390999 : if (!ok) {
316 : return;
317 : }
318 390891 : if (shape.size() < 2 && myCurrentEdge->getFunction() != SumoXMLEdgeFunc::WALKINGAREA) {
319 72 : WRITE_ERRORF(TL("Ignoring lane '%' with broken shape."), id);
320 24 : return;
321 : }
322 : // get the length
323 : // get the vehicle classes
324 390867 : SVCPermissions permissions = parseVehicleClasses(allow, disallow, myNetworkVersion);
325 390867 : if (permissions != SVCAll) {
326 260019 : myNet.setPermissionsFound();
327 : }
328 : // add when both values are valid
329 390867 : if (maxSpeed > 0 && length > 0 && id.length() > 0) {
330 390867 : myCurrentEdge->addLane(new ROLane(id, myCurrentEdge, length, maxSpeed, permissions, shape));
331 : } else {
332 0 : WRITE_WARNING("Ignoring lane '" + id + "' with speed " + toString(maxSpeed) + " and length " + toString(length));
333 : }
334 390999 : }
335 :
336 :
337 : void
338 109700 : RONetHandler::parseJunction(const SUMOSAXAttributes& attrs) {
339 109700 : bool ok = true;
340 : // get the id, report an error if not given or empty...
341 109700 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
342 109700 : const SumoXMLNodeType type = attrs.get<SumoXMLNodeType>(SUMO_ATTR_TYPE, id.c_str(), ok);
343 109700 : if (type == SumoXMLNodeType::INTERNAL) {
344 : return;
345 : }
346 : myUnseenNodeIDs.erase(id);
347 : // get the position of the node
348 80674 : const double x = attrs.get<double>(SUMO_ATTR_X, id.c_str(), ok);
349 80674 : const double y = attrs.get<double>(SUMO_ATTR_Y, id.c_str(), ok);
350 80674 : const double z = attrs.getOpt<double>(SUMO_ATTR_Z, id.c_str(), ok, 0.);
351 80674 : if (!ok) {
352 : return;
353 : }
354 80629 : RONode* n = myNet.getNode(id);
355 80525 : if (n == nullptr) {
356 312 : WRITE_WARNINGF(TL("Skipping isolated junction '%'."), id);
357 : } else {
358 80525 : n->setPosition(Position(x, y, z));
359 : }
360 : }
361 :
362 :
363 : void
364 506828 : RONetHandler::parseConnection(const SUMOSAXAttributes& attrs) {
365 506828 : bool ok = true;
366 506828 : std::string fromID = attrs.get<std::string>(SUMO_ATTR_FROM, nullptr, ok);
367 506828 : std::string toID = attrs.get<std::string>(SUMO_ATTR_TO, nullptr, ok);
368 506828 : const int fromLane = attrs.get<int>(SUMO_ATTR_FROM_LANE, nullptr, ok);
369 506828 : const int toLane = attrs.get<int>(SUMO_ATTR_TO_LANE, nullptr, ok);
370 506828 : std::string dir = attrs.get<std::string>(SUMO_ATTR_DIR, nullptr, ok);
371 507146 : std::string viaID = attrs.getOpt<std::string>(SUMO_ATTR_VIA, nullptr, ok, "");
372 507146 : std::string tlID = attrs.getOpt<std::string>(SUMO_ATTR_TLID, nullptr, ok, "");
373 506828 : ROEdge* from = myNet.getEdge(fromID);
374 : ROEdge* to = myNet.getEdge(toID);
375 506828 : if (from == nullptr) {
376 207 : throw ProcessError(TLF("unknown from-edge '%' in connection", fromID));
377 : }
378 506759 : if (to == nullptr) {
379 207 : throw ProcessError(TLF("unknown to-edge '%' in connection", toID));
380 : }
381 506690 : if ((int)from->getLanes().size() <= fromLane) {
382 270 : throw ProcessError("invalid fromLane '" + toString(fromLane) + "' in connection from '" + fromID + "'.");
383 : }
384 506600 : if ((int)to->getLanes().size() <= toLane) {
385 270 : throw ProcessError("invalid toLane '" + toString(toLane) + "' in connection to '" + toID + "'.");
386 : }
387 506510 : if (myIgnoreInternal || viaID == "") {
388 333325 : std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, nullptr, ok, "");
389 333325 : std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, nullptr, ok, "");
390 : ROEdge* dummyVia = nullptr;
391 : SVCPermissions permissions;
392 333325 : if (allow == "" && disallow == "") {
393 : permissions = SVC_UNSPECIFIED;
394 : } else {
395 16 : myNet.setPermissionsFound();
396 : // dummyVia is only needed to hold permissions
397 16 : permissions = parseVehicleClasses(allow, disallow);
398 16 : dummyVia = new ROEdge("dummyVia_" + from->getLanes()[fromLane]->getID() + "->" + to->getLanes()[toLane]->getID(),
399 32 : from->getToJunction(), from->getToJunction(), permissions);
400 16 : myNet.addEdge(dummyVia);
401 : }
402 333325 : from->getLanes()[fromLane]->addOutgoingLane(to->getLanes()[toLane], dummyVia);
403 999975 : from->addSuccessor(to, nullptr, dir);
404 : } else {
405 173185 : ROEdge* const via = myNet.getEdge(SUMOXMLDefinitions::getEdgeIDFromLane(viaID));
406 173185 : if (via == nullptr) {
407 0 : throw ProcessError(TLF("unknown via-edge '%' in connection", viaID));
408 : }
409 173185 : from->getLanes()[fromLane]->addOutgoingLane(to->getLanes()[toLane], via);
410 346370 : from->addSuccessor(to, via, dir);
411 346370 : via->addSuccessor(to, nullptr, dir);
412 173185 : LinkState state = SUMOXMLDefinitions::LinkStates.get(attrs.get<std::string>(SUMO_ATTR_STATE, nullptr, ok));
413 173185 : if (state == LINKSTATE_MINOR || state == LINKSTATE_EQUAL || state == LINKSTATE_STOP || state == LINKSTATE_ALLWAY_STOP) {
414 100866 : via->setTimePenalty(myMinorPenalty);
415 : }
416 308021 : if (dir == toString(LinkDirection::TURN) || dir == toString(LinkDirection::TURN_LEFTHAND)) {
417 38671 : via->setTimePenalty(myTurnaroundPenalty);
418 : }
419 173185 : if (tlID != "") {
420 13717 : via->setTimePenalty(myTLSPenalty);
421 : }
422 : }
423 506510 : if (to->isCrossing()) {
424 12468 : to->setTimePenalty(myTLSPenalty);
425 : }
426 506510 : }
427 :
428 :
429 : void
430 2335 : RONetHandler::parseStoppingPlace(const SUMOSAXAttributes& attrs, const SumoXMLTag element) {
431 2335 : bool ok = true;
432 2335 : myCurrentStoppingPlace = new SUMOVehicleParameter::Stop();
433 : // get the id, throw if not given or empty...
434 2335 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, toString(element).c_str(), ok);
435 : // get the lane
436 2335 : myCurrentStoppingPlace->lane = attrs.get<std::string>(SUMO_ATTR_LANE, toString(element).c_str(), ok);
437 2335 : if (!ok) {
438 0 : throw ProcessError();
439 : }
440 2335 : const ROEdge* edge = myNet.getEdgeForLaneID(myCurrentStoppingPlace->lane);
441 2335 : if (edge == nullptr) {
442 0 : throw InvalidArgument("Unknown lane '" + myCurrentStoppingPlace->lane + "' for " + toString(element) + " '" + id + "'.");
443 : }
444 : // get the positions
445 2335 : myCurrentStoppingPlace->startPos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, id.c_str(), ok, 0.);
446 2335 : myCurrentStoppingPlace->endPos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok, edge->getLength());
447 2335 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
448 2335 : if (!ok || (SUMORouteHandler::checkStopPos(myCurrentStoppingPlace->startPos, myCurrentStoppingPlace->endPos, edge->getLength(), POSITION_EPS, friendlyPos) != SUMORouteHandler::StopPos::STOPPOS_VALID)) {
449 0 : throw InvalidArgument("Invalid position for " + toString(element) + " '" + id + "'.");
450 : }
451 : // 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
452 2335 : myCurrentStoppingPlace->busstop = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok, "");
453 : // this is a hack: the actType is not used when using this to encode a stopping place
454 2335 : myCurrentStoppingPlace->actType = toString(element);
455 2335 : myNet.addStoppingPlace(id, element, myCurrentStoppingPlace);
456 2335 : }
457 :
458 :
459 : void
460 2219 : RONetHandler::parseAccess(const SUMOSAXAttributes& attrs) {
461 2219 : bool ok = true;
462 2219 : const std::string lane = attrs.get<std::string>(SUMO_ATTR_LANE, "access", ok);
463 2219 : const ROEdge* edge = myNet.getEdgeForLaneID(lane);
464 2219 : if (edge == nullptr) {
465 0 : throw InvalidArgument("Unknown lane '" + lane + "' for access.");
466 : }
467 2219 : if ((edge->getPermissions() & SVC_PEDESTRIAN) == 0) {
468 0 : WRITE_WARNINGF(TL("Ignoring invalid access from non-pedestrian edge '%'."), edge->getID());
469 : return;
470 : }
471 2219 : const bool random = attrs.getOpt<std::string>(SUMO_ATTR_POSITION, "access", ok) == "random";
472 2219 : double pos = random ? edge->getLength() / 2. : attrs.getOpt<double>(SUMO_ATTR_POSITION, "access", ok, 0.);
473 2219 : double length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, "access", ok, -1);
474 2219 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, "access", ok, false);
475 2219 : if (!ok || (SUMORouteHandler::checkStopPos(pos, pos, edge->getLength(), 0., friendlyPos) != SUMORouteHandler::StopPos::STOPPOS_VALID)) {
476 0 : throw InvalidArgument("Invalid position " + toString(pos) + " for access on lane '" + lane + "'.");
477 : }
478 : if (!ok) {
479 : throw ProcessError();
480 : }
481 2219 : if (length < 0) {
482 710 : const Position accPos = myNet.getLane(lane)->geometryPositionAtOffset(pos);
483 710 : const double stopCenter = (myCurrentStoppingPlace->startPos + myCurrentStoppingPlace->endPos) / 2;
484 710 : const Position stopPos = myNet.getLane(myCurrentStoppingPlace->lane)->geometryPositionAtOffset(stopCenter);
485 710 : length = accPos.distanceTo(stopPos);
486 : }
487 4438 : myCurrentStoppingPlace->accessPos.push_back(std::make_tuple(lane, pos, length));
488 : }
489 :
490 :
491 : void
492 427 : RONetHandler::parseDistrict(const SUMOSAXAttributes& attrs) {
493 427 : myCurrentEdge = nullptr;
494 427 : bool ok = true;
495 427 : myCurrentName = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
496 427 : if (!ok) {
497 0 : return;
498 : }
499 854 : ROEdge* const sink = myEdgeBuilder.buildEdge(myCurrentName + "-sink", nullptr, nullptr, 0, "", "");
500 854 : ROEdge* const source = myEdgeBuilder.buildEdge(myCurrentName + "-source", nullptr, nullptr, 0, "", "");
501 427 : myNet.addDistrict(myCurrentName, source, sink);
502 427 : if (attrs.hasAttribute(SUMO_ATTR_EDGES)) {
503 265 : const std::vector<std::string>& desc = attrs.get<std::vector<std::string> >(SUMO_ATTR_EDGES, myCurrentName.c_str(), ok);
504 875 : for (const std::string& eID : desc) {
505 1830 : myNet.addDistrictEdge(myCurrentName, eID, true);
506 1830 : myNet.addDistrictEdge(myCurrentName, eID, false);
507 : }
508 265 : }
509 : }
510 :
511 :
512 : void
513 290 : RONetHandler::parseDistrictEdge(const SUMOSAXAttributes& attrs, bool isSource) {
514 290 : bool ok = true;
515 290 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, myCurrentName.c_str(), ok);
516 870 : myNet.addDistrictEdge(myCurrentName, id, isSource);
517 290 : }
518 :
519 : void
520 5032 : RONetHandler::setLocation(const SUMOSAXAttributes& attrs) {
521 5032 : bool ok = true;
522 5032 : PositionVector s = attrs.get<PositionVector>(SUMO_ATTR_NET_OFFSET, nullptr, ok);
523 5032 : Boundary convBoundary = attrs.get<Boundary>(SUMO_ATTR_CONV_BOUNDARY, nullptr, ok);
524 5032 : Boundary origBoundary = attrs.get<Boundary>(SUMO_ATTR_ORIG_BOUNDARY, nullptr, ok);
525 5032 : std::string proj = attrs.get<std::string>(SUMO_ATTR_ORIG_PROJ, nullptr, ok);
526 5032 : if (ok) {
527 5032 : Position networkOffset = s[0];
528 5032 : GeoConvHelper::init(proj, networkOffset, origBoundary, convBoundary);
529 : }
530 5032 : }
531 :
532 :
533 : /****************************************************************************/
|