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-2014 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  myHaveSeenInternalEdge(false)
86 {}
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::isReadable(*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, true);
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 || ed->func == EDGEFUNC_CROSSING || ed->func == EDGEFUNC_WALKINGAREA) {
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  } 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  }
181  if (nbe->hasConnectionTo(toEdge, c.toLaneIdx)) {
182  WRITE_WARNING("Target lane '" + toEdge->getLaneID(c.toLaneIdx) + "' has multiple connections from '" + nbe->getID() + "'.");
183  }
185  fromLaneIndex, toEdge, c.toLaneIdx, NBEdge::L2L_VALIDATED,
186  true, c.mayDefinitelyPass);
187 
188  // maybe we have a tls-controlled connection
189  if (c.tlID != "") {
190  const std::map<std::string, NBTrafficLightDefinition*>& programs = myTLLCont.getPrograms(c.tlID);
191  if (programs.size() > 0) {
192  std::map<std::string, NBTrafficLightDefinition*>::const_iterator it;
193  for (it = programs.begin(); it != programs.end(); it++) {
194  NBLoadedSUMOTLDef* tlDef = dynamic_cast<NBLoadedSUMOTLDef*>(it->second);
195  if (tlDef) {
196  tlDef->addConnection(nbe, toEdge, fromLaneIndex, c.toLaneIdx, c.tlLinkNo);
197  } else {
198  throw ProcessError("Corrupt traffic light definition '" + c.tlID + "' (program '" + it->first + "')");
199  }
200  }
201  } else {
202  WRITE_ERROR("The traffic light '" + c.tlID + "' is not known.");
203  }
204  }
205  }
206  // allow/disallow XXX preferred
207  nbe->setPermissions(parseVehicleClasses(lane->allow, lane->disallow), fromLaneIndex);
208  // width, offset
209  nbe->setLaneWidth(fromLaneIndex, lane->width);
210  nbe->setEndOffset(fromLaneIndex, lane->endOffset);
211  nbe->setSpeed(fromLaneIndex, lane->maxSpeed);
212  }
214  if (!nbe->hasLaneSpecificWidth() && nbe->getLanes()[0].width != NBEdge::UNSPECIFIED_WIDTH) {
215  nbe->setLaneWidth(-1, nbe->getLaneWidth(0));
216  }
218  nbe->setEndOffset(-1, nbe->getEndOffset(0));
219  }
220  }
221  // insert loaded prohibitions
222  for (std::vector<Prohibition>::const_iterator it = myProhibitions.begin(); it != myProhibitions.end(); it++) {
223  NBEdge* prohibitedFrom = myEdges[it->prohibitedFrom]->builtEdge;
224  if (prohibitedFrom == 0) {
225  WRITE_ERROR("Edge '" + it->prohibitedFrom + "' in prohibition was not built");
226  } else {
227  NBNode* n = prohibitedFrom->getToNode();
229  NBConnection(myEdges[it->prohibitorFrom]->builtEdge, myEdges[it->prohibitorTo]->builtEdge),
230  NBConnection(prohibitedFrom, myEdges[it->prohibitedTo]->builtEdge));
231  }
232  }
233  if (!myHaveSeenInternalEdge && oc.isDefault("no-internal-links")) {
234  oc.set("no-internal-links", "true");
235  }
236  if (!deprecatedVehicleClassesSeen.empty()) {
237  WRITE_WARNING("Deprecated vehicle class(es) '" + toString(deprecatedVehicleClassesSeen) + "' in input network.");
239  }
240  // add loaded crossings
241  for (std::map<std::string, std::vector<Crossing> >::const_iterator it = myPedestrianCrossings.begin(); it != myPedestrianCrossings.end(); ++it) {
242  NBNode* node = myNodeCont.retrieve((*it).first);
243  for (std::vector<Crossing>::const_iterator it_c = (*it).second.begin(); it_c != (*it).second.end(); ++it_c) {
244  const Crossing& crossing = (*it_c);
245  EdgeVector edges;
246  for (std::vector<std::string>::const_iterator it_e = crossing.crossingEdges.begin(); it_e != crossing.crossingEdges.end(); ++it_e) {
247  NBEdge* edge = myNetBuilder.getEdgeCont().retrieve(*it_e);
248  assert(edge != 0);
249  edges.push_back(edge);
250  }
251  node->addCrossing(edges, crossing.width, crossing.priority);
252  }
253  }
254 }
255 
256 
257 
258 void
260  const SUMOSAXAttributes& attrs) {
261  /* our goal is to reproduce the input net faithfully
262  * there are different types of objects in the netfile:
263  * 1) those which must be loaded into NBNetBuilder-Containers for processing
264  * 2) those which can be ignored because they are recomputed based on group 1
265  * 3) those which are of no concern to NBNetBuilder but should be exposed to
266  * NETEDIT. We will probably have to patch NBNetBuilder to contain them
267  * and hand them over to NETEDIT
268  * alternative idea: those shouldn't really be contained within the
269  * network but rather in separate files. teach NETEDIT how to open those
270  * (POI?)
271  * 4) those which are of concern neither to NBNetBuilder nor NETEDIT and
272  * must be copied over - need to patch NBNetBuilder for this.
273  * copy unknown by default
274  */
275  switch (element) {
276  case SUMO_TAG_EDGE:
277  addEdge(attrs);
278  break;
279  case SUMO_TAG_LANE:
280  addLane(attrs);
281  break;
282  case SUMO_TAG_JUNCTION:
283  addJunction(attrs);
284  break;
285  case SUMO_TAG_REQUEST:
286  addRequest(attrs);
287  break;
288  case SUMO_TAG_CONNECTION:
289  addConnection(attrs);
290  break;
291  case SUMO_TAG_TLLOGIC:
293  break;
294  case SUMO_TAG_PHASE:
295  addPhase(attrs, myCurrentTL);
296  break;
297  case SUMO_TAG_LOCATION:
298  myLocation = loadLocation(attrs);
299  break;
301  addProhibition(attrs);
302  break;
303  case SUMO_TAG_ROUNDABOUT:
305  break;
306  default:
307  break;
308  }
309 }
310 
311 
312 void
314  switch (element) {
315  case SUMO_TAG_EDGE:
316  if (myEdges.find(myCurrentEdge->id) != myEdges.end()) {
317  WRITE_ERROR("Edge '" + myCurrentEdge->id + "' occured at least twice in the input.");
318  } else {
320  }
321  myCurrentEdge = 0;
322  break;
323  case SUMO_TAG_LANE:
324  if (myCurrentEdge != 0) {
326  myCurrentEdge->lanes.push_back(myCurrentLane);
327  }
328  myCurrentLane = 0;
329  break;
330  case SUMO_TAG_TLLOGIC:
331  if (!myCurrentTL) {
332  WRITE_ERROR("Unmatched closing tag for tl-logic.");
333  } else {
334  if (!myTLLCont.insert(myCurrentTL)) {
335  WRITE_WARNING("Could not add program '" + myCurrentTL->getProgramID() + "' for traffic light '" + myCurrentTL->getID() + "'");
336  delete myCurrentTL;
337  }
338  myCurrentTL = 0;
339  }
340  break;
341  case SUMO_TAG_JUNCTION:
342  // in a network without internal lanes, we do not need to check for crossings
343  if (myCurrentJunction.node != 0 && myCurrentJunction.intLanes.size() > 0) {
344  assert(myCurrentJunction.intLanes.size() == myCurrentJunction.response.size());
345  std::vector<Crossing>& crossings = myPedestrianCrossings[myCurrentJunction.node->getID()];
346  for (std::vector<Crossing>::iterator it = crossings.begin(); it != crossings.end(); ++it) {
347  for (int i = 0; i < (int)myCurrentJunction.intLanes.size(); ++i) {
348  if (myCurrentJunction.intLanes[i] == (*it).laneID) {
349  (*it).priority = myCurrentJunction.response[i].find("1") == std::string::npos;
350  }
351  }
352  }
353  }
354  default:
355  break;
356  }
357 }
358 
359 
360 void
362  // get the id, report an error if not given or empty...
363  bool ok = true;
364  std::string id = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok);
365  if (!ok) {
366  return;
367  }
368  myCurrentEdge = new EdgeAttrs();
370  myCurrentEdge->id = id;
371  // get the function
372  myCurrentEdge->func = attrs.getEdgeFunc(ok);
374  // add the crossing crossing but don't do anything else
375  Crossing c;
378  return;
380  return; // skip internal edges
381  }
382  // get the type
383  myCurrentEdge->type = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, id.c_str(), ok, "");
384  // get the origin and the destination node
385  myCurrentEdge->fromNode = attrs.getOpt<std::string>(SUMO_ATTR_FROM, id.c_str(), ok, "");
386  myCurrentEdge->toNode = attrs.getOpt<std::string>(SUMO_ATTR_TO, id.c_str(), ok, "");
387  myCurrentEdge->priority = attrs.getOpt<int>(SUMO_ATTR_PRIORITY, id.c_str(), ok, -1);
388  myCurrentEdge->type = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, id.c_str(), ok, "");
392  myCurrentEdge->maxSpeed = 0;
393  myCurrentEdge->streetName = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok, "");
394  if (myCurrentEdge->streetName != "" && OptionsCont::getOptions().isDefault("output.street-names")) {
395  OptionsCont::getOptions().set("output.street-names", "true");
396  }
397 
398  std::string lsfS = toString(LANESPREAD_RIGHT);
399  lsfS = attrs.getOpt<std::string>(SUMO_ATTR_SPREADTYPE, id.c_str(), ok, lsfS);
400  if (SUMOXMLDefinitions::LaneSpreadFunctions.hasString(lsfS)) {
402  } else {
403  WRITE_ERROR("Unknown spreadType '" + lsfS + "' for edge '" + id + "'.");
404  }
405 }
406 
407 
408 void
410  bool ok = true;
411  std::string id = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok);
412  if (!ok) {
413  return;
414  }
415  if (!myCurrentEdge) {
416  WRITE_ERROR("Found lane '" + id + "' not within edge element");
417  return;
418  }
419  myCurrentLane = new LaneAttrs;
421  // save the width and the lane id of the crossing but don't do anything else
423  assert(crossings.size() > 0);
424  crossings.back().laneID = id;
425  crossings.back().width = attrs.get<SUMOReal>(SUMO_ATTR_WIDTH, id.c_str(), ok);
426  return;
428  myHaveSeenInternalEdge = true;
429  return; // skip internal lanes
430  }
431  if (attrs.hasAttribute("maxspeed")) {
432  // !!! deprecated
433  myCurrentLane->maxSpeed = attrs.getFloat("maxspeed");
434  } else {
435  myCurrentLane->maxSpeed = attrs.get<SUMOReal>(SUMO_ATTR_SPEED, id.c_str(), ok);
436  }
437  try {
438  myCurrentLane->allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, id.c_str(), ok, "", false);
439  } catch (EmptyData e) {
440  // !!! deprecated
441  myCurrentLane->allow = "";
442  }
443  myCurrentLane->disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, id.c_str(), ok, "");
446  myCurrentLane->shape = attrs.get<PositionVector>(SUMO_ATTR_SHAPE, id.c_str(), ok);
447  // lane coordinates are derived (via lane spread) do not include them in convex boundary
449 }
450 
451 
452 void
454  // get the id, report an error if not given or empty...
456  bool ok = true;
457  std::string id = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok);
458  if (!ok) {
459  return;
460  }
461  if (id[0] == ':') { // internal node
462  return;
463  }
464  SumoXMLNodeType type = attrs.getNodeType(ok);
465  if (ok) {
466  if (type == NODETYPE_DEAD_END_DEPRECATED || type == NODETYPE_DEAD_END) {
467  // dead end is a computed status. Reset this to unknown so it will
468  // be corrected if additional connections are loaded
469  type = NODETYPE_UNKNOWN;
470  }
471  } else {
472  WRITE_WARNING("Unknown node type for junction '" + id + "'.");
473  }
474  Position pos = readPosition(attrs, id, ok);
476  NBNode* node = new NBNode(id, pos, type);
477  if (!myNodeCont.insert(node)) {
478  WRITE_ERROR("Problems on adding junction '" + id + "'.");
479  delete node;
480  return;
481  }
482  myCurrentJunction.node = node;
484 }
485 
486 
487 void
489  if (myCurrentJunction.node != 0) {
490  bool ok = true;
491  myCurrentJunction.response.push_back(attrs.get<std::string>(SUMO_ATTR_RESPONSE, 0, ok));
492  }
493 }
494 
495 
496 void
498  bool ok = true;
499  std::string fromID = attrs.get<std::string>(SUMO_ATTR_FROM, 0, ok);
500  if (myEdges.count(fromID) == 0) {
501  WRITE_ERROR("Unknown edge '" + fromID + "' given in connection.");
502  return;
503  }
504  EdgeAttrs* from = myEdges[fromID];
505  Connection conn;
506  conn.toEdgeID = attrs.get<std::string>(SUMO_ATTR_TO, 0, ok);
507  unsigned int fromLaneIdx = attrs.get<int>(SUMO_ATTR_FROM_LANE, 0, ok);
508  conn.toLaneIdx = attrs.get<int>(SUMO_ATTR_TO_LANE, 0, ok);
509  conn.tlID = attrs.getOpt<std::string>(SUMO_ATTR_TLID, 0, ok, "");
510  conn.mayDefinitelyPass = attrs.getOpt<bool>(SUMO_ATTR_PASS, 0, ok, false);
511  if (conn.tlID != "") {
512  conn.tlLinkNo = attrs.get<int>(SUMO_ATTR_TLLINKINDEX, 0, ok);
513  }
514  if (from->lanes.size() <= (size_t) fromLaneIdx) {
515  WRITE_ERROR("Invalid lane index '" + toString(fromLaneIdx) + "' for connection from '" + fromID + "'.");
516  return;
517  }
518  from->lanes[fromLaneIdx]->connections.push_back(conn);
519 }
520 
521 
522 void
524  bool ok = true;
525  std::string prohibitor = attrs.getOpt<std::string>(SUMO_ATTR_PROHIBITOR, 0, ok, "");
526  std::string prohibited = attrs.getOpt<std::string>(SUMO_ATTR_PROHIBITED, 0, ok, "");
527  if (!ok) {
528  return;
529  }
530  Prohibition p;
533  if (!ok) {
534  return;
535  }
536  myProhibitions.push_back(p);
537 }
538 
539 
541 NIImporter_SUMO::getLaneAttrsFromID(EdgeAttrs* edge, std::string lane_id) {
542  std::string edge_id;
543  unsigned int index;
544  interpretLaneID(lane_id, edge_id, index);
545  assert(edge->id == edge_id);
546  if (edge->lanes.size() <= (size_t) index) {
547  WRITE_ERROR("Unknown lane '" + lane_id + "' given in succedge.");
548  return 0;
549  } else {
550  return edge->lanes[index];
551  }
552 }
553 
554 
555 void
556 NIImporter_SUMO::interpretLaneID(const std::string& lane_id, std::string& edge_id, unsigned int& index) {
557  // assume lane_id = edge_id + '_' + index
558  size_t sep_index = lane_id.rfind('_');
559  if (sep_index == std::string::npos) {
560  WRITE_ERROR("Invalid lane id '" + lane_id + "' (missing '_').");
561  }
562  edge_id = lane_id.substr(0, sep_index);
563  std::string index_string = lane_id.substr(sep_index + 1);
564  try {
565  index = (unsigned int)TplConvert::_2int(index_string.c_str());
566  } catch (NumberFormatException) {
567  WRITE_ERROR("Invalid lane index '" + index_string + "' for lane '" + lane_id + "'.");
568  }
569 }
570 
571 
574  if (currentTL) {
575  WRITE_ERROR("Definition of tl-logic '" + currentTL->getID() + "' was not finished.");
576  return 0;
577  }
578  bool ok = true;
579  std::string id = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok);
580  SUMOTime offset = TIME2STEPS(attrs.get<SUMOReal>(SUMO_ATTR_OFFSET, id.c_str(), ok));
581  std::string programID = attrs.getOpt<std::string>(SUMO_ATTR_PROGRAMID, id.c_str(), ok, "<unknown>");
582  std::string typeS = attrs.get<std::string>(SUMO_ATTR_TYPE, 0, ok);
583  TrafficLightType type;
584  if (SUMOXMLDefinitions::TrafficLightTypes.hasString(typeS)) {
586  } else {
587  WRITE_ERROR("Unknown traffic light type '" + typeS + "' for tlLogic '" + id + "'.");
588  return 0;
589  }
590  if (ok) {
591  return new NBLoadedSUMOTLDef(id, programID, offset, type);
592  } else {
593  return 0;
594  }
595 }
596 
597 
598 void
600  if (!currentTL) {
601  WRITE_ERROR("found phase without tl-logic");
602  return;
603  }
604  const std::string& id = currentTL->getID();
605  bool ok = true;
606  std::string state = attrs.get<std::string>(SUMO_ATTR_STATE, id.c_str(), ok);
607  SUMOTime duration = TIME2STEPS(attrs.get<SUMOReal>(SUMO_ATTR_DURATION, id.c_str(), ok));
608  if (duration < 0) {
609  WRITE_ERROR("Phase duration for tl-logic '" + id + "/" + currentTL->getProgramID() + "' must be positive.");
610  return;
611  }
612  // if the traffic light is an actuated traffic light, try to get
613  // the minimum and maximum durations
614  //SUMOTime minDuration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MINDURATION, id.c_str(), ok, -1);
615  //SUMOTime maxDuration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MAXDURATION, id.c_str(), ok, -1);
616  if (ok) {
617  currentTL->addPhase(duration, state);
618  }
619 }
620 
621 
623 NIImporter_SUMO::reconstructEdgeShape(const EdgeAttrs* edge, const Position& from, const Position& to) {
624  const PositionVector& firstLane = edge->lanes[0]->shape;
625  PositionVector result;
626  result.push_back(from);
627 
628  // reverse logic of NBEdge::computeLaneShape
629  // !!! this will only work for old-style constant width lanes
630  const size_t noLanes = edge->lanes.size();
631  SUMOReal offset;
632  if (edge->lsf == LANESPREAD_RIGHT) {
633  offset = (SUMO_const_laneWidth + SUMO_const_laneOffset) / 2.; // @todo: why is the lane offset counted in here?
634  } else {
635  offset = (SUMO_const_laneWidth) / 2. - (SUMO_const_laneWidth * (SUMOReal)noLanes - 1) / 2.;
636  }
637  for (unsigned int i = 1; i < firstLane.size() - 1; i++) {
638  Position from = firstLane[i - 1];
639  Position me = firstLane[i];
640  Position to = firstLane[i + 1];
641  std::pair<SUMOReal, SUMOReal> offsets = NBEdge::laneOffset(from, me, offset, false);
642  std::pair<SUMOReal, SUMOReal> offsets2 = NBEdge::laneOffset(me, to, offset, false);
643 
644  Line l1(
645  Position(from.x() + offsets.first, from.y() + offsets.second),
646  Position(me.x() + offsets.first, me.y() + offsets.second));
647  l1.extrapolateBy(100);
648  Line l2(
649  Position(me.x() + offsets2.first, me.y() + offsets2.second),
650  Position(to.x() + offsets2.first, to.y() + offsets2.second));
651  l2.extrapolateBy(100);
652  if (l1.intersects(l2)) {
653  result.push_back(l1.intersectsAt(l2));
654  } else {
655  WRITE_WARNING("Could not reconstruct shape for edge '" + edge->id + "'.");
656  }
657  }
658 
659  result.push_back(to);
660  return result;
661 }
662 
663 
666  // @todo refactor parsing of location since its duplicated in NLHandler and PCNetProjectionLoader
667  bool ok = true;
668  GeoConvHelper* result = 0;
670  Boundary convBoundary = attrs.get<Boundary>(SUMO_ATTR_CONV_BOUNDARY, 0, ok);
671  Boundary origBoundary = attrs.get<Boundary>(SUMO_ATTR_ORIG_BOUNDARY, 0, ok);
672  std::string proj = attrs.get<std::string>(SUMO_ATTR_ORIG_PROJ, 0, ok);
673  if (ok) {
674  Position networkOffset = s[0];
675  result = new GeoConvHelper(proj, networkOffset, origBoundary, convBoundary);
676  GeoConvHelper::setLoaded(*result);
677  }
678  return result;
679 }
680 
681 
682 Position
683 NIImporter_SUMO::readPosition(const SUMOSAXAttributes& attrs, const std::string& id, bool& ok) {
684  SUMOReal x = attrs.get<SUMOReal>(SUMO_ATTR_X, id.c_str(), ok);
685  SUMOReal y = attrs.get<SUMOReal>(SUMO_ATTR_Y, id.c_str(), ok);
686  SUMOReal z = 0;
687  if (attrs.hasAttribute(SUMO_ATTR_Z)) {
688  z = attrs.get<SUMOReal>(SUMO_ATTR_Z, id.c_str(), ok);
689  }
690  return Position(x, y, z);
691 }
692 
693 
694 void
695 NIImporter_SUMO::parseProhibitionConnection(const std::string& attr, std::string& from, std::string& to, bool& ok) {
696  // split from/to
697  size_t div = attr.find("->");
698  if (div == std::string::npos) {
699  WRITE_ERROR("Missing connection divider in prohibition attribute '" + attr + "'");
700  ok = false;
701  }
702  from = attr.substr(0, div);
703  to = attr.substr(div + 2);
704  // check whether the definition includes a lane information and discard it
705  if (from.find('_') != std::string::npos) {
706  from = from.substr(0, from.find('_'));
707  }
708  if (to.find('_') != std::string::npos) {
709  to = to.substr(0, to.find('_'));
710  }
711  // check whether the edges are known
712  if (myEdges.count(from) == 0) {
713  WRITE_ERROR("Unknown edge prohibition '" + from + "'");
714  ok = false;
715  }
716  if (myEdges.count(to) == 0) {
717  WRITE_ERROR("Unknown edge prohibition '" + to + "'");
718  ok = false;
719  }
720 }
721 /****************************************************************************/