SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NIImporter_SUMO.cpp
Go to the documentation of this file.
1 /****************************************************************************/
9 // Importer for networks stored in SUMO format
10 /****************************************************************************/
11 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/
12 // Copyright (C) 2001-2013 DLR (http://www.dlr.de/) and contributors
13 /****************************************************************************/
14 //
15 // This file is part of SUMO.
16 // SUMO is free software: you can redistribute it and/or modify
17 // it under the terms of the GNU General Public License as published by
18 // the Free Software Foundation, either version 3 of the License, or
19 // (at your option) any later version.
20 //
21 /****************************************************************************/
22 
23 
24 // ===========================================================================
25 // included modules
26 // ===========================================================================
27 #ifdef _MSC_VER
28 #include <windows_config.h>
29 #else
30 #include <config.h>
31 #endif
32 #include <string>
38 #include <utils/common/ToString.h>
42 #include <utils/xml/XMLSubSys.h>
46 #include <netbuild/NBEdge.h>
47 #include <netbuild/NBEdgeCont.h>
48 #include <netbuild/NBNode.h>
49 #include <netbuild/NBNodeCont.h>
51 #include <netbuild/NBNetBuilder.h>
52 #include "NILoader.h"
53 #include "NIImporter_SUMO.h"
54 
55 #ifdef CHECK_MEMORY_LEAKS
56 #include <foreign/nvwa/debug_new.h>
57 #endif // CHECK_MEMORY_LEAKS
58 
59 
60 // ===========================================================================
61 // method definitions
62 // ===========================================================================
63 // ---------------------------------------------------------------------------
64 // static methods (interface in this case)
65 // ---------------------------------------------------------------------------
66 void
68  NIImporter_SUMO importer(nb);
69  importer._loadNetwork(oc);
70 }
71 
72 
73 // ---------------------------------------------------------------------------
74 // loader methods
75 // ---------------------------------------------------------------------------
77  : SUMOSAXHandler("sumo-network"),
78  myNetBuilder(nb),
79  myNodeCont(nb.getNodeCont()),
80  myTLLCont(nb.getTLLogicCont()),
81  myCurrentEdge(0),
82  myCurrentLane(0),
83  myCurrentTL(0),
84  myLocation(0),
85  mySuspectKeepShape(false),
86  myHaveSeenInternalEdge(false) {}
87 
88 
90  for (std::map<std::string, EdgeAttrs*>::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
91  EdgeAttrs* ed = (*i).second;
92  for (std::vector<LaneAttrs*>::const_iterator j = ed->lanes.begin(); j != ed->lanes.end(); ++j) {
93  delete *j;
94  }
95  delete ed;
96  }
97  delete myLocation;
98 }
99 
100 
101 void
103  // check whether the option is set (properly)
104  if (!oc.isUsableFileList("sumo-net-file")) {
105  return;
106  }
107  // parse file(s)
108  std::vector<std::string> files = oc.getStringVector("sumo-net-file");
109  for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
110  if (!FileHelpers::exists(*file)) {
111  WRITE_ERROR("Could not open sumo-net-file '" + *file + "'.");
112  return;
113  }
114  setFileName(*file);
115  PROGRESS_BEGIN_MESSAGE("Parsing sumo-net from '" + *file + "'");
116  XMLSubSys::runParser(*this, *file);
118  }
119  // build edges
120  for (std::map<std::string, EdgeAttrs*>::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
121  EdgeAttrs* ed = (*i).second;
122  // skip internal edges
123  if (ed->func == EDGEFUNC_INTERNAL) {
124  continue;
125  }
126  // get and check the nodes
127  NBNode* from = myNodeCont.retrieve(ed->fromNode);
128  NBNode* to = myNodeCont.retrieve(ed->toNode);
129  if (from == 0) {
130  WRITE_ERROR("Edge's '" + ed->id + "' from-node '" + ed->fromNode + "' is not known.");
131  continue;
132  }
133  if (to == 0) {
134  WRITE_ERROR("Edge's '" + ed->id + "' to-node '" + ed->toNode + "' is not known.");
135  continue;
136  }
137  // edge shape
138  PositionVector geom;
139  if (ed->shape.size() > 0) {
140  geom = ed->shape;
141  mySuspectKeepShape = false; // no problem with reconstruction if edge shape is given explicit
142  } else {
143  // either the edge has default shape consisting only of the two node
144  // positions or we have a legacy network
145  geom = reconstructEdgeShape(ed, from->getPosition(), to->getPosition());
146  }
147  // build and insert the edge
148  NBEdge* e = new NBEdge(ed->id, from, to,
149  ed->type, ed->maxSpeed,
150  (unsigned int) ed->lanes.size(),
152  geom, ed->streetName, ed->lsf, true); // always use tryIgnoreNodePositions to keep original shape
153  e->setLoadedLength(ed->length);
154  if (!myNetBuilder.getEdgeCont().insert(e)) {
155  WRITE_ERROR("Could not insert edge '" + ed->id + "'.");
156  delete e;
157  continue;
158  }
160  }
161  // assign further lane attributes (edges are built)
162  for (std::map<std::string, EdgeAttrs*>::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
163  EdgeAttrs* ed = (*i).second;
164  NBEdge* nbe = ed->builtEdge;
165  if (nbe == 0) { // inner edge or removed by explicit list, vclass, ...
166  continue;
167  }
168  for (unsigned int fromLaneIndex = 0; fromLaneIndex < (unsigned int) ed->lanes.size(); ++fromLaneIndex) {
169  LaneAttrs* lane = ed->lanes[fromLaneIndex];
170  // connections
171  const std::vector<Connection>& connections = lane->connections;
172  for (std::vector<Connection>::const_iterator c_it = connections.begin(); c_it != connections.end(); c_it++) {
173  const Connection& c = *c_it;
174  if (myEdges.count(c.toEdgeID) == 0) {
175  WRITE_ERROR("Unknown edge '" + c.toEdgeID + "' given in connection.");
176  continue;
177  }
178  NBEdge* toEdge = myEdges[c.toEdgeID]->builtEdge;
179  if (toEdge == 0) { // removed by explicit list, vclass, ...
180  continue;
181  }
183  fromLaneIndex, toEdge, c.toLaneIdx, NBEdge::L2L_VALIDATED,
184  false, c.mayDefinitelyPass);
185 
186  // maybe we have a tls-controlled connection
187  if (c.tlID != "") {
188  const std::map<std::string, NBTrafficLightDefinition*>& programs = myTLLCont.getPrograms(c.tlID);
189  if (programs.size() > 0) {
190  std::map<std::string, NBTrafficLightDefinition*>::const_iterator it;
191  for (it = programs.begin(); it != programs.end(); it++) {
192  NBLoadedSUMOTLDef* tlDef = dynamic_cast<NBLoadedSUMOTLDef*>(it->second);
193  if (tlDef) {
194  tlDef->addConnection(nbe, toEdge, fromLaneIndex, c.toLaneIdx, c.tlLinkNo);
195  } else {
196  throw ProcessError("Corrupt traffic light definition '" + c.tlID + "' (program '" + it->first + "')");
197  }
198  }
199  } else {
200  WRITE_ERROR("The traffic light '" + c.tlID + "' is not known.");
201  }
202  }
203  }
204  // allow/disallow XXX preferred
205  nbe->setPermissions(parseVehicleClasses(lane->allow, lane->disallow), fromLaneIndex);
206  // width, offset
207  nbe->setLaneWidth(fromLaneIndex, lane->width);
208  nbe->setOffset(fromLaneIndex, lane->offset);
209  nbe->setSpeed(fromLaneIndex, lane->maxSpeed);
210  }
212  }
213  // insert loaded prohibitions
214  for (std::vector<Prohibition>::const_iterator it = myProhibitions.begin(); it != myProhibitions.end(); it++) {
215  NBEdge* prohibitedFrom = myEdges[it->prohibitedFrom]->builtEdge;
216  if (prohibitedFrom == 0) {
217  WRITE_ERROR("Edge '" + it->prohibitedFrom + "' in prohibition was not built");
218  } else {
219  NBNode* n = prohibitedFrom->getToNode();
221  NBConnection(myEdges[it->prohibitorFrom]->builtEdge, myEdges[it->prohibitorTo]->builtEdge),
222  NBConnection(prohibitedFrom, myEdges[it->prohibitedTo]->builtEdge));
223  }
224  }
225  if (!myHaveSeenInternalEdge && oc.isDefault("no-internal-links")) {
226  oc.set("no-internal-links", "true");
227  }
228  // final warning
229  if (mySuspectKeepShape) {
230  WRITE_WARNING("The input network may have been built using option 'xml.keep-shape'.\n... Accuracy of junction positions cannot be guaranteed.");
231  }
232 
233 }
234 
235 
236 
237 void
239  const SUMOSAXAttributes& attrs) {
240  /* our goal is to reproduce the input net faithfully
241  * there are different types of objects in the netfile:
242  * 1) those which must be loaded into NBNetBuilder-Containers for processing
243  * 2) those which can be ignored because they are recomputed based on group 1
244  * 3) those which are of no concern to NBNetBuilder but should be exposed to
245  * NETEDIT. We will probably have to patch NBNetBuilder to contain them
246  * and hand them over to NETEDIT
247  * alternative idea: those shouldn't really be contained within the
248  * network but rather in separate files. teach NETEDIT how to open those
249  * (POI?)
250  * 4) those which are of concern neither to NBNetBuilder nor NETEDIT and
251  * must be copied over - need to patch NBNetBuilder for this.
252  * copy unknown by default
253  */
254  switch (element) {
255  case SUMO_TAG_EDGE:
256  addEdge(attrs);
257  break;
258  case SUMO_TAG_LANE:
259  addLane(attrs);
260  break;
261  case SUMO_TAG_JUNCTION:
262  addJunction(attrs);
263  break;
264  case SUMO_TAG_CONNECTION:
265  addConnection(attrs);
266  break;
267  case SUMO_TAG_TLLOGIC:
269  break;
270  case SUMO_TAG_PHASE:
271  addPhase(attrs, myCurrentTL);
272  break;
273  case SUMO_TAG_LOCATION:
274  myLocation = loadLocation(attrs);
275  break;
277  addProhibition(attrs);
278  break;
279  case SUMO_TAG_ROUNDABOUT:
281  break;
282  default:
283  break;
284  }
285 }
286 
287 
288 void
290  switch (element) {
291  case SUMO_TAG_EDGE:
292  if (myEdges.find(myCurrentEdge->id) != myEdges.end()) {
293  WRITE_ERROR("Edge '" + myCurrentEdge->id + "' occured at least twice in the input.");
294  } else {
296  }
297  myCurrentEdge = 0;
298  break;
299  case SUMO_TAG_LANE:
300  if (myCurrentEdge != 0) {
302  myCurrentEdge->lanes.push_back(myCurrentLane);
303  }
304  myCurrentLane = 0;
305  break;
306  case SUMO_TAG_TLLOGIC:
307  if (!myCurrentTL) {
308  WRITE_ERROR("Unmatched closing tag for tl-logic.");
309  } else {
310  if (!myTLLCont.insert(myCurrentTL)) {
311  WRITE_WARNING("Could not add program '" + myCurrentTL->getProgramID() + "' for traffic light '" + myCurrentTL->getID() + "'");
312  delete myCurrentTL;
313  }
314  myCurrentTL = 0;
315  }
316  break;
317  default:
318  break;
319  }
320 }
321 
322 
323 void
325  // get the id, report an error if not given or empty...
326  bool ok = true;
327  std::string id = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok);
328  if (!ok) {
329  return;
330  }
331  myCurrentEdge = new EdgeAttrs();
333  myCurrentEdge->id = id;
334  // get the function
335  myCurrentEdge->func = attrs.getEdgeFunc(ok);
337  return; // skip internal edges
338  }
339  // get the type
340  myCurrentEdge->type = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, id.c_str(), ok, "");
341  // get the origin and the destination node
342  myCurrentEdge->fromNode = attrs.getOpt<std::string>(SUMO_ATTR_FROM, id.c_str(), ok, "");
343  myCurrentEdge->toNode = attrs.getOpt<std::string>(SUMO_ATTR_TO, id.c_str(), ok, "");
344  myCurrentEdge->priority = attrs.getOpt<int>(SUMO_ATTR_PRIORITY, id.c_str(), ok, -1);
345  myCurrentEdge->type = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, id.c_str(), ok, "");
349  myCurrentEdge->maxSpeed = 0;
350  myCurrentEdge->streetName = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok, "");
351 
352  std::string lsfS = toString(LANESPREAD_RIGHT);
353  lsfS = attrs.getOpt<std::string>(SUMO_ATTR_SPREADTYPE, id.c_str(), ok, lsfS);
354  if (SUMOXMLDefinitions::LaneSpreadFunctions.hasString(lsfS)) {
356  } else {
357  WRITE_ERROR("Unknown spreadType '" + lsfS + "' for edge '" + id + "'.");
358  }
359 }
360 
361 
362 void
364  bool ok = true;
365  std::string id = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok);
366  if (!ok) {
367  return;
368  }
369  if (!myCurrentEdge) {
370  WRITE_ERROR("Found lane '" + id + "' not within edge element");
371  return;
372  }
373  myCurrentLane = new LaneAttrs;
375  myHaveSeenInternalEdge = true;
376  return; // skip internal lanes
377  }
378  if (attrs.hasAttribute("maxspeed")) {
379  // !!! deprecated
380  myCurrentLane->maxSpeed = attrs.getFloat("maxspeed");
381  } else {
382  myCurrentLane->maxSpeed = attrs.get<SUMOReal>(SUMO_ATTR_SPEED, id.c_str(), ok);
383  }
384  try {
385  myCurrentLane->allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, id.c_str(), ok, "", false);
386  } catch (EmptyData e) {
387  // !!! deprecated
388  myCurrentLane->allow = "";
389  }
390  myCurrentLane->disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, id.c_str(), ok, "");
393  myCurrentLane->shape = attrs.get<PositionVector>(SUMO_ATTR_SHAPE, id.c_str(), ok);
394  // lane coordinates are derived (via lane spread) do not include them in convex boundary
396 }
397 
398 
399 void
401  // get the id, report an error if not given or empty...
402  bool ok = true;
403  std::string id = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok);
404  if (!ok) {
405  return;
406  }
407  if (id[0] == ':') { // internal node
408  return;
409  }
410  SumoXMLNodeType type = attrs.getNodeType(ok);
411  if (ok) {
412  if (type == NODETYPE_DEAD_END_DEPRECATED) { // patch legacy type
413  type = NODETYPE_DEAD_END;
414  }
415  } else {
416  WRITE_WARNING("Unknown node type for junction '" + id + "'.");
417  }
418  Position pos = readPosition(attrs, id, ok);
420  // the network may have non-default edge geometry.
421  // accurate reconstruction of legacy networks is not possible. We ought to warn about this
422  if (attrs.hasAttribute(SUMO_ATTR_SHAPE)) {
423  PositionVector shape = attrs.getOpt<PositionVector>(SUMO_ATTR_SHAPE, id.c_str(), ok, PositionVector());
424  if (shape.size() > 0) {
425  shape.push_back_noDoublePos(shape[0]); // need closed shape
426  if (!shape.around(pos) && shape.distance(pos) > 1) { // MAGIC_THRESHOLD
427  // WRITE_WARNING("Junction '" + id + "': distance between pos and shape is " + toString(shape.distance(pos)));
428  mySuspectKeepShape = true;
429  }
430  }
431  }
432  NBNode* node = new NBNode(id, pos, type);
433  if (!myNodeCont.insert(node)) {
434  WRITE_ERROR("Problems on adding junction '" + id + "'.");
435  delete node;
436  return;
437  }
438 }
439 
440 
441 void
443  bool ok = true;
444  std::string fromID = attrs.get<std::string>(SUMO_ATTR_FROM, 0, ok);
445  if (myEdges.count(fromID) == 0) {
446  WRITE_ERROR("Unknown edge '" + fromID + "' given in connection.");
447  return;
448  }
449  EdgeAttrs* from = myEdges[fromID];
450  Connection conn;
451  conn.toEdgeID = attrs.get<std::string>(SUMO_ATTR_TO, 0, ok);
452  unsigned int fromLaneIdx = attrs.get<int>(SUMO_ATTR_FROM_LANE, 0, ok);
453  conn.toLaneIdx = attrs.get<int>(SUMO_ATTR_TO_LANE, 0, ok);
454  conn.tlID = attrs.getOpt<std::string>(SUMO_ATTR_TLID, 0, ok, "");
455  conn.mayDefinitelyPass = attrs.getOpt<bool>(SUMO_ATTR_PASS, 0, ok, false);
456  const size_t suffixSize = NBRampsComputer::ADDED_ON_RAMP_EDGE.size();
457  if (!conn.mayDefinitelyPass && conn.toEdgeID.size() > suffixSize &&
458  conn.toEdgeID.substr(conn.toEdgeID.size() - suffixSize) == NBRampsComputer::ADDED_ON_RAMP_EDGE) {
459  WRITE_MESSAGE("Infering connection attribute pass=\"1\" from to-edge id '" + conn.toEdgeID + "'");
460  conn.mayDefinitelyPass = true;
461  }
462  if (conn.tlID != "") {
463  conn.tlLinkNo = attrs.get<int>(SUMO_ATTR_TLLINKINDEX, 0, ok);
464  }
465 
466  if (from->lanes.size() <= (size_t) fromLaneIdx) {
467  WRITE_ERROR("Invalid lane index '" + toString(fromLaneIdx) + "' for connection from '" + fromID + "'.");
468  return;
469  }
470  from->lanes[fromLaneIdx]->connections.push_back(conn);
471 }
472 
473 
474 void
476  bool ok = true;
477  std::string prohibitor = attrs.getOpt<std::string>(SUMO_ATTR_PROHIBITOR, 0, ok, "");
478  std::string prohibited = attrs.getOpt<std::string>(SUMO_ATTR_PROHIBITED, 0, ok, "");
479  if (!ok) {
480  return;
481  }
482  Prohibition p;
485  if (!ok) {
486  return;
487  }
488  myProhibitions.push_back(p);
489 }
490 
491 
493 NIImporter_SUMO::getLaneAttrsFromID(EdgeAttrs* edge, std::string lane_id) {
494  std::string edge_id;
495  unsigned int index;
496  interpretLaneID(lane_id, edge_id, index);
497  assert(edge->id == edge_id);
498  if (edge->lanes.size() <= (size_t) index) {
499  WRITE_ERROR("Unknown lane '" + lane_id + "' given in succedge.");
500  return 0;
501  } else {
502  return edge->lanes[index];
503  }
504 }
505 
506 
507 void
508 NIImporter_SUMO::interpretLaneID(const std::string& lane_id, std::string& edge_id, unsigned int& index) {
509  // assume lane_id = edge_id + '_' + index
510  size_t sep_index = lane_id.rfind('_');
511  if (sep_index == std::string::npos) {
512  WRITE_ERROR("Invalid lane id '" + lane_id + "' (missing '_').");
513  }
514  edge_id = lane_id.substr(0, sep_index);
515  std::string index_string = lane_id.substr(sep_index + 1);
516  try {
517  index = (unsigned int)TplConvert::_2int(index_string.c_str());
518  } catch (NumberFormatException) {
519  WRITE_ERROR("Invalid lane index '" + index_string + "' for lane '" + lane_id + "'.");
520  }
521 }
522 
523 
526  if (currentTL) {
527  WRITE_ERROR("Definition of tl-logic '" + currentTL->getID() + "' was not finished.");
528  return 0;
529  }
530  bool ok = true;
531  std::string id = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok);
532  SUMOTime offset = TIME2STEPS(attrs.get<SUMOReal>(SUMO_ATTR_OFFSET, id.c_str(), ok));
533  std::string programID = attrs.getOpt<std::string>(SUMO_ATTR_PROGRAMID, id.c_str(), ok, "<unknown>");
534  std::string typeS = attrs.get<std::string>(SUMO_ATTR_TYPE, 0, ok);
535  TrafficLightType type;
536  if (SUMOXMLDefinitions::TrafficLightTypes.hasString(typeS)) {
538  } else {
539  WRITE_ERROR("Unknown traffic light type '" + typeS + "' for tlLogic '" + id + "'.");
540  ok = false;
541  }
542  if (ok) {
543  return new NBLoadedSUMOTLDef(id, programID, offset, type);
544  } else {
545  return 0;
546  }
547 }
548 
549 
550 void
552  if (!currentTL) {
553  WRITE_ERROR("found phase without tl-logic");
554  return;
555  }
556  const std::string& id = currentTL->getID();
557  bool ok = true;
558  std::string state = attrs.get<std::string>(SUMO_ATTR_STATE, id.c_str(), ok);
559  SUMOTime duration = TIME2STEPS(attrs.get<SUMOReal>(SUMO_ATTR_DURATION, id.c_str(), ok));
560  if (duration < 0) {
561  WRITE_ERROR("Phase duration for tl-logic '" + id + "/" + currentTL->getProgramID() + "' must be positive.");
562  return;
563  }
564  // if the traffic light is an actuated traffic light, try to get
565  // the minimum and maximum durations
566  //SUMOTime minDuration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MINDURATION, id.c_str(), ok, -1);
567  //SUMOTime maxDuration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MAXDURATION, id.c_str(), ok, -1);
568  if (ok) {
569  currentTL->addPhase(duration, state);
570  }
571 }
572 
573 
575 NIImporter_SUMO::reconstructEdgeShape(const EdgeAttrs* edge, const Position& from, const Position& to) {
576  const PositionVector& firstLane = edge->lanes[0]->shape;
577  PositionVector result;
578  result.push_back(from);
579 
580  // reverse logic of NBEdge::computeLaneShape
581  // !!! this will only work for old-style constant width lanes
582  const size_t noLanes = edge->lanes.size();
583  SUMOReal offset;
584  if (edge->lsf == LANESPREAD_RIGHT) {
585  offset = (SUMO_const_laneWidth + SUMO_const_laneOffset) / 2.; // @todo: why is the lane offset counted in here?
586  } else {
587  offset = (SUMO_const_laneWidth) / 2. - (SUMO_const_laneWidth * (SUMOReal)noLanes - 1) / 2.;
588  }
589  for (unsigned int i = 1; i < firstLane.size() - 1; i++) {
590  Position from = firstLane[i - 1];
591  Position me = firstLane[i];
592  Position to = firstLane[i + 1];
593  std::pair<SUMOReal, SUMOReal> offsets = NBEdge::laneOffset(from, me, offset, false);
594  std::pair<SUMOReal, SUMOReal> offsets2 = NBEdge::laneOffset(me, to, offset, false);
595 
596  Line l1(
597  Position(from.x() + offsets.first, from.y() + offsets.second),
598  Position(me.x() + offsets.first, me.y() + offsets.second));
599  l1.extrapolateBy(100);
600  Line l2(
601  Position(me.x() + offsets2.first, me.y() + offsets2.second),
602  Position(to.x() + offsets2.first, to.y() + offsets2.second));
603  l2.extrapolateBy(100);
604  if (l1.intersects(l2)) {
605  result.push_back(l1.intersectsAt(l2));
606  } else {
607  WRITE_WARNING("Could not reconstruct shape for edge '" + edge->id + "'.");
608  }
609  }
610 
611  result.push_back(to);
612  return result;
613 }
614 
615 
618  // @todo refactor parsing of location since its duplicated in NLHandler and PCNetProjectionLoader
619  bool ok = true;
620  GeoConvHelper* result = 0;
622  Boundary convBoundary = attrs.get<Boundary>(SUMO_ATTR_CONV_BOUNDARY, 0, ok);
623  Boundary origBoundary = attrs.get<Boundary>(SUMO_ATTR_ORIG_BOUNDARY, 0, ok);
624  std::string proj = attrs.get<std::string>(SUMO_ATTR_ORIG_PROJ, 0, ok);
625  if (ok) {
626  Position networkOffset = s[0];
627  result = new GeoConvHelper(proj, networkOffset, origBoundary, convBoundary);
628  GeoConvHelper::setLoaded(*result);
629  }
630  return result;
631 }
632 
633 
634 Position
635 NIImporter_SUMO::readPosition(const SUMOSAXAttributes& attrs, const std::string& id, bool& ok) {
636  SUMOReal x = attrs.get<SUMOReal>(SUMO_ATTR_X, id.c_str(), ok);
637  SUMOReal y = attrs.get<SUMOReal>(SUMO_ATTR_Y, id.c_str(), ok);
638  SUMOReal z = 0;
639  if (attrs.hasAttribute(SUMO_ATTR_Z)) {
640  z = attrs.get<SUMOReal>(SUMO_ATTR_Z, id.c_str(), ok);
641  }
642  return Position(x, y, z);
643 }
644 
645 
646 void
647 NIImporter_SUMO::parseProhibitionConnection(const std::string& attr, std::string& from, std::string& to, bool& ok) {
648  // split from/to
649  size_t div = attr.find("->");
650  if (div == std::string::npos) {
651  WRITE_ERROR("Missing connection divider in prohibition attribute '" + attr + "'");
652  ok = false;
653  }
654  from = attr.substr(0, div);
655  to = attr.substr(div + 2);
656  // check whether the definition includes a lane information and discard it
657  if (from.find('_') != std::string::npos) {
658  from = from.substr(0, from.find('_'));
659  }
660  if (to.find('_') != std::string::npos) {
661  to = to.substr(0, to.find('_'));
662  }
663  // check whether the edges are known
664  if (myEdges.count(from) == 0) {
665  WRITE_ERROR("Unknown edge prohibition '" + from + "'");
666  ok = false;
667  }
668  if (myEdges.count(to) == 0) {
669  WRITE_ERROR("Unknown edge prohibition '" + to + "'");
670  ok = false;
671  }
672 }
673 /****************************************************************************/