SUMO - Simulation of Urban MObility
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.dlr.de/
13 // Copyright (C) 2001-2017 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 //#define DEBUG_LAYER_ELEVATION
65 
66 // ---------------------------------------------------------------------------
67 // static members
68 // ---------------------------------------------------------------------------
70 
72 
73 // ===========================================================================
74 // Private classes
75 // ===========================================================================
76 
80 public:
81  bool operator()(const Edge* e1, const Edge* e2) const {
82  if (e1->myHighWayType != e2->myHighWayType) {
83  return e1->myHighWayType > e2->myHighWayType;
84  }
85  if (e1->myNoLanes != e2->myNoLanes) {
86  return e1->myNoLanes > e2->myNoLanes;
87  }
88  if (e1->myNoLanesForward != e2->myNoLanesForward) {
89  return e1->myNoLanesForward > e2->myNoLanesForward;
90  }
91  if (e1->myMaxSpeed != e2->myMaxSpeed) {
92  return e1->myMaxSpeed > e2->myMaxSpeed;
93  }
94  if (e1->myIsOneWay != e2->myIsOneWay) {
95  return e1->myIsOneWay > e2->myIsOneWay;
96  }
97  return e1->myCurrentNodes > e2->myCurrentNodes;
98  }
99 };
100 
101 // ===========================================================================
102 // method definitions
103 // ===========================================================================
104 // ---------------------------------------------------------------------------
105 // static methods
106 // ---------------------------------------------------------------------------
108 
109 
110 void
112  NIImporter_OpenStreetMap importer;
113  importer.load(oc, nb);
114 }
115 
116 
118 
119 
121  // delete nodes
122  for (std::set<NIOSMNode*, CompareNodes>::iterator i = myUniqueNodes.begin(); i != myUniqueNodes.end(); i++) {
123  delete *i;
124  }
125  // delete edges
126  for (std::map<long long int, Edge*>::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
127  delete(*i).second;
128  }
129 }
130 
131 
132 void
134  // check whether the option is set (properly)
135  if (!oc.isSet("osm-files")) {
136  return;
137  }
138  /* Parse file(s)
139  * Each file is parsed twice: first for nodes, second for edges. */
140  std::vector<std::string> files = oc.getStringVector("osm-files");
141  // load nodes, first
142  NodesHandler nodesHandler(myOSMNodes, myUniqueNodes, oc.getBool("osm.elevation"));
143  for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
144  // nodes
145  if (!FileHelpers::isReadable(*file)) {
146  WRITE_ERROR("Could not open osm-file '" + *file + "'.");
147  return;
148  }
149  nodesHandler.setFileName(*file);
150  PROGRESS_BEGIN_MESSAGE("Parsing nodes from osm-file '" + *file + "'");
151  if (!XMLSubSys::runParser(nodesHandler, *file)) {
152  return;
153  }
155  }
156  // load edges, then
157  EdgesHandler edgesHandler(myOSMNodes, myEdges);
158  for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
159  // edges
160  edgesHandler.setFileName(*file);
161  PROGRESS_BEGIN_MESSAGE("Parsing edges from osm-file '" + *file + "'");
162  XMLSubSys::runParser(edgesHandler, *file);
164  }
165 
166  /* Remove duplicate edges with the same shape and attributes */
167  if (!oc.getBool("osm.skip-duplicates-check")) {
168  PROGRESS_BEGIN_MESSAGE("Removing duplicate edges");
169  if (myEdges.size() > 1) {
170  std::set<const Edge*, CompareEdges> dupsFinder;
171  for (std::map<long long int, Edge*>::iterator it = myEdges.begin(); it != myEdges.end();) {
172  if (dupsFinder.count(it->second) > 0) {
173  WRITE_MESSAGE("Found duplicate edges. Removing " + toString(it->first));
174  delete it->second;
175  myEdges.erase(it++);
176  } else {
177  dupsFinder.insert(it->second);
178  it++;
179  }
180  }
181  }
183  }
184 
185  /* Mark which nodes are used (by edges or traffic lights).
186  * This is necessary to detect which OpenStreetMap nodes are for
187  * geometry only */
188  std::map<long long int, int> nodeUsage;
189  // Mark which nodes are used by edges (begin and end)
190  for (std::map<long long int, Edge*>::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
191  Edge* e = (*i).second;
192  assert(e->myCurrentIsRoad);
193  for (std::vector<long long int>::const_iterator j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
194  if (nodeUsage.find(*j) == nodeUsage.end()) {
195  nodeUsage[*j] = 0;
196  }
197  nodeUsage[*j] = nodeUsage[*j] + 1;
198  }
199  }
200  // Mark which nodes are used by traffic lights
201  for (std::map<long long int, NIOSMNode*>::const_iterator nodesIt = myOSMNodes.begin(); nodesIt != myOSMNodes.end(); ++nodesIt) {
202  if (nodesIt->second->tlsControlled /* || nodesIt->second->railwayCrossing*/) {
203  // If the key is not found in the map, the value is automatically
204  // initialized with 0.
205  nodeUsage[nodesIt->first] += 1;
206  }
207  }
208 
209  /* Instantiate edges
210  * Only those nodes in the middle of an edge which are used by more than
211  * one edge are instantiated. Other nodes are considered as geometry nodes. */
212  NBNodeCont& nc = nb.getNodeCont();
214  for (std::map<long long int, Edge*>::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
215  Edge* e = (*i).second;
216  assert(e->myCurrentIsRoad);
217  if (e->myCurrentNodes.size() < 2) {
218  WRITE_WARNING("Discarding way '" + toString(e->id) + "' because it has only " +
219  toString(e->myCurrentNodes.size()) + " node(s)");
220  continue;
221  }
222  // build nodes;
223  // - the from- and to-nodes must be built in any case
224  // - the in-between nodes are only built if more than one edge references them
225  NBNode* currentFrom = insertNodeChecking(*e->myCurrentNodes.begin(), nc, tlsc);
226  NBNode* last = insertNodeChecking(*(e->myCurrentNodes.end() - 1), nc, tlsc);
227  int running = 0;
228  std::vector<long long int> passed;
229  for (std::vector<long long int>::iterator j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
230  passed.push_back(*j);
231  if (nodeUsage[*j] > 1 && j != e->myCurrentNodes.end() - 1 && j != e->myCurrentNodes.begin()) {
232  NBNode* currentTo = insertNodeChecking(*j, nc, tlsc);
233  running = insertEdge(e, running, currentFrom, currentTo, passed, nb);
234  currentFrom = currentTo;
235  passed.clear();
236  passed.push_back(*j);
237  }
238  }
239  if (running == 0) {
240  running = -1;
241  }
242  insertEdge(e, running, currentFrom, last, passed, nb);
243  }
244 
245  const SUMOReal layerElevation = oc.getFloat("osm.layer-elevation");
246  if (layerElevation > 0) {
247  reconstructLayerElevation(layerElevation, nb);
248  }
249 
250  // load relations (after edges are built since we want to apply
251  // turn-restrictions directly to NBEdges)
252  RelationHandler relationHandler(myOSMNodes, myEdges);
253  for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
254  // relations
255  relationHandler.setFileName(*file);
256  PROGRESS_BEGIN_MESSAGE("Parsing relations from osm-file '" + *file + "'");
257  XMLSubSys::runParser(relationHandler, *file);
259  }
260 }
261 
262 
263 NBNode*
265  NBNode* node = nc.retrieve(toString(id));
266  if (node == 0) {
267  NIOSMNode* n = myOSMNodes.find(id)->second;
268  Position pos(n->lon, n->lat, n->ele);
269  if (!NBNetBuilder::transformCoordinate(pos, true)) {
270  WRITE_ERROR("Unable to project coordinates for junction '" + toString(id) + "'.");
271  return 0;
272  }
273  node = new NBNode(toString(id), pos);
274  if (!nc.insert(node)) {
275  WRITE_ERROR("Could not insert junction '" + toString(id) + "'.");
276  delete node;
277  return 0;
278  }
279  n->node = node;
280  if (n->railwayCrossing) {
281  node->reinit(pos, NODETYPE_RAIL_CROSSING);
282  } else if (n->tlsControlled) {
283  // ok, this node is a traffic light node where no other nodes
284  // participate
285  // @note: The OSM-community has not settled on a schema for differentiating between fixed and actuated lights
287  NBOwnTLDef* tlDef = new NBOwnTLDef(toString(id), node, 0, type);
288  if (!tlsc.insert(tlDef)) {
289  // actually, nothing should fail here
290  delete tlDef;
291  throw ProcessError("Could not allocate tls '" + toString(id) + "'.");
292  }
293  }
294  }
295  return node;
296 }
297 
298 
299 int
301  const std::vector<long long int>& passed, NBNetBuilder& nb) {
302  NBNodeCont& nc = nb.getNodeCont();
303  NBEdgeCont& ec = nb.getEdgeCont();
304  NBTypeCont& tc = nb.getTypeCont();
306  // patch the id
307  std::string id = toString(e->id);
308  if (from == 0 || to == 0) {
309  WRITE_ERROR("Discarding edge '" + id + "' because the nodes could not be built.");
310  return index;
311  }
312  if (index >= 0) {
313  id = id + "#" + toString(index);
314  } else {
315  index = 0;
316  }
317  if (from == to) {
318  assert(passed.size() >= 2);
319  if (passed.size() == 2) {
320  WRITE_WARNING("Discarding edge '" + id + "' which connects two identical nodes without geometry.");
321  return index;
322  }
323  // in the special case of a looped way split again using passed
324  int intermediateIndex = (int)passed.size() / 2;
325  NBNode* intermediate = insertNodeChecking(passed[intermediateIndex], nc, tlsc);
326  std::vector<long long int> part1(passed.begin(), passed.begin() + intermediateIndex + 1);
327  std::vector<long long int> part2(passed.begin() + intermediateIndex, passed.end());
328  index = insertEdge(e, index, from, intermediate, part1, nb);
329  return insertEdge(e, index, intermediate, to, part2, nb);
330  }
331  const int newIndex = index + 1;
332 
333  // convert the shape
334  PositionVector shape;
335  for (std::vector<long long int>::const_iterator i = passed.begin(); i != passed.end(); ++i) {
336  NIOSMNode* n = myOSMNodes.find(*i)->second;
337  Position pos(n->lon, n->lat, n->ele);
338  shape.push_back(pos);
339  }
341  WRITE_ERROR("Unable to project coordinates for edge '" + id + "'.");
342  }
343 
344  std::string type = e->myHighWayType;
345  if (!tc.knows(type)) {
346  if (myUnusableTypes.count(type) > 0) {
347  return newIndex;
348  } else if (myKnownCompoundTypes.count(type) > 0) {
349  type = myKnownCompoundTypes[type];
350  } else {
351  // this edge has a type which does not yet exist in the TypeContainer
353  std::vector<std::string> types;
354  while (tok.hasNext()) {
355  std::string t = tok.next();
356  if (tc.knows(t)) {
357  if (std::find(types.begin(), types.end(), t) == types.end()) {
358  types.push_back(t);
359  }
360  } else if (tok.size() > 1) {
361  WRITE_WARNING("Discarding unknown compound '" + t + "' in type '" + type + "' (first occurence for edge '" + id + "').");
362  }
363  }
364  if (types.size() == 0) {
365  WRITE_WARNING("Discarding unusable type '" + type + "' (first occurence for edge '" + id + "').");
366  myUnusableTypes.insert(type);
367  return newIndex;
368  } else {
369  const std::string newType = joinToString(types, "|");
370  if (tc.knows(newType)) {
371  myKnownCompoundTypes[type] = newType;
372  type = newType;
373  } else if (myKnownCompoundTypes.count(newType) > 0) {
374  type = myKnownCompoundTypes[newType];
375  } else {
376  // build a new type by merging all values
377  int numLanes = 0;
378  SUMOReal maxSpeed = 0;
379  int prio = 0;
381  SUMOReal sidewalkWidth = NBEdge::UNSPECIFIED_WIDTH;
382  SUMOReal bikelaneWidth = NBEdge::UNSPECIFIED_WIDTH;
383  bool defaultIsOneWay = false;
384  SVCPermissions permissions = 0;
385  bool discard = true;
386  for (std::vector<std::string>::iterator it = types.begin(); it != types.end(); it++) {
387  if (!tc.getShallBeDiscarded(*it)) {
388  numLanes = MAX2(numLanes, tc.getNumLanes(*it));
389  maxSpeed = MAX2(maxSpeed, tc.getSpeed(*it));
390  prio = MAX2(prio, tc.getPriority(*it));
391  defaultIsOneWay &= tc.getIsOneWay(*it);
392  permissions |= tc.getPermissions(*it);
393  width = MAX2(width, tc.getWidth(*it));
394  sidewalkWidth = MAX2(sidewalkWidth, tc.getSidewalkWidth(*it));
395  bikelaneWidth = MAX2(bikelaneWidth, tc.getBikeLaneWidth(*it));
396  discard = false;
397  }
398  }
399  if (width != NBEdge::UNSPECIFIED_WIDTH) {
400  width = MAX2(width, SUMO_const_laneWidth);
401  }
402  if (discard) {
403  WRITE_WARNING("Discarding compound type '" + newType + "' (first occurence for edge '" + id + "').");
404  myUnusableTypes.insert(newType);
405  return newIndex;
406  } else {
407  WRITE_MESSAGE("Adding new type '" + type + "' (first occurence for edge '" + id + "').");
408  tc.insert(newType, numLanes, maxSpeed, prio, permissions, width, defaultIsOneWay, sidewalkWidth, bikelaneWidth);
409  for (std::vector<std::string>::iterator it = types.begin(); it != types.end(); it++) {
410  if (!tc.getShallBeDiscarded(*it)) {
411  tc.copyRestrictionsAndAttrs(*it, newType);
412  }
413  }
414  myKnownCompoundTypes[type] = newType;
415  type = newType;
416  }
417  }
418  }
419  }
420  }
421 
422  // otherwise it is not an edge and will be ignored
423  bool ok = true;
424  int numLanesForward = tc.getNumLanes(type);
425  int numLanesBackward = tc.getNumLanes(type);
426  SUMOReal speed = tc.getSpeed(type);
427  bool defaultsToOneWay = tc.getIsOneWay(type);
428  SVCPermissions forwardPermissions = tc.getPermissions(type);
429  SVCPermissions backwardPermissions = tc.getPermissions(type);
430  SUMOReal forwardWidth = tc.getWidth(type);
431  SUMOReal backwardWidth = tc.getWidth(type);
432  const bool addSidewalk = (tc.getSidewalkWidth(type) != NBEdge::UNSPECIFIED_WIDTH);
433  const bool addBikeLane = (tc.getBikeLaneWidth(type) != NBEdge::UNSPECIFIED_WIDTH);
434  // check directions
435  bool addForward = true;
436  bool addBackward = true;
437  if (e->myIsOneWay == "true" || e->myIsOneWay == "yes" || e->myIsOneWay == "1" || (defaultsToOneWay && e->myIsOneWay != "no" && e->myIsOneWay != "false" && e->myIsOneWay != "0")) {
438  addBackward = false;
439  }
440  if (e->myIsOneWay == "-1" || e->myIsOneWay == "reverse") {
441  // one-way in reversed direction of way
442  addForward = false;
443  addBackward = true;
444  }
445  if (e->myIsOneWay != "" && e->myIsOneWay != "false" && e->myIsOneWay != "no" && e->myIsOneWay != "true" && e->myIsOneWay != "yes" && e->myIsOneWay != "-1" && e->myIsOneWay != "1" && e->myIsOneWay != "reverse") {
446  WRITE_WARNING("New value for oneway found: " + e->myIsOneWay);
447  }
448  // if we had been able to extract the number of lanes, override the highway type default
449  if (e->myNoLanes > 0) {
450  if (addForward && !addBackward) {
451  numLanesForward = e->myNoLanes;
452  } else if (!addForward && addBackward) {
453  numLanesBackward = e->myNoLanes;
454  } else {
455  if (e->myNoLanesForward > 0) {
456  numLanesForward = e->myNoLanesForward;
457  } else if (e->myNoLanesForward < 0) {
458  numLanesForward = e->myNoLanes + e->myNoLanesForward;
459  } else {
460  numLanesForward = (int)std::ceil(e->myNoLanes / 2.0);
461  }
462  numLanesBackward = e->myNoLanes - numLanesForward;
463  // sometimes ways are tagged according to their physical width of a single
464  // lane but they are intended for traffic in both directions
465  numLanesForward = MAX2(1, numLanesForward);
466  numLanesBackward = MAX2(1, numLanesBackward);
467  }
468  } else if (e->myNoLanes == 0) {
469  WRITE_WARNING("Skipping edge '" + id + "' because it has zero lanes.");
470  ok = false;
471  }
472  // if we had been able to extract the maximum speed, override the type's default
473  if (e->myMaxSpeed != MAXSPEED_UNGIVEN) {
474  speed = (SUMOReal)(e->myMaxSpeed / 3.6);
475  }
476  if (speed <= 0) {
477  WRITE_WARNING("Skipping edge '" + id + "' because it has speed " + toString(speed));
478  ok = false;
479  }
480  // deal with cycleways that run in the opposite direction of a one-way street
481  if (addBikeLane) {
482  if (!addForward && (e->myCyclewayType & WAY_FORWARD) != 0) {
483  addForward = true;
484  forwardPermissions = SVC_BICYCLE;
485  forwardWidth = tc.getBikeLaneWidth(type);
486  numLanesForward = 1;
487  // do not add an additional cycle lane
489  }
490  if (!addBackward && (e->myCyclewayType & WAY_BACKWARD) != 0) {
491  addBackward = true;
492  backwardPermissions = SVC_BICYCLE;
493  backwardWidth = tc.getBikeLaneWidth(type);
494  numLanesBackward = 1;
495  // do not add an additional cycle lane
497  }
498  }
499  // deal with busways that run in the opposite direction of a one-way street
500  if (!addForward && (e->myBuswayType & WAY_FORWARD) != 0) {
501  addForward = true;
502  forwardPermissions = SVC_BUS;
503  numLanesForward = 1;
504  }
505  if (!addBackward && (e->myBuswayType & WAY_BACKWARD) != 0) {
506  addBackward = true;
507  backwardPermissions = SVC_BUS;
508  numLanesBackward = 1;
509  }
510 
511  if (ok) {
512  LaneSpreadFunction lsf = (addBackward || OptionsCont::getOptions().getBool("osm.oneway-spread-right")) ? LANESPREAD_RIGHT : LANESPREAD_CENTER;
513  id = StringUtils::escapeXML(id);
514  if (addForward) {
515  assert(numLanesForward > 0);
516  NBEdge* nbe = new NBEdge(id, from, to, type, speed, numLanesForward, tc.getPriority(type),
517  forwardWidth, NBEdge::UNSPECIFIED_OFFSET, shape,
518  StringUtils::escapeXML(e->streetName), toString(e->id), lsf, true);
519  nbe->setPermissions(forwardPermissions);
520  if ((e->myBuswayType & WAY_FORWARD) != 0) {
521  nbe->setPermissions(SVC_BUS, 0);
522  }
523  if (addBikeLane && (e->myCyclewayType == WAY_UNKNOWN || (e->myCyclewayType & WAY_FORWARD) != 0)) {
524  nbe->addBikeLane(tc.getBikeLaneWidth(type));
525  } else if (nbe->getPermissions(0) == SVC_BUS) {
526  // bikes drive on buslanes if no separate cycle lane is available
528  }
529  if (addSidewalk) {
530  nbe->addSidewalk(tc.getSidewalkWidth(type));
531  }
532  nbe->addParameter(*e);
533  if (!ec.insert(nbe)) {
534  delete nbe;
535  throw ProcessError("Could not add edge '" + id + "'.");
536  }
537  }
538  if (addBackward) {
539  assert(numLanesBackward > 0);
540  NBEdge* nbe = new NBEdge("-" + id, to, from, type, speed, numLanesBackward, tc.getPriority(type),
541  backwardWidth, NBEdge::UNSPECIFIED_OFFSET, shape.reverse(),
542  StringUtils::escapeXML(e->streetName), toString(e->id), lsf, true);
543  nbe->setPermissions(backwardPermissions);
544  if ((e->myBuswayType & WAY_BACKWARD) != 0) {
545  nbe->setPermissions(SVC_BUS, 0);
546  }
547  if (addBikeLane && (e->myCyclewayType == WAY_UNKNOWN || (e->myCyclewayType & WAY_BACKWARD) != 0)) {
548  nbe->addBikeLane(tc.getBikeLaneWidth(type));
549  } else if (nbe->getPermissions(0) == SVC_BUS) {
550  // bikes drive on buslanes if no separate cycle lane is available
552  }
553  if (addSidewalk) {
554  nbe->addSidewalk(tc.getSidewalkWidth(type));
555  }
556  nbe->addParameter(*e);
557  if (!ec.insert(nbe)) {
558  delete nbe;
559  throw ProcessError("Could not add edge '-" + id + "'.");
560  }
561  }
562  }
563  return newIndex;
564 }
565 
566 
567 // ---------------------------------------------------------------------------
568 // definitions of NIImporter_OpenStreetMap::NodesHandler-methods
569 // ---------------------------------------------------------------------------
571  std::map<long long int, NIOSMNode*>& toFill,
572  std::set<NIOSMNode*, CompareNodes>& uniqueNodes,
573  bool importElevation) :
574  SUMOSAXHandler("osm - file"),
575  myToFill(toFill),
576  myLastNodeID(-1),
577  myIsInValidNodeTag(false),
578  myHierarchyLevel(0),
579  myUniqueNodes(uniqueNodes),
580  myImportElevation(importElevation) {
581 }
582 
583 
585 
586 
587 void
590  if (element == SUMO_TAG_NODE) {
591  bool ok = true;
592  if (myHierarchyLevel != 2) {
593  WRITE_ERROR("Node element on wrong XML hierarchy level (id='" + toString(attrs.get<long long int>(SUMO_ATTR_ID, 0, ok)) + "', level='" + toString(myHierarchyLevel) + "').");
594  return;
595  }
596  long long int id = attrs.get<long long int>(SUMO_ATTR_ID, 0, ok);
597  std::string action = attrs.hasAttribute("action") ? attrs.getStringSecure("action", "") : "";
598  if (action == "delete") {
599  return;
600  }
601  if (!ok) {
602  return;
603  }
604  myLastNodeID = -1;
605  if (myToFill.find(id) == myToFill.end()) {
606  myLastNodeID = id;
607  // assume we are loading multiple files...
608  // ... so we won't report duplicate nodes
609  bool ok = true;
610  double tlat, tlon;
611  std::istringstream lon(attrs.get<std::string>(SUMO_ATTR_LON, toString(id).c_str(), ok));
612  if (!ok) {
613  return;
614  }
615  lon >> tlon;
616  if (lon.fail()) {
617  WRITE_ERROR("Node's '" + toString(id) + "' lon information is not numeric.");
618  return;
619  }
620  std::istringstream lat(attrs.get<std::string>(SUMO_ATTR_LAT, toString(id).c_str(), ok));
621  if (!ok) {
622  return;
623  }
624  lat >> tlat;
625  if (lat.fail()) {
626  WRITE_ERROR("Node's '" + toString(id) + "' lat information is not numeric.");
627  return;
628  }
629  NIOSMNode* toAdd = new NIOSMNode(id, tlon, tlat);
630  myIsInValidNodeTag = true;
631 
632  std::set<NIOSMNode*, CompareNodes>::iterator similarNode = myUniqueNodes.find(toAdd);
633  if (similarNode == myUniqueNodes.end()) {
634  myUniqueNodes.insert(toAdd);
635  } else {
636  delete toAdd;
637  toAdd = *similarNode;
638  WRITE_MESSAGE("Found duplicate nodes. Substituting " + toString(id) + " with " + toString(toAdd->id));
639  }
640  myToFill[id] = toAdd;
641  }
642  }
643  if (element == SUMO_TAG_TAG && myIsInValidNodeTag) {
644  if (myHierarchyLevel != 3) {
645  WRITE_ERROR("Tag element on wrong XML hierarchy level.");
646  return;
647  }
648  bool ok = true;
649  std::string key = attrs.get<std::string>(SUMO_ATTR_K, toString(myLastNodeID).c_str(), ok, false);
650  // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
651  if (key == "highway" || key == "ele" || key == "crossing" || key == "railway") {
652  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myLastNodeID).c_str(), ok, false);
653  if (key == "highway" && value.find("traffic_signal") != std::string::npos) {
654  myToFill[myLastNodeID]->tlsControlled = true;
655  } else if (key == "crossing" && value.find("traffic_signals") != std::string::npos) {
656  myToFill[myLastNodeID]->tlsControlled = true;
657  } else if (key == "railway" && value.find("crossing") != std::string::npos) {
658  myToFill[myLastNodeID]->railwayCrossing = true;
659  } else if (myImportElevation && key == "ele") {
660  try {
661  myToFill[myLastNodeID]->ele = TplConvert::_2SUMOReal(value.c_str());
662  } catch (...) {
663  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in node '" +
664  toString(myLastNodeID) + "'.");
665  }
666  }
667  }
668  }
669 }
670 
671 
672 void
674  if (element == SUMO_TAG_NODE && myHierarchyLevel == 2) {
675  myLastNodeID = -1;
676  myIsInValidNodeTag = false;
677  }
679 }
680 
681 
682 // ---------------------------------------------------------------------------
683 // definitions of NIImporter_OpenStreetMap::EdgesHandler-methods
684 // ---------------------------------------------------------------------------
686  const std::map<long long int, NIOSMNode*>& osmNodes,
687  std::map<long long int, Edge*>& toFill) :
688  SUMOSAXHandler("osm - file"),
689  myOSMNodes(osmNodes),
690  myEdgeMap(toFill) {
691  mySpeedMap["signals"] = MAXSPEED_UNGIVEN;
692  mySpeedMap["none"] = 300.;
693  mySpeedMap["no"] = 300.;
694  mySpeedMap["walk"] = 5.;
695  mySpeedMap["DE:rural"] = 100.;
696  mySpeedMap["DE:urban"] = 50.;
697  mySpeedMap["DE:living_street"] = 10.;
698 
699 }
700 
701 
703 }
704 
705 
706 void
708  const SUMOSAXAttributes& attrs) {
709  myParentElements.push_back(element);
710  // parse "way" elements
711  if (element == SUMO_TAG_WAY) {
712  bool ok = true;
713  long long int id = attrs.get<long long int>(SUMO_ATTR_ID, 0, ok);
714  std::string action = attrs.hasAttribute("action") ? attrs.getStringSecure("action", "") : "";
715  if (action == "delete") {
716  myCurrentEdge = 0;
717  return;
718  }
719  if (!ok) {
720  myCurrentEdge = 0;
721  return;
722  }
723  myCurrentEdge = new Edge(id);
724  }
725  // parse "nd" (node) elements
726  if (element == SUMO_TAG_ND) {
727  bool ok = true;
728  long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, 0, ok);
729  if (ok) {
730  std::map<long long int, NIOSMNode*>::const_iterator node = myOSMNodes.find(ref);
731  if (node == myOSMNodes.end()) {
732  WRITE_WARNING("The referenced geometry information (ref='" + toString(ref) + "') is not known");
733  return;
734  } else {
735  ref = node->second->id; // node may have been substituted
736  if (myCurrentEdge->myCurrentNodes.size() == 0 ||
737  myCurrentEdge->myCurrentNodes.back() != ref) { // avoid consecutive duplicates
738  myCurrentEdge->myCurrentNodes.push_back(ref);
739  }
740  }
741  }
742  }
743  // parse values
744  if (element == SUMO_TAG_TAG && myParentElements.size() > 2 && myParentElements[myParentElements.size() - 2] == SUMO_TAG_WAY) {
745  if (myCurrentEdge == 0) {
746  return;
747  }
748  bool ok = true;
749  std::string key = attrs.get<std::string>(SUMO_ATTR_K, toString(myCurrentEdge->id).c_str(), ok, false);
750  if (key.size() > 8 && StringUtils::startsWith(key, "cycleway:")) {
751  // handle special busway keys
752  const std::string cyclewaySpec = key.substr(9);
753  key = "cycleway";
754  if (cyclewaySpec == "right") {
756  } else if (cyclewaySpec == "left") {
758  } else if (cyclewaySpec == "both") {
760  } else {
761  key = "ignore";
762  }
763  if ((myCurrentEdge->myCyclewayType & WAY_BOTH) != 0) {
764  // now we have some info on directionality
766  }
767  } else if (key.size() > 6 && StringUtils::startsWith(key, "busway:")) {
768  // handle special busway keys
769  const std::string buswaySpec = key.substr(7);
770  key = "busway";
771  if (buswaySpec == "right") {
773  } else if (buswaySpec == "left") {
775  } else if (buswaySpec == "both") {
777  } else {
778  key = "ignore";
779  }
780  }
781  if (key == "bridge" || key == "tunnel") {
782  myCurrentEdge->addParameter(key, "true"); // could be differentiated further if necessary
783  }
784 
785  // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
786  if (!StringUtils::endsWith(key, "way") && !StringUtils::startsWith(key, "lanes")
787  && key != "maxspeed" && key != "junction" && key != "name" && key != "tracks" && key != "layer" && key != "route" && key != "postal_code") {
788  return;
789  }
790  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentEdge->id).c_str(), ok, false);
791 
792  if (key == "highway" || key == "railway" || key == "waterway" || key == "cycleway" || key == "busway" || key == "route") {
794  // special cycleway stuff
795  if (key == "cycleway") {
796  if (value == "no") {
797  return;
798  } else if (value == "opposite_track") {
800  } else if (value == "opposite_lane") {
802  }
803  }
804  // special busway stuff
805  if (key == "busway") {
806  if (value == "no") {
807  return;
808  } else if (value == "opposite_track") {
810  } else if (value == "opposite_lane") {
812  }
813  // no need to extend the type id
814  return;
815  }
816  // build type id
817  const std::string singleTypeID = key + "." + value;
818  if (myCurrentEdge->myHighWayType != "") {
819  // osm-ways may be used by more than one mode (eg railway.tram + highway.residential. this is relevant for multimodal traffic)
820  // we create a new type for this kind of situation which must then be resolved in insertEdge()
821  std::vector<std::string> types = StringTokenizer(myCurrentEdge->myHighWayType, compoundTypeSeparator).getVector();
822  types.push_back(singleTypeID);
824  } else {
825  myCurrentEdge->myHighWayType = singleTypeID;
826  }
827  } else if (key == "lanes") {
828  try {
829  myCurrentEdge->myNoLanes = TplConvert::_2int(value.c_str());
830  } catch (NumberFormatException&) {
831  // might be a list of values
832  StringTokenizer st(value, ";", true);
833  std::vector<std::string> list = st.getVector();
834  if (list.size() >= 2) {
835  int minLanes = std::numeric_limits<int>::max();
836  try {
837  for (std::vector<std::string>::iterator i = list.begin(); i != list.end(); ++i) {
838  int numLanes = TplConvert::_2int(StringUtils::prune(*i).c_str());
839  minLanes = MIN2(minLanes, numLanes);
840  }
841  myCurrentEdge->myNoLanes = minLanes;
842  WRITE_WARNING("Using minimum lane number from list (" + value + ") for edge '" + toString(myCurrentEdge->id) + "'.");
843  } catch (NumberFormatException&) {
844  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
845  toString(myCurrentEdge->id) + "'.");
846  }
847  }
848  } catch (EmptyData&) {
849  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
850  toString(myCurrentEdge->id) + "'.");
851  }
852  } else if (key == "lanes:forward") {
853  try {
855  } catch (...) {
856  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
857  toString(myCurrentEdge->id) + "'.");
858  }
859  } else if (key == "lanes:backward") {
860  try {
861  // denote backwards count with a negative sign
863  } catch (...) {
864  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
865  toString(myCurrentEdge->id) + "'.");
866  }
867  } else if (key == "maxspeed") {
868  if (mySpeedMap.find(value) != mySpeedMap.end()) {
870  } else {
871  SUMOReal conversion = 1; // OSM default is km/h
872  if (StringUtils::to_lower_case(value).find("km/h") != std::string::npos) {
873  value = StringUtils::prune(value.substr(0, value.find_first_not_of("0123456789")));
874  } else if (StringUtils::to_lower_case(value).find("mph") != std::string::npos) {
875  value = StringUtils::prune(value.substr(0, value.find_first_not_of("0123456789")));
876  conversion = 1.609344; // kilometers per mile
877  }
878  try {
879  myCurrentEdge->myMaxSpeed = TplConvert::_2SUMOReal(value.c_str()) * conversion;
880  } catch (...) {
881  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
882  toString(myCurrentEdge->id) + "'.");
883  }
884  }
885  } else if (key == "junction") {
886  if ((value == "roundabout") && (myCurrentEdge->myIsOneWay == "")) {
887  myCurrentEdge->myIsOneWay = "yes";
888  }
889  } else if (key == "oneway") {
890  myCurrentEdge->myIsOneWay = value;
891  } else if (key == "name") {
892  myCurrentEdge->streetName = value;
893  } else if (key == "layer") {
894  try {
895  myCurrentEdge->myLayer = TplConvert::_2int(value.c_str());
896  } catch (...) {
897  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
898  toString(myCurrentEdge->id) + "'.");
899  }
900  } else if (key == "tracks") {
901  try {
902  if (TplConvert::_2int(value.c_str()) > 1) {
903  myCurrentEdge->myIsOneWay = "false";
904  } else {
905  myCurrentEdge->myIsOneWay = "true";
906  }
907  } catch (...) {
908  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
909  toString(myCurrentEdge->id) + "'.");
910  }
911  } else if (key == "postal_code") {
912  myCurrentEdge->addParameter(key, value);
913  }
914  }
915 }
916 
917 
918 void
920  myParentElements.pop_back();
921  if (element == SUMO_TAG_WAY) {
924  } else {
925  delete myCurrentEdge;
926  }
927  myCurrentEdge = 0;
928  }
929 }
930 
931 
932 // ---------------------------------------------------------------------------
933 // definitions of NIImporter_OpenStreetMap::RelationHandler-methods
934 // ---------------------------------------------------------------------------
936  const std::map<long long int, NIOSMNode*>& osmNodes,
937  const std::map<long long int, Edge*>& osmEdges) :
938  SUMOSAXHandler("osm - file"),
939  myOSMNodes(osmNodes),
940  myOSMEdges(osmEdges) {
941  resetValues();
942 }
943 
944 
946 }
947 
948 void
951  myIsRestriction = false;
957 }
958 
959 void
961  const SUMOSAXAttributes& attrs) {
962  myParentElements.push_back(element);
963  // parse "way" elements
964  if (element == SUMO_TAG_RELATION) {
965  bool ok = true;
966  myCurrentRelation = attrs.get<long long int>(SUMO_ATTR_ID, 0, ok);
967  std::string action = attrs.hasAttribute("action") ? attrs.getStringSecure("action", "") : "";
968  if (action == "delete" || !ok) {
970  }
971  return;
972  } else if (myCurrentRelation == INVALID_ID) {
973  return;
974  }
975  // parse member elements
976  if (element == SUMO_TAG_MEMBER) {
977  bool ok = true;
978  std::string role = attrs.hasAttribute("role") ? attrs.getStringSecure("role", "") : "";
979  long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, 0, ok);
980  if (role == "via") {
981  // u-turns for divided ways may be given with 2 via-nodes or 1 via-way
982  std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, 0, ok);
983  if (memberType == "way" && checkEdgeRef(ref)) {
984  myViaWay = ref;
985  } else if (memberType == "node") {
986  if (myOSMNodes.find(ref) != myOSMNodes.end()) {
987  myViaNode = ref;
988  } else {
989  WRITE_WARNING("No node found for reference '" + toString(ref) + "' in relation '" + toString(myCurrentRelation) + "'");
990  }
991  }
992  } else if (role == "from" && checkEdgeRef(ref)) {
993  myFromWay = ref;
994  } else if (role == "to" && checkEdgeRef(ref)) {
995  myToWay = ref;
996  }
997  return;
998  }
999  // parse values
1000  if (element == SUMO_TAG_TAG) {
1001  bool ok = true;
1002  std::string key = attrs.get<std::string>(SUMO_ATTR_K, toString(myCurrentRelation).c_str(), ok, false);
1003  // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
1004  if (key == "type" || key == "restriction") {
1005  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1006  if (key == "type" && value == "restriction") {
1007  myIsRestriction = true;
1008  return;
1009  }
1010  if (key == "restriction") {
1011  // @note: the 'right/left/straight' part is ignored since the information is
1012  // redundantly encoded in the 'from', 'to' and 'via' members
1013  if (value.substr(0, 5) == "only_") {
1015  } else if (value.substr(0, 3) == "no_") {
1017  } else {
1018  WRITE_WARNING("Found unknown restriction type '" + value + "' in relation '" + toString(myCurrentRelation) + "'");
1019  }
1020  return;
1021  }
1022  }
1023  }
1024 }
1025 
1026 
1027 bool
1029  if (myOSMEdges.find(ref) != myOSMEdges.end()) {
1030  return true;
1031  } else {
1032  WRITE_WARNING("No way found for reference '" + toString(ref) + "' in relation '" + toString(myCurrentRelation) + "'");
1033  return false;
1034  }
1035 }
1036 
1037 
1038 void
1040  myParentElements.pop_back();
1041  if (element == SUMO_TAG_RELATION) {
1042  if (myIsRestriction) {
1043  assert(myCurrentRelation != INVALID_ID);
1044  bool ok = true;
1046  WRITE_WARNING("Ignoring restriction relation '" + toString(myCurrentRelation) + "' with unknown type.");
1047  ok = false;
1048  }
1049  if (myFromWay == INVALID_ID) {
1050  WRITE_WARNING("Ignoring restriction relation '" + toString(myCurrentRelation) + "' with unknown from-way.");
1051  ok = false;
1052  }
1053  if (myToWay == INVALID_ID) {
1054  WRITE_WARNING("Ignoring restriction relation '" + toString(myCurrentRelation) + "' with unknown to-way.");
1055  ok = false;
1056  }
1057  if (myViaNode == INVALID_ID && myViaWay == INVALID_ID) {
1058  WRITE_WARNING("Ignoring restriction relation '" + toString(myCurrentRelation) + "' with unknown via.");
1059  ok = false;
1060  }
1061  if (ok && !applyRestriction()) {
1062  WRITE_WARNING("Ignoring restriction relation '" + toString(myCurrentRelation) + "'.");
1063  }
1064  }
1065  // other relations might use similar subelements so reset in any case
1066  resetValues();
1067  }
1068 }
1069 
1070 
1071 bool
1073  // since OSM ways are bidirectional we need the via to figure out which direction was meant
1074  if (myViaNode != INVALID_ID) {
1075  NBNode* viaNode = myOSMNodes.find(myViaNode)->second->node;
1076  if (viaNode == 0) {
1077  WRITE_WARNING("Via-node '" + toString(myViaNode) + "' was not instantiated");
1078  return false;
1079  }
1080  NBEdge* from = findEdgeRef(myFromWay, viaNode->getIncomingEdges());
1081  NBEdge* to = findEdgeRef(myToWay, viaNode->getOutgoingEdges());
1082  if (from == 0) {
1083  WRITE_WARNING("from-edge of restriction relation could not be determined");
1084  return false;
1085  }
1086  if (to == 0) {
1087  WRITE_WARNING("to-edge of restriction relation could not be determined");
1088  return false;
1089  }
1091  from->addEdge2EdgeConnection(to);
1092  } else {
1093  from->removeFromConnections(to, -1, -1, true);
1094  }
1095  } else {
1096  // XXX interpreting via-ways or via-node lists not yet implemented
1097  WRITE_WARNING("direction of restriction relation could not be determined");
1098  return false;
1099  }
1100  return true;
1101 }
1102 
1103 
1104 NBEdge*
1105 NIImporter_OpenStreetMap::RelationHandler::findEdgeRef(long long int wayRef, const std::vector<NBEdge*>& candidates) const {
1106  const std::string prefix = toString(wayRef);
1107  const std::string backPrefix = "-" + prefix;
1108  NBEdge* result = 0;
1109  int found = 0;
1110  for (EdgeVector::const_iterator it = candidates.begin(); it != candidates.end(); ++it) {
1111  if (((*it)->getID().substr(0, prefix.size()) == prefix) ||
1112  ((*it)->getID().substr(0, backPrefix.size()) == backPrefix)) {
1113  result = *it;
1114  found++;
1115  }
1116  }
1117  if (found > 1) {
1118  WRITE_WARNING("Ambigous way reference '" + prefix + "' in restriction relation");
1119  result = 0;
1120  }
1121  return result;
1122 }
1123 
1124 
1125 void
1127  NBNodeCont& nc = nb.getNodeCont();
1128  NBEdgeCont& ec = nb.getEdgeCont();
1129  // reconstruct elevation from layer info
1130  // build a map of raising and lowering forces (attractor and distance)
1131  // for all nodes unknownElevation
1132  std::map<NBNode*, std::vector<std::pair<SUMOReal, SUMOReal> > > layerForces;
1133 
1134  // collect all nodes that belong to a way with layer information
1135  std::set<NBNode*> knownElevation;
1136  for (std::map<long long int, Edge*>::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
1137  Edge* e = (*i).second;
1138  if (e->myLayer != 0) {
1139  for (std::vector<long long int>::iterator j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
1140  NBNode* node = nc.retrieve(toString(*j));
1141  if (node != 0) {
1142  knownElevation.insert(node);
1143  layerForces[node].push_back(std::make_pair(e->myLayer * layerElevation, POSITION_EPS));
1144  }
1145  }
1146  }
1147  }
1148 #ifdef DEBUG_LAYER_ELEVATION
1149  std::cout << "known elevations:\n";
1150  for (std::set<NBNode*>::iterator it = knownElevation.begin(); it != knownElevation.end(); ++it) {
1151  const std::vector<std::pair<SUMOReal, SUMOReal> >& primaryLayers = layerForces[*it];
1152  std::cout << " node=" << (*it)->getID() << " ele=";
1153  for (std::vector<std::pair<SUMOReal, SUMOReal> >::const_iterator it_ele = primaryLayers.begin(); it_ele != primaryLayers.end(); ++it_ele) {
1154  std::cout << it_ele->first << " ";
1155  }
1156  std::cout << "\n";
1157  }
1158 #endif
1159  // layer data only provides a lower bound on elevation since it is used to
1160  // resolve the relation among overlapping ways.
1161  // Perform a sanity check for steep inclines and raise the knownElevation if necessary
1162  std::map<NBNode*, SUMOReal> knownEleMax;
1163  for (std::set<NBNode*>::iterator it = knownElevation.begin(); it != knownElevation.end(); ++it) {
1165  const std::vector<std::pair<SUMOReal, SUMOReal> >& primaryLayers = layerForces[*it];
1166  for (std::vector<std::pair<SUMOReal, SUMOReal> >::const_iterator it_ele = primaryLayers.begin(); it_ele != primaryLayers.end(); ++it_ele) {
1167  eleMax = MAX2(eleMax, it_ele->first);
1168  }
1169  knownEleMax[*it] = eleMax;
1170  }
1171  const SUMOReal gradeThreshold = OptionsCont::getOptions().getFloat("osm.layer-elevation.max-grade") / 100;
1172  bool changed = true;
1173  while (changed) {
1174  changed = false;
1175  for (std::set<NBNode*>::iterator it = knownElevation.begin(); it != knownElevation.end(); ++it) {
1176  std::map<NBNode*, std::pair<SUMOReal, SUMOReal> > neighbors = getNeighboringNodes(*it, knownEleMax[*it] / gradeThreshold * 3, knownElevation);
1177  for (std::map<NBNode*, std::pair<SUMOReal, SUMOReal> >::iterator it_neigh = neighbors.begin(); it_neigh != neighbors.end(); ++it_neigh) {
1178  if (knownElevation.count(it_neigh->first) != 0) {
1179  const SUMOReal grade = fabs(knownEleMax[*it] - knownEleMax[it_neigh->first]) / MAX2(POSITION_EPS, it_neigh->second.first);
1180 #ifdef DEBUG_LAYER_ELEVATION
1181  std::cout << " grade at node=" << (*it)->getID() << " ele=" << knownEleMax[*it] << " neigh=" << it_neigh->first->getID() << " neighEle=" << knownEleMax[it_neigh->first] << " grade=" << grade << " dist=" << it_neigh->second.first << " speed=" << it_neigh->second.second << "\n";
1182 #endif
1183  if (grade > gradeThreshold * 50 / 3.6 / it_neigh->second.second) {
1184  // raise the lower node to the higher level
1185  const SUMOReal eleMax = MAX2(knownEleMax[*it], knownEleMax[it_neigh->first]);
1186  if (knownEleMax[*it] < eleMax) {
1187  knownEleMax[*it] = eleMax;
1188  } else {
1189  knownEleMax[it_neigh->first] = eleMax;
1190  }
1191  changed = true;
1192  }
1193  }
1194  }
1195  }
1196  }
1197 
1198  // collect all nodes within a grade-dependent range around knownElevation-nodes and apply knowElevation forces
1199  std::set<NBNode*> unknownElevation;
1200  for (std::set<NBNode*>::iterator it = knownElevation.begin(); it != knownElevation.end(); ++it) {
1201  const SUMOReal eleMax = knownEleMax[*it];
1202  const SUMOReal maxDist = fabs(eleMax) * 100 / layerElevation;
1203  std::map<NBNode*, std::pair<SUMOReal, SUMOReal> > neighbors = getNeighboringNodes(*it, maxDist, knownElevation);
1204  for (std::map<NBNode*, std::pair<SUMOReal, SUMOReal> >::iterator it_neigh = neighbors.begin(); it_neigh != neighbors.end(); ++it_neigh) {
1205  if (knownElevation.count(it_neigh->first) == 0) {
1206  unknownElevation.insert(it_neigh->first);
1207  layerForces[it_neigh->first].push_back(std::make_pair(eleMax, it_neigh->second.first));
1208  }
1209  }
1210  }
1211 
1212  // apply forces to ground-level nodes (neither in knownElevation nor unknownElevation)
1213  for (std::set<NBNode*>::iterator it = unknownElevation.begin(); it != unknownElevation.end(); ++it) {
1215  const std::vector<std::pair<SUMOReal, SUMOReal> >& primaryLayers = layerForces[*it];
1216  for (std::vector<std::pair<SUMOReal, SUMOReal> >::const_iterator it_ele = primaryLayers.begin(); it_ele != primaryLayers.end(); ++it_ele) {
1217  eleMax = MAX2(eleMax, it_ele->first);
1218  }
1219  const SUMOReal maxDist = fabs(eleMax) * 100 / layerElevation;
1220  std::map<NBNode*, std::pair<SUMOReal, SUMOReal> > neighbors = getNeighboringNodes(*it, maxDist, knownElevation);
1221  for (std::map<NBNode*, std::pair<SUMOReal, SUMOReal> >::iterator it_neigh = neighbors.begin(); it_neigh != neighbors.end(); ++it_neigh) {
1222  if (knownElevation.count(it_neigh->first) == 0 && unknownElevation.count(it_neigh->first) == 0) {
1223  layerForces[*it].push_back(std::make_pair(0, it_neigh->second.first));
1224  }
1225  }
1226  }
1227  // compute the elevation for each node as the weighted average of all forces
1228 #ifdef DEBUG_LAYER_ELEVATION
1229  std::cout << "summation of forces\n";
1230 #endif
1231  std::map<NBNode*, SUMOReal> nodeElevation;
1232  for (std::map<NBNode*, std::vector<std::pair<SUMOReal, SUMOReal> > >::iterator it = layerForces.begin(); it != layerForces.end(); ++it) {
1233  const std::vector<std::pair<SUMOReal, SUMOReal> >& forces = it->second;
1234  if (knownElevation.count(it->first) != 0) {
1235  // use the maximum value
1236  /*
1237  SUMOReal eleMax = -std::numeric_limits<SUMOReal>::max();
1238  for (std::vector<std::pair<SUMOReal, SUMOReal> >::const_iterator it_force = forces.begin(); it_force != forces.end(); ++it_force) {
1239  eleMax = MAX2(eleMax, it_force->first);
1240  }
1241  */
1242 #ifdef DEBUG_LAYER_ELEVATION
1243  std::cout << " node=" << it->first->getID() << " knownElevation=" << knownEleMax[it->first] << "\n";
1244 #endif
1245  nodeElevation[it->first] = knownEleMax[it->first];
1246  } else if (forces.size() == 1) {
1247  nodeElevation[it->first] = forces.front().first;
1248  } else {
1249  // use the weighted sum
1250  SUMOReal distSum = 0;
1251  for (std::vector<std::pair<SUMOReal, SUMOReal> >::const_iterator it_force = forces.begin(); it_force != forces.end(); ++it_force) {
1252  distSum += it_force->second;
1253  }
1254  SUMOReal weightSum = 0;
1255  SUMOReal elevation = 0;
1256 #ifdef DEBUG_LAYER_ELEVATION
1257  std::cout << " node=" << it->first->getID() << " distSum=" << distSum << "\n";
1258 #endif
1259  for (std::vector<std::pair<SUMOReal, SUMOReal> >::const_iterator it_force = forces.begin(); it_force != forces.end(); ++it_force) {
1260  const SUMOReal weight = (distSum - it_force->second) / distSum;
1261  weightSum += weight;
1262  elevation += it_force->first * weight;
1263 
1264 #ifdef DEBUG_LAYER_ELEVATION
1265  std::cout << " force=" << it_force->first << " dist=" << it_force->second << " weight=" << weight << " ele=" << elevation << "\n";
1266 #endif
1267  }
1268  nodeElevation[it->first] = elevation / weightSum;
1269  }
1270  }
1271 #ifdef DEBUG_LAYER_ELEVATION
1272  std::cout << "final elevations:\n";
1273  for (std::map<NBNode*, SUMOReal>::iterator it = nodeElevation.begin(); it != nodeElevation.end(); ++it) {
1274  std::cout << " node=" << (it->first)->getID() << " ele=" << it->second << "\n";;
1275  }
1276 #endif
1277  // apply node elevations
1278  for (std::map<NBNode*, SUMOReal>::iterator it = nodeElevation.begin(); it != nodeElevation.end(); ++it) {
1279  NBNode* n = it->first;
1280  Position pos = n->getPosition();
1281  n->reinit(n->getPosition() + Position(0, 0, it->second), n->getType());
1282  }
1283 
1284  // apply way elevation to all edges that had layer information
1285  for (std::map<std::string, NBEdge*>::const_iterator it = ec.begin(); it != ec.end(); ++it) {
1286  NBEdge* edge = it->second;
1287  const PositionVector& geom = edge->getGeometry();
1288  const SUMOReal length = geom.length2D();
1289  const SUMOReal zFrom = nodeElevation[edge->getFromNode()];
1290  const SUMOReal zTo = nodeElevation[edge->getToNode()];
1291  // XXX if the from- or to-node was part of multiple ways with
1292  // different layers, reconstruct the layer value from origID
1293  SUMOReal dist = 0;
1294  PositionVector newGeom;
1295  for (PositionVector::const_iterator it_pos = geom.begin(); it_pos != geom.end(); ++it_pos) {
1296  if (it_pos != geom.begin()) {
1297  dist += (*it_pos).distanceTo2D(*(it_pos - 1));
1298  }
1299  newGeom.push_back((*it_pos) + Position(0, 0, zFrom + (zTo - zFrom) * dist / length));
1300  }
1301  edge->setGeometry(newGeom);
1302  }
1303 }
1304 
1305 
1306 std::map<NBNode*, std::pair<SUMOReal, SUMOReal> >
1307 NIImporter_OpenStreetMap::getNeighboringNodes(NBNode* node, SUMOReal maxDist, const std::set<NBNode*>& knownElevation) {
1308  std::map<NBNode*, std::pair<SUMOReal, SUMOReal> > result;
1309  std::set<NBNode*> visited;
1310  std::vector<NBNode*> open;
1311  open.push_back(node);
1312  while (open.size() > 0) {
1313  NBNode* n = open.back();
1314  open.pop_back();
1315  if (visited.count(n) != 0) {
1316  continue;
1317  }
1318  visited.insert(n);
1319  const EdgeVector& edges = n->getEdges();
1320  for (EdgeVector::const_iterator j = edges.begin(); j != edges.end(); ++j) {
1321  NBEdge* e = *j;
1322  NBNode* s = 0;
1323  if (n->hasIncoming(e)) {
1324  s = e->getFromNode();
1325  } else {
1326  s = e->getToNode();
1327  }
1328  const SUMOReal dist = result[n].first + e->getGeometry().length2D();
1329  const SUMOReal speed = MAX2(e->getSpeed(), result[n].second);
1330  if (result.count(s) == 0) {
1331  result[s] = std::make_pair(dist, speed);
1332  } else {
1333  result[s] = std::make_pair(MIN2(dist, result[s].first), MAX2(speed, result[s].second));
1334  }
1335  if (dist < maxDist && knownElevation.count(s) == 0) {
1336  open.push_back(s);
1337  }
1338  }
1339  }
1340  return result;
1341 }
1342 
1343 
1344 /****************************************************************************/
1345 
const std::map< long long int, NIOSMNode * > & myOSMNodes
The previously parsed nodes.
const SUMOReal lat
The latitude the node is located at.
void reconstructLayerElevation(SUMOReal layerElevation, NBNetBuilder &nb)
reconstruct elevation from layer info
An internal definition of a loaded edge.
const bool myImportElevation
whether elevation data should be imported
const std::map< long long int, Edge * > & myOSMEdges
The previously parsed edges.
An internal representation of an OSM-node.
std::vector< std::string > getStringVector(const std::string &name) const
Returns the list of string-vector-value of the named option (only for Option_String) ...
const EdgeVector & getIncomingEdges() const
Returns this node&#39;s incoming edges (The edges which yield in this node)
Definition: NBNode.h:240
const long long int id
The edge&#39;s id.
static const SUMOReal UNSPECIFIED_WIDTH
unspecified lane width
Definition: NBEdge.h:244
std::string streetName
The edge&#39;s street name.
NBTypeCont & getTypeCont()
Returns a reference to the type container.
Definition: NBNetBuilder.h:154
const SUMOReal SUMO_const_laneWidth
Definition: StdDefs.h:48
static bool transformCoordinate(Position &from, bool includeInBoundary=true, GeoConvHelper *from_srs=0)
transforms loaded coordinates handles projections, offsets (using GeoConvHelper) and import of height...
std::string next()
const std::map< long long int, NIOSMNode * > & myOSMNodes
The previously parsed nodes.
void myStartElement(int element, const SUMOSAXAttributes &attrs)
Called on the opening of a tag;.
const long long int id
The node&#39;s id.
static bool isReadable(std::string path)
Checks whether the given file is readable.
Definition: FileHelpers.cpp:58
static bool endsWith(const std::string &str, const std::string suffix)
Checks whether a given string ends with the suffix.
WayType myBuswayType
Information about the kind of busway along this road.
static SUMOReal _2SUMOReal(const E *const data)
converts a char-type array into the SUMOReal value described by it
Definition: TplConvert.h:297
long long int myFromWay
the origination way for the current restriction
A container for traffic light definitions and built programs.
void reinit(const Position &position, SumoXMLNodeType type, bool updateEdgeGeometries=false)
Resets initial values.
Definition: NBNode.cpp:266
bool applyRestriction() const
try to apply the parsed restriction and return whether successful
void addSidewalk(SUMOReal width)
add a pedestrian sidewalk of the given width and shift existing connctions
Definition: NBEdge.cpp:2861
vehicle is a bicycle
void myEndElement(int element)
Called when a closing tag occurs.
int SVCPermissions
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
The representation of a single edge during network building.
Definition: NBEdge.h:71
void myStartElement(int element, const SUMOSAXAttributes &attrs)
Called on the opening of a tag;.
bool getIsOneWay(const std::string &type) const
Returns whether edges are one-way per default for the given type.
Definition: NBTypeCont.cpp:197
long long int myCurrentRelation
The currently parsed relation.
T MAX2(T a, T b)
Definition: StdDefs.h:70
void setPermissions(SVCPermissions permissions, int lane=-1)
set allowed/disallowed classes for the given lane or for all lanes if -1 is given ...
Definition: NBEdge.cpp:2735
static bool transformCoordinates(PositionVector &from, bool includeInBoundary=true, GeoConvHelper *from_srs=0)
SUMOReal getFloat(const std::string &name) const
Returns the SUMOReal-value of the named option (only for Option_Float)
void myEndElement(int element)
Called when a closing tag occurs.
static const SUMOReal UNSPECIFIED_OFFSET
unspecified lane offset
Definition: NBEdge.h:247
SAX-handler base for SUMO-files.
static bool runParser(GenericSAXHandler &handler, const std::string &file, const bool isNet=false)
Runs the given handler on the given file; returns if everything&#39;s ok.
Definition: XMLSubSys.cpp:114
bool hasIncoming(const NBEdge *const e) const
Returns whether the given edge ends at this node.
Definition: NBNode.cpp:1222
std::vector< long long int > myCurrentNodes
The list of nodes this edge is made of.
void setGeometry(const PositionVector &g, bool inner=false)
(Re)sets the edge&#39;s geometry
Definition: NBEdge.cpp:499
SUMOReal getWidth(const std::string &type) const
Returns the lane width for the given type [m].
Definition: NBTypeCont.cpp:221
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:200
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:69
SUMOReal ele
The elevation of this node.
std::set< NIOSMNode *, CompareNodes > & myUniqueNodes
the set of unique nodes (used for duplicate detection/substitution)
NBNode * node
the NBNode that was instantiated
PositionVector reverse() const
reverse position vector
static const SUMOReal MAXSPEED_UNGIVEN
SUMOReal getSidewalkWidth(const std::string &type) const
Returns the lane width for a sidewalk to be added [m].
Definition: NBTypeCont.cpp:227
virtual std::string getStringSecure(int id, const std::string &def) const =0
Returns the string-value of the named (by its enum-value) attribute.
static void loadNetwork(const OptionsCont &oc, NBNetBuilder &nb)
Loads content of the optionally given OSM file.
Functor which compares two Edges.
WayType myCyclewayType
Information about the kind of cycleway along this road.
const EdgeVector & getOutgoingEdges() const
Returns this node&#39;s outgoing edges (The edges which start at this node)
Definition: NBNode.h:245
const std::string & getID() const
Returns the id.
Definition: Named.h:66
SUMOReal length2D() const
Returns the length.
int myNoLanesForward
number of lanes in forward direction or 0 if unknown, negative if backwards lanes are meant ...
bool addEdge2EdgeConnection(NBEdge *dest)
Adds a connection to another edge.
Definition: NBEdge.cpp:802
const Position & getPosition() const
Definition: NBNode.h:232
RelationHandler(const std::map< long long int, NIOSMNode * > &osmNodes, const std::map< long long int, Edge * > &osmEdges)
Constructor.
#define max(a, b)
Definition: polyfonts.c:65
void load(const OptionsCont &oc, NBNetBuilder &nb)
SUMOReal getSpeed(const std::string &type) const
Returns the maximal velocity for the given type [m/s].
Definition: NBTypeCont.cpp:185
static bool startsWith(const std::string &str, const std::string prefix)
Checks whether a given string starts with the prefix.
void setFileName(const std::string &name)
Sets the current file name.
SUMOReal getBikeLaneWidth(const std::string &type) const
Returns the lane width for a bike lane to be added [m].
Definition: NBTypeCont.cpp:233
std::map< std::string, NBEdge * >::const_iterator end() const
Returns the pointer to the end of the stored edges.
Definition: NBEdgeCont.h:198
A class which extracts OSM-edges from a parsed OSM-file.
int insertEdge(Edge *e, int index, NBNode *from, NBNode *to, const std::vector< long long int > &passed, NBNetBuilder &nb)
Builds an NBEdge.
bool insert(NBEdge *edge, bool ignorePrunning=false)
Adds an edge to the dictionary.
Definition: NBEdgeCont.cpp:162
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:55
std::vector< int > myParentElements
The element stack.
Encapsulated SAX-Attributes.
static StringBijection< TrafficLightType > TrafficLightTypes
traffic light types
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:46
int getNumLanes(const std::string &type) const
Returns the number of lanes for the given type.
Definition: NBTypeCont.cpp:179
NBEdgeCont & getEdgeCont()
Definition: NBNetBuilder.h:144
A list of positions.
SumoXMLNodeType getType() const
Returns the type of this node.
Definition: NBNode.h:257
int getPriority(const std::string &type) const
Returns the priority for the given type.
Definition: NBTypeCont.cpp:191
void myEndElement(int element)
Called when a closing tag occurs.
const EdgeVector & getEdges() const
Returns all edges which participate in this node (Edges that start or end at this node) ...
Definition: NBNode.h:250
Storage for edges, including some functionality operating on multiple edges.
Definition: NBEdgeCont.h:66
T MIN2(T a, T b)
Definition: StdDefs.h:64
#define PROGRESS_BEGIN_MESSAGE(msg)
Definition: MsgHandler.h:202
#define POSITION_EPS
Definition: config.h:182
long long int myLastNodeID
ID of the currently parsed node, for reporting mainly.
NodesHandler(std::map< long long int, NIOSMNode * > &toFill, std::set< NIOSMNode *, CompareNodes > &uniqueNodes, bool importElevation)
Contructor.
std::map< long long int, NIOSMNode * > & myToFill
The nodes container to fill.
bool myIsRestriction
whether the currently parsed relation is a restriction
bool knows(const std::string &type) const
Returns whether the named type is in the container.
Definition: NBTypeCont.cpp:79
void removeFromConnections(NBEdge *toEdge, int fromLane=-1, int toLane=-1, bool tryLater=false)
Removes the specified connection(s)
Definition: NBEdge.cpp:1100
static std::string escapeXML(const std::string &orig, const bool maskDoubleHyphen=false)
Replaces the standard escapes by their XML entities.
bool railwayCrossing
Whether this is a railway crossing.
void myStartElement(int element, const SUMOSAXAttributes &attrs)
Called on the opening of a tag;.
double myMaxSpeed
maximum speed in km/h, or MAXSPEED_UNGIVEN
virtual bool hasAttribute(int id) const =0
Returns the information whether the named (by its enum-value) attribute is within the current list...
void insert(const std::string &id, int numLanes, SUMOReal maxSpeed, int prio, SVCPermissions permissions, SUMOReal width, bool oneWayIsDefault, SUMOReal sidewalkWidth, SUMOReal bikeLaneWidth)
Adds a type into the list.
Definition: NBTypeCont.cpp:65
bool checkEdgeRef(long long int ref) const
check whether a referenced way has a corresponding edge
bool myIsInValidNodeTag
Hierarchy helper for parsing a node&#39;s tags.
std::map< long long int, Edge * > myEdges
the map from OSM way ids to edge objects
std::vector< std::string > getVector()
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:206
std::map< std::string, NBEdge * >::const_iterator begin() const
Returns the pointer to the begin of the stored edges.
Definition: NBEdgeCont.h:190
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:2763
void addParameter(const std::string &key, const std::string &value)
Adds a parameter.
int myNoLanes
number of lanes, or -1 if unknown
vehicle is a bus
void addBikeLane(SUMOReal width)
add a bicycle lane of the given width and shift existing connctions
Definition: NBEdge.cpp:2873
static std::string to_lower_case(std::string str)
Transfers the content to lower case.
Definition: StringUtils.cpp:67
static int _2int(const E *const data)
converts a char-type array into the integer value described by it
Definition: TplConvert.h:149
bool tlsControlled
Whether this is a tls controlled junction.
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:423
std::map< std::string, std::string > myKnownCompoundTypes
The compound types that have already been mapped to other known types.
static std::string prune(const std::string &str)
Removes trailing and leading whitechars.
Definition: StringUtils.cpp:56
EdgesHandler(const std::map< long long int, NIOSMNode * > &osmNodes, std::map< long long int, Edge * > &toFill)
Constructor.
std::map< long long int, Edge * > & myEdgeMap
A map of built edges.
const SUMOReal lon
The longitude the node is located at.
NBNodeCont & getNodeCont()
Returns a reference to the node container.
Definition: NBNetBuilder.h:149
long long int myToWay
the destination way for the current restriction
int myLayer
Information about the relative z-ordering of ways.
Instance responsible for building networks.
Definition: NBNetBuilder.h:112
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition: NBCont.h:41
bool getShallBeDiscarded(const std::string &type) const
Returns the information whether edges of this type shall be discarded.
Definition: NBTypeCont.cpp:203
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition: NBEdge.h:584
static const std::string compoundTypeSeparator
The separator within newly created compound type names.
std::map< std::string, SUMOReal > mySpeedMap
A map of non-numeric speed descriptions to their numeric values.
alternative definition for junction
A storage for options typed value containers)
Definition: OptionsCont.h:99
long long int myViaNode
the via node/way for the current restriction
std::string joinToStringSorting(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:204
bool copyRestrictionsAndAttrs(const std::string &fromId, const std::string &toId)
Copy restrictions to a type.
Definition: NBTypeCont.cpp:118
bool insert(const std::string &id, const Position &position, NBDistrict *district=0)
Inserts a node into the map.
Definition: NBNodeCont.cpp:81
NBTrafficLightLogicCont & getTLLogicCont()
Returns a reference to the traffic light logics container.
Definition: NBNetBuilder.h:159
LaneSpreadFunction
Numbers representing special SUMO-XML-attribute values Information how the edge&#39;s lateral offset shal...
NBEdge * findEdgeRef(long long int wayRef, const std::vector< NBEdge * > &candidates) const
try to find the way segment among candidates
A class which extracts OSM-nodes from a parsed OSM-file.
Represents a single node (junction) during network building.
Definition: NBNode.h:75
void resetValues()
reset members to their defaults for parsing a new relation
NBNode * insertNodeChecking(long long int id, NBNodeCont &nc, NBTrafficLightLogicCont &tlsc)
Builds an NBNode.
T get(const std::string &str) const
int myHierarchyLevel
The current hierarchy level.
std::string myHighWayType
The type, stored in "highway" key.
bool insert(NBTrafficLightDefinition *logic, bool forceInsert=false)
Adds a logic definition to the dictionary.
Importer for networks stored in OpenStreetMap format.
static const long long int INVALID_ID
#define SUMOReal
Definition: config.h:208
bool myCurrentIsRoad
Information whether this is a road.
bool operator()(const Edge *e1, const Edge *e2) const
Edge * myCurrentEdge
The currently built edge.
std::set< std::string > myUnusableTypes
The compounds types that do not contain known types.
NBNode * retrieve(const std::string &id) const
Returns the node with the given name.
Definition: NBNodeCont.cpp:110
SVCPermissions getPermissions(const std::string &type) const
Returns allowed vehicle classes for the given type.
Definition: NBTypeCont.cpp:215
SUMOReal getSpeed() const
Returns the speed allowed on this edge.
Definition: NBEdge.h:496
Container for nodes during the netbuilding process.
Definition: NBNodeCont.h:63
T get(int attr, const char *objectid, bool &ok, bool report=true) const
Tries to read given attribute assuming it is an int.
#define PROGRESS_DONE_MESSAGE()
Definition: MsgHandler.h:203
std::map< long long int, NIOSMNode * > myOSMNodes
the map from OSM node ids to actual nodes
A traffic light logics which must be computed (only nodes/edges are given)
Definition: NBOwnTLDef.h:54
std::vector< int > myParentElements
The element stack.
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:201
std::set< NIOSMNode *, CompareNodes > myUniqueNodes
the set of unique nodes used in NodesHandler, used when freeing memory
std::map< NBNode *, std::pair< SUMOReal, SUMOReal > > getNeighboringNodes(NBNode *node, SUMOReal maxDist, const std::set< NBNode * > &knownElevation)
collect neighboring nodes with their road distance and maximum between-speed. Search does not continu...
A class which extracts relevant relation information from a parsed OSM-file.
std::string myIsOneWay
Information whether this is an one-way road.
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:188
TrafficLightType
A storage for available types of edges.
Definition: NBTypeCont.h:62
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:416