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