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-2012 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 
87 
89  for (std::map<std::string, EdgeAttrs*>::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
90  EdgeAttrs* ed = (*i).second;
91  for (std::vector<LaneAttrs*>::const_iterator j = ed->lanes.begin(); j != ed->lanes.end(); ++j) {
92  delete *j;
93  }
94  delete ed;
95  }
96  delete myLocation;
97 }
98 
99 
100 void
102  // check whether the option is set (properly)
103  if (!oc.isUsableFileList("sumo-net-file")) {
104  return;
105  }
106  // parse file(s)
107  std::vector<std::string> files = oc.getStringVector("sumo-net-file");
108  for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
109  if (!FileHelpers::exists(*file)) {
110  WRITE_ERROR("Could not open sumo-net-file '" + *file + "'.");
111  return;
112  }
113  setFileName(*file);
114  PROGRESS_BEGIN_MESSAGE("Parsing sumo-net from '" + *file + "'");
115  XMLSubSys::runParser(*this, *file);
117  }
118  // build edges
119  for (std::map<std::string, EdgeAttrs*>::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
120  EdgeAttrs* ed = (*i).second;
121  // skip internal edges
122  if (ed->func == EDGEFUNC_INTERNAL) {
123  continue;
124  }
125  // get and check the nodes
126  NBNode* from = myNodeCont.retrieve(ed->fromNode);
127  NBNode* to = myNodeCont.retrieve(ed->toNode);
128  if (from == 0) {
129  WRITE_ERROR("Edge's '" + ed->id + "' from-node '" + ed->fromNode + "' is not known.");
130  continue;
131  }
132  if (to == 0) {
133  WRITE_ERROR("Edge's '" + ed->id + "' to-node '" + ed->toNode + "' is not known.");
134  continue;
135  }
136  // edge shape
137  PositionVector geom;
138  if (ed->shape.size() > 0) {
139  geom = ed->shape;
140  mySuspectKeepShape = false; // no problem with reconstruction if edge shape is given explicit
141  } else {
142  // either the edge has default shape consisting only of the two node
143  // positions or we have a legacy network
144  geom = reconstructEdgeShape(ed, from->getPosition(), to->getPosition());
145  }
146  // build and insert the edge
147  NBEdge* e = new NBEdge(ed->id, from, to,
148  ed->type, ed->maxSpeed,
149  (unsigned int) ed->lanes.size(),
151  geom, ed->streetName, ed->lsf, true); // always use tryIgnoreNodePositions to keep original shape
152  e->setLoadedLength(ed->length);
153  if (!myNetBuilder.getEdgeCont().insert(e)) {
154  WRITE_ERROR("Could not insert edge '" + ed->id + "'.");
155  delete e;
156  continue;
157  }
159  }
160  // assign further lane attributes (edges are built)
161  for (std::map<std::string, EdgeAttrs*>::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
162  EdgeAttrs* ed = (*i).second;
163  NBEdge* nbe = ed->builtEdge;
164  if (nbe == 0) { // inner edge or removed by explicit list, vclass, ...
165  continue;
166  }
167  for (unsigned int fromLaneIndex = 0; fromLaneIndex < (unsigned int) ed->lanes.size(); ++fromLaneIndex) {
168  LaneAttrs* lane = ed->lanes[fromLaneIndex];
169  // connections
170  const std::vector<Connection>& connections = lane->connections;
171  for (std::vector<Connection>::const_iterator c_it = connections.begin(); c_it != connections.end(); c_it++) {
172  const Connection& c = *c_it;
173  if (myEdges.count(c.toEdgeID) == 0) {
174  WRITE_ERROR("Unknown edge '" + c.toEdgeID + "' given in connection.");
175  continue;
176  }
177  NBEdge* toEdge = myEdges[c.toEdgeID]->builtEdge;
178  if (toEdge == 0) { // removed by explicit list, vclass, ...
179  continue;
180  }
182  fromLaneIndex, toEdge, c.toLaneIdx, NBEdge::L2L_VALIDATED,
183  false, c.mayDefinitelyPass);
184 
185  // maybe we have a tls-controlled connection
186  if (c.tlID != "" && !OptionsCont::getOptions().getBool("tls.discard-loaded")) {
187  const std::map<std::string, NBTrafficLightDefinition*>& programs = myTLLCont.getPrograms(c.tlID);
188  if (programs.size() > 0) {
189  std::map<std::string, NBTrafficLightDefinition*>::const_iterator it;
190  for (it = programs.begin(); it != programs.end(); it++) {
191  NBLoadedSUMOTLDef* tlDef = dynamic_cast<NBLoadedSUMOTLDef*>(it->second);
192  if (tlDef) {
193  tlDef->addConnection(nbe, toEdge, fromLaneIndex, c.toLaneIdx, c.tlLinkNo);
194  } else {
195  throw ProcessError("Corrupt traffic light definition '" + c.tlID + "' (program '" + it->first + "')");
196  }
197  }
198  } else {
199  WRITE_ERROR("The traffic light '" + c.tlID + "' is not known.");
200  }
201  }
202  }
203  // allow/disallow XXX preferred
204  nbe->setPermissions(parseVehicleClasses(lane->allow, lane->disallow), fromLaneIndex);
205  // width, offset
206  nbe->setWidth(fromLaneIndex, lane->width);
207  nbe->setOffset(fromLaneIndex, lane->offset);
208  nbe->setSpeed(fromLaneIndex, lane->maxSpeed);
209  }
211  }
212  // insert loaded prohibitions
213  for (std::vector<Prohibition>::const_iterator it = myProhibitions.begin(); it != myProhibitions.end(); it++) {
214  NBEdge* prohibitedFrom = myEdges[it->prohibitedFrom]->builtEdge;
215  if (prohibitedFrom == 0) {
216  WRITE_ERROR("Edge '" + it->prohibitedFrom + "' in prohibition was not built");
217  } else {
218  NBNode* n = prohibitedFrom->getToNode();
220  NBConnection(myEdges[it->prohibitorFrom]->builtEdge, myEdges[it->prohibitorTo]->builtEdge),
221  NBConnection(prohibitedFrom, myEdges[it->prohibitedTo]->builtEdge));
222  }
223  }
224 
225  // final warning
226  if (mySuspectKeepShape) {
227  WRITE_WARNING("The input network may have been built using option 'xml.keep-shape'.\n... Accuracy of junction positions cannot be guaranteed.");
228  }
229 
230 }
231 
232 
233 
234 void
236  const SUMOSAXAttributes& attrs) {
237  /* our goal is to reproduce the input net faithfully
238  * there are different types of objects in the netfile:
239  * 1) those which must be loaded into NBNetBuilder-Containers for processing
240  * 2) those which can be ignored because they are recomputed based on group 1
241  * 3) those which are of no concern to NBNetBuilder but should be exposed to
242  * NETEDIT. We will probably have to patch NBNetBuilder to contain them
243  * and hand them over to NETEDIT
244  * alternative idea: those shouldn't really be contained within the
245  * network but rather in separate files. teach NETEDIT how to open those
246  * (POI?)
247  * 4) those which are of concern neither to NBNetBuilder nor NETEDIT and
248  * must be copied over - need to patch NBNetBuilder for this.
249  * copy unknown by default
250  */
251  switch (element) {
252  case SUMO_TAG_EDGE:
253  addEdge(attrs);
254  break;
255  case SUMO_TAG_LANE:
256  addLane(attrs);
257  break;
258  case SUMO_TAG_JUNCTION:
259  addJunction(attrs);
260  break;
261  case SUMO_TAG_CONNECTION:
262  addConnection(attrs);
263  break;
264  case SUMO_TAG_TLLOGIC:
265  if (!OptionsCont::getOptions().getBool("tls.discard-loaded")) {
267  }
268  break;
269  case SUMO_TAG_PHASE:
270  if (!OptionsCont::getOptions().getBool("tls.discard-loaded")) {
271  addPhase(attrs, myCurrentTL);
272  }
273  break;
274  case SUMO_TAG_LOCATION:
275  myLocation = loadLocation(attrs);
276  break;
278  addProhibition(attrs);
279  break;
280  default:
281  break;
282  }
283 }
284 
285 
286 void
288  switch (element) {
289  case SUMO_TAG_EDGE:
290  if (myEdges.find(myCurrentEdge->id) != myEdges.end()) {
291  WRITE_ERROR("Edge '" + myCurrentEdge->id + "' occured at least twice in the input.");
292  } else {
294  }
295  myCurrentEdge = 0;
296  break;
297  case SUMO_TAG_LANE:
298  if (myCurrentEdge != 0) {
300  myCurrentEdge->lanes.push_back(myCurrentLane);
301  }
302  myCurrentLane = 0;
303  break;
304  case SUMO_TAG_TLLOGIC:
305  if (!OptionsCont::getOptions().getBool("tls.discard-loaded")) {
306  if (!myCurrentTL) {
307  WRITE_ERROR("Unmatched closing tag for tl-logic.");
308  } else {
309  if (!myTLLCont.insert(myCurrentTL)) {
310  WRITE_WARNING("Could not add program '" + myCurrentTL->getProgramID() + "' for traffic light '" + myCurrentTL->getID() + "'");
311  delete myCurrentTL;
312  }
313  myCurrentTL = 0;
314  }
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.getStringReporting(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.getOptStringReporting(SUMO_ATTR_TYPE, id.c_str(), ok, "");
341  // get the origin and the destination node
342  myCurrentEdge->fromNode = attrs.getOptStringReporting(SUMO_ATTR_FROM, id.c_str(), ok, "");
343  myCurrentEdge->toNode = attrs.getOptStringReporting(SUMO_ATTR_TO, id.c_str(), ok, "");
344  myCurrentEdge->priority = attrs.getOptIntReporting(SUMO_ATTR_PRIORITY, id.c_str(), ok, -1);
345  myCurrentEdge->type = attrs.getOptStringReporting(SUMO_ATTR_TYPE, id.c_str(), ok, "");
346  myCurrentEdge->shape = attrs.getShapeReporting(SUMO_ATTR_SHAPE, id.c_str(), ok, true);
349  myCurrentEdge->maxSpeed = 0;
350  myCurrentEdge->streetName = attrs.getOptStringReporting(SUMO_ATTR_NAME, id.c_str(), ok, "");
351 
352  std::string lsfS = toString(LANESPREAD_RIGHT);
353  lsfS = attrs.getOptStringReporting(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.getStringReporting(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  return; // skip internal lanes
376  }
378  myCurrentLane->allow = attrs.getOptStringReporting(SUMO_ATTR_ALLOW, id.c_str(), ok, "");
379  myCurrentLane->disallow = attrs.getOptStringReporting(SUMO_ATTR_DISALLOW, id.c_str(), ok, "");
382  myCurrentLane->shape = attrs.getShapeReporting(SUMO_ATTR_SHAPE, id.c_str(), ok, false);
383  // lane coordinates are derived (via lane spread) do not include them in convex boundary
385 }
386 
387 
388 void
390  // get the id, report an error if not given or empty...
391  bool ok = true;
392  std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok);
393  if (!ok) {
394  return;
395  }
396  if (id[0] == ':') { // internal node
397  return;
398  }
399  SumoXMLNodeType type = attrs.getNodeType(ok);
400  if (ok) {
401  if (type == NODETYPE_DEAD_END_DEPRECATED) { // patch legacy type
402  type = NODETYPE_DEAD_END;
403  }
404  } else {
405  WRITE_WARNING("Unknown node type for junction '" + id + "'.");
406  }
407  Position pos = readPosition(attrs, id, ok);
409  // the network may have non-default edge geometry.
410  // accurate reconstruction of legacy networks is not possible. We ought to warn about this
411  if (attrs.hasAttribute(SUMO_ATTR_SHAPE)) {
412  PositionVector shape = attrs.getShapeReporting(SUMO_ATTR_SHAPE, id.c_str(), ok, true);
413  if (shape.size() > 0) {
414  shape.push_back_noDoublePos(shape[0]); // need closed shape
415  if (!shape.around(pos) && shape.distance(pos) > 1) { // MAGIC_THRESHOLD
416  // WRITE_WARNING("Junction '" + id + "': distance between pos and shape is " + toString(shape.distance(pos)));
417  mySuspectKeepShape = true;
418  }
419  }
420  }
421  NBNode* node = new NBNode(id, pos, type);
422  if (!myNodeCont.insert(node)) {
423  WRITE_ERROR("Problems on adding junction '" + id + "'.");
424  delete node;
425  return;
426  }
427 }
428 
429 
430 void
432  bool ok = true;
433  std::string fromID = attrs.getStringReporting(SUMO_ATTR_FROM, 0, ok);
434  if (myEdges.count(fromID) == 0) {
435  WRITE_ERROR("Unknown edge '" + fromID + "' given in connection.");
436  return;
437  }
438  EdgeAttrs* from = myEdges[fromID];
439  Connection conn;
440  conn.toEdgeID = attrs.getStringReporting(SUMO_ATTR_TO, 0, ok);
441  unsigned int fromLaneIdx = attrs.getIntReporting(SUMO_ATTR_FROM_LANE, 0, ok);
442  conn.toLaneIdx = attrs.getIntReporting(SUMO_ATTR_TO_LANE, 0, ok);
443  conn.tlID = attrs.getOptStringReporting(SUMO_ATTR_TLID, 0, ok, "");
444  conn.mayDefinitelyPass = attrs.getOptBoolReporting(SUMO_ATTR_PASS, 0, ok, false);
445  const size_t suffixSize = NBRampsComputer::ADDED_ON_RAMP_EDGE.size();
446  if (!conn.mayDefinitelyPass && conn.toEdgeID.size() > suffixSize &&
447  conn.toEdgeID.substr(conn.toEdgeID.size() - suffixSize) == NBRampsComputer::ADDED_ON_RAMP_EDGE) {
448  WRITE_MESSAGE("Infering connection attribute pass=\"1\" from to-edge id '" + conn.toEdgeID + "'");
449  conn.mayDefinitelyPass = true;
450  }
451  if (conn.tlID != "") {
452  conn.tlLinkNo = attrs.getIntReporting(SUMO_ATTR_TLLINKINDEX, 0, ok);
453  }
454 
455  if (from->lanes.size() <= (size_t) fromLaneIdx) {
456  WRITE_ERROR("Invalid lane index '" + toString(fromLaneIdx) + "' for connection from '" + fromID + "'.");
457  return;
458  }
459  from->lanes[fromLaneIdx]->connections.push_back(conn);
460 }
461 
462 
463 void
465  bool ok = true;
466  std::string prohibitor = attrs.getOptStringReporting(SUMO_ATTR_PROHIBITOR, 0, ok, "");
467  std::string prohibited = attrs.getOptStringReporting(SUMO_ATTR_PROHIBITED, 0, ok, "");
468  if (!ok) {
469  return;
470  }
471  Prohibition p;
474  if (!ok) {
475  return;
476  }
477  myProhibitions.push_back(p);
478 }
479 
480 
482 NIImporter_SUMO::getLaneAttrsFromID(EdgeAttrs* edge, std::string lane_id) {
483  std::string edge_id;
484  unsigned int index;
485  interpretLaneID(lane_id, edge_id, index);
486  assert(edge->id == edge_id);
487  if (edge->lanes.size() <= (size_t) index) {
488  WRITE_ERROR("Unknown lane '" + lane_id + "' given in succedge.");
489  return 0;
490  } else {
491  return edge->lanes[index];
492  }
493 }
494 
495 
496 void
497 NIImporter_SUMO::interpretLaneID(const std::string& lane_id, std::string& edge_id, unsigned int& index) {
498  // assume lane_id = edge_id + '_' + index
499  size_t sep_index = lane_id.rfind('_');
500  if (sep_index == std::string::npos) {
501  WRITE_ERROR("Invalid lane id '" + lane_id + "' (missing '_').");
502  }
503  edge_id = lane_id.substr(0, sep_index);
504  std::string index_string = lane_id.substr(sep_index + 1);
505  try {
506  index = (unsigned int)TplConvert::_2int(index_string.c_str());
507  } catch (NumberFormatException) {
508  WRITE_ERROR("Invalid lane index '" + index_string + "' for lane '" + lane_id + "'.");
509  }
510 }
511 
512 
515  if (currentTL) {
516  WRITE_ERROR("Definition of tl-logic '" + currentTL->getID() + "' was not finished.");
517  return 0;
518  }
519  bool ok = true;
520  std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok);
521  SUMOTime offset = TIME2STEPS(attrs.getSUMORealReporting(SUMO_ATTR_OFFSET, id.c_str(), ok));
522  std::string programID = attrs.getOptStringReporting(SUMO_ATTR_PROGRAMID, id.c_str(), ok, "<unknown>");
523  std::string type = attrs.getStringReporting(SUMO_ATTR_TYPE, 0, ok);
524  if (type != toString(TLTYPE_STATIC)) {
525  WRITE_WARNING("Traffic light '" + id + "' has unsupported type '" + type + "' and will be converted to '" +
526  toString(TLTYPE_STATIC) + "'");
527  }
528  if (ok) {
529  return new NBLoadedSUMOTLDef(id, programID, offset);
530  } else {
531  return 0;
532  }
533 }
534 
535 
536 void
538  if (!currentTL) {
539  WRITE_ERROR("found phase without tl-logic");
540  return;
541  }
542  const std::string& id = currentTL->getID();
543  bool ok = true;
544  std::string state = attrs.getStringReporting(SUMO_ATTR_STATE, id.c_str(), ok);
545  SUMOTime duration = TIME2STEPS(attrs.getSUMORealReporting(SUMO_ATTR_DURATION, id.c_str(), ok));
546  if (duration < 0) {
547  WRITE_ERROR("Phase duration for tl-logic '" + id + "/" + currentTL->getProgramID() + "' must be positive.");
548  return;
549  }
550  // if the traffic light is an actuated traffic light, try to get
551  // the minimum and maximum durations
552  //SUMOTime minDuration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MINDURATION, id.c_str(), ok, -1);
553  //SUMOTime maxDuration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MAXDURATION, id.c_str(), ok, -1);
554  if (ok) {
555  currentTL->addPhase(duration, state);
556  }
557 }
558 
559 
561 NIImporter_SUMO::reconstructEdgeShape(const EdgeAttrs* edge, const Position& from, const Position& to) {
562  const PositionVector& firstLane = edge->lanes[0]->shape;
563  PositionVector result;
564  result.push_back(from);
565 
566  // reverse logic of NBEdge::computeLaneShape
567  // !!! this will only work for old-style constant width lanes
568  const size_t noLanes = edge->lanes.size();
569  for (unsigned int i = 1; i < firstLane.size() - 1; i++) {
570  Position from = firstLane[i - 1];
571  Position me = firstLane[i];
572  Position to = firstLane[i + 1];
573  std::pair<SUMOReal, SUMOReal> offsets = NBEdge::laneOffset(
574  from, me, SUMO_const_laneWidthAndOffset, (unsigned int)noLanes - 1,
575  noLanes, edge->lsf, false);
576  std::pair<SUMOReal, SUMOReal> offsets2 = NBEdge::laneOffset(
577  me, to, SUMO_const_laneWidthAndOffset, (unsigned int)noLanes - 1,
578  noLanes, edge->lsf, false);
579 
580  Line l1(
581  Position(from.x() + offsets.first, from.y() + offsets.second),
582  Position(me.x() + offsets.first, me.y() + offsets.second));
583  l1.extrapolateBy(100);
584  Line l2(
585  Position(me.x() + offsets2.first, me.y() + offsets2.second),
586  Position(to.x() + offsets2.first, to.y() + offsets2.second));
587  l2.extrapolateBy(100);
588  if (l1.intersects(l2)) {
589  result.push_back(l1.intersectsAt(l2));
590  } else {
591  WRITE_WARNING("Could not reconstruct shape for edge '" + edge->id + "'.");
592  }
593  }
594 
595  result.push_back(to);
596  return result;
597 }
598 
599 
602  // @todo refactor parsing of location since its duplicated in NLHandler and PCNetProjectionLoader
603  bool ok = true;
604  GeoConvHelper* result = 0;
605  PositionVector s = attrs.getShapeReporting(SUMO_ATTR_NET_OFFSET, 0, ok, false);
606  Boundary convBoundary = attrs.getBoundaryReporting(SUMO_ATTR_CONV_BOUNDARY, 0, ok);
607  Boundary origBoundary = attrs.getBoundaryReporting(SUMO_ATTR_ORIG_BOUNDARY, 0, ok);
608  std::string proj = attrs.getStringReporting(SUMO_ATTR_ORIG_PROJ, 0, ok);
609  if (ok) {
610  Position networkOffset = s[0];
611  result = new GeoConvHelper(proj, networkOffset, origBoundary, convBoundary);
612  GeoConvHelper::setLoaded(*result);
613  }
614  return result;
615 }
616 
617 
618 Position
619 NIImporter_SUMO::readPosition(const SUMOSAXAttributes& attrs, const std::string& id, bool& ok) {
620  SUMOReal x = attrs.getSUMORealReporting(SUMO_ATTR_X, id.c_str(), ok);
621  SUMOReal y = attrs.getSUMORealReporting(SUMO_ATTR_Y, id.c_str(), ok);
622  SUMOReal z = 0;
623  if (attrs.hasAttribute(SUMO_ATTR_Z)) {
624  z = attrs.getSUMORealReporting(SUMO_ATTR_Z, id.c_str(), ok);
625  }
626  return Position(x, y, z);
627 }
628 
629 
630 void
631 NIImporter_SUMO::parseProhibitionConnection(const std::string& attr, std::string& from, std::string& to, bool& ok) {
632  // split from/to
633  size_t div = attr.find("->");
634  if (div == std::string::npos) {
635  WRITE_ERROR("Missing connection divider in prohibition attribute '" + attr + "'");
636  ok = false;
637  }
638  from = attr.substr(0, div);
639  to = attr.substr(div + 2);
640  // check whether the definition includes a lane information and discard it
641  if (from.find('_') != std::string::npos) {
642  from = from.substr(0, from.find('_'));
643  }
644  if (to.find('_') != std::string::npos) {
645  to = to.substr(0, to.find('_'));
646  }
647  // check whether the edges are known
648  if (myEdges.count(from) == 0) {
649  WRITE_ERROR("Unknown edge prohibition '" + from + "'");
650  ok = false;
651  }
652  if (myEdges.count(to) == 0) {
653  WRITE_ERROR("Unknown edge prohibition '" + to + "'");
654  ok = false;
655  }
656 }
657 /****************************************************************************/