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