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)(300. / 3.6), 15, WIDTH, SVC_RAIL_FAST, true);
169  tc.insert("railway.tram", 1, (SUMOReal)(100. / 3.6), 15, WIDTH, SVC_CITYRAIL, true);
170  tc.insert("railway.light_rail", 1, (SUMOReal)(100. / 3.6), 15, WIDTH, SVC_LIGHTRAIL, true);
171  tc.insert("railway.subway", 1, (SUMOReal)(100. / 3.6), 15, WIDTH, SVC_CITYRAIL, true);
172  tc.insert("railway.preserved", 1, (SUMOReal)(100. / 3.6), 15, WIDTH, SVC_LIGHTRAIL, true);
173  tc.insert("railway.monorail", 1, (SUMOReal)(300. / 3.6), 15, WIDTH, SVC_LIGHTRAIL, true); // 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<SUMOLong, 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<SUMOLong>::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<SUMOLong, 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();
251  for (std::map<std::string, Edge*>::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
252  Edge* e = (*i).second;
253  assert(e->myCurrentIsRoad);
254  if (e->myCurrentNodes.size() < 2) {
255  WRITE_WARNING("Discarding way '" + e->id + "' because it has only " + toString(e->myCurrentNodes.size()) + " node(s)");
256  continue;
257  }
258  // build nodes;
259  // - the from- and to-nodes must be built in any case
260  // - the in-between nodes are only built if more than one edge references them
261  NBNode* currentFrom = insertNodeChecking(*e->myCurrentNodes.begin(), nc, tlsc);
262  NBNode* last = insertNodeChecking(*(e->myCurrentNodes.end() - 1), nc, tlsc);
263  int running = 0;
264  std::vector<SUMOLong> passed;
265  for (std::vector<SUMOLong>::iterator j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
266  passed.push_back(*j);
267  if (nodeUsage[*j] > 1 && j != e->myCurrentNodes.end() - 1 && j != e->myCurrentNodes.begin()) {
268  NBNode* currentTo = insertNodeChecking(*j, nc, tlsc);
269  running = insertEdge(e, running, currentFrom, currentTo, passed, nb);
270  currentFrom = currentTo;
271  passed.clear();
272  }
273  }
274  if (running == 0) {
275  running = -1;
276  }
277  insertEdge(e, running, currentFrom, last, passed, nb);
278  }
279 }
280 
281 
282 NBNode*
284  NBNode* from = nc.retrieve(toString(id));
285  if (from == 0) {
286  NIOSMNode* n = myOSMNodes.find(id)->second;
287  Position pos(n->lon, n->lat);
288  if (!NILoader::transformCoordinates(pos, true)) {
289  WRITE_ERROR("Unable to project coordinates for node " + toString(id) + ".");
290  delete from;
291  return 0;
292  }
293  from = new NBNode(toString(id), pos);
294  if (!nc.insert(from)) {
295  WRITE_ERROR("Could not insert node '" + toString(id) + "').");
296  delete from;
297  return 0;
298  }
299  if (n->tlsControlled) {
300  // ok, this node is a traffic light node where no other nodes
301  // participate
302  NBOwnTLDef* tlDef = new NBOwnTLDef(toString(id), from, 0);
303  if (!tlsc.insert(tlDef)) {
304  // actually, nothing should fail here
305  delete tlDef;
306  throw ProcessError("Could not allocate tls '" + toString(id) + "'.");
307  }
308  }
309  }
310  return from;
311 }
312 
313 
314 int
316  const std::vector<SUMOLong>& passed, NBNetBuilder& nb) {
317  NBNodeCont& nc = nb.getNodeCont();
318  NBEdgeCont& ec = nb.getEdgeCont();
319  NBTypeCont& tc = nb.getTypeCont();
321 
322  // patch the id
323  std::string id = e->id;
324  if (index >= 0) {
325  id = id + "#" + toString(index);
326  } else {
327  index = 0;
328  }
329  if (from == to) {
330  // in the special case of a looped way split again using passed
331  assert(passed.size() >= 2);
332  std::vector<SUMOLong> geom(passed);
333  geom.pop_back(); // remove to-node
334  NBNode* intermediate = insertNodeChecking(geom.back(), nc, tlsc);
335  index = insertEdge(e, index, from, intermediate, geom, nb);
336  geom.clear();
337  return insertEdge(e, index, intermediate, to, geom, nb);
338  }
339  const int newIndex = index + 1;
340 
341  // convert the shape
342  PositionVector shape;
343  for (std::vector<SUMOLong>::const_iterator i = passed.begin(); i != passed.end(); ++i) {
344  NIOSMNode* n = myOSMNodes.find(*i)->second;
345  Position pos(n->lon, n->lat);
346  if (!NILoader::transformCoordinates(pos, true)) {
347  throw ProcessError("Unable to project coordinates for edge " + id + ".");
348  }
349  shape.push_back_noDoublePos(pos);
350  }
351 
352  std::string type = e->myHighWayType;
353  if (!tc.knows(type)) {
354  if (type.find(compoundTypeSeparator) != std::string::npos) {
355  // this edge has a combination type which does not yet exist in the TypeContainer
357  std::set<std::string> types;
358  while (tok.hasNext()) {
359  std::string t = tok.next();
360  if (tc.knows(t)) {
361  types.insert(t);
362  } else {
363  WRITE_WARNING("Discarding unknown compound \"" + t + "\" for edge " + id + " with type \"" + type + "\".");
364  }
365  }
366  switch (types.size()) {
367  case 0:
368  WRITE_WARNING("Discarding edge " + id + " with type unknown compound type \"" + type + "\".");
369  return newIndex;
370  break;
371  case 1: {
372  type = *(types.begin());
373  break;
374  }
375  default:
376  // build a new type by merging all values
377  int noLanes = 0;
378  SUMOReal maxSpeed = 0;
379  int prio = 0;
381  bool defaultIsOneWay = false;
382  for (std::set<std::string>::iterator it = types.begin(); it != types.end(); it++) {
383  noLanes = MAX2(noLanes, tc.getNumLanes(*it));
384  maxSpeed = MAX2(maxSpeed, tc.getSpeed(*it));
385  prio = MAX2(prio, tc.getPriority(*it));
386  defaultIsOneWay &= tc.getIsOneWay(*it);
387  }
388  WRITE_MESSAGE("Adding new compound type \"" + type + "\" for edge " + id + ".");
389  // @todo use the propper bitsets instead of SVC_UNKNOWN (see #675)
390  tc.insert(type, noLanes, maxSpeed, prio, width, SVC_UNKNOWN, defaultIsOneWay);
391  }
392  } else {
393  // we do not know the type -> something else, ignore
394  //WRITE_WARNING("Discarding edge " + id + " with unknown type \"" + type + "\".");
395  return newIndex;
396  }
397  }
398 
399  // otherwise it is not an edge and will be ignored
400  int noLanes = tc.getNumLanes(type);
401  SUMOReal speed = tc.getSpeed(type);
402  bool defaultsToOneWay = tc.getIsOneWay(type);
403  SVCPermissions permissions = tc.getPermissions(type);
404  // check directions
405  bool addSecond = true;
406  if (e->myIsOneWay == "true" || e->myIsOneWay == "yes" || e->myIsOneWay == "1" || (defaultsToOneWay && e->myIsOneWay != "no" && e->myIsOneWay != "false" && e->myIsOneWay != "0")) {
407  addSecond = false;
408  }
409  // if we had been able to extract the number of lanes, override the highway type default
410  if (e->myNoLanes >= 0) {
411  if (!addSecond) {
412  noLanes = e->myNoLanes;
413  } else {
414  noLanes = e->myNoLanes / 2;
415  }
416  }
417  // if we had been able to extract the maximum speed, override the type's default
418  if (e->myMaxSpeed != MAXSPEED_UNGIVEN) {
419  speed = (SUMOReal)(e->myMaxSpeed / 3.6);
420  }
421 
422  if (noLanes != 0 && speed != 0) {
423  if (e->myIsOneWay != "" && e->myIsOneWay != "false" && e->myIsOneWay != "no" && e->myIsOneWay != "true" && e->myIsOneWay != "yes" && e->myIsOneWay != "-1" && e->myIsOneWay != "1") {
424  WRITE_WARNING("New value for oneway found: " + e->myIsOneWay);
425  }
427  if (e->myIsOneWay != "-1") {
428  NBEdge* nbe = new NBEdge(StringUtils::escapeXML(id), from, to, type, speed, noLanes, tc.getPriority(type),
430  nbe->setPermissions(permissions);
431  if (!ec.insert(nbe)) {
432  delete nbe;
433  throw ProcessError("Could not add edge '" + id + "'.");
434  }
435  }
436  if (addSecond) {
437  if (e->myIsOneWay != "-1") {
438  id = "-" + id;
439  }
440  NBEdge* nbe = new NBEdge(StringUtils::escapeXML(id), to, from, type, speed, noLanes, tc.getPriority(type),
442  nbe->setPermissions(permissions);
443  if (!ec.insert(nbe)) {
444  delete nbe;
445  throw ProcessError("Could not add edge '-" + id + "'.");
446  }
447  }
448  }
449  return newIndex;
450 }
451 
452 
453 // ---------------------------------------------------------------------------
454 // definitions of NIImporter_OpenStreetMap::NodesHandler-methods
455 // ---------------------------------------------------------------------------
457  std::map<SUMOLong, NIOSMNode*>& toFill,
458  std::set<NIOSMNode*, CompareNodes>& uniqueNodes) :
459  SUMOSAXHandler("osm - file"),
460  myToFill(toFill),
461  myLastNodeID(-1),
462  myIsInValidNodeTag(false),
463  myHierarchyLevel(0),
464  myUniqueNodes(uniqueNodes) {
465 }
466 
467 
469 
470 
471 void
473  ++myHierarchyLevel;
474  if (element == SUMO_TAG_NODE) {
475  bool ok = true;
476  if (myHierarchyLevel != 2) {
477  WRITE_ERROR("Node element on wrong XML hierarchy level (id='" + toString(attrs.getLongReporting(SUMO_ATTR_ID, 0, ok)) + "', level='" + toString(myHierarchyLevel) + "').");
478  return;
479  }
480  SUMOLong id = attrs.getLongReporting(SUMO_ATTR_ID, 0, ok);
481  std::string action = attrs.hasAttribute("action") ? attrs.getStringSecure("action", "") : "";
482  if (action == "delete") {
483  return;
484  }
485  if (!ok) {
486  return;
487  }
488  myLastNodeID = -1;
489  if (myToFill.find(id) == myToFill.end()) {
490  myLastNodeID = id;
491  // assume we are loading multiple files...
492  // ... so we won't report duplicate nodes
493  bool ok = true;
494  double tlat, tlon;
495  std::istringstream lon(attrs.getStringReporting(SUMO_ATTR_LON, toString(id).c_str(), ok));
496  if (!ok) {
497  return;
498  }
499  lon >> tlon;
500  if (lon.fail()) {
501  WRITE_ERROR("Node's '" + toString(id) + "' lon information is not numeric.");
502  return;
503  }
504  std::istringstream lat(attrs.getStringReporting(SUMO_ATTR_LAT, toString(id).c_str(), ok));
505  if (!ok) {
506  return;
507  }
508  lat >> tlat;
509  if (lat.fail()) {
510  WRITE_ERROR("Node's '" + toString(id) + "' lat information is not numeric.");
511  return;
512  }
513  NIOSMNode* toAdd = new NIOSMNode();
514  toAdd->id = id;
515  toAdd->tlsControlled = false;
516  toAdd->lat = tlat;
517  toAdd->lon = tlon;
518  myIsInValidNodeTag = true;
519 
520  std::set<NIOSMNode*, CompareNodes>::iterator similarNode = myUniqueNodes.find(toAdd);
521  if (similarNode == myUniqueNodes.end()) {
522  myUniqueNodes.insert(toAdd);
523  } else {
524  delete toAdd;
525  toAdd = *similarNode;
526  WRITE_MESSAGE("Found duplicate nodes. Substituting " + toString(id) + " with " + toString(toAdd->id));
527  }
528  myToFill[id] = toAdd;
529  }
530  }
531  if (element == SUMO_TAG_TAG && myIsInValidNodeTag) {
532  if (myHierarchyLevel != 3) {
533  WRITE_ERROR("Tag element on wrong XML hierarchy level.");
534  return;
535  }
536  bool ok = true;
537  std::string key = attrs.getStringReporting(SUMO_ATTR_K, toString(myLastNodeID).c_str(), ok);
538  std::string value = attrs.getStringReporting(SUMO_ATTR_V, toString(myLastNodeID).c_str(), ok, false);
539  if (!ok) {
540  return;
541  }
542  if (key == "highway" && value.find("traffic_signal") != std::string::npos && !OptionsCont::getOptions().getBool("tls.discard-loaded")) {
543  myToFill[myLastNodeID]->tlsControlled = true;
544  }
545  }
546 }
547 
548 
549 void
551  if (element == SUMO_TAG_NODE && myHierarchyLevel == 2) {
552  myLastNodeID = -1;
553  myIsInValidNodeTag = false;
554  }
555  --myHierarchyLevel;
556 }
557 
558 
559 // ---------------------------------------------------------------------------
560 // definitions of NIImporter_OpenStreetMap::EdgesHandler-methods
561 // ---------------------------------------------------------------------------
563  const std::map<SUMOLong, NIOSMNode*>& osmNodes,
564  std::map<std::string, Edge*>& toFill)
565  : SUMOSAXHandler("osm - file"),
566  myOSMNodes(osmNodes), myEdgeMap(toFill) {
567  mySpeedMap["signals"] = MAXSPEED_UNGIVEN;
568  mySpeedMap["none"] = 300.;
569  mySpeedMap["no"] = 300.;
570  mySpeedMap["walk"] = 5.;
571  mySpeedMap["DE:rural"] = 100.;
572  mySpeedMap["DE:urban"] = 50.;
573  mySpeedMap["DE:living_street"] = 10.;
574 
575 }
576 
577 
579 }
580 
581 
582 void
584  const SUMOSAXAttributes& attrs) {
585  myParentElements.push_back(element);
586  // parse "way" elements
587  if (element == SUMO_TAG_WAY) {
588  bool ok = true;
589  std::string id = attrs.getStringReporting(SUMO_ATTR_ID, 0, ok);
590  std::string action = attrs.hasAttribute("action") ? attrs.getStringSecure("action", "") : "";
591  if (action == "delete") {
592  myCurrentEdge = 0;
593  return;
594  }
595  if (!ok) {
596  myCurrentEdge = 0;
597  return;
598  }
599  myCurrentEdge = new Edge();
600  myCurrentEdge->id = id;
601  myCurrentEdge->myNoLanes = -1;
602  myCurrentEdge->myMaxSpeed = MAXSPEED_UNGIVEN;
603  myCurrentEdge->myCurrentIsRoad = false;
604  }
605  // parse "nd" (node) elements
606  if (element == SUMO_TAG_ND) {
607  bool ok = true;
608  SUMOLong ref = attrs.getLongReporting(SUMO_ATTR_REF, 0, ok);
609  if (ok) {
610  std::map<SUMOLong, NIOSMNode*>::const_iterator node = myOSMNodes.find(ref);
611  if (node == myOSMNodes.end()) {
612  WRITE_WARNING("The referenced geometry information (ref='" + toString(ref) + "') is not known");
613  return;
614  } else {
615  ref = node->second->id; // node may have been substituted
616  if (myCurrentEdge->myCurrentNodes.size() == 0 ||
617  myCurrentEdge->myCurrentNodes.back() != ref) { // avoid consecutive duplicates
618  myCurrentEdge->myCurrentNodes.push_back(ref);
619  }
620  }
621  }
622  }
623  // parse values
624  if (element == SUMO_TAG_TAG && myParentElements.size() > 2 && myParentElements[myParentElements.size() - 2] == SUMO_TAG_WAY) {
625  if (myCurrentEdge == 0) {
626  return;
627  }
628  bool ok = true;
629  std::string key = attrs.getStringReporting(SUMO_ATTR_K, toString(myCurrentEdge->id).c_str(), ok);
630  std::string value = attrs.getStringReporting(SUMO_ATTR_V, toString(myCurrentEdge->id).c_str(), ok, false);
631  if (!ok) {
632  return;
633  }
634  if (key == "highway" || key == "railway") {
635  if (myCurrentEdge->myHighWayType != "") {
636  // osm-ways may be used by more than one mode (eg railway.tram + highway.residential. this is relevant for multimodal traffic)
637  // we create a new type for this kind of situation which must then be resolved in insertEdge()
638  myCurrentEdge->myHighWayType = myCurrentEdge->myHighWayType + compoundTypeSeparator + key + "." + value;
639  } else {
640  myCurrentEdge->myHighWayType = key + "." + value;
641  }
642  myCurrentEdge->myCurrentIsRoad = true;
643  } else if (key == "lanes") {
644  try {
645  myCurrentEdge->myNoLanes = TplConvert::_2int(value.c_str());
646  } catch (NumberFormatException&) {
647  // might be a list of values
648  StringTokenizer st(value, ";", true);
649  std::vector<std::string> list = st.getVector();
650  if (list.size() >= 2) {
651  int minLanes = std::numeric_limits<int>::max();
652  try {
653  for (std::vector<std::string>::iterator i = list.begin(); i != list.end(); ++i) {
654  int numLanes = TplConvert::_2int(StringUtils::prune(*i).c_str());
655  minLanes = MIN2(minLanes, numLanes);
656  }
657  myCurrentEdge->myNoLanes = minLanes;
658  WRITE_WARNING("Using minimum lane number from list (" + value + ") for edge '" + myCurrentEdge->id + "'.");
659  } catch (NumberFormatException&) {
660  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" + myCurrentEdge->id + "'.");
661  }
662  }
663  }
664  } else if (key == "maxspeed") {
665  if (mySpeedMap.find(value) != mySpeedMap.end()) {
666  myCurrentEdge->myMaxSpeed = mySpeedMap[value];
667  } else {
668  SUMOReal conversion = 1; // OSM default is km/h
669  if (StringUtils::to_lower_case(value).find("km/h") != std::string::npos) {
670  value = StringUtils::prune(value.substr(0, value.find_first_not_of("0123456789")));
671  } else if (StringUtils::to_lower_case(value).find("mph") != std::string::npos) {
672  value = StringUtils::prune(value.substr(0, value.find_first_not_of("0123456789")));
673  conversion = 1.609344; // kilometers per mile
674  }
675  try {
676  myCurrentEdge->myMaxSpeed = TplConvert::_2SUMOReal(value.c_str()) * conversion;
677  } catch (NumberFormatException&) {
678  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" + myCurrentEdge->id + "'.");
679  }
680  }
681  } else if (key == "junction") {
682  if ((value == "roundabout") && (myCurrentEdge->myIsOneWay == "")) {
683  myCurrentEdge->myIsOneWay = "yes";
684  }
685  } else if (key == "oneway") {
686  myCurrentEdge->myIsOneWay = value;
687  } else if (key == "name") {
688  myCurrentEdge->streetName = value;
689  }
690  }
691 }
692 
693 
694 void
696  myParentElements.pop_back();
697  if (element == SUMO_TAG_WAY) {
698  if (myCurrentEdge != 0 && myCurrentEdge->myCurrentIsRoad) {
699  myEdgeMap[myCurrentEdge->id] = myCurrentEdge;
700  } else {
701  delete myCurrentEdge;
702  }
703  myCurrentEdge = 0;
704  }
705 }
706 
707 
708 
709 
710 /****************************************************************************/
711