1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2002-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file RONetHandler.cpp
11 /// @author Daniel Krajzewicz
12 /// @author Jakob Erdmann
13 /// @author Christian Roessel
14 /// @author Michael Behrisch
15 /// @author Yun-Pang Floetteroed
16 /// @date Sept 2002
17 /// @version $Id$
18 ///
19 // The handler for SUMO-Networks
20 /****************************************************************************/
21
22
23 // ===========================================================================
24 // included modules
25 // ===========================================================================
26 #include <config.h>
27
28 #include <string>
29 #include <utils/common/MsgHandler.h>
30 #include <utils/common/StringTokenizer.h>
31 #include <utils/common/UtilExceptions.h>
32 #include <utils/common/ToString.h>
33 #include <utils/common/StringUtils.h>
34 #include <utils/geom/PositionVector.h>
35 #include <utils/geom/GeoConvHelper.h>
36 #include <utils/vehicle/SUMORouteHandler.h>
37 #include <utils/xml/SUMOSAXHandler.h>
38 #include <utils/xml/SUMOXMLDefinitions.h>
39 #include "ROEdge.h"
40 #include "ROLane.h"
41 #include "RONode.h"
42 #include "RONet.h"
43 #include "RONetHandler.h"
44 #include "ROAbstractEdgeBuilder.h"
45
46
47 // ===========================================================================
48 // method definitions
49 // ===========================================================================
RONetHandler(RONet & net,ROAbstractEdgeBuilder & eb,const bool ignoreInternal,const double minorPenalty)50 RONetHandler::RONetHandler(RONet& net, ROAbstractEdgeBuilder& eb, const bool ignoreInternal, const double minorPenalty) :
51 SUMOSAXHandler("sumo-network"),
52 myNet(net), myEdgeBuilder(eb), myIgnoreInternal(ignoreInternal),
53 myCurrentName(), myCurrentEdge(nullptr), myCurrentStoppingPlace(nullptr),
54 myMinorPenalty(minorPenalty)
55 {}
56
57
~RONetHandler()58 RONetHandler::~RONetHandler() {}
59
60
61 void
myStartElement(int element,const SUMOSAXAttributes & attrs)62 RONetHandler::myStartElement(int element,
63 const SUMOSAXAttributes& attrs) {
64 switch (element) {
65 case SUMO_TAG_LOCATION:
66 setLocation(attrs);
67 break;
68 case SUMO_TAG_EDGE:
69 // in the first step, we do need the name to allocate the edge
70 // in the second, we need it to know to which edge we have to add
71 // the following edges to
72 parseEdge(attrs);
73 break;
74 case SUMO_TAG_LANE:
75 parseLane(attrs);
76 break;
77 case SUMO_TAG_JUNCTION:
78 parseJunction(attrs);
79 break;
80 case SUMO_TAG_CONNECTION:
81 parseConnection(attrs);
82 break;
83 case SUMO_TAG_BUS_STOP:
84 case SUMO_TAG_TRAIN_STOP:
85 case SUMO_TAG_CONTAINER_STOP:
86 case SUMO_TAG_PARKING_AREA:
87 parseStoppingPlace(attrs, (SumoXMLTag)element);
88 break;
89 case SUMO_TAG_ACCESS:
90 parseAccess(attrs);
91 break;
92 case SUMO_TAG_TAZ:
93 parseDistrict(attrs);
94 break;
95 case SUMO_TAG_TAZSOURCE:
96 parseDistrictEdge(attrs, true);
97 break;
98 case SUMO_TAG_TAZSINK:
99 parseDistrictEdge(attrs, false);
100 break;
101 case SUMO_TAG_TYPE: {
102 bool ok = true;
103 myCurrentTypeID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
104 break;
105 }
106 case SUMO_TAG_RESTRICTION: {
107 bool ok = true;
108 const SUMOVehicleClass svc = getVehicleClassID(attrs.get<std::string>(SUMO_ATTR_VCLASS, myCurrentTypeID.c_str(), ok));
109 const double speed = attrs.get<double>(SUMO_ATTR_SPEED, myCurrentTypeID.c_str(), ok);
110 if (ok) {
111 myNet.addRestriction(myCurrentTypeID, svc, speed);
112 }
113 break;
114 }
115 default:
116 break;
117 }
118 }
119
120
121 void
myEndElement(int element)122 RONetHandler::myEndElement(int element) {
123 switch (element) {
124 case SUMO_TAG_NET:
125 // build junction graph
126 for (std::set<std::string>::const_iterator it = myUnseenNodeIDs.begin(); it != myUnseenNodeIDs.end(); ++it) {
127 WRITE_ERROR("Unknown node '" + *it + "'.");
128 }
129 break;
130 default:
131 break;
132 }
133 }
134
135
136 void
parseEdge(const SUMOSAXAttributes & attrs)137 RONetHandler::parseEdge(const SUMOSAXAttributes& attrs) {
138 // get the id, report an error if not given or empty...
139 bool ok = true;
140 myCurrentName = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
141 if (!ok) {
142 throw ProcessError();
143 }
144 const SumoXMLEdgeFunc func = attrs.getEdgeFunc(ok);
145 if (!ok) {
146 WRITE_ERROR("Edge '" + myCurrentName + "' has an unknown type.");
147 return;
148 }
149 // get the edge
150 std::string from;
151 std::string to;
152 int priority;
153 myCurrentEdge = nullptr;
154 if (func == EDGEFUNC_INTERNAL || func == EDGEFUNC_CROSSING || func == EDGEFUNC_WALKINGAREA) {
155 assert(myCurrentName[0] == ':');
156 const std::string junctionID = myCurrentName.substr(1, myCurrentName.rfind('_') - 1);
157 from = junctionID;
158 to = junctionID;
159 priority = 0;
160 } else {
161 from = attrs.get<std::string>(SUMO_ATTR_FROM, myCurrentName.c_str(), ok);
162 to = attrs.get<std::string>(SUMO_ATTR_TO, myCurrentName.c_str(), ok);
163 priority = attrs.get<int>(SUMO_ATTR_PRIORITY, myCurrentName.c_str(), ok);
164 if (!ok) {
165 return;
166 }
167 }
168 RONode* fromNode = myNet.getNode(from);
169 if (fromNode == nullptr) {
170 myUnseenNodeIDs.insert(from);
171 fromNode = new RONode(from);
172 myNet.addNode(fromNode);
173 }
174 RONode* toNode = myNet.getNode(to);
175 if (toNode == nullptr) {
176 myUnseenNodeIDs.insert(to);
177 toNode = new RONode(to);
178 myNet.addNode(toNode);
179 }
180 // build the edge
181 myCurrentEdge = myEdgeBuilder.buildEdge(myCurrentName, fromNode, toNode, priority);
182 // set the type
183 myCurrentEdge->setRestrictions(myNet.getRestrictions(attrs.getOpt<std::string>(SUMO_ATTR_TYPE, myCurrentName.c_str(), ok, "")));
184 myCurrentEdge->setFunction(func);
185
186 if (myNet.addEdge(myCurrentEdge)) {
187 fromNode->addOutgoing(myCurrentEdge);
188 toNode->addIncoming(myCurrentEdge);
189 } else {
190 myCurrentEdge = nullptr;
191 }
192 }
193
194
195 void
parseLane(const SUMOSAXAttributes & attrs)196 RONetHandler::parseLane(const SUMOSAXAttributes& attrs) {
197 if (myCurrentEdge == nullptr) {
198 // was an internal edge to skip or an error occurred
199 return;
200 }
201 bool ok = true;
202 // get the id, report an error if not given or empty...
203 std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
204 if (!ok) {
205 return;
206 }
207 // get the speed
208 double maxSpeed = attrs.get<double>(SUMO_ATTR_SPEED, id.c_str(), ok);
209 double length = attrs.get<double>(SUMO_ATTR_LENGTH, id.c_str(), ok);
210 std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, id.c_str(), ok, "");
211 std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, id.c_str(), ok, "");
212 const PositionVector shape = attrs.get<PositionVector>(SUMO_ATTR_SHAPE, id.c_str(), ok);
213 if (!ok) {
214 return;
215 }
216 if (shape.size() < 2) {
217 WRITE_ERROR("Ignoring lane '" + id + "' with broken shape.");
218 return;
219 }
220 // get the length
221 // get the vehicle classes
222 SVCPermissions permissions = parseVehicleClasses(allow, disallow);
223 if (permissions != SVCAll) {
224 myNet.setPermissionsFound();
225 }
226 // add when both values are valid
227 if (maxSpeed > 0 && length > 0 && id.length() > 0) {
228 myCurrentEdge->addLane(new ROLane(id, myCurrentEdge, length, maxSpeed, permissions, shape));
229 } else {
230 WRITE_WARNING("Ignoring lane '" + id + "' with speed " + toString(maxSpeed) + " and length " + toString(length));
231 }
232 }
233
234
235 void
parseJunction(const SUMOSAXAttributes & attrs)236 RONetHandler::parseJunction(const SUMOSAXAttributes& attrs) {
237 bool ok = true;
238 // get the id, report an error if not given or empty...
239 std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
240 if (attrs.getNodeType(ok) == NODETYPE_INTERNAL) {
241 return;
242 }
243 myUnseenNodeIDs.erase(id);
244 // get the position of the node
245 const double x = attrs.get<double>(SUMO_ATTR_X, id.c_str(), ok);
246 const double y = attrs.get<double>(SUMO_ATTR_Y, id.c_str(), ok);
247 const double z = attrs.getOpt<double>(SUMO_ATTR_Z, id.c_str(), ok, 0.);
248 if (!ok) {
249 return;
250 }
251 RONode* n = myNet.getNode(id);
252 if (n == nullptr) {
253 WRITE_WARNING("Skipping isolated junction '" + id + "'.");
254 } else {
255 n->setPosition(Position(x, y, z));
256 }
257 }
258
259
260 void
parseConnection(const SUMOSAXAttributes & attrs)261 RONetHandler::parseConnection(const SUMOSAXAttributes& attrs) {
262 bool ok = true;
263 std::string fromID = attrs.get<std::string>(SUMO_ATTR_FROM, nullptr, ok);
264 std::string toID = attrs.get<std::string>(SUMO_ATTR_TO, nullptr, ok);
265 const int fromLane = attrs.get<int>(SUMO_ATTR_FROM_LANE, nullptr, ok);
266 const int toLane = attrs.get<int>(SUMO_ATTR_TO_LANE, nullptr, ok);
267 std::string dir = attrs.get<std::string>(SUMO_ATTR_DIR, nullptr, ok);
268 std::string viaID = attrs.getOpt<std::string>(SUMO_ATTR_VIA, nullptr, ok, "");
269 ROEdge* from = myNet.getEdge(fromID);
270 ROEdge* to = myNet.getEdge(toID);
271 if (from == nullptr) {
272 throw ProcessError("unknown from-edge '" + fromID + "' in connection");
273 }
274 if (to == nullptr) {
275 throw ProcessError("unknown to-edge '" + toID + "' in connection");
276 }
277 if ((int)from->getLanes().size() <= fromLane) {
278 throw ProcessError("invalid fromLane '" + toString(fromLane) + "' in connection from '" + fromID + "'.");
279 }
280 if ((int)to->getLanes().size() <= toLane) {
281 throw ProcessError("invalid toLane '" + toString(toLane) + "' in connection to '" + toID + "'.");
282 }
283 if (myIgnoreInternal || viaID == "") {
284 from->getLanes()[fromLane]->addOutgoingLane(to->getLanes()[toLane]);
285 from->addSuccessor(to, nullptr, dir);
286 } else {
287 ROEdge* const via = myNet.getEdge(viaID.substr(0, viaID.rfind('_')));
288 if (via == nullptr) {
289 throw ProcessError("unknown via-edge '" + viaID + "' in connection");
290 }
291 from->getLanes()[fromLane]->addOutgoingLane(to->getLanes()[toLane], via);
292 from->addSuccessor(to, via, dir);
293 via->addSuccessor(to, nullptr, dir);
294 LinkState state = SUMOXMLDefinitions::LinkStates.get(attrs.get<std::string>(SUMO_ATTR_STATE, nullptr, ok));
295 if (state == LINKSTATE_MINOR || state == LINKSTATE_EQUAL || state == LINKSTATE_STOP || state == LINKSTATE_ALLWAY_STOP) {
296 via->setTimePenalty(myMinorPenalty);
297 }
298 }
299 }
300
301
302 void
parseStoppingPlace(const SUMOSAXAttributes & attrs,const SumoXMLTag element)303 RONetHandler::parseStoppingPlace(const SUMOSAXAttributes& attrs, const SumoXMLTag element) {
304 bool ok = true;
305 myCurrentStoppingPlace = new SUMOVehicleParameter::Stop();
306 // get the id, throw if not given or empty...
307 std::string id = attrs.get<std::string>(SUMO_ATTR_ID, toString(element).c_str(), ok);
308 // get the lane
309 myCurrentStoppingPlace->lane = attrs.get<std::string>(SUMO_ATTR_LANE, toString(element).c_str(), ok);
310 if (!ok) {
311 throw ProcessError();
312 }
313 const ROEdge* edge = myNet.getEdgeForLaneID(myCurrentStoppingPlace->lane);
314 if (edge == nullptr) {
315 throw InvalidArgument("Unknown lane '" + myCurrentStoppingPlace->lane + "' for " + toString(element) + " '" + id + "'.");
316 }
317 // get the positions
318 myCurrentStoppingPlace->startPos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, id.c_str(), ok, 0.);
319 myCurrentStoppingPlace->endPos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok, edge->getLength());
320 const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
321 if (!ok || !SUMORouteHandler::checkStopPos(myCurrentStoppingPlace->startPos, myCurrentStoppingPlace->endPos, edge->getLength(), POSITION_EPS, friendlyPos)) {
322 throw InvalidArgument("Invalid position for " + toString(element) + " '" + id + "'.");
323 }
324 // 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
325 myCurrentStoppingPlace->busstop = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok, "");
326 myNet.addStoppingPlace(id, element, myCurrentStoppingPlace);
327 }
328
329
330 void
parseAccess(const SUMOSAXAttributes & attrs)331 RONetHandler::parseAccess(const SUMOSAXAttributes& attrs) {
332 bool ok = true;
333 const std::string lane = attrs.get<std::string>(SUMO_ATTR_LANE, "access", ok);
334 const ROEdge* edge = myNet.getEdgeForLaneID(lane);
335 if (edge == nullptr) {
336 throw InvalidArgument("Unknown lane '" + lane + "' for access.");
337 }
338 double pos = attrs.getOpt<double>(SUMO_ATTR_POSITION, "access", ok, 0.);
339 const double length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, "access", ok, -1);
340 const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, "access", ok, false);
341 if (!ok || !SUMORouteHandler::checkStopPos(pos, pos, edge->getLength(), 0., friendlyPos)) {
342 throw InvalidArgument("Invalid position " + toString(pos) + " for access on lane '" + lane + "'.");
343 }
344 if (!ok) {
345 throw ProcessError();
346 }
347 myCurrentStoppingPlace->accessPos.push_back(std::make_tuple(lane, pos, length));
348 }
349
350
351 void
parseDistrict(const SUMOSAXAttributes & attrs)352 RONetHandler::parseDistrict(const SUMOSAXAttributes& attrs) {
353 myCurrentEdge = nullptr;
354 bool ok = true;
355 myCurrentName = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
356 if (!ok) {
357 return;
358 }
359 myNet.addDistrict(myCurrentName, myEdgeBuilder.buildEdge(myCurrentName + "-source", nullptr, nullptr, 0), myEdgeBuilder.buildEdge(myCurrentName + "-sink", nullptr, nullptr, 0));
360 if (attrs.hasAttribute(SUMO_ATTR_EDGES)) {
361 std::vector<std::string> desc = attrs.getStringVector(SUMO_ATTR_EDGES);
362 for (std::vector<std::string>::const_iterator i = desc.begin(); i != desc.end(); ++i) {
363 myNet.addDistrictEdge(myCurrentName, *i, true);
364 myNet.addDistrictEdge(myCurrentName, *i, false);
365 }
366 }
367 }
368
369
370 void
parseDistrictEdge(const SUMOSAXAttributes & attrs,bool isSource)371 RONetHandler::parseDistrictEdge(const SUMOSAXAttributes& attrs, bool isSource) {
372 bool ok = true;
373 std::string id = attrs.get<std::string>(SUMO_ATTR_ID, myCurrentName.c_str(), ok);
374 myNet.addDistrictEdge(myCurrentName, id, isSource);
375 }
376
377 void
setLocation(const SUMOSAXAttributes & attrs)378 RONetHandler::setLocation(const SUMOSAXAttributes& attrs) {
379 bool ok = true;
380 PositionVector s = attrs.get<PositionVector>(SUMO_ATTR_NET_OFFSET, nullptr, ok);
381 Boundary convBoundary = attrs.get<Boundary>(SUMO_ATTR_CONV_BOUNDARY, nullptr, ok);
382 Boundary origBoundary = attrs.get<Boundary>(SUMO_ATTR_ORIG_BOUNDARY, nullptr, ok);
383 std::string proj = attrs.get<std::string>(SUMO_ATTR_ORIG_PROJ, nullptr, ok);
384 if (ok) {
385 Position networkOffset = s[0];
386 GeoConvHelper::init(proj, networkOffset, origBoundary, convBoundary);
387 }
388 }
389
390 /****************************************************************************/
391