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