SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NIImporter_OpenStreetMap.cpp
Go to the documentation of this file.
1 /****************************************************************************/
10 // Importer for networks stored in OpenStreetMap format
11 /****************************************************************************/
12 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/
13 // Copyright (C) 2001-2012 DLR (http://www.dlr.de/) and contributors
14 /****************************************************************************/
15 //
16 // This file is part of SUMO.
17 // SUMO is free software: you can redistribute it and/or modify
18 // it under the terms of the GNU General Public License as published by
19 // the Free Software Foundation, either version 3 of the License, or
20 // (at your option) any later version.
21 //
22 /****************************************************************************/
23 
24 
25 // ===========================================================================
26 // included modules
27 // ===========================================================================
28 #ifdef _MSC_VER
29 #include <windows_config.h>
30 #else
31 #include <config.h>
32 #endif
33 #include <algorithm>
34 #include <set>
35 #include <functional>
36 #include <sstream>
37 #include <limits>
41 #include <utils/common/ToString.h>
45 #include <netbuild/NBEdge.h>
46 #include <netbuild/NBEdgeCont.h>
47 #include <netbuild/NBNode.h>
48 #include <netbuild/NBNodeCont.h>
49 #include <netbuild/NBNetBuilder.h>
50 #include <netbuild/NBOwnTLDef.h>
56 #include <utils/xml/XMLSubSys.h>
57 #include "NILoader.h"
59 
60 #ifdef CHECK_MEMORY_LEAKS
61 #include <foreign/nvwa/debug_new.h>
62 #endif // CHECK_MEMORY_LEAKS
63 
64 // ---------------------------------------------------------------------------
65 // static members
66 // ---------------------------------------------------------------------------
68 
69 
70 // ===========================================================================
71 // Private classes
72 // ===========================================================================
73 
77 public:
78  bool operator()(const Edge* e1, const Edge* e2) const {
79  if (e1->myHighWayType != e2->myHighWayType) {
80  return e1->myHighWayType > e2->myHighWayType;
81  }
82  if (e1->myNoLanes != e2->myNoLanes) {
83  return e1->myNoLanes > e2->myNoLanes;
84  }
85  if (e1->myMaxSpeed != e2->myMaxSpeed) {
86  return e1->myMaxSpeed > e2->myMaxSpeed;
87  }
88  if (e1->myIsOneWay != e2->myIsOneWay) {
89  return e1->myIsOneWay > e2->myIsOneWay;
90  }
91  return e1->myCurrentNodes > e2->myCurrentNodes;
92  }
93 };
94 
95 // ===========================================================================
96 // method definitions
97 // ===========================================================================
98 // ---------------------------------------------------------------------------
99 // static methods
100 // ---------------------------------------------------------------------------
102 
103 
104 void
106  NIImporter_OpenStreetMap importer;
107  importer.load(oc, nb);
108 }
109 
110 
112 
113 
115  // delete nodes
116  for (std::set<NIOSMNode*, CompareNodes>::iterator i = myUniqueNodes.begin(); i != myUniqueNodes.end(); i++) {
117  delete *i;
118  }
119  // delete edges
120  for (std::map<std::string, Edge*>::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
121  delete(*i).second;
122  }
123 }
124 
125 
126 void
128  // check whether the option is set (properly)
129  if (!oc.isSet("osm-files")) {
130  return;
131  }
132  // preset types
133  // for highways
134  NBTypeCont& tc = nb.getTypeCont();
135  SUMOReal const WIDTH = NBEdge::UNSPECIFIED_WIDTH;
136  tc.insert("highway.motorway", 3, (SUMOReal)(160./ 3.6), 13, WIDTH, SVC_UNKNOWN, true);
137  tc.insert("highway.motorway_link", 1, (SUMOReal)(80. / 3.6), 12, WIDTH, SVC_UNKNOWN, true);
138  tc.insert("highway.trunk", 2, (SUMOReal)(100./ 3.6), 11, WIDTH); // !!! 130km/h?
139  tc.insert("highway.trunk_link", 1, (SUMOReal)(80. / 3.6), 10, WIDTH);
140  tc.insert("highway.primary", 2, (SUMOReal)(100./ 3.6), 9, WIDTH);
141  tc.insert("highway.primary_link", 1, (SUMOReal)(80. / 3.6), 8, WIDTH);
142  tc.insert("highway.secondary", 2, (SUMOReal)(100./ 3.6), 7, WIDTH);
143  tc.insert("highway.secondary_link",1, (SUMOReal)(80. / 3.6), 6, WIDTH);
144  tc.insert("highway.tertiary", 1, (SUMOReal)(80. / 3.6), 6, WIDTH);
145  tc.insert("highway.tertiary_link", 1, (SUMOReal)(80. / 3.6), 5, WIDTH);
146  tc.insert("highway.unclassified", 1, (SUMOReal)(80. / 3.6), 5, WIDTH);
147  tc.insert("highway.residential", 1, (SUMOReal)(50. / 3.6), 4, WIDTH); // actually, maybe one lane for parking would be nice...
148  tc.insert("highway.living_street", 1, (SUMOReal)(10. / 3.6), 3, WIDTH);
149  tc.insert("highway.service", 1, (SUMOReal)(20. / 3.6), 2, WIDTH, SVC_DELIVERY);
150  tc.insert("highway.track", 1, (SUMOReal)(20. / 3.6), 1, WIDTH);
151  tc.insert("highway.services", 1, (SUMOReal)(30. / 3.6), 1, WIDTH);
152  tc.insert("highway.unsurfaced", 1, (SUMOReal)(30. / 3.6), 1, WIDTH); // unofficial value, used outside germany
153  tc.insert("highway.footway", 1, (SUMOReal)(30. / 3.6), 1, WIDTH, SVC_PEDESTRIAN);
154  tc.insert("highway.pedestrian", 1, (SUMOReal)(30. / 3.6), 1, WIDTH, SVC_PEDESTRIAN);
155 
156  tc.insert("highway.path", 1, (SUMOReal)(10. / 3.6), 1, WIDTH, SVC_PEDESTRIAN);
157  tc.insert("highway.bridleway", 1, (SUMOReal)(10. / 3.6), 1, WIDTH, SVC_BICYCLE); // no horse stuff
158  tc.insert("highway.cycleway", 1, (SUMOReal)(20. / 3.6), 1, WIDTH, SVC_BICYCLE);
159  tc.insert("highway.footway", 1, (SUMOReal)(10. / 3.6), 1, WIDTH, SVC_PEDESTRIAN);
160  tc.insert("highway.step", 1, (SUMOReal)(5. / 3.6), 1, WIDTH, SVC_PEDESTRIAN); // additional
161  tc.insert("highway.steps", 1, (SUMOReal)(5. / 3.6), 1, WIDTH, SVC_PEDESTRIAN); // :-) do not run too fast
162  tc.insert("highway.stairs", 1, (SUMOReal)(5. / 3.6), 1, WIDTH, SVC_PEDESTRIAN); // additional
163  tc.insert("highway.bus_guideway", 1, (SUMOReal)(30. / 3.6), 1, WIDTH, SVC_BUS);
164  tc.insert("highway.raceway", 2, (SUMOReal)(300./ 3.6), 14, WIDTH, SVC_VIP);
165  tc.insert("highway.ford", 1, (SUMOReal)(10. / 3.6), 1, WIDTH, SVC_PUBLIC_ARMY);
166 
167  // for railways
168  tc.insert("railway.rail", 1, (SUMOReal)(30. / 3.6), 1, WIDTH, SVC_RAIL_FAST);
169  tc.insert("railway.tram", 1, (SUMOReal)(30. / 3.6), 1, WIDTH, SVC_CITYRAIL);
170  tc.insert("railway.light_rail", 1, (SUMOReal)(30. / 3.6), 1, WIDTH, SVC_LIGHTRAIL);
171  tc.insert("railway.subway", 1, (SUMOReal)(30. / 3.6), 1, WIDTH, SVC_CITYRAIL);
172  tc.insert("railway.preserved", 1, (SUMOReal)(30. / 3.6), 1, WIDTH, SVC_LIGHTRAIL);
173  tc.insert("railway.monorail", 1, (SUMOReal)(30. / 3.6), 1, WIDTH, SVC_LIGHTRAIL); // rail stuff has to be discussed
174 
175 
176  /* Parse file(s)
177  * Each file is parsed twice: first for nodes, second for edges. */
178  std::vector<std::string> files = oc.getStringVector("osm-files");
179  // load nodes, first
180  NodesHandler nodesHandler(myOSMNodes, myUniqueNodes);
181  for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
182  // nodes
183  if (!FileHelpers::exists(*file)) {
184  WRITE_ERROR("Could not open osm-file '" + *file + "'.");
185  return;
186  }
187  nodesHandler.setFileName(*file);
188  PROGRESS_BEGIN_MESSAGE("Parsing nodes from osm-file '" + *file + "'");
189  if (!XMLSubSys::runParser(nodesHandler, *file)) {
190  return;
191  }
193  }
194  // load edges, then
195  EdgesHandler edgesHandler(myOSMNodes, myEdges);
196  for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
197  // edges
198  edgesHandler.setFileName(*file);
199  PROGRESS_BEGIN_MESSAGE("Parsing edges from osm-file '" + *file + "'");
200  XMLSubSys::runParser(edgesHandler, *file);
202  }
203 
204  /* Remove duplicate edges with the same shape and attributes */
205  if (!OptionsCont::getOptions().getBool("osm.skip-duplicates-check")) {
206  PROGRESS_BEGIN_MESSAGE("Removing duplicate edges");
207  if (myEdges.size() > 1) {
208  std::set<const Edge*, CompareEdges> dupsFinder;
209  for (std::map<std::string, Edge*>::iterator it = myEdges.begin(); it != myEdges.end();) {
210  if (dupsFinder.count(it->second) > 0) {
211  WRITE_MESSAGE("Found duplicate edges. Removing " + it->first);
212  delete it->second;
213  myEdges.erase(it++);
214  } else {
215  dupsFinder.insert(it->second);
216  it++;
217  }
218  }
219  }
221  }
222 
223  /* Mark which nodes are used (by edges or traffic lights).
224  * This is necessary to detect which OpenStreetMap nodes are for
225  * geometry only */
226  std::map<long, int> nodeUsage;
227  // Mark which nodes are used by edges (begin and end)
228  for (std::map<std::string, Edge*>::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
229  Edge* e = (*i).second;
230  assert(e->myCurrentIsRoad);
231  for (std::vector<long>::const_iterator j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
232  if (nodeUsage.find(*j) == nodeUsage.end()) {
233  nodeUsage[*j] = 0;
234  }
235  nodeUsage[*j] = nodeUsage[*j] + 1;
236  }
237  }
238  // Mark which nodes are used by traffic lights
239  for (std::map<long, NIOSMNode*>::const_iterator nodesIt = myOSMNodes.begin(); nodesIt != myOSMNodes.end(); ++nodesIt) {
240  if (nodesIt->second->tlsControlled) {
241  // If the key is not found in the map, the value is automatically
242  // initialized with 0.
243  nodeUsage[nodesIt->first] += 1;
244  }
245  }
246  /* Instantiate edges
247  * Only those nodes in the middle of an edge which are used by more than
248  * one edge are instantiated. Other nodes are considered as geometry nodes. */
249  NBNodeCont& nc = nb.getNodeCont();
250  NBEdgeCont& ec = nb.getEdgeCont();
252  for (std::map<std::string, Edge*>::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
253  Edge* e = (*i).second;
254  assert(e->myCurrentIsRoad);
255  if (e->myCurrentNodes.size() < 2) {
256  WRITE_WARNING("Discarding way '" + e->id + "' because it has only " + toString(e->myCurrentNodes.size()) + " node(s)");
257  continue;
258  }
259  // build nodes;
260  // - the from- and to-nodes must be built in any case
261  // - the in-between nodes are only built if more than one edge references them
262  NBNode* currentFrom = insertNodeChecking(*e->myCurrentNodes.begin(), nc, tlsc);
263  NBNode* last = insertNodeChecking(*(e->myCurrentNodes.end() - 1), nc, tlsc);
264  int running = 0;
265  std::vector<long> passed;
266  for (std::vector<long>::iterator j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
267  passed.push_back(*j);
268  if (nodeUsage[*j] > 1 && j != e->myCurrentNodes.end() - 1 && j != e->myCurrentNodes.begin()) {
269  NBNode* currentTo = insertNodeChecking(*j, nc, tlsc);
270  running = insertEdge(e, running, currentFrom, currentTo, passed, nb);
271  currentFrom = currentTo;
272  passed.clear();
273  }
274  }
275  if (running == 0) {
276  running = -1;
277  }
278  insertEdge(e, running, currentFrom, last, passed, nb);
279  }
280 }
281 
282 
283 NBNode*
285  NBNode* from = nc.retrieve(toString(id));
286  if (from == 0) {
287  NIOSMNode* n = myOSMNodes.find(id)->second;
288  Position pos(n->lon, n->lat);
289  if (!NILoader::transformCoordinates(pos, true)) {
290  WRITE_ERROR("Unable to project coordinates for node " + toString(id) + ".");
291  delete from;
292  return 0;
293  }
294  from = new NBNode(toString(id), pos);
295  if (!nc.insert(from)) {
296  WRITE_ERROR("Could not insert node '" + toString(id) + "').");
297  delete from;
298  return 0;
299  }
300  if (n->tlsControlled) {
301  // ok, this node is a traffic light node where no other nodes
302  // participate
303  NBOwnTLDef* tlDef = new NBOwnTLDef(toString(id), from);
304  if (!tlsc.insert(tlDef)) {
305  // actually, nothing should fail here
306  delete tlDef;
307  throw ProcessError("Could not allocate tls '" + toString(id) + "'.");
308  }
309  }
310  }
311  return from;
312 }
313 
314 
315 int
317  const std::vector<long> &passed, NBNetBuilder& nb) {
318  NBNodeCont& nc = nb.getNodeCont();
319  NBEdgeCont& ec = nb.getEdgeCont();
320  NBTypeCont& tc = nb.getTypeCont();
322 
323  // patch the id
324  std::string id = e->id;
325  if (index >= 0) {
326  id = id + "#" + toString(index);
327  } else {
328  index = 0;
329  }
330  if (from == to) {
331  // in the special case of a looped way split again using passed
332  assert(passed.size() >= 2);
333  std::vector<long> geom(passed);
334  geom.pop_back(); // remove to-node
335  NBNode* intermediate = insertNodeChecking(geom.back(), nc, tlsc);
336  index = insertEdge(e, index, from, intermediate, geom, nb);
337  geom.clear();
338  return insertEdge(e, index, intermediate, to, geom, nb);
339  }
340  const int newIndex = index + 1;
341 
342  // convert the shape
343  PositionVector shape;
344  for (std::vector<long>::const_iterator i = passed.begin(); i != passed.end(); ++i) {
345  NIOSMNode* n = myOSMNodes.find(*i)->second;
346  Position pos(n->lon, n->lat);
347  if (!NILoader::transformCoordinates(pos, true)) {
348  throw ProcessError("Unable to project coordinates for edge " + id + ".");
349  }
350  shape.push_back_noDoublePos(pos);
351  }
352 
353  std::string type = e->myHighWayType;
354  if (!tc.knows(type)) {
355  if (type.find(compoundTypeSeparator) != std::string::npos) {
356  // this edge has a combination type which does not yet exist in the TypeContainer
358  std::set<std::string> types;
359  while (tok.hasNext()) {
360  std::string t = tok.next();
361  if (tc.knows(t)) {
362  types.insert(t);
363  } else {
364  WRITE_WARNING("Discarding unknown compound \"" + t + "\" for edge " + id + " with type \"" + type + "\".");
365  }
366  }
367  switch (types.size()) {
368  case 0:
369  WRITE_WARNING("Discarding edge " + id + " with type unknown compound type \"" + type + "\".");
370  return newIndex;
371  break;
372  case 1: {
373  type = *(types.begin());
374  break;
375  }
376  default:
377  // build a new type by merging all values
378  int noLanes = 0;
379  SUMOReal maxSpeed = 0;
380  int prio = 0;
382  bool defaultIsOneWay = false;
383  for (std::set<std::string>::iterator it = types.begin(); it != types.end(); it++) {
384  noLanes = MAX2(noLanes, tc.getNumLanes(*it));
385  maxSpeed = MAX2(maxSpeed, tc.getSpeed(*it));
386  prio = MAX2(prio, tc.getPriority(*it));
387  defaultIsOneWay |= tc.getIsOneWay(*it);
388  }
389  WRITE_MESSAGE("Adding new compound type \"" + type + "\" for edge " + id + ".");
390  // @todo use the propper bitsets instead of SVC_UNKNOWN (see #675)
391  tc.insert(type, noLanes, maxSpeed, prio, width, SVC_UNKNOWN, defaultIsOneWay);
392  }
393  } else {
394  // we do not know the type -> something else, ignore
395  //WRITE_WARNING("Discarding edge " + id + " with unknown type \"" + type + "\".");
396  return newIndex;
397  }
398  }
399 
400  // otherwise it is not an edge and will be ignored
401  int noLanes = tc.getNumLanes(type);
402  SUMOReal speed = tc.getSpeed(type);
403  bool defaultsToOneWay = tc.getIsOneWay(type);
404  SVCPermissions permissions = tc.getPermissions(type);
405  // check directions
406  bool addSecond = true;
407  if (e->myIsOneWay == "true" || e->myIsOneWay == "yes" || e->myIsOneWay == "1" || (defaultsToOneWay && e->myIsOneWay != "no" && e->myIsOneWay != "false" && e->myIsOneWay != "0")) {
408  addSecond = false;
409  }
410  // if we had been able to extract the number of lanes, override the highway type default
411  if (e->myNoLanes >= 0) {
412  if (!addSecond) {
413  noLanes = e->myNoLanes;
414  } else {
415  noLanes = e->myNoLanes / 2;
416  }
417  }
418  // if we had been able to extract the maximum speed, override the type's default
419  if (e->myMaxSpeed != MAXSPEED_UNGIVEN) {
420  speed = (SUMOReal)(e->myMaxSpeed / 3.6);
421  }
422 
423  if (noLanes != 0 && speed != 0) {
424  if (e->myIsOneWay != "" && e->myIsOneWay != "false" && e->myIsOneWay != "no" && e->myIsOneWay != "true" && e->myIsOneWay != "yes" && e->myIsOneWay != "-1" && e->myIsOneWay != "1") {
425  WRITE_WARNING("New value for oneway found: " + e->myIsOneWay);
426  }
428  if (e->myIsOneWay != "-1") {
429  NBEdge* nbe = new NBEdge(StringUtils::escapeXML(id), from, to, type, speed, noLanes, tc.getPriority(type),
431  nbe->setPermissions(permissions);
432  if (!ec.insert(nbe)) {
433  delete nbe;
434  throw ProcessError("Could not add edge '" + id + "'.");
435  }
436  }
437  if (addSecond) {
438  if (e->myIsOneWay != "-1") {
439  id = "-" + id;
440  }
441  NBEdge* nbe = new NBEdge(StringUtils::escapeXML(id), to, from, type, speed, noLanes, tc.getPriority(type),
443  nbe->setPermissions(permissions);
444  if (!ec.insert(nbe)) {
445  delete nbe;
446  throw ProcessError("Could not add edge '-" + id + "'.");
447  }
448  }
449  }
450  return newIndex;
451 }
452 
453 
454 // ---------------------------------------------------------------------------
455 // definitions of NIImporter_OpenStreetMap::NodesHandler-methods
456 // ---------------------------------------------------------------------------
458  std::map<long, NIOSMNode*> &toFill,
459  std::set<NIOSMNode*, CompareNodes> &uniqueNodes) :
460  SUMOSAXHandler("osm - file"),
461  myToFill(toFill),
462  myUniqueNodes(uniqueNodes),
463  myLastNodeID(-1),
464  myIsInValidNodeTag(false),
465  myHierarchyLevel(0) {
466 }
467 
468 
470 
471 
472 void
474  ++myHierarchyLevel;
475  if (element == SUMO_TAG_NODE) {
476  bool ok = true;
477  if (myHierarchyLevel != 2) {
478  WRITE_ERROR("Node element on wrong XML hierarchy level (id='" + toString(attrs.getLongReporting(SUMO_ATTR_ID, 0, ok)) + "', level='" + toString(myHierarchyLevel) + "').");
479  return;
480  }
481  long id = attrs.getLongReporting(SUMO_ATTR_ID, 0, ok);
482  std::string action = attrs.hasAttribute("action") ? attrs.getStringSecure("action", "") : "";
483  if (action == "delete") {
484  return;
485  }
486  if (!ok) {
487  return;
488  }
489  myLastNodeID = -1;
490  if (myToFill.find(id) == myToFill.end()) {
491  myLastNodeID = id;
492  // assume we are loading multiple files...
493  // ... so we won't report duplicate nodes
494  bool ok = true;
495  double tlat, tlon;
496  std::istringstream lon(attrs.getStringReporting(SUMO_ATTR_LON, toString(id).c_str(), ok));
497  if (!ok) {
498  return;
499  }
500  lon >> tlon;
501  if (lon.fail()) {
502  WRITE_ERROR("Node's '" + toString(id) + "' lon information is not numeric.");
503  return;
504  }
505  std::istringstream lat(attrs.getStringReporting(SUMO_ATTR_LAT, toString(id).c_str(), ok));
506  if (!ok) {
507  return;
508  }
509  lat >> tlat;
510  if (lat.fail()) {
511  WRITE_ERROR("Node's '" + toString(id) + "' lat information is not numeric.");
512  return;
513  }
514  NIOSMNode* toAdd = new NIOSMNode();
515  toAdd->id = id;
516  toAdd->tlsControlled = false;
517  toAdd->lat = tlat;
518  toAdd->lon = tlon;
519  myIsInValidNodeTag = true;
520 
521  std::set<NIOSMNode*, CompareNodes>::iterator similarNode = myUniqueNodes.find(toAdd);
522  if (similarNode == myUniqueNodes.end()) {
523  myUniqueNodes.insert(toAdd);
524  } else {
525  delete toAdd;
526  toAdd = *similarNode;
527  WRITE_MESSAGE("Found duplicate nodes. Substituting " + toString(id) + " with " + toString(toAdd->id));
528  }
529  myToFill[id] = toAdd;
530  }
531  }
532  if (element == SUMO_TAG_TAG && myIsInValidNodeTag) {
533  if (myHierarchyLevel != 3) {
534  WRITE_ERROR("Tag element on wrong XML hierarchy level.");
535  return;
536  }
537  bool ok = true;
538  std::string key = attrs.getStringReporting(SUMO_ATTR_K, toString(myLastNodeID).c_str(), ok);
539  std::string value = attrs.getOptStringReporting(SUMO_ATTR_V, toString(myLastNodeID).c_str(), ok, "");
540  if (!ok) {
541  return;
542  }
543  if (key == "highway" && value.find("traffic_signal") != std::string::npos &&
544  !OptionsCont::getOptions().getBool("osm.discard-tls")) {
545  myToFill[myLastNodeID]->tlsControlled = true;
546  }
547  }
548 }
549 
550 
551 void
553  if (element == SUMO_TAG_NODE && myHierarchyLevel == 2) {
554  myLastNodeID = -1;
555  myIsInValidNodeTag = false;
556  }
557  --myHierarchyLevel;
558 }
559 
560 
561 // ---------------------------------------------------------------------------
562 // definitions of NIImporter_OpenStreetMap::EdgesHandler-methods
563 // ---------------------------------------------------------------------------
565  const std::map<long, NIOSMNode*> &osmNodes,
566  std::map<std::string, Edge*> &toFill)
567  : SUMOSAXHandler("osm - file"),
568  myOSMNodes(osmNodes), myEdgeMap(toFill) {
569  mySpeedMap["signals"] = MAXSPEED_UNGIVEN;
570  mySpeedMap["none"] = 300.;
571  mySpeedMap["no"] = 300.;
572  mySpeedMap["walk"] = 5.;
573  mySpeedMap["DE:rural"] = 100.;
574  mySpeedMap["DE:urban"] = 50.;
575  mySpeedMap["DE:living_street"] = 10.;
576 
577 }
578 
579 
581 }
582 
583 
584 void
586  const SUMOSAXAttributes& attrs) {
587  myParentElements.push_back(element);
588  // parse "way" elements
589  if (element == SUMO_TAG_WAY) {
590  bool ok = true;
591  std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok);
592  std::string action = attrs.hasAttribute("action") ? attrs.getStringSecure("action", "") : "";
593  if (action == "delete") {
594  myCurrentEdge = 0;
595  return;
596  }
597  if (!ok) {
598  myCurrentEdge = 0;
599  return;
600  }
601  myCurrentEdge = new Edge();
602  myCurrentEdge->id = id;
603  myCurrentEdge->myNoLanes = -1;
604  myCurrentEdge->myMaxSpeed = MAXSPEED_UNGIVEN;
605  myCurrentEdge->myCurrentIsRoad = false;
606  }
607  // parse "nd" (node) elements
608  if (element == SUMO_TAG_ND) {
609  bool ok = true;
610  long ref = attrs.getLongReporting(SUMO_ATTR_REF, 0, ok);
611  if (ok) {
612  std::map<long, NIOSMNode*>::const_iterator node = myOSMNodes.find(ref);
613  if (node == myOSMNodes.end()) {
614  WRITE_WARNING("The referenced geometry information (ref='" + toString(ref) + "') is not known");
615  return;
616  } else {
617  ref = node->second->id; // node may have been substituted
618  if (myCurrentEdge->myCurrentNodes.size() == 0 ||
619  myCurrentEdge->myCurrentNodes.back() != ref) { // avoid consecutive duplicates
620  myCurrentEdge->myCurrentNodes.push_back(ref);
621  }
622  }
623  }
624  }
625  // parse values
626  if (element == SUMO_TAG_TAG && myParentElements.size() > 2 && myParentElements[myParentElements.size() - 2] == SUMO_TAG_WAY) {
627  if (myCurrentEdge == 0) {
628  return;
629  }
630  bool ok = true;
631  std::string key = attrs.getStringReporting(SUMO_ATTR_K, toString(myCurrentEdge->id).c_str(), ok);
632  std::string value = attrs.getStringReporting(SUMO_ATTR_V, toString(myCurrentEdge->id).c_str(), ok);
633  if (!ok) {
634  return;
635  }
636  if (key == "highway" || key == "railway") {
637  if (myCurrentEdge->myHighWayType != "") {
638  // osm-ways may be used by more than one mode (eg railway.tram + highway.residential. this is relevant for multimodal traffic)
639  // we create a new type for this kind of situation which must then be resolved in insertEdge()
640  myCurrentEdge->myHighWayType = myCurrentEdge->myHighWayType + compoundTypeSeparator + key + "." + value;
641  } else {
642  myCurrentEdge->myHighWayType = key + "." + value;
643  }
644  myCurrentEdge->myCurrentIsRoad = true;
645  } else if (key == "lanes") {
646  try {
647  myCurrentEdge->myNoLanes = TplConvert<char>::_2int(value.c_str());
648  } catch (NumberFormatException&) {
649  // might be a list of values
650  StringTokenizer st(value, ";", true);
651  std::vector<std::string> list = st.getVector();
652  if (list.size() >= 2) {
653  int minLanes = std::numeric_limits<int>::max();
654  try {
655  for (std::vector<std::string>::iterator i = list.begin(); i != list.end(); ++i) {
656  int numLanes = TplConvert<char>::_2int(StringUtils::prune(*i).c_str());
657  minLanes = MIN2(minLanes, numLanes);
658  }
659  myCurrentEdge->myNoLanes = minLanes;
660  WRITE_WARNING("Using minimum lane number from list (" + value + ") for edge '" + myCurrentEdge->id + "'.");
661  } catch (NumberFormatException&) {
662  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" + myCurrentEdge->id + "'.");
663  }
664  }
665  }
666  } else if (key == "maxspeed") {
667  if (mySpeedMap.find(value) != mySpeedMap.end()) {
668  myCurrentEdge->myMaxSpeed = mySpeedMap[value];
669  } else {
670  SUMOReal conversion = 1; // OSM default is km/h
671  if (StringUtils::to_lower_case(value).find("km/h") != std::string::npos) {
672  value = StringUtils::prune(value.substr(0, value.find_first_not_of("0123456789")));
673  } else if (StringUtils::to_lower_case(value).find("mph") != std::string::npos) {
674  value = StringUtils::prune(value.substr(0, value.find_first_not_of("0123456789")));
675  conversion = 1.609344; // kilometers per mile
676  }
677  try {
678  myCurrentEdge->myMaxSpeed = TplConvert<char>::_2SUMOReal(value.c_str()) * conversion;
679  } catch (NumberFormatException&) {
680  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" + myCurrentEdge->id + "'.");
681  }
682  }
683  } else if (key == "junction") {
684  if ((value == "roundabout") && (myCurrentEdge->myIsOneWay == "")) {
685  myCurrentEdge->myIsOneWay = "yes";
686  }
687  } else if (key == "oneway") {
688  myCurrentEdge->myIsOneWay = value;
689  } else if (key == "name") {
690  myCurrentEdge->streetName = value;
691  }
692  }
693 }
694 
695 
696 void
698  myParentElements.pop_back();
699  if (element == SUMO_TAG_WAY) {
700  if (myCurrentEdge != 0 && myCurrentEdge->myCurrentIsRoad) {
701  myEdgeMap[myCurrentEdge->id] = myCurrentEdge;
702  } else {
703  delete myCurrentEdge;
704  }
705  myCurrentEdge = 0;
706  }
707 }
708 
709 
710 
711 
712 /****************************************************************************/
713