SUMO - Simulation of Urban MObility
NIImporter_OpenStreetMap.cpp
Go to the documentation of this file.
1 /*************************************************OC***************************/
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 <netbuild/NBPTLine.h>
59 #include <netbuild/NBPTLineCont.h>
60 #include "NILoader.h"
62 
63 //#define DEBUG_LAYER_ELEVATION
64 
65 // ---------------------------------------------------------------------------
66 // static members
67 // ---------------------------------------------------------------------------
69 
71 
72 // ===========================================================================
73 // Private classes
74 // ===========================================================================
75 
79 public:
80  bool operator()(const Edge* e1, const Edge* e2) const {
81  if (e1->myHighWayType != e2->myHighWayType) {
82  return e1->myHighWayType > e2->myHighWayType;
83  }
84  if (e1->myNoLanes != e2->myNoLanes) {
85  return e1->myNoLanes > e2->myNoLanes;
86  }
87  if (e1->myNoLanesForward != e2->myNoLanesForward) {
88  return e1->myNoLanesForward > e2->myNoLanesForward;
89  }
90  if (e1->myMaxSpeed != e2->myMaxSpeed) {
91  return e1->myMaxSpeed > e2->myMaxSpeed;
92  }
93  if (e1->myIsOneWay != e2->myIsOneWay) {
94  return e1->myIsOneWay > e2->myIsOneWay;
95  }
96  return e1->myCurrentNodes > e2->myCurrentNodes;
97  }
98 };
99 
100 // ===========================================================================
101 // method definitions
102 // ===========================================================================
103 // ---------------------------------------------------------------------------
104 // static methods
105 // ---------------------------------------------------------------------------
106 const std::string NIImporter_OpenStreetMap::compoundTypeSeparator("|"); //clang-tidy says: "compundTypeSeparator with
107 // static storage duration my throw an exception that cannot be caught
108 
109 void
111  NIImporter_OpenStreetMap importer;
112  importer.load(oc, nb);
113 }
114 
116 
118  // delete nodes
119  for (auto myUniqueNode : myUniqueNodes) {
120  delete myUniqueNode;
121  }
122  // delete edges
123  for (auto& myEdge : myEdges) {
124  delete myEdge.second;
125  }
126  // delete platform shapes
127  for (auto& myPlatformShape : myPlatformShapes) {
128  delete myPlatformShape.second;
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);
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
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 (auto 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();
194  j != e->myCurrentNodes.end();
195  ++j) {
196  if (nodeUsage.find(*j) == nodeUsage.end()) {
197  nodeUsage[*j] = 0;
198  }
199  nodeUsage[*j] = nodeUsage[*j] + 1;
200  }
201  }
202  // Mark which nodes are used by traffic lights
203  for (std::map<long long int, NIOSMNode*>::const_iterator nodesIt = myOSMNodes.begin();
204  nodesIt != myOSMNodes.end();
205  ++nodesIt) {
206  if (nodesIt->second->tlsControlled /* || nodesIt->second->railwayCrossing*/) {
207  // If the key is not found in the map, the value is automatically
208  // initialized with 0.
209  nodeUsage[nodesIt->first] += 1;
210  }
211  }
212 
213  /* Instantiate edges
214  * Only those nodes in the middle of an edge which are used by more than
215  * one edge are instantiated. Other nodes are considered as geometry nodes. */
216  NBNodeCont& nc = nb.getNodeCont();
218  for (auto& myEdge : myEdges) {
219  Edge* e = myEdge.second;
220  assert(e->myCurrentIsRoad);
221  if (e->myCurrentNodes.size() < 2) {
222  WRITE_WARNING("Discarding way '" + toString(e->id) + "' because it has only " +
223  toString(e->myCurrentNodes.size()) + " node(s)");
224  continue;
225  }
226  // build nodes;
227  // - the from- and to-nodes must be built in any case
228  // - the in-between nodes are only built if more than one edge references them
229  NBNode* currentFrom = insertNodeChecking(*e->myCurrentNodes.begin(), nc, tlsc);
230  NBNode* last = insertNodeChecking(*(e->myCurrentNodes.end() - 1), nc, tlsc);
231  int running = 0;
232  std::vector<long long int> passed;
233  for (auto j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
234  passed.push_back(*j);
235  if (nodeUsage[*j] > 1 && j != e->myCurrentNodes.end() - 1 && j != e->myCurrentNodes.begin()) {
236  NBNode* currentTo = insertNodeChecking(*j, nc, tlsc);
237  running = insertEdge(e, running, currentFrom, currentTo, passed, nb);
238  currentFrom = currentTo;
239  passed.clear();
240  passed.push_back(*j);
241  }
242  }
243  if (running == 0) {
244  running = -1;
245  }
246  insertEdge(e, running, currentFrom, last, passed, nb);
247  }
248 
249  const double layerElevation = oc.getFloat("osm.layer-elevation");
250  if (layerElevation > 0) {
251  reconstructLayerElevation(layerElevation, nb);
252  }
253 
254  //revise pt stops; remove stops on deleted edges
255  if (OptionsCont::getOptions().isSet("ptstop-output")) {
257  }
258 
259  // load relations (after edges are built since we want to apply
260  // turn-restrictions directly to NBEdges)
261  RelationHandler relationHandler(myOSMNodes, myEdges, &(nb.getPTStopCont()), myPlatformShapes,
262  &(nb.getPTLineCont()), oc);
263  for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
264  // relations
265  relationHandler.setFileName(*file);
266  PROGRESS_BEGIN_MESSAGE("Parsing relations from osm-file '" + *file + "'");
267  XMLSubSys::runParser(relationHandler, *file);
269  }
270 }
271 
272 NBNode*
274  NBNode* node = nc.retrieve(toString(id));
275  if (node == 0) {
276  NIOSMNode* n = myOSMNodes.find(id)->second;
277  Position pos(n->lon, n->lat, n->ele);
278  if (!NBNetBuilder::transformCoordinate(pos, true)) {
279  WRITE_ERROR("Unable to project coordinates for junction '" + toString(id) + "'.");
280  return 0;
281  }
282  node = new NBNode(toString(id), pos);
283  if (!nc.insert(node)) {
284  WRITE_ERROR("Could not insert junction '" + toString(id) + "'.");
285  delete node;
286  return 0;
287  }
288  n->node = node;
289  if (n->railwayCrossing) {
290  node->reinit(pos, NODETYPE_RAIL_CROSSING);
291  } else if (n->tlsControlled) {
292  // ok, this node is a traffic light node where no other nodes
293  // participate
294  // @note: The OSM-community has not settled on a schema for differentiating between fixed and actuated lights
296  OptionsCont::getOptions().getString("tls.default-type"));
297  NBOwnTLDef* tlDef = new NBOwnTLDef(toString(id), node, 0, type);
298  if (!tlsc.insert(tlDef)) {
299  // actually, nothing should fail here
300  delete tlDef;
301  throw ProcessError("Could not allocate tls '" + toString(id) + "'.");
302  }
303  }
304  }
305  return node;
306 }
307 
308 int
310  const std::vector<long long int>& passed, NBNetBuilder& nb) {
311  NBNodeCont& nc = nb.getNodeCont();
312  NBEdgeCont& ec = nb.getEdgeCont();
313  NBTypeCont& tc = nb.getTypeCont();
314  NBPTStopCont& sc = nb.getPTStopCont();
315 
317  // patch the id
318  std::string id = toString(e->id);
319  if (from == 0 || to == 0) {
320  WRITE_ERROR("Discarding edge '" + id + "' because the nodes could not be built.");
321  return index;
322  }
323  if (index >= 0) {
324  id = id + "#" + toString(index);
325  } else {
326  index = 0;
327  }
328  if (from == to) {
329  assert(passed.size() >= 2);
330  if (passed.size() == 2) {
331  WRITE_WARNING("Discarding edge '" + id + "' which connects two identical nodes without geometry.");
332  return index;
333  }
334  // in the special case of a looped way split again using passed
335  int intermediateIndex = (int) passed.size() / 2;
336  NBNode* intermediate = insertNodeChecking(passed[intermediateIndex], nc, tlsc);
337  std::vector<long long int> part1(passed.begin(), passed.begin() + intermediateIndex + 1);
338  std::vector<long long int> part2(passed.begin() + intermediateIndex, passed.end());
339  index = insertEdge(e, index, from, intermediate, part1, nb);
340  return insertEdge(e, index, intermediate, to, part2, nb);
341  }
342  const int newIndex = index + 1;
343 
344  // convert the shape
345  PositionVector shape;
346  for (long long i : passed) {
347  NIOSMNode* n = myOSMNodes.find(i)->second;
348 
349  if (n->ptStopPosition) {
350  NBPTStop* existingPtStop = sc.get(toString(n->id));
351  if (existingPtStop != nullptr) {
352  existingPtStop->registerAdditionalEdge(toString(e->id), id);
353  } else {
354  Position ptPos(n->lon, n->lat, n->ele);
355  if (!NBNetBuilder::transformCoordinate(ptPos)) {
356  WRITE_ERROR("Unable to project coordinates for node '" + toString(n->id) + "'.");
357  }
358  NBPTStop* ptStop = new NBPTStop(toString(n->id), ptPos, id, toString(e->id), n->ptStopLength, n->name,
359  n->permissions);
360 
361  sc.insert(ptStop);
362  }
363  }
364  Position pos(n->lon, n->lat, n->ele);
365  shape.push_back(pos);
366  }
368  WRITE_ERROR("Unable to project coordinates for edge '" + id + "'.");
369  }
370 // shape.in
371 
372  std::string type = e->myHighWayType;
373  if (!tc.knows(type)) {
374  if (myUnusableTypes.count(type) > 0) {
375  return newIndex;
376  }
377  if (myKnownCompoundTypes.count(type) > 0) {
378  type = myKnownCompoundTypes[type];
379  } else {
380  // this edge has a type which does not yet exist in the TypeContainer
382  std::vector<std::string> types;
383  while (tok.hasNext()) {
384  std::string t = tok.next();
385  if (tc.knows(t)) {
386  if (std::find(types.begin(), types.end(), t) == types.end()) {
387  types.push_back(t);
388  }
389  } else if (tok.size() > 1) {
391  "Discarding unknown compound '" + t + "' in type '" + type + "' (first occurence for edge '"
392  + id
393  + "').");
394  }
395  }
396  if (types.empty()) {
397  WRITE_WARNING("Discarding unusable type '" + type + "' (first occurence for edge '" + id + "').");
398  myUnusableTypes.insert(type);
399  return newIndex;
400  }
401 
402  const std::string newType = joinToString(types, "|");
403  if (tc.knows(newType)) {
404  myKnownCompoundTypes[type] = newType;
405  type = newType;
406  } else if (myKnownCompoundTypes.count(newType) > 0) {
407  type = myKnownCompoundTypes[newType];
408  } else {
409  // build a new type by merging all values
410  int numLanes = 0;
411  double maxSpeed = 0;
412  int prio = 0;
413  double width = NBEdge::UNSPECIFIED_WIDTH;
414  double sidewalkWidth = NBEdge::UNSPECIFIED_WIDTH;
415  double bikelaneWidth = NBEdge::UNSPECIFIED_WIDTH;
416  bool defaultIsOneWay = false;
417  SVCPermissions permissions = 0;
418  bool discard = true;
419  for (auto& type2 : types) {
420  if (!tc.getShallBeDiscarded(type2)) {
421  numLanes = MAX2(numLanes, tc.getNumLanes(type2));
422  maxSpeed = MAX2(maxSpeed, tc.getSpeed(type2));
423  prio = MAX2(prio, tc.getPriority(type2));
424  defaultIsOneWay &= tc.getIsOneWay(type2);
425  permissions |= tc.getPermissions(type2);
426  width = MAX2(width, tc.getWidth(type2));
427  sidewalkWidth = MAX2(sidewalkWidth, tc.getSidewalkWidth(type2));
428  bikelaneWidth = MAX2(bikelaneWidth, tc.getBikeLaneWidth(type2));
429  discard = false;
430  }
431  }
432  if (width != NBEdge::UNSPECIFIED_WIDTH) {
433  width = MAX2(width, SUMO_const_laneWidth);
434  }
435  if (discard) {
437  "Discarding compound type '" + newType + "' (first occurence for edge '" + id + "').");
438  myUnusableTypes.insert(newType);
439  return newIndex;
440  }
441 
442  WRITE_MESSAGE("Adding new type '" + type + "' (first occurence for edge '" + id + "').");
443  tc.insert(newType, numLanes, maxSpeed, prio, permissions, width, defaultIsOneWay, sidewalkWidth,
444  bikelaneWidth);
445  for (auto& type3 : types) {
446  if (!tc.getShallBeDiscarded(type3)) {
447  tc.copyRestrictionsAndAttrs(type3, newType);
448  }
449  }
450  myKnownCompoundTypes[type] = newType;
451  type = newType;
452 
453  }
454 
455  }
456  }
457 
458  // otherwise it is not an edge and will be ignored
459  bool ok = true;
460  int numLanesForward = tc.getNumLanes(type);
461  int numLanesBackward = tc.getNumLanes(type);
462  double speed = tc.getSpeed(type);
463  bool defaultsToOneWay = tc.getIsOneWay(type);
464  SVCPermissions forwardPermissions = tc.getPermissions(type);
465  SVCPermissions backwardPermissions = tc.getPermissions(type);
466  double forwardWidth = tc.getWidth(type);
467  double backwardWidth = tc.getWidth(type);
468  const bool addSidewalk = (tc.getSidewalkWidth(type) != NBEdge::UNSPECIFIED_WIDTH);
469  const bool addBikeLane = (tc.getBikeLaneWidth(type) != NBEdge::UNSPECIFIED_WIDTH);
470  // check directions
471  bool addForward = true;
472  bool addBackward = true;
473  if (e->myIsOneWay == "true" || e->myIsOneWay == "yes" || e->myIsOneWay == "1"
474  || (defaultsToOneWay && e->myIsOneWay != "no" && e->myIsOneWay != "false" && e->myIsOneWay != "0" &&
475  e->getParameter("railway:preferred_direction", "") != "both")) {
476  addBackward = false;
477  }
478  if (e->myIsOneWay == "-1" || e->myIsOneWay == "reverse") {
479  // one-way in reversed direction of way
480  addForward = false;
481  addBackward = true;
482  }
483  if (!e->myIsOneWay.empty() && e->myIsOneWay != "false" && e->myIsOneWay != "no" && e->myIsOneWay != "true"
484  && e->myIsOneWay != "yes" && e->myIsOneWay != "-1" && e->myIsOneWay != "1" && e->myIsOneWay != "reverse") {
485  WRITE_WARNING("New value for oneway found: " + e->myIsOneWay);
486  }
487  // if we had been able to extract the number of lanes, override the highway type default
488  if (e->myNoLanes > 0) {
489  if (addForward && !addBackward) {
490  numLanesForward = e->myNoLanes;
491  } else if (!addForward && addBackward) {
492  numLanesBackward = e->myNoLanes;
493  } else {
494  if (e->myNoLanesForward > 0) {
495  numLanesForward = e->myNoLanesForward;
496  } else if (e->myNoLanesForward < 0) {
497  numLanesForward = e->myNoLanes + e->myNoLanesForward;
498  } else {
499  numLanesForward = (int) std::ceil(e->myNoLanes / 2.0);
500  }
501  numLanesBackward = e->myNoLanes - numLanesForward;
502  // sometimes ways are tagged according to their physical width of a single
503  // lane but they are intended for traffic in both directions
504  numLanesForward = MAX2(1, numLanesForward);
505  numLanesBackward = MAX2(1, numLanesBackward);
506  }
507  } else if (e->myNoLanes == 0) {
508  WRITE_WARNING("Skipping edge '" + id + "' because it has zero lanes.");
509  ok = false;
510  }
511  // if we had been able to extract the maximum speed, override the type's default
512  if (e->myMaxSpeed != MAXSPEED_UNGIVEN) {
513  speed = (double)(e->myMaxSpeed / 3.6);
514  }
515  if (speed <= 0) {
516  WRITE_WARNING("Skipping edge '" + id + "' because it has speed " + toString(speed));
517  ok = false;
518  }
519  // deal with cycleways that run in the opposite direction of a one-way street
520  if (addBikeLane) {
521  if (!addForward && (e->myCyclewayType & WAY_FORWARD) != 0) {
522  addForward = true;
523  forwardPermissions = SVC_BICYCLE;
524  forwardWidth = tc.getBikeLaneWidth(type);
525  numLanesForward = 1;
526  // do not add an additional cycle lane
527  e->myCyclewayType = (WayType)(e->myCyclewayType & !WAY_FORWARD); //clang tidy thinks "!WAY_FORWARD" is always false
528  }
529  if (!addBackward && (e->myCyclewayType & WAY_BACKWARD) != 0) {
530  addBackward = true;
531  backwardPermissions = SVC_BICYCLE;
532  backwardWidth = tc.getBikeLaneWidth(type);
533  numLanesBackward = 1;
534  // do not add an additional cycle lane
535  e->myCyclewayType = (WayType)(e->myCyclewayType & !WAY_BACKWARD); //clang tidy thinks "!WAY_BACKWARD" is always false
536  }
537  }
538  // deal with busways that run in the opposite direction of a one-way street
539  if (!addForward && (e->myBuswayType & WAY_FORWARD) != 0) {
540  addForward = true;
541  forwardPermissions = SVC_BUS;
542  numLanesForward = 1;
543  }
544  if (!addBackward && (e->myBuswayType & WAY_BACKWARD) != 0) {
545  addBackward = true;
546  backwardPermissions = SVC_BUS;
547  numLanesBackward = 1;
548  }
549 
550  if (ok) {
551  LaneSpreadFunction lsf = (addBackward || OptionsCont::getOptions().getBool("osm.oneway-spread-right")) &&
552  e->getParameter("railway:preferred_direction", "") != "both" ? LANESPREAD_RIGHT : LANESPREAD_CENTER;
553 
554  id = StringUtils::escapeXML(id);
555  if (addForward) {
556  assert(numLanesForward > 0);
557  NBEdge* nbe = new NBEdge(id, from, to, type, speed, numLanesForward, tc.getPriority(type),
558  forwardWidth, NBEdge::UNSPECIFIED_OFFSET, shape,
559  StringUtils::escapeXML(e->streetName), toString(e->id), lsf, true);
560  nbe->setPermissions(forwardPermissions);
561  if ((e->myBuswayType & WAY_FORWARD) != 0) {
562  nbe->setPermissions(SVC_BUS, 0);
563  }
564  if (addBikeLane && (e->myCyclewayType == WAY_UNKNOWN || (e->myCyclewayType & WAY_FORWARD) != 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  if (addBackward) {
580  assert(numLanesBackward > 0);
581  NBEdge* nbe = new NBEdge("-" + id, to, from, type, speed, numLanesBackward, tc.getPriority(type),
582  backwardWidth, NBEdge::UNSPECIFIED_OFFSET, shape.reverse(),
583  StringUtils::escapeXML(e->streetName), toString(e->id), lsf, true);
584  nbe->setPermissions(backwardPermissions);
585  if ((e->myBuswayType & WAY_BACKWARD) != 0) {
586  nbe->setPermissions(SVC_BUS, 0);
587  }
588  if (addBikeLane && (e->myCyclewayType == WAY_UNKNOWN || (e->myCyclewayType & WAY_BACKWARD) != 0)) {
589  nbe->addBikeLane(tc.getBikeLaneWidth(type));
590  } else if (nbe->getPermissions(0) == SVC_BUS) {
591  // bikes drive on buslanes if no separate cycle lane is available
593  }
594  if (addSidewalk) {
595  nbe->addSidewalk(tc.getSidewalkWidth(type));
596  }
597  nbe->addParameter(*e);
598  if (!ec.insert(nbe)) {
599  delete nbe;
600  throw ProcessError("Could not add edge '-" + id + "'.");
601  }
602  }
603  }
604  return newIndex;
605 }
606 
607 // ---------------------------------------------------------------------------
608 // definitions of NIImporter_OpenStreetMap::NodesHandler-methods
609 // ---------------------------------------------------------------------------
610 NIImporter_OpenStreetMap::NodesHandler::NodesHandler(std::map<long long int, NIOSMNode*>& toFill,
611  std::set<NIOSMNode*, CompareNodes>& uniqueNodes,
612  const OptionsCont& oc)
613 
614  :
615  SUMOSAXHandler("osm - file"),
616  myToFill(toFill),
617  myLastNodeID(-1),
618  myIsInValidNodeTag(false),
619  myHierarchyLevel(0),
620  myUniqueNodes(uniqueNodes),
621  myImportElevation(oc.getBool("osm.elevation")),
622  myOptionsCont(oc) {
623 }
624 
626 
627 void
630  if (element == SUMO_TAG_NODE) {
631  bool ok = true;
632  if (myHierarchyLevel != 2) {
633  WRITE_ERROR("Node element on wrong XML hierarchy level (id='" + toString(attrs.get<long
634  long
635  int>(SUMO_ATTR_ID,
636  nullptr, ok))
637  + "', level='" + toString(myHierarchyLevel) + "').");
638  return;
639  }
640  auto id = attrs.get<long
641  long
642  int>(SUMO_ATTR_ID, nullptr, ok);
643  std::string action = attrs.hasAttribute("action") ? attrs.getStringSecure("action", "") : "";
644  if (action == "delete") {
645  return;
646  }
647  if (!ok) {
648  return;
649  }
650  myLastNodeID = -1;
651  if (myToFill.find(id) == myToFill.end()) {
652  myLastNodeID = id;
653  // assume we are loading multiple files...
654  // ... so we won't report duplicate nodes
655  bool ok2 = true;
656  double tlat, tlon;
657  std::istringstream lon(attrs.get<std::string>(SUMO_ATTR_LON, toString(id).c_str(), ok2));
658  if (!ok2) {
659  return;
660  }
661  lon >> tlon;
662  if (lon.fail()) {
663  WRITE_ERROR("Node's '" + toString(id) + "' lon information is not numeric.");
664  return;
665  }
666  std::istringstream lat(attrs.get<std::string>(SUMO_ATTR_LAT, toString(id).c_str(), ok2));
667  if (!ok2) {
668  return;
669  }
670  lat >> tlat;
671  if (lat.fail()) {
672  WRITE_ERROR("Node's '" + toString(id) + "' lat information is not numeric.");
673  return;
674  }
675  auto* toAdd = new NIOSMNode(id, tlon, tlat);
676  myIsInValidNodeTag = true;
677 
678  auto similarNode = myUniqueNodes.find(toAdd);
679  if (similarNode == myUniqueNodes.end()) {
680  myUniqueNodes.insert(toAdd);
681  } else {
682  delete toAdd;
683  toAdd = *similarNode;
684  WRITE_MESSAGE("Found duplicate nodes. Substituting " + toString(id) + " with " + toString(toAdd->id));
685  }
686  myToFill[id] = toAdd;
687  }
688  }
689  if (element == SUMO_TAG_TAG && myIsInValidNodeTag) {
690  if (myHierarchyLevel != 3) {
691  WRITE_ERROR("Tag element on wrong XML hierarchy level.");
692  return;
693  }
694  bool ok = true;
695  std::string key = attrs.get<std::string>(SUMO_ATTR_K, toString(myLastNodeID).c_str(), ok, false);
696  // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
697  if (key == "highway" || key == "ele" || key == "crossing" || key == "railway" || key == "public_transport"
698  || key == "name" || key == "train" || key == "bus" || key == "tram") {
699  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myLastNodeID).c_str(), ok, false);
700  if (key == "highway" && value.find("traffic_signal") != std::string::npos) {
701  myToFill[myLastNodeID]->tlsControlled = true;
702  } else if (key == "crossing" && value.find("traffic_signals") != std::string::npos) {
703  myToFill[myLastNodeID]->tlsControlled = true;
704  } else if (key == "railway" && value.find("crossing") != std::string::npos) {
705  myToFill[myLastNodeID]->railwayCrossing = true;
706  } else if (key == "public_transport" && value.find("stop_position") != std::string::npos) {
707  myToFill[myLastNodeID]->ptStopPosition = true;
708  myToFill[myLastNodeID]->ptStopLength = myOptionsCont.getFloat(
709  "osm.stop-output.length");
710  } else if (key == "name") {
711  myToFill[myLastNodeID]->name = value;
712  } else if (key == "train") {
713  myToFill[myLastNodeID]->permissions = SVC_RAIL;
714  } else if (key == "bus") {
715  myToFill[myLastNodeID]->permissions = SVC_BUS;
716  } else if (key == "tram") {
717  myToFill[myLastNodeID]->permissions = SVC_TRAM;
718  } else if (myImportElevation && key == "ele") {
719  try {
720  myToFill[myLastNodeID]->ele = TplConvert::_2double(value.c_str());
721  } catch (...) {
722  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in node '" +
723  toString(myLastNodeID) + "'.");
724  }
725  }
726  }
727  }
728 }
729 
730 void
732  if (element == SUMO_TAG_NODE && myHierarchyLevel == 2) {
733  myLastNodeID = -1;
734  myIsInValidNodeTag = false;
735  }
737 }
738 
739 // ---------------------------------------------------------------------------
740 // definitions of NIImporter_OpenStreetMap::EdgesHandler-methods
741 // ---------------------------------------------------------------------------
743  const std::map<long long int, NIOSMNode*>& osmNodes,
744  std::map<long long int, Edge*>& toFill, std::map<long long int, Edge*>& platformShapes)
745  :
746  SUMOSAXHandler("osm - file"),
747  myOSMNodes(osmNodes),
748  myEdgeMap(toFill),
749  myPlatformShapesMap(platformShapes) {
750  mySpeedMap["signals"] = MAXSPEED_UNGIVEN;
751  mySpeedMap["none"] = 300.;
752  mySpeedMap["no"] = 300.;
753  mySpeedMap["walk"] = 5.;
754  mySpeedMap["DE:rural"] = 100.;
755  mySpeedMap["DE:urban"] = 50.;
756  mySpeedMap["DE:living_street"] = 10.;
757 
758 }
759 
761 
762 void
764  const SUMOSAXAttributes& attrs) {
765  myParentElements.push_back(element);
766  // parse "way" elements
767  if (element == SUMO_TAG_WAY) {
768  bool ok = true;
769  auto id = attrs.get<long
770  long
771  int>(SUMO_ATTR_ID, 0, ok);
772  std::string action = attrs.hasAttribute("action") ? attrs.getStringSecure("action", "") : "";
773  if (action == "delete") {
774  myCurrentEdge = 0;
775  return;
776  }
777  if (!ok) {
778  myCurrentEdge = 0;
779  return;
780  }
781  myCurrentEdge = new Edge(id);
782  }
783  // parse "nd" (node) elements
784  if (element == SUMO_TAG_ND) {
785  bool ok = true;
786  auto ref = attrs.get<long
787  long
788  int>(SUMO_ATTR_REF, 0, ok);
789  if (ok) {
790  auto node = myOSMNodes.find(ref);
791  if (node == myOSMNodes.end()) {
792  WRITE_WARNING("The referenced geometry information (ref='" + toString(ref) + "') is not known");
793  return;
794  }
795 
796  ref = node->second->id; // node may have been substituted
797  if (myCurrentEdge->myCurrentNodes.empty() ||
798  myCurrentEdge->myCurrentNodes.back() != ref) { // avoid consecutive duplicates
799  myCurrentEdge->myCurrentNodes.push_back(ref);
800  }
801 
802  }
803  }
804  // parse values
805  if (element == SUMO_TAG_TAG && myParentElements.size() > 2
806  && myParentElements[myParentElements.size() - 2] == SUMO_TAG_WAY) {
807  if (myCurrentEdge == 0) {
808  return;
809  }
810  bool ok = true;
811  std::string key = attrs.get<std::string>(SUMO_ATTR_K, toString(myCurrentEdge->id).c_str(), ok, false);
812  if (key.size() > 8 && StringUtils::startsWith(key, "cycleway:")) {
813  // handle special busway keys
814  const std::string cyclewaySpec = key.substr(9);
815  key = "cycleway";
816  if (cyclewaySpec == "right") {
818  } else if (cyclewaySpec == "left") {
820  } else if (cyclewaySpec == "both") {
822  } else {
823  key = "ignore";
824  }
825  if ((myCurrentEdge->myCyclewayType & WAY_BOTH) != 0) {
826  // now we have some info on directionality
828  }
829  } else if (key.size() > 6 && StringUtils::startsWith(key, "busway:")) {
830  // handle special busway keys
831  const std::string buswaySpec = key.substr(7);
832  key = "busway";
833  if (buswaySpec == "right") {
835  } else if (buswaySpec == "left") {
837  } else if (buswaySpec == "both") {
839  } else {
840  key = "ignore";
841  }
842  }
843  if (key == "bridge" || key == "tunnel") {
844  myCurrentEdge->addParameter(key, "true"); // could be differentiated further if necessary
845  }
846 
847  // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
848  if (!StringUtils::endsWith(key, "way") && !StringUtils::startsWith(key, "lanes")
849  && key != "maxspeed" && key != "junction" && key != "name" && key != "tracks" && key != "layer"
850  && key != "route"
851  && key != "postal_code" && key != "railway:preferred_direction" && key != "public_transport") {
852  return;
853  }
854  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentEdge->id).c_str(), ok, false);
855 
856  if ((key == "highway" && value != "platform") || key == "railway" || key == "waterway" || key == "cycleway"
857  || key == "busway" || key == "route") {
859  // special cycleway stuff
860  if (key == "cycleway") {
861  if (value == "no") {
862  return;
863  }
864  if (value == "opposite_track") {
866  } else if (value == "opposite_lane") {
868  }
869  }
870  // special busway stuff
871  if (key == "busway") {
872  if (value == "no") {
873  return;
874  }
875  if (value == "opposite_track") {
877  } else if (value == "opposite_lane") {
879  }
880  // no need to extend the type id
881  return;
882  }
883  // build type id
884  const std::string singleTypeID = key + "." + value;
885  if (!myCurrentEdge->myHighWayType.empty()) {
886  // osm-ways may be used by more than one mode (eg railway.tram + highway.residential. this is relevant for multimodal traffic)
887  // we create a new type for this kind of situation which must then be resolved in insertEdge()
888  std::vector<std::string> types = StringTokenizer(myCurrentEdge->myHighWayType,
890  types.push_back(singleTypeID);
892  } else {
893  myCurrentEdge->myHighWayType = singleTypeID;
894  }
895  } else if (key == "lanes") {
896  try {
897  myCurrentEdge->myNoLanes = TplConvert::_2int(value.c_str());
898  } catch (NumberFormatException&) {
899  // might be a list of values
900  StringTokenizer st(value, ";", true);
901  std::vector<std::string> list = st.getVector();
902  if (list.size() >= 2) {
903  int minLanes = std::numeric_limits<int>::max();
904  try {
905  for (auto& i : list) {
906  int numLanes = TplConvert::_2int(StringUtils::prune(i).c_str());
907  minLanes = MIN2(minLanes, numLanes);
908  }
909  myCurrentEdge->myNoLanes = minLanes;
911  "Using minimum lane number from list (" + value + ") for edge '"
913  + "'.");
914  } catch (NumberFormatException&) {
915  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
916  toString(myCurrentEdge->id) + "'.");
917  }
918  }
919  } catch (EmptyData&) {
920  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
921  toString(myCurrentEdge->id) + "'.");
922  }
923  } else if (key == "lanes:forward") {
924  try {
926  } catch (...) {
927  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
928  toString(myCurrentEdge->id) + "'.");
929  }
930  } else if (key == "lanes:backward") {
931  try {
932  // denote backwards count with a negative sign
934  } catch (...) {
935  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
936  toString(myCurrentEdge->id) + "'.");
937  }
938  } else if (key == "maxspeed") {
939  if (mySpeedMap.find(value) != mySpeedMap.end()) {
941  } else {
942  double conversion = 1; // OSM default is km/h
943  if (StringUtils::to_lower_case(value).find("km/h") != std::string::npos) {
944  value = StringUtils::prune(value.substr(0, value.find_first_not_of("0123456789")));
945  } else if (StringUtils::to_lower_case(value).find("mph") != std::string::npos) {
946  value = StringUtils::prune(value.substr(0, value.find_first_not_of("0123456789")));
947  conversion = 1.609344; // kilometers per mile
948  }
949  try {
950  myCurrentEdge->myMaxSpeed = TplConvert::_2double(value.c_str()) * conversion;
951  } catch (...) {
952  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
953  toString(myCurrentEdge->id) + "'.");
954  }
955  }
956  } else if (key == "junction") {
957  if ((value == "roundabout") && (myCurrentEdge->myIsOneWay.empty())) {
958  myCurrentEdge->myIsOneWay = "yes";
959  }
960  } else if (key == "oneway") {
961  myCurrentEdge->myIsOneWay = value;
962  } else if (key == "name") {
963  myCurrentEdge->streetName = value;
964  } else if (key == "layer") {
965  try {
966  myCurrentEdge->myLayer = TplConvert::_2int(value.c_str());
967  } catch (...) {
968  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
969  toString(myCurrentEdge->id) + "'.");
970  }
971  } else if (key == "tracks") {
972  try {
973  if (TplConvert::_2int(value.c_str()) > 1) {
974  myCurrentEdge->myIsOneWay = "false";
975  } else {
976  myCurrentEdge->myIsOneWay = "true";
977  }
978  } catch (...) {
979  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
980  toString(myCurrentEdge->id) + "'.");
981  }
982  } else if (key == "postal_code") {
983  myCurrentEdge->addParameter(key, value);
984  } else if (key == "railway:preferred_direction") {
985  myCurrentEdge->addParameter(key, value);
986  } else if (key == "public_transport" && value == "platform") {
988  }
989  }
990 }
991 
992 void
994  myParentElements.pop_back();
995  if (element == SUMO_TAG_WAY) {
996  if (myCurrentEdge != nullptr) {
999  } else if (myCurrentEdge->myCurrentIsPlatform) {
1001  } else {
1002  delete myCurrentEdge;
1003  }
1004  } else {
1005  delete myCurrentEdge;
1006  }
1007  myCurrentEdge = 0;
1008  }
1009 }
1010 
1011 // ---------------------------------------------------------------------------
1012 // definitions of NIImporter_OpenStreetMap::RelationHandler-methods
1013 // ---------------------------------------------------------------------------
1015  const std::map<long long int, NIOSMNode*>& osmNodes,
1016  const std::map<long long int, Edge*>& osmEdges, NBPTStopCont* nbptStopCont,
1017  const std::map<long long int, Edge*>& platformShapes,
1018  NBPTLineCont* nbptLineCont,
1019  const OptionsCont& oc)
1020  :
1021  SUMOSAXHandler("osm - file"),
1022  myOSMNodes(osmNodes),
1023  myOSMEdges(osmEdges),
1024  myPlatformShapes(platformShapes),
1025  myNBPTStopCont(nbptStopCont),
1026  myNBPTLineCont(nbptLineCont),
1027  myOptionsCont(oc) {
1028  resetValues();
1029 }
1030 
1032 
1033 void
1036  myIsRestriction = false;
1038  myToWay = INVALID_ID;
1040  myViaWay = INVALID_ID;
1042  myPlatforms.clear();
1043  myStops.clear();
1044  myWays.clear();
1045  myIsStopArea = false;
1046  myIsRoute = false;
1047  myIsPTRoute = false;
1048 }
1049 
1050 void
1052  const SUMOSAXAttributes& attrs) {
1053  myParentElements.push_back(element);
1054  // parse "way" elements
1055  if (element == SUMO_TAG_RELATION) {
1056  bool ok = true;
1057  myCurrentRelation = attrs.get<long
1058  long
1059  int>(SUMO_ATTR_ID, 0, ok);
1060  std::string action = attrs.hasAttribute("action") ? attrs.getStringSecure("action", "") : "";
1061  if (action == "delete" || !ok) {
1063  }
1064  return;
1065  }
1066  if (myCurrentRelation == INVALID_ID) {
1067  return;
1068  }
1069  // parse member elements
1070  if (element == SUMO_TAG_MEMBER) {
1071  bool ok = true;
1072  std::string role = attrs.hasAttribute("role") ? attrs.getStringSecure("role", "") : "";
1073  auto ref = attrs.get<long
1074  long
1075  int>(SUMO_ATTR_REF, 0, ok);
1076  if (role == "via") {
1077  // u-turns for divided ways may be given with 2 via-nodes or 1 via-way
1078  std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, 0, ok);
1079  if (memberType == "way" && checkEdgeRef(ref)) {
1080  myViaWay = ref;
1081  } else if (memberType == "node") {
1082  if (myOSMNodes.find(ref) != myOSMNodes.end()) {
1083  myViaNode = ref;
1084  } else {
1085  WRITE_WARNING(
1086  "No node found for reference '" + toString(ref) + "' in relation '"
1088  + "'");
1089  }
1090  }
1091  } else if (role == "from" && checkEdgeRef(ref)) {
1092  myFromWay = ref;
1093  } else if (role == "to" && checkEdgeRef(ref)) {
1094  myToWay = ref;
1095  } else if (role == "stop") {
1096  myStops.push_back(ref);
1097  } else if (role == "platform") {
1098  std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, 0, ok);
1099  if (memberType == "way") {
1100  const std::map<long long int,
1101  NIImporter_OpenStreetMap::Edge*>::const_iterator& wayIt = myPlatformShapes.find(ref);
1102  if (wayIt != myPlatformShapes.end()) {
1103 
1104  NIIPTPlatform platform;
1105  platform.isWay = true;
1106  platform.ref = ref;
1107  myPlatforms.push_back(platform);
1108  }
1109  } else if (memberType == "node") {
1110  NIIPTPlatform platform;
1111  platform.isWay = false;
1112  platform.ref = ref;
1113  myPlatforms.push_back(platform);
1114  }
1115 
1116  } else if (role.empty()) {
1117  std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, 0, ok);
1118  if (memberType == "way") {
1119  myWays.push_back(ref);
1120  }
1121  }
1122  return;
1123  }
1124  // parse values
1125  if (element == SUMO_TAG_TAG) {
1126  bool ok = true;
1127  std::string key = attrs.get<std::string>(SUMO_ATTR_K, toString(myCurrentRelation).c_str(), ok, false);
1128  // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
1129  if (key == "type" || key == "restriction") {
1130  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1131  if (key == "type" && value == "restriction") {
1132  myIsRestriction = true;
1133  return;
1134  }
1135  if (key == "type" && value == "route") {
1136  myIsRoute = true;
1137  return;
1138  }
1139  if (key == "restriction") {
1140  // @note: the 'right/left/straight' part is ignored since the information is
1141  // redundantly encoded in the 'from', 'to' and 'via' members
1142  if (value.substr(0, 5) == "only_") {
1144  } else if (value.substr(0, 3) == "no_") {
1146  } else {
1147  WRITE_WARNING(
1148  "Found unknown restriction type '" + value + "' in relation '" + toString(myCurrentRelation)
1149  + "'");
1150  }
1151  return;
1152  }
1153  } else if (key == "public_transport") {
1154  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1155  if (value == "stop_area") {
1156  myIsStopArea = true;
1157  }
1158  } else if (key == "route") {
1159  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1160  if (value == "train" || value == "subway" || value == "monorail" || value == "tram" || value == "bus"
1161  || value == "trolleybus" || value == "arialway" || value == "ferry") {
1162  myIsPTRoute = true;
1163  }
1164 
1165  } else if (key == "name") {
1166  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1167  myName = value;
1168  } else if (key == "ref") {
1169  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1170  myRef = value;
1171  }
1172  }
1173 }
1174 
1175 bool
1177  if (myOSMEdges.find(ref) != myOSMEdges.end()) {
1178  return true;
1179  }
1180 
1181  WRITE_WARNING(
1182  "No way found for reference '" + toString(ref) + "' in relation '" + toString(myCurrentRelation) + "'");
1183  return false;
1184 
1185 }
1186 
1187 void
1189  myParentElements.pop_back();
1190  if (element == SUMO_TAG_RELATION) {
1191  if (myIsRestriction) {
1192  assert(myCurrentRelation != INVALID_ID);
1193  bool ok = true;
1195  WRITE_WARNING("Ignoring restriction relation '" + toString(myCurrentRelation) + "' with unknown type.");
1196  ok = false;
1197  }
1198  if (myFromWay == INVALID_ID) {
1199  WRITE_WARNING(
1200  "Ignoring restriction relation '" + toString(myCurrentRelation) + "' with unknown from-way.");
1201  ok = false;
1202  }
1203  if (myToWay == INVALID_ID) {
1204  WRITE_WARNING(
1205  "Ignoring restriction relation '" + toString(myCurrentRelation) + "' with unknown to-way.");
1206  ok = false;
1207  }
1208  if (myViaNode == INVALID_ID && myViaWay == INVALID_ID) {
1209  WRITE_WARNING("Ignoring restriction relation '" + toString(myCurrentRelation) + "' with unknown via.");
1210  ok = false;
1211  }
1212  if (ok && !applyRestriction()) {
1213  WRITE_WARNING("Ignoring restriction relation '" + toString(myCurrentRelation) + "'.");
1214  }
1215  } else if (myIsStopArea && OptionsCont::getOptions().isSet("ptstop-output")) {
1216  for (long long ref : myStops) {
1217  if (myOSMNodes.find(ref) == myOSMNodes.end()) {
1218  WRITE_WARNING(
1219  "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
1220  + "' does not exist. Probably OSM file is incomplete.");
1221  continue;
1222  }
1223 
1224  NIOSMNode* n = myOSMNodes.find(ref)->second;
1225  NBPTStop* ptStop = myNBPTStopCont->get(toString(n->id));
1226  if (ptStop == 0) {
1227  WRITE_WARNING(
1228  "Relation '" + toString(myCurrentRelation) + "' refers to a non existing pt stop at node: '"
1229  + toString(n->id) + "'. Probably OSM file is incomplete.");
1230  continue;
1231  }
1232  for (NIIPTPlatform& myPlatform : myPlatforms) {
1233  if (myPlatform.isWay) {
1234  assert(myPlatformShapes.find(myPlatform.ref) != myPlatformShapes.end()); //already tested earlier
1235  Edge* edge = (*myPlatformShapes.find(myPlatform.ref)).second;
1236  if (edge->myCurrentNodes[0] == *(edge->myCurrentNodes.end() - 1)) {
1237  WRITE_WARNING("Platform '" + toString(myPlatform.ref) + "' in relation: '" + toString(myCurrentRelation)
1238  + "' is given as polygon, which currently is not supported.");
1239  continue;
1240 
1241  }
1242  PositionVector p;
1243  for (auto nodeRef : edge->myCurrentNodes) {
1244  if (myOSMNodes.find(nodeRef) == myOSMNodes.end()) {
1245  WRITE_WARNING(
1246  "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
1247  + "' does not exist. Probably OSM file is incomplete.");
1248  continue;
1249  }
1250  NIOSMNode* pNode = myOSMNodes.find(nodeRef)->second;
1251  Position pNodePos(pNode->lon, pNode->lat, pNode->ele);
1252  if (!NBNetBuilder::transformCoordinate(pNodePos)) {
1253  WRITE_ERROR("Unable to project coordinates for node '" + toString(pNode->id) + "'.");
1254  continue;
1255  }
1256  p.push_back(pNodePos);
1257  }
1258  if (p.size() == 0) {
1259  WRITE_WARNING(
1260  "Referenced platform: '" + toString(myPlatform.ref) + "' in relation: '" + toString(myCurrentRelation)
1261  + "' is corrupt. Probably OSM file is incomplete.");
1262  continue;
1263  }
1264  NBPTPlatform platform(p[(int)p.size() / 2], p.length());
1265  ptStop->addPlatformCand(platform);
1266  } else {
1267  if (myOSMNodes.find(myPlatform.ref) == myOSMNodes.end()) {
1268  WRITE_WARNING(
1269  "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
1270  + "' does not exist. Probably OSM file is incomplete.");
1271  continue;
1272  }
1273  NIOSMNode* pNode = myOSMNodes.find(myPlatform.ref)->second;
1274  Position platformPos(pNode->lon, pNode->lat, pNode->ele);
1275  if (!NBNetBuilder::transformCoordinate(platformPos)) {
1276  WRITE_ERROR("Unable to project coordinates for node '" + toString(pNode->id) + "'.");
1277  }
1278  NBPTPlatform platform(platformPos, myOptionsCont.getFloat(
1279  "osm.stop-output.length"));
1280  ptStop->addPlatformCand(platform);
1281 
1282  }
1283  }
1284  ptStop->setIsMultipleStopPositions(myStops.size() > 1);;
1285  }
1286  } else if (myIsPTRoute && myIsRoute && OptionsCont::getOptions().isSet("ptline-output") && myStops.size() > 1) {
1287  NBPTLine* ptLine = new NBPTLine(myName);
1288  ptLine->setMyNumOfStops(myStops.size());
1289  for (long long ref : myStops) {
1290  if (myOSMNodes.find(ref) == myOSMNodes.end()) {
1291  WRITE_WARNING(
1292  "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
1293  + "' does not exist. Probably OSM file is incomplete.");
1294 // resetValues();
1295 // return;
1296  if (!ptLine->getStops().empty()){
1297  WRITE_WARNING("Done reading first coherent junk of pt stops. Further stops in relation " + toString(myCurrentRelation) + " are ignored");
1298  break;
1299  }
1300  continue;
1301  }
1302 
1303  NIOSMNode* n = myOSMNodes.find(ref)->second;
1304  NBPTStop* ptStop = myNBPTStopCont->get(toString(n->id));
1305  if (ptStop == 0) {
1306  WRITE_WARNING("Relation '" + toString(myCurrentRelation)
1307  + "' refers to a non existing pt stop at node: '" + toString(n->id)
1308  + "'. Probably OSM file is incomplete.");
1309 // resetValues();
1310 // return;
1311  if (!ptLine->getStops().empty()){
1312  WRITE_WARNING("Done reading first coherent junk of pt stops. Further stops in relation " + toString(myCurrentRelation) + " are ignored");
1313  break;
1314  }
1315  continue;
1316  }
1317  ptLine->addPTStop(ptStop);
1318  if (myRef != "") {
1319  ptLine->setRef(myRef);
1320  }
1321 
1322  }
1323  for (long long& myWay : myWays) {
1324  auto entr = myOSMEdges.find(myWay);
1325  if (entr != myOSMEdges.end()) {
1326  Edge* edge = entr->second;
1327  for (long long& myCurrentNode : edge->myCurrentNodes) {
1328  ptLine->addWayNode(myWay, myCurrentNode);
1329  }
1330  }
1331  }
1332  if (ptLine->getStops().empty()){
1333  WRITE_WARNING("PT line in relation " + toString(myCurrentRelation) + " with no stops ignored. Probably OSM file is incomplete.");
1334  resetValues();
1335  return;
1336  }
1337  myNBPTLineCont->insert(ptLine);
1338  }
1339  // other relations might use similar subelements so reset in any case
1340  resetValues();
1341  }
1342 }
1343 
1344 bool
1346  // since OSM ways are bidirectional we need the via to figure out which direction was meant
1347  if (myViaNode != INVALID_ID) {
1348  NBNode* viaNode = myOSMNodes.find(myViaNode)->second->node;
1349  if (viaNode == 0) {
1350  WRITE_WARNING("Via-node '" + toString(myViaNode) + "' was not instantiated");
1351  return false;
1352  }
1353  NBEdge* from = findEdgeRef(myFromWay, viaNode->getIncomingEdges());
1354  NBEdge* to = findEdgeRef(myToWay, viaNode->getOutgoingEdges());
1355  if (from == 0) {
1356  WRITE_WARNING("from-edge of restriction relation could not be determined");
1357  return false;
1358  }
1359  if (to == 0) {
1360  WRITE_WARNING("to-edge of restriction relation could not be determined");
1361  return false;
1362  }
1364  from->addEdge2EdgeConnection(to);
1365  } else {
1366  from->removeFromConnections(to, -1, -1, true);
1367  }
1368  } else {
1369  // XXX interpreting via-ways or via-node lists not yet implemented
1370  WRITE_WARNING("direction of restriction relation could not be determined");
1371  return false;
1372  }
1373  return true;
1374 }
1375 
1376 NBEdge*
1378  const std::vector<NBEdge*>& candidates) const {
1379  const std::string prefix = toString(wayRef);
1380  const std::string backPrefix = "-" + prefix;
1381  NBEdge* result = 0;
1382  int found = 0;
1383  for (auto candidate : candidates) {
1384  if ((candidate->getID().substr(0, prefix.size()) == prefix) ||
1385  (candidate->getID().substr(0, backPrefix.size()) == backPrefix)) {
1386  result = candidate;
1387  found++;
1388  }
1389  }
1390  if (found > 1) {
1391  WRITE_WARNING("Ambigous way reference '" + prefix + "' in restriction relation");
1392  result = 0;
1393  }
1394  return result;
1395 }
1396 
1397 void
1399  NBNodeCont& nc = nb.getNodeCont();
1400  NBEdgeCont& ec = nb.getEdgeCont();
1401  // reconstruct elevation from layer info
1402  // build a map of raising and lowering forces (attractor and distance)
1403  // for all nodes unknownElevation
1404  std::map<NBNode*, std::vector<std::pair<double, double> > > layerForces;
1405 
1406  // collect all nodes that belong to a way with layer information
1407  std::set<NBNode*> knownElevation;
1408  for (auto& myEdge : myEdges) {
1409  Edge* e = myEdge.second;
1410  if (e->myLayer != 0) {
1411  for (auto j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
1412  NBNode* node = nc.retrieve(toString(*j));
1413  if (node != 0) {
1414  knownElevation.insert(node);
1415  layerForces[node].emplace_back(e->myLayer * layerElevation, POSITION_EPS);
1416  }
1417  }
1418  }
1419  }
1420 #ifdef DEBUG_LAYER_ELEVATION
1421  std::cout << "known elevations:\n";
1422  for (std::set<NBNode*>::iterator it = knownElevation.begin(); it != knownElevation.end(); ++it) {
1423  const std::vector<std::pair<double, double> >& primaryLayers = layerForces[*it];
1424  std::cout << " node=" << (*it)->getID() << " ele=";
1425  for (std::vector<std::pair<double, double> >::const_iterator it_ele = primaryLayers.begin(); it_ele != primaryLayers.end(); ++it_ele) {
1426  std::cout << it_ele->first << " ";
1427  }
1428  std::cout << "\n";
1429  }
1430 #endif
1431  // layer data only provides a lower bound on elevation since it is used to
1432  // resolve the relation among overlapping ways.
1433  // Perform a sanity check for steep inclines and raise the knownElevation if necessary
1434  std::map<NBNode*, double> knownEleMax;
1435  for (auto it : knownElevation) {
1436  double eleMax = -std::numeric_limits<double>::max();
1437  const std::vector<std::pair<double, double> >& primaryLayers = layerForces[it];
1438  for (const auto& primaryLayer : primaryLayers) {
1439  eleMax = MAX2(eleMax, primaryLayer.first);
1440  }
1441  knownEleMax[it] = eleMax;
1442  }
1443  const double gradeThreshold = OptionsCont::getOptions().getFloat("osm.layer-elevation.max-grade") / 100;
1444  bool changed = true;
1445  while (changed) {
1446  changed = false;
1447  for (auto it = knownElevation.begin(); it != knownElevation.end(); ++it) {
1448  std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it,
1449  knownEleMax[*it]
1450  / gradeThreshold * 3,
1451  knownElevation);
1452  for (auto& neighbor : neighbors) {
1453  if (knownElevation.count(neighbor.first) != 0) {
1454  const double grade = fabs(knownEleMax[*it] - knownEleMax[neighbor.first])
1455  / MAX2(POSITION_EPS, neighbor.second.first);
1456 #ifdef DEBUG_LAYER_ELEVATION
1457  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";
1458 #endif
1459  if (grade > gradeThreshold * 50 / 3.6 / neighbor.second.second) {
1460  // raise the lower node to the higher level
1461  const double eleMax = MAX2(knownEleMax[*it], knownEleMax[neighbor.first]);
1462  if (knownEleMax[*it] < eleMax) {
1463  knownEleMax[*it] = eleMax;
1464  } else {
1465  knownEleMax[neighbor.first] = eleMax;
1466  }
1467  changed = true;
1468  }
1469  }
1470  }
1471  }
1472  }
1473 
1474  // collect all nodes within a grade-dependent range around knownElevation-nodes and apply knowElevation forces
1475  std::set<NBNode*> unknownElevation;
1476  for (auto it = knownElevation.begin(); it != knownElevation.end(); ++it) {
1477  const double eleMax = knownEleMax[*it];
1478  const double maxDist = fabs(eleMax) * 100 / layerElevation;
1479  std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it, maxDist, knownElevation);
1480  for (auto& neighbor : neighbors) {
1481  if (knownElevation.count(neighbor.first) == 0) {
1482  unknownElevation.insert(neighbor.first);
1483  layerForces[neighbor.first].emplace_back(eleMax, neighbor.second.first);
1484  }
1485  }
1486  }
1487 
1488  // apply forces to ground-level nodes (neither in knownElevation nor unknownElevation)
1489  for (auto it = unknownElevation.begin(); it != unknownElevation.end(); ++it) {
1490  double eleMax = -std::numeric_limits<double>::max();
1491  const std::vector<std::pair<double, double> >& primaryLayers = layerForces[*it];
1492  for (const auto& primaryLayer : primaryLayers) {
1493  eleMax = MAX2(eleMax, primaryLayer.first);
1494  }
1495  const double maxDist = fabs(eleMax) * 100 / layerElevation;
1496  std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it, maxDist, knownElevation);
1497  for (auto& neighbor : neighbors) {
1498  if (knownElevation.count(neighbor.first) == 0 && unknownElevation.count(neighbor.first) == 0) {
1499  layerForces[*it].emplace_back(0, neighbor.second.first);
1500  }
1501  }
1502  }
1503  // compute the elevation for each node as the weighted average of all forces
1504 #ifdef DEBUG_LAYER_ELEVATION
1505  std::cout << "summation of forces\n";
1506 #endif
1507  std::map<NBNode*, double> nodeElevation;
1508  for (auto& layerForce : layerForces) {
1509  const std::vector<std::pair<double, double> >& forces = layerForce.second;
1510  if (knownElevation.count(layerForce.first) != 0) {
1511  // use the maximum value
1512  /*
1513  double eleMax = -std::numeric_limits<double>::max();
1514  for (std::vector<std::pair<double, double> >::const_iterator it_force = forces.begin(); it_force != forces.end(); ++it_force) {
1515  eleMax = MAX2(eleMax, it_force->first);
1516  }
1517  */
1518 #ifdef DEBUG_LAYER_ELEVATION
1519  std::cout << " node=" << it->first->getID() << " knownElevation=" << knownEleMax[it->first] << "\n";
1520 #endif
1521  nodeElevation[layerForce.first] = knownEleMax[layerForce.first];
1522  } else if (forces.size() == 1) {
1523  nodeElevation[layerForce.first] = forces.front().first;
1524  } else {
1525  // use the weighted sum
1526  double distSum = 0;
1527  for (const auto& force : forces) {
1528  distSum += force.second;
1529  }
1530  double weightSum = 0;
1531  double elevation = 0;
1532 #ifdef DEBUG_LAYER_ELEVATION
1533  std::cout << " node=" << it->first->getID() << " distSum=" << distSum << "\n";
1534 #endif
1535  for (const auto& force : forces) {
1536  const double weight = (distSum - force.second) / distSum;
1537  weightSum += weight;
1538  elevation += force.first * weight;
1539 
1540 #ifdef DEBUG_LAYER_ELEVATION
1541  std::cout << " force=" << it_force->first << " dist=" << it_force->second << " weight=" << weight << " ele=" << elevation << "\n";
1542 #endif
1543  }
1544  nodeElevation[layerForce.first] = elevation / weightSum;
1545  }
1546  }
1547 #ifdef DEBUG_LAYER_ELEVATION
1548  std::cout << "final elevations:\n";
1549  for (std::map<NBNode*, double>::iterator it = nodeElevation.begin(); it != nodeElevation.end(); ++it) {
1550  std::cout << " node=" << (it->first)->getID() << " ele=" << it->second << "\n";;
1551  }
1552 #endif
1553  // apply node elevations
1554  for (auto& it : nodeElevation) {
1555  NBNode* n = it.first;
1556  Position pos = n->getPosition();
1557  n->reinit(n->getPosition() + Position(0, 0, it.second), n->getType());
1558  }
1559 
1560  // apply way elevation to all edges that had layer information
1561  for (const auto& it : ec) {
1562  NBEdge* edge = it.second;
1563  const PositionVector& geom = edge->getGeometry();
1564  const double length = geom.length2D();
1565  const double zFrom = nodeElevation[edge->getFromNode()];
1566  const double zTo = nodeElevation[edge->getToNode()];
1567  // XXX if the from- or to-node was part of multiple ways with
1568  // different layers, reconstruct the layer value from origID
1569  double dist = 0;
1570  PositionVector newGeom;
1571  for (auto it_pos = geom.begin(); it_pos != geom.end(); ++it_pos) {
1572  if (it_pos != geom.begin()) {
1573  dist += (*it_pos).distanceTo2D(*(it_pos - 1));
1574  }
1575  newGeom.push_back((*it_pos) + Position(0, 0, zFrom + (zTo - zFrom) * dist / length));
1576  }
1577  edge->setGeometry(newGeom);
1578  }
1579 }
1580 
1581 std::map<NBNode*, std::pair<double, double> >
1582 NIImporter_OpenStreetMap::getNeighboringNodes(NBNode* node, double maxDist, const std::set<NBNode*>& knownElevation) {
1583  std::map<NBNode*, std::pair<double, double> > result;
1584  std::set<NBNode*> visited;
1585  std::vector<NBNode*> open;
1586  open.push_back(node);
1587  result[node] = std::make_pair(0, 0);
1588  while (!open.empty()) {
1589  NBNode* n = open.back();
1590  open.pop_back();
1591  if (visited.count(n) != 0) {
1592  continue;
1593  }
1594  visited.insert(n);
1595  const EdgeVector& edges = n->getEdges();
1596  for (auto e : edges) {
1597  NBNode* s = 0;
1598  if (n->hasIncoming(e)) {
1599  s = e->getFromNode();
1600  } else {
1601  s = e->getToNode();
1602  }
1603  const double dist = result[n].first + e->getGeometry().length2D();
1604  const double speed = MAX2(e->getSpeed(), result[n].second);
1605  if (result.count(s) == 0) {
1606  result[s] = std::make_pair(dist, speed);
1607  } else {
1608  result[s] = std::make_pair(MIN2(dist, result[s].first), MAX2(speed, result[s].second));
1609  }
1610  if (dist < maxDist && knownElevation.count(s) == 0) {
1611  open.push_back(s);
1612  }
1613  }
1614  }
1615  result.erase(node);
1616  return result;
1617 }
1618 
1619 
1620 /****************************************************************************/
1621 
const std::map< long long int, NIOSMNode * > & myOSMNodes
The previously parsed nodes.
An internal definition of a loaded edge.
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.
std::map< long long int, Edge * > & myPlatformShapesMap
A map of built edges.
void myStartElement(int element, const SUMOSAXAttributes &attrs) override
Called on the opening of a tag;.
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:243
const long long int id
The edge&#39;s id.
void reviseStops(NBEdgeCont &cont)
revise pt stops and remove stops on non existing (removed) edges
~EdgesHandler() override
Destructor.
std::string streetName
The edge&#39;s street name.
NBTypeCont & getTypeCont()
Returns a reference to the type container.
Definition: NBNetBuilder.h:166
NBPTLineCont * myNBPTLineCont
PT Line container to be filled.
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.
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
vehicle is a not electrified rail
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:264
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
double getWidth(const std::string &type) const
Returns the lane width for the given type [m].
Definition: NBTypeCont.cpp:217
bool applyRestriction() const
try to apply the parsed restriction and return whether successful
vehicle is a bicycle
const double SUMO_const_laneWidth
Definition: StdDefs.h:50
int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
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
vehicle is a light rail
static const double UNSPECIFIED_OFFSET
unspecified lane offset
Definition: NBEdge.h:259
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:1187
bool getIsOneWay(const std::string &type) const
Returns whether edges are one-way per default for the given type.
Definition: NBTypeCont.cpp:193
long long int myCurrentRelation
The currently parsed relation.
void addPTStop(NBPTStop *pStop)
Definition: NBPTLine.cpp:31
T MAX2(T a, T b)
Definition: StdDefs.h:74
NBPTStopCont & getPTStopCont()
Returns a reference to the pt stop container.
Definition: NBNetBuilder.h:182
void setMyNumOfStops(unsigned long numStops)
Definition: NBPTLine.cpp:106
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:2960
std::vector< NIIPTPlatform > myPlatforms
bus stop platforms
NBPTLineCont & getPTLineCont()
Returns a reference to the pt line container.
Definition: NBNetBuilder.h:187
static bool transformCoordinates(PositionVector &from, bool includeInBoundary=true, GeoConvHelper *from_srs=0)
The representation of a single pt stop.
Definition: NBPTStop.h:51
std::vector< long long int > myStops
bus stop references
void registerAdditionalEdge(std::string wayId, std::string edgeId)
Definition: NBPTStop.cpp:125
const std::string & getParameter(const std::string &key, const std::string &defaultValue) const
Returns the value for a given key.
SAX-handler base for SUMO-files.
void myEndElement(int element) override
Called when a closing tag occurs.
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
bool hasIncoming(const NBEdge *const e) const
Returns whether the given edge ends at this node.
Definition: NBNode.cpp:1208
void addSidewalk(double width)
add a pedestrian sidewalk of the given width and shift existing connctions
Definition: NBEdge.cpp:3086
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:524
static const double UNSPECIFIED_WIDTH
unspecified lane width
Definition: NBEdge.h:256
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:200
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:65
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
std::vector< long long int > myWays
ways in pt line references
const OptionsCont & myOptionsCont
the options cont
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:248
RelationHandler(const std::map< long long int, NIOSMNode * > &osmNodes, const std::map< long long int, Edge * > &osmEdges, NBPTStopCont *nbptStopCont, const std::map< long long int, Edge * > &platfromShapes, NBPTLineCont *nbptLineCont, const OptionsCont &oc)
Constructor.
const std::string & getID() const
Returns the id.
Definition: Named.h:66
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:889
const std::map< long long int, Edge * > & myPlatformShapes
The previously parsed platform shapes.
const Position & getPosition() const
Definition: NBNode.h:235
#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.
void addWayNode(long long int way, long long int node)
Definition: NBPTLine.cpp:72
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.
void insert(NBPTLine *pLine)
insert new line
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.
bool ptStopPosition
Whether this is a public transport stop position.
Encapsulated SAX-Attributes.
void setRef(std::string basic_string)
Definition: NBPTLine.cpp:90
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:175
void myEndElement(int element) override
Called when a closing tag occurs.
NBEdgeCont & getEdgeCont()
Definition: NBNetBuilder.h:156
A list of positions.
SumoXMLNodeType getType() const
Returns the type of this node.
Definition: NBNode.h:260
int getPriority(const std::string &type) const
Returns the priority for the given type.
Definition: NBTypeCont.cpp:187
const EdgeVector & getEdges() const
Returns all edges which participate in this node (Edges that start or end at this node) ...
Definition: NBNode.h:253
double length() const
Returns the length.
Storage for edges, including some functionality operating on multiple edges.
Definition: NBEdgeCont.h:66
T MIN2(T a, T b)
Definition: StdDefs.h:68
#define PROGRESS_BEGIN_MESSAGE(msg)
Definition: MsgHandler.h:202
#define POSITION_EPS
Definition: config.h:176
NodesHandler(std::map< long long int, NIOSMNode * > &toFill, std::set< NIOSMNode *, CompareNodes > &uniqueNodes, const OptionsCont &cont)
Contructor.
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
bool knows(const std::string &type) const
Returns whether the named type is in the container.
Definition: NBTypeCont.cpp:75
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...
static std::string escapeXML(const std::string &orig, const bool maskDoubleHyphen=false)
Replaces the standard escapes by their XML entities.
void setIsMultipleStopPositions(bool multipleStopPositions)
Definition: NBPTStop.cpp:116
bool railwayCrossing
Whether this is a railway crossing.
~NodesHandler() override
Destructor.
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 myEndElement(int element) override
Called when a closing tag occurs.
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()
const double lat
The latitude the node is located at.
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:206
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:2988
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
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:156
bool tlsControlled
Whether this is a tls controlled junction.
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:435
double getSidewalkWidth(const std::string &type) const
Returns the lane width for a sidewalk to be added [m].
Definition: NBTypeCont.cpp:223
void myStartElement(int element, const SUMOSAXAttributes &attrs) override
Called on the opening of a tag;.
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.
double length2D() const
Returns the length.
bool myCurrentIsPlatform
Information whether this is a pt platform.
NBNodeCont & getNodeCont()
Returns a reference to the node container.
Definition: NBNetBuilder.h:161
long long int myToWay
the destination way for the current restriction
bool myIsRoute
indicates whether current relation is a route
int myLayer
Information about the relative z-ordering of ways.
Instance responsible for building networks.
Definition: NBNetBuilder.h:115
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:199
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition: NBEdge.h:596
static const std::string compoundTypeSeparator
The separator within newly created compound type names.
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:253
NBPTStop * get(std::string id)
Retrieve a previously inserted pt stop.
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:312
void addBikeLane(double width)
add a bicycle lane of the given width and shift existing connctions
Definition: NBEdge.cpp:3098
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:171
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
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.
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.
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.
bool myIsStopArea
indicates whether current relation is a pt stop area
static const long long int INVALID_ID
double getSpeed(const std::string &type) const
Returns the maximal velocity for the given type [m/s].
Definition: NBTypeCont.cpp:181
bool myCurrentIsRoad
Information whether this is a road.
bool operator()(const Edge *e1, const Edge *e2) const
Edge * myCurrentEdge
The currently built edge.
std::map< long long int, Edge * > myPlatformShapes
the map from OSM way ids to platform shapes
std::set< std::string > myUnusableTypes
The compounds types that do not contain known types.
std::vector< NBPTStop * > getStops()
Definition: NBPTLine.cpp:38
SVCPermissions permissions
type of pt stop
EdgesHandler(const std::map< long long int, NIOSMNode * > &osmNodes, std::map< long long int, Edge * > &toFill, std::map< long long int, Edge * > &platformShapes)
Constructor.
NBNode * retrieve(const std::string &id) const
Returns the node with the given name.
Definition: NBNodeCont.cpp:106
SVCPermissions getPermissions(const std::string &type) const
Returns allowed vehicle classes for the given type.
Definition: NBTypeCont.cpp:211
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.
void myStartElement(int element, const SUMOSAXAttributes &attrs) override
Called on the opening of a tag;.
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.
#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
void addPlatformCand(NBPTPlatform platform)
Definition: NBPTStop.cpp:106
static const double MAXSPEED_UNGIVEN
bool myIsPTRoute
indicates whether current relation is a pt route
const OptionsCont & myOptionsCont
the options
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:237
std::map< std::string, double > mySpeedMap
A map of non-numeric speed descriptions to their numeric values.
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.
double getBikeLaneWidth(const std::string &type) const
Returns the lane width for a bike lane to be added [m].
Definition: NBTypeCont.cpp:229
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:428
NBPTStopCont * myNBPTStopCont
The previously filled pt stop container.