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>
50 #include <netbuild/NBNetBuilder.h>
51 #include "NILoader.h"
52 #include "NIImporter_SUMO.h"
53 
54 #ifdef CHECK_MEMORY_LEAKS
55 #include <foreign/nvwa/debug_new.h>
56 #endif // CHECK_MEMORY_LEAKS
57 
58 
59 // ===========================================================================
60 // method definitions
61 // ===========================================================================
62 // ---------------------------------------------------------------------------
63 // static methods (interface in this case)
64 // ---------------------------------------------------------------------------
65 void
67  NIImporter_SUMO importer(nb);
68  importer._loadNetwork(oc);
69 }
70 
71 
72 // ---------------------------------------------------------------------------
73 // loader methods
74 // ---------------------------------------------------------------------------
76  : SUMOSAXHandler("sumo-network"),
77  myNetBuilder(nb),
78  myNodeCont(nb.getNodeCont()),
79  myTLLCont(nb.getTLLogicCont()),
80  myCurrentEdge(0),
81  myCurrentLane(0),
82  myCurrentTL(0),
83  myLocation(0),
84  mySuspectKeepShape(false),
85  myHaveWarnedAboutDeprecatedSpreadType(false),
86  myHaveWarnedAboutDeprecatedMaxSpeed(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 == toString(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 '"
197  + c.tlID + "' (program '" + it->first + "')");
198  }
199  }
200  } else {
201  WRITE_ERROR("The traffic light '" + c.tlID + "' is not known.");
202  }
203  }
204  }
205  // allow/disallow XXX preferred
206  nbe->setPermissions(parseVehicleClasses(lane->allow, lane->disallow), fromLaneIndex);
207  // width, offset
208  nbe->setWidth(fromLaneIndex, lane->width);
209  nbe->setOffset(fromLaneIndex, lane->offset);
210  nbe->setSpeed(fromLaneIndex, lane->maxSpeed);
211  }
213  }
214  // insert loaded prohibitions
215  for (std::vector<Prohibition>::const_iterator it = myProhibitions.begin(); it != myProhibitions.end(); it++) {
216  NBEdge* prohibitedFrom = myEdges[it->prohibitedFrom]->builtEdge;
217  if (prohibitedFrom == 0) {
218  WRITE_ERROR("Edge '" + it->prohibitedFrom + "' in prohibition was not built");
219  } else {
220  NBNode* n = prohibitedFrom->getToNode();
222  NBConnection(myEdges[it->prohibitorFrom]->builtEdge, myEdges[it->prohibitorTo]->builtEdge),
223  NBConnection(prohibitedFrom, myEdges[it->prohibitedTo]->builtEdge));
224  }
225  }
226 
227  // final warning
228  if (mySuspectKeepShape) {
229  WRITE_WARNING("The input network may have been built using option 'xml.keep-shape'.\n... Accuracy of junction positions cannot be guaranteed.");
230  }
231 
232 }
233 
234 
235 
236 void
238  const SUMOSAXAttributes& attrs) {
239  /* our goal is to reproduce the input net faithfully
240  * there are different types of objects in the netfile:
241  * 1) those which must be loaded into NBNetBuilder-Containers for processing
242  * 2) those which can be ignored because they are recomputed based on group 1
243  * 3) those which are of no concern to NBNetBuilder but should be exposed to
244  * NETEDIT. We will probably have to patch NBNetBuilder to contain them
245  * and hand them over to NETEDIT
246  * alternative idea: those shouldn't really be contained within the
247  * network but rather in separate files. teach NETEDIT how to open those
248  * (POI?)
249  * 4) those which are of concern neither to NBNetBuilder nor NETEDIT and
250  * must be copied over - need to patch NBNetBuilder for this.
251  * copy unknown by default
252  */
253  switch (element) {
254  case SUMO_TAG_EDGE:
255  addEdge(attrs);
256  break;
257  case SUMO_TAG_LANE:
258  addLane(attrs);
259  break;
260  case SUMO_TAG_JUNCTION:
261  addJunction(attrs);
262  break;
263  case SUMO_TAG_SUCC:
264  addSuccEdge(attrs);
265  break;
266  case SUMO_TAG_SUCCLANE:
267  addSuccLane(attrs);
268  break;
269  case SUMO_TAG_CONNECTION:
270  addConnection(attrs);
271  break;
273  case SUMO_TAG_TLLOGIC:
275  break;
276  case SUMO_TAG_PHASE:
277  addPhase(attrs, myCurrentTL);
278  break;
279  case SUMO_TAG_LOCATION:
280  myLocation = loadLocation(attrs);
281  break;
283  addProhibition(attrs);
284  break;
285  default:
286  break;
287  }
288 }
289 
290 
291 void
293  const std::string& chars) {
294  UNUSED_PARAMETER(element);
295  UNUSED_PARAMETER(chars);
296 }
297 
298 
299 void
301  switch (element) {
302  case SUMO_TAG_EDGE:
303  if (myEdges.find(myCurrentEdge->id) != myEdges.end()) {
304  WRITE_ERROR("Edge '" + myCurrentEdge->id + "' occured at least twice in the input.");
305  } else {
307  }
308  myCurrentEdge = 0;
309  break;
310  case SUMO_TAG_LANE:
311  if (myCurrentEdge != 0) {
313  myCurrentEdge->lanes.push_back(myCurrentLane);
314  }
315  myCurrentLane = 0;
316  break;
318  case SUMO_TAG_TLLOGIC:
319  if (!myCurrentTL) {
320  WRITE_ERROR("Unmatched closing tag for tl-logic.");
321  } else {
322  if (!myTLLCont.insert(myCurrentTL)) {
323  WRITE_WARNING("Could not add program '" + myCurrentTL->getProgramID() +
324  "' for traffic light '" + myCurrentTL->getID() + "'");
325  delete myCurrentTL;
326  }
327  myCurrentTL = 0;
328  }
329  break;
330  default:
331  break;
332  }
333 }
334 
335 
336 void
338  // get the id, report an error if not given or empty...
339  bool ok = true;
340  std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok);
341  if (!ok) {
342  return;
343  }
344  myCurrentEdge = new EdgeAttrs();
346  myCurrentEdge->id = id;
347  // get the function
348  myCurrentEdge->func = attrs.getOptStringReporting(SUMO_ATTR_FUNCTION, id.c_str(), ok, "normal");
350  return; // skip internal edges
351  }
352  // get the type
353  myCurrentEdge->type = attrs.getOptStringReporting(SUMO_ATTR_TYPE, id.c_str(), ok, "");
354  // get the origin and the destination node
355  myCurrentEdge->fromNode = attrs.getOptStringReporting(SUMO_ATTR_FROM, id.c_str(), ok, "");
356  myCurrentEdge->toNode = attrs.getOptStringReporting(SUMO_ATTR_TO, id.c_str(), ok, "");
357  myCurrentEdge->priority = attrs.getOptIntReporting(SUMO_ATTR_PRIORITY, id.c_str(), ok, -1);
358  myCurrentEdge->type = attrs.getOptStringReporting(SUMO_ATTR_TYPE, id.c_str(), ok, "");
360  attrs.getOptStringReporting(SUMO_ATTR_SHAPE, id.c_str(), ok, ""),
361  attrs.getObjectType(), id.c_str(), ok, true);
364  myCurrentEdge->maxSpeed = 0;
365  myCurrentEdge->streetName = attrs.getOptStringReporting(SUMO_ATTR_NAME, id.c_str(), ok, "");
366 
367  std::string lsfS = toString(LANESPREAD_RIGHT);
369  lsfS = attrs.getStringReporting(SUMO_ATTR_SPREADFUNC__DEPRECATED, id.c_str(), ok);
371  WRITE_WARNING("'" + toString(SUMO_ATTR_SPREADFUNC__DEPRECATED) + "' is deprecated; please use '" + toString(SUMO_ATTR_SPREADTYPE) + "'.");
373  }
374  } else {
375  lsfS = attrs.getOptStringReporting(SUMO_ATTR_SPREADTYPE, id.c_str(), ok, lsfS);
376  }
377  if (SUMOXMLDefinitions::LaneSpreadFunctions.hasString(lsfS)) {
379  } else {
380  WRITE_ERROR("Unknown spreadType '" + lsfS + "' for edge '" + id + "'.");
381  }
382 }
383 
384 
385 void
387  bool ok = true;
388  std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok);
389  if (!ok) {
390  return;
391  }
392  if (!myCurrentEdge) {
393  WRITE_ERROR("Found lane '" + id + "' not within edge element");
394  return;
395  }
396  myCurrentLane = new LaneAttrs;
398  return; // skip internal lanes
399  }
404  WRITE_WARNING("'" + toString(SUMO_ATTR_MAXSPEED__DEPRECATED) + "' is deprecated, please use '" + toString(SUMO_ATTR_SPEED) + "' instead.");
405  }
406  } else {
408  }
409  myCurrentLane->allow = attrs.getOptStringReporting(SUMO_ATTR_ALLOW, id.c_str(), ok, "");
410  myCurrentLane->disallow = attrs.getOptStringReporting(SUMO_ATTR_DISALLOW, id.c_str(), ok, "");
414  attrs.getStringReporting(SUMO_ATTR_SHAPE, id.c_str(), ok),
415  attrs.getObjectType(), id.c_str(), ok, false);
416  // lane coordinates are derived (via lane spread) do not include them in convex boundary
418 }
419 
420 
421 void
423  // get the id, report an error if not given or empty...
424  bool ok = true;
425  std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok);
426  if (!ok) {
427  return;
428  }
429  if (id[0] == ':') { // internal node
430  return;
431  }
433  std::string typeS = attrs.getStringReporting(SUMO_ATTR_TYPE, id.c_str(), ok);
434  if (SUMOXMLDefinitions::NodeTypes.hasString(typeS)) {
435  type = SUMOXMLDefinitions::NodeTypes.get(typeS);
436  if (type == NODETYPE_DEAD_END_DEPRECATED) { // patch legacy type
437  type = NODETYPE_DEAD_END;
438  }
439  } else {
440  WRITE_WARNING("Unknown node type '" + typeS + "' for junction '" + id + "'.");
441  }
442  Position pos = readPosition(attrs, id, ok);
444  // the network may have been built with the option "plain.keep-edge-shape" this
445  // makes accurate reconstruction of legacy networks impossible. We ought to warn about this
446  std::string shapeS = attrs.getStringReporting(SUMO_ATTR_SHAPE, id.c_str(), ok, false);
447  if (shapeS != "") {
449  shapeS, attrs.getObjectType(), id.c_str(), ok, false);
450  shape.push_back_noDoublePos(shape[0]); // need closed shape
451  if (!shape.around(pos) && shape.distance(pos) > 1) { // MAGIC_THRESHOLD
452  // WRITE_WARNING("Junction '" + id + "': distance between pos and shape is " + toString(shape.distance(pos)));
453  mySuspectKeepShape = true;
454  }
455  }
456  NBNode* node = new NBNode(id, pos, type);
457  if (!myNodeCont.insert(node)) {
458  WRITE_ERROR("Problems on adding junction '" + id + "'.");
459  delete node;
460  return;
461  }
462 }
463 
464 
465 void
467  bool ok = true;
468  std::string edge_id = attrs.getStringReporting(SUMO_ATTR_EDGE, 0, ok);
469  myCurrentEdge = 0;
470  if (myEdges.count(edge_id) == 0) {
471  WRITE_ERROR("Unknown edge '" + edge_id + "' given in succedge.");
472  return;
473  }
474  myCurrentEdge = myEdges[edge_id];
475  std::string lane_id = attrs.getStringReporting(SUMO_ATTR_LANE, 0, ok);
477 }
478 
479 
480 void
482  if (myCurrentLane == 0) {
483  WRITE_ERROR("Found succlane outside succ element");
484  return;
485  }
486  bool ok = true;
487  Connection conn;
488  std::string laneID = attrs.getStringReporting(SUMO_ATTR_LANE, 0, ok);
489  if (laneID == "SUMO_NO_DESTINATION") { // legacy check
490  // deprecated
491  return;
492  }
493  interpretLaneID(laneID, conn.toEdgeID, conn.toLaneIdx);
494  conn.tlID = attrs.getOptStringReporting(SUMO_ATTR_TLID, 0, ok, "");
495  conn.mayDefinitelyPass = false; // (attrs.getStringReporting(SUMO_ATTR_STATE, 0, ok, "") == "M");
496  if (conn.tlID != "") {
498  ? attrs.getIntReporting(SUMO_ATTR_TLLINKINDEX, 0, ok)
500  }
501  myCurrentLane->connections.push_back(conn);
502 }
503 
504 
505 void
507  bool ok = true;
508  std::string fromID = attrs.getStringReporting(SUMO_ATTR_FROM, 0, ok);
509  if (myEdges.count(fromID) == 0) {
510  WRITE_ERROR("Unknown edge '" + fromID + "' given in connection.");
511  return;
512  }
513  EdgeAttrs* from = myEdges[fromID];
514  Connection conn;
515  conn.toEdgeID = attrs.getStringReporting(SUMO_ATTR_TO, 0, ok);
516  unsigned int fromLaneIdx = attrs.getIntReporting(SUMO_ATTR_FROM_LANE, 0, ok);
517  conn.toLaneIdx = attrs.getIntReporting(SUMO_ATTR_TO_LANE, 0, ok);
518  conn.tlID = attrs.getOptStringReporting(SUMO_ATTR_TLID, 0, ok, "");
519  conn.mayDefinitelyPass = false; // (attrs.getStringReporting(SUMO_ATTR_STATE, 0, ok, "") == "M");
520  if (conn.tlID != "") {
521  conn.tlLinkNo = attrs.getIntReporting(SUMO_ATTR_TLLINKINDEX, 0, ok);
522  }
523 
524  if (from->lanes.size() <= (size_t) fromLaneIdx) {
525  WRITE_ERROR("Invalid lane index '" + toString(fromLaneIdx) + "' for connection from '" + fromID + "'.");
526  return;
527  }
528  from->lanes[fromLaneIdx]->connections.push_back(conn);
529 }
530 
531 
532 void
534  bool ok = true;
535  std::string prohibitor = attrs.getOptStringReporting(SUMO_ATTR_PROHIBITOR, 0, ok, "");
536  std::string prohibited = attrs.getOptStringReporting(SUMO_ATTR_PROHIBITED, 0, ok, "");
537  if (!ok) {
538  return;
539  }
540  Prohibition p;
543  if (!ok) {
544  return;
545  }
546  myProhibitions.push_back(p);
547 }
548 
549 
551 NIImporter_SUMO::getLaneAttrsFromID(EdgeAttrs* edge, std::string lane_id) {
552  std::string edge_id;
553  unsigned int index;
554  interpretLaneID(lane_id, edge_id, index);
555  assert(edge->id == edge_id);
556  if (edge->lanes.size() <= (size_t) index) {
557  WRITE_ERROR("Unknown lane '" + lane_id + "' given in succedge.");
558  return 0;
559  } else {
560  return edge->lanes[index];
561  }
562 }
563 
564 
565 void
566 NIImporter_SUMO::interpretLaneID(const std::string& lane_id, std::string& edge_id, unsigned int& index) {
567  // assume lane_id = edge_id + '_' + index
568  size_t sep_index = lane_id.rfind('_');
569  if (sep_index == std::string::npos) {
570  WRITE_ERROR("Invalid lane id '" + lane_id + "' (missing '_').");
571  }
572  edge_id = lane_id.substr(0, sep_index);
573  std::string index_string = lane_id.substr(sep_index + 1);
574  try {
575  index = (unsigned int)TplConvert<char>::_2int(index_string.c_str());
576  } catch (NumberFormatException) {
577  WRITE_ERROR("Invalid lane index '" + index_string + "' for lane '" + lane_id + "'.");
578  }
579 }
580 
581 
584  if (currentTL) {
585  WRITE_ERROR("Definition of tl-logic '" + currentTL->getID() + "' was not finished.");
586  return 0;
587  }
588  bool ok = true;
589  std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok);
590  SUMOTime offset = TIME2STEPS(attrs.getSUMORealReporting(SUMO_ATTR_OFFSET, id.c_str(), ok));
591  std::string programID = attrs.getOptStringReporting(SUMO_ATTR_PROGRAMID, id.c_str(), ok, "<unknown>");
592  std::string type = attrs.getStringReporting(SUMO_ATTR_TYPE, 0, ok);
593  if (type != toString(TLTYPE_STATIC)) {
594  WRITE_WARNING("Traffic light '" + id + "' has unsupported type '" + type + "' and will be converted to '" +
595  toString(TLTYPE_STATIC) + "'");
596  }
597  if (ok) {
598  return new NBLoadedSUMOTLDef(id, programID, offset);
599  } else {
600  return 0;
601  }
602 }
603 
604 
605 void
607  if (!currentTL) {
608  WRITE_ERROR("found phase without tl-logic");
609  return;
610  }
611  const std::string& id = currentTL->getID();
612  bool ok = true;
613  std::string state = attrs.getStringReporting(SUMO_ATTR_STATE, id.c_str(), ok);
614  SUMOTime duration = TIME2STEPS(attrs.getSUMORealReporting(SUMO_ATTR_DURATION, id.c_str(), ok));
615  if (duration < 0) {
616  WRITE_ERROR("Phase duration for tl-logic '" + id + "/" + currentTL->getProgramID() + "' must be positive.");
617  return;
618  }
619  // if the traffic light is an actuated traffic light, try to get
620  // the minimum and maximum durations
621  //SUMOTime minDuration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MINDURATION, id.c_str(), ok, -1);
622  //SUMOTime maxDuration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MAXDURATION, id.c_str(), ok, -1);
623  if (ok) {
624  currentTL->addPhase(duration, state);
625  }
626 }
627 
628 
630 NIImporter_SUMO::reconstructEdgeShape(const EdgeAttrs* edge, const Position& from, const Position& to) {
631  const PositionVector& firstLane = edge->lanes[0]->shape;
632  PositionVector result;
633  result.push_back(from);
634 
635  // reverse logic of NBEdge::computeLaneShape
636  // !!! this will only work for old-style constant width lanes
637  const size_t noLanes = edge->lanes.size();
638  for (unsigned int i = 1; i < firstLane.size() - 1; i++) {
639  Position from = firstLane[i - 1];
640  Position me = firstLane[i];
641  Position to = firstLane[i + 1];
642  std::pair<SUMOReal, SUMOReal> offsets = NBEdge::laneOffset(
643  from, me, SUMO_const_laneWidthAndOffset, (unsigned int)noLanes - 1,
644  noLanes, edge->lsf, false);
645  std::pair<SUMOReal, SUMOReal> offsets2 = NBEdge::laneOffset(
646  me, to, SUMO_const_laneWidthAndOffset, (unsigned int)noLanes - 1,
647  noLanes, edge->lsf, false);
648 
649  Line l1(
650  Position(from.x() + offsets.first, from.y() + offsets.second),
651  Position(me.x() + offsets.first, me.y() + offsets.second));
652  l1.extrapolateBy(100);
653  Line l2(
654  Position(me.x() + offsets2.first, me.y() + offsets2.second),
655  Position(to.x() + offsets2.first, to.y() + offsets2.second));
656  l2.extrapolateBy(100);
657  if (l1.intersects(l2)) {
658  result.push_back(l1.intersectsAt(l2));
659  } else {
660  WRITE_WARNING("Could not reconstruct shape for edge '" + edge->id + "'.");
661  }
662  }
663 
664  result.push_back(to);
665  return result;
666 }
667 
668 
671  // @todo refactor parsing of location since its duplicated in NLHandler and PCNetProjectionLoader
672  bool ok = true;
673  GeoConvHelper* result = 0;
676  attrs.getObjectType(), 0, ok, false);
679  attrs.getObjectType(), 0, ok);
682  attrs.getObjectType(), 0, ok);
683  std::string proj = attrs.getStringReporting(SUMO_ATTR_ORIG_PROJ, 0, ok);
684  if (ok) {
685  Position networkOffset = s[0];
686  result = new GeoConvHelper(proj, networkOffset, origBoundary, convBoundary);
687  GeoConvHelper::setLoaded(*result);
688  }
689  return result;
690 }
691 
692 
693 Position
694 NIImporter_SUMO::readPosition(const SUMOSAXAttributes& attrs, const std::string& id, bool& ok) {
695  SUMOReal x = attrs.getSUMORealReporting(SUMO_ATTR_X, id.c_str(), ok);
696  SUMOReal y = attrs.getSUMORealReporting(SUMO_ATTR_Y, id.c_str(), ok);
697  SUMOReal z = 0;
698  if (attrs.hasAttribute(SUMO_ATTR_Z)) {
699  z = attrs.getSUMORealReporting(SUMO_ATTR_Z, id.c_str(), ok);
700  }
701  return Position(x, y, z);
702 }
703 
704 
705 void
706 NIImporter_SUMO::parseProhibitionConnection(const std::string& attr, std::string& from, std::string& to, bool& ok) {
707  // split from/to
708  size_t div = attr.find("->");
709  if (div == std::string::npos) {
710  WRITE_ERROR("Missing connection divider in prohibition attribute '" + attr + "'");
711  ok = false;
712  }
713  from = attr.substr(0, div);
714  to = attr.substr(div + 2);
715  // check whether the definition includes a lane information and discard it
716  if (from.find('_') != std::string::npos) {
717  from = from.substr(0, from.find('_'));
718  }
719  if (to.find('_') != std::string::npos) {
720  to = to.substr(0, to.find('_'));
721  }
722  // check whether the edges are known
723  if (myEdges.count(from) == 0) {
724  WRITE_ERROR("Unknown edge prohibition '" + from + "'");
725  ok = false;
726  }
727  if (myEdges.count(to) == 0) {
728  WRITE_ERROR("Unknown edge prohibition '" + to + "'");
729  ok = false;
730  }
731 }
732 /****************************************************************************/