SUMO - Simulation of Urban MObility
NIImporter_OpenStreetMap.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2018 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
19 // Importer for networks stored in OpenStreetMap format
20 /****************************************************************************/
21 
22 
23 // ===========================================================================
24 // included modules
25 // ===========================================================================
26 #include <config.h>
27 #include <algorithm>
28 #include <set>
29 #include <functional>
30 #include <sstream>
31 #include <limits>
35 #include <utils/common/ToString.h>
39 #include <netbuild/NBEdge.h>
40 #include <netbuild/NBEdgeCont.h>
41 #include <netbuild/NBNode.h>
42 #include <netbuild/NBNodeCont.h>
43 #include <netbuild/NBNetBuilder.h>
44 #include <netbuild/NBOwnTLDef.h>
50 #include <utils/xml/XMLSubSys.h>
51 #include <netbuild/NBPTLine.h>
52 #include <netbuild/NBPTLineCont.h>
53 #include "NILoader.h"
55 
56 //#define DEBUG_LAYER_ELEVATION
57 
58 // ---------------------------------------------------------------------------
59 // static members
60 // ---------------------------------------------------------------------------
62 
63 const long long int NIImporter_OpenStreetMap::INVALID_ID = std::numeric_limits<long long int>::max();
64 
65 // ===========================================================================
66 // Private classes
67 // ===========================================================================
68 
72 public:
73  bool operator()(const Edge* e1, const Edge* e2) const {
74  if (e1->myHighWayType != e2->myHighWayType) {
75  return e1->myHighWayType > e2->myHighWayType;
76  }
77  if (e1->myNoLanes != e2->myNoLanes) {
78  return e1->myNoLanes > e2->myNoLanes;
79  }
80  if (e1->myNoLanesForward != e2->myNoLanesForward) {
81  return e1->myNoLanesForward > e2->myNoLanesForward;
82  }
83  if (e1->myMaxSpeed != e2->myMaxSpeed) {
84  return e1->myMaxSpeed > e2->myMaxSpeed;
85  }
86  if (e1->myIsOneWay != e2->myIsOneWay) {
87  return e1->myIsOneWay > e2->myIsOneWay;
88  }
89  return e1->myCurrentNodes > e2->myCurrentNodes;
90  }
91 };
92 
93 // ===========================================================================
94 // method definitions
95 // ===========================================================================
96 // ---------------------------------------------------------------------------
97 // static methods
98 // ---------------------------------------------------------------------------
99 const std::string NIImporter_OpenStreetMap::compoundTypeSeparator("|"); //clang-tidy says: "compundTypeSeparator with
100 // static storage duration my throw an exception that cannot be caught
101 
102 void
104  NIImporter_OpenStreetMap importer;
105  importer.load(oc, nb);
106 }
107 
109 
111  // delete nodes
112  for (auto myUniqueNode : myUniqueNodes) {
113  delete myUniqueNode;
114  }
115  // delete edges
116  for (auto& myEdge : myEdges) {
117  delete myEdge.second;
118  }
119  // delete platform shapes
120  for (auto& myPlatformShape : myPlatformShapes) {
121  delete myPlatformShape.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
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 (auto 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->railwaySignal /* || 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 (auto& myEdge : myEdges) {
212  Edge* e = myEdge.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 (auto 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  //revise pt stops; remove stops on deleted edges
248  if (OptionsCont::getOptions().isSet("ptstop-output")) {
250  }
251 
252  // load relations (after edges are built since we want to apply
253  // turn-restrictions directly to NBEdges)
254  RelationHandler relationHandler(myOSMNodes, myEdges, &(nb.getPTStopCont()), myPlatformShapes,
255  &(nb.getPTLineCont()), oc);
256  for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
257  // relations
258  relationHandler.setFileName(*file);
259  PROGRESS_BEGIN_MESSAGE("Parsing relations from osm-file '" + *file + "'");
260  XMLSubSys::runParser(relationHandler, *file);
262  }
263 }
264 
265 NBNode*
267  NBNode* node = nc.retrieve(toString(id));
268  if (node == 0) {
269  NIOSMNode* n = myOSMNodes.find(id)->second;
270  Position pos(n->lon, n->lat, n->ele);
271  if (!NBNetBuilder::transformCoordinate(pos, true)) {
272  WRITE_ERROR("Unable to project coordinates for junction '" + toString(id) + "'.");
273  return 0;
274  }
275  node = new NBNode(toString(id), pos);
276  if (!nc.insert(node)) {
277  WRITE_ERROR("Could not insert junction '" + toString(id) + "'.");
278  delete node;
279  return 0;
280  }
281  n->node = node;
282  if (n->railwayCrossing) {
283  node->reinit(pos, NODETYPE_RAIL_CROSSING);
284  } else if (n->railwaySignal) {
285  node->reinit(pos, NODETYPE_RAIL_SIGNAL);
286  } else if (n->tlsControlled) {
287  // ok, this node is a traffic light node where no other nodes
288  // participate
289  // @note: The OSM-community has not settled on a schema for differentiating between fixed and actuated lights
291  OptionsCont::getOptions().getString("tls.default-type"));
292  NBOwnTLDef* tlDef = new NBOwnTLDef(toString(id), node, 0, type);
293  if (!tlsc.insert(tlDef)) {
294  // actually, nothing should fail here
295  delete tlDef;
296  throw ProcessError("Could not allocate tls '" + toString(id) + "'.");
297  }
298  }
299  if (n->railwayBufferStop) {
300  node->setParameter("buffer_stop", "true");
301  }
302  }
303  return node;
304 }
305 
306 int
308  const std::vector<long long int>& passed, NBNetBuilder& nb) {
309  NBNodeCont& nc = nb.getNodeCont();
310  NBEdgeCont& ec = nb.getEdgeCont();
311  NBTypeCont& tc = nb.getTypeCont();
312  NBPTStopCont& sc = nb.getPTStopCont();
313 
315  // patch the id
316  std::string id = toString(e->id);
317  if (from == 0 || to == 0) {
318  WRITE_ERROR("Discarding edge '" + id + "' because the nodes could not be built.");
319  return index;
320  }
321  if (index >= 0) {
322  id = id + "#" + toString(index);
323  } else {
324  index = 0;
325  }
326  if (from == to) {
327  assert(passed.size() >= 2);
328  if (passed.size() == 2) {
329  WRITE_WARNING("Discarding edge '" + id + "' which connects two identical nodes without geometry.");
330  return index;
331  }
332  // in the special case of a looped way split again using passed
333  int intermediateIndex = (int) passed.size() / 2;
334  NBNode* intermediate = insertNodeChecking(passed[intermediateIndex], nc, tlsc);
335  std::vector<long long int> part1(passed.begin(), passed.begin() + intermediateIndex + 1);
336  std::vector<long long int> part2(passed.begin() + intermediateIndex, passed.end());
337  index = insertEdge(e, index, from, intermediate, part1, nb);
338  return insertEdge(e, index, intermediate, to, part2, nb);
339  }
340  const int newIndex = index + 1;
341 
342  // convert the shape
343  PositionVector shape;
344  for (long long i : passed) {
345  NIOSMNode* n = myOSMNodes.find(i)->second;
346 
347  if (n->ptStopPosition) {
348  NBPTStop* existingPtStop = sc.get(toString(n->id));
349  if (existingPtStop != nullptr) {
350  existingPtStop->registerAdditionalEdge(toString(e->id), id);
351  } else {
352  Position ptPos(n->lon, n->lat, n->ele);
353  if (!NBNetBuilder::transformCoordinate(ptPos)) {
354  WRITE_ERROR("Unable to project coordinates for node '" + toString(n->id) + "'.");
355  }
356  NBPTStop* ptStop = new NBPTStop(toString(n->id), ptPos, id, toString(e->id), n->ptStopLength, n->name,
357  n->permissions);
358 
359  sc.insert(ptStop);
360  }
361  }
362  Position pos(n->lon, n->lat, n->ele);
363  shape.push_back(pos);
364  }
366  WRITE_ERROR("Unable to project coordinates for edge '" + id + "'.");
367  }
368 // shape.in
369 
370  std::string type = e->myHighWayType;
371  if (!tc.knows(type)) {
372  if (myUnusableTypes.count(type) > 0) {
373  return newIndex;
374  }
375  if (myKnownCompoundTypes.count(type) > 0) {
376  type = myKnownCompoundTypes[type];
377  } else {
378  // this edge has a type which does not yet exist in the TypeContainer
380  std::vector<std::string> types;
381  while (tok.hasNext()) {
382  std::string t = tok.next();
383  if (tc.knows(t)) {
384  if (std::find(types.begin(), types.end(), t) == types.end()) {
385  types.push_back(t);
386  }
387  } else if (tok.size() > 1) {
389  "Discarding unknown compound '" + t + "' in type '" + type + "' (first occurence for edge '"
390  + id
391  + "').");
392  }
393  }
394  if (types.empty()) {
395  WRITE_WARNING("Discarding unusable type '" + type + "' (first occurence for edge '" + id + "').");
396  myUnusableTypes.insert(type);
397  return newIndex;
398  }
399 
400  const std::string newType = joinToString(types, "|");
401  if (tc.knows(newType)) {
402  myKnownCompoundTypes[type] = newType;
403  type = newType;
404  } else if (myKnownCompoundTypes.count(newType) > 0) {
405  type = myKnownCompoundTypes[newType];
406  } else {
407  // build a new type by merging all values
408  int numLanes = 0;
409  double maxSpeed = 0;
410  int prio = 0;
411  double width = NBEdge::UNSPECIFIED_WIDTH;
412  double sidewalkWidth = NBEdge::UNSPECIFIED_WIDTH;
413  double bikelaneWidth = NBEdge::UNSPECIFIED_WIDTH;
414  bool defaultIsOneWay = false;
415  SVCPermissions permissions = 0;
416  bool discard = true;
417  for (auto& type2 : types) {
418  if (!tc.getShallBeDiscarded(type2)) {
419  numLanes = MAX2(numLanes, tc.getNumLanes(type2));
420  maxSpeed = MAX2(maxSpeed, tc.getSpeed(type2));
421  prio = MAX2(prio, tc.getPriority(type2));
422  defaultIsOneWay &= tc.getIsOneWay(type2);
423  //std::cout << "merging component " << type2 << " into type " << newType << " allows=" << getVehicleClassNames(tc.getPermissions(type2)) << "\n";
424  permissions |= tc.getPermissions(type2);
425  width = MAX2(width, tc.getWidth(type2));
426  sidewalkWidth = MAX2(sidewalkWidth, tc.getSidewalkWidth(type2));
427  bikelaneWidth = MAX2(bikelaneWidth, tc.getBikeLaneWidth(type2));
428  discard = false;
429  }
430  }
431  if (width != NBEdge::UNSPECIFIED_WIDTH) {
432  width = MAX2(width, SUMO_const_laneWidth);
433  }
434  // ensure pedestrians don't run into trains
435  if (sidewalkWidth == NBEdge::UNSPECIFIED_WIDTH
436  && (permissions & SVC_PEDESTRIAN) != 0
437  && (permissions & SVC_RAIL_CLASSES) != 0) {
438  //std::cout << "patching sidewalk for type '" << newType << "' which allows=" << getVehicleClassNames(permissions) << "\n";
439  sidewalkWidth = OptionsCont::getOptions().getFloat("default.sidewalk-width");
440  }
441 
442  if (discard) {
444  "Discarding compound type '" + newType + "' (first occurence for edge '" + id + "').");
445  myUnusableTypes.insert(newType);
446  return newIndex;
447  }
448 
449  WRITE_MESSAGE("Adding new type '" + type + "' (first occurence for edge '" + id + "').");
450  tc.insert(newType, numLanes, maxSpeed, prio, permissions, width, defaultIsOneWay, sidewalkWidth,
451  bikelaneWidth);
452  for (auto& type3 : types) {
453  if (!tc.getShallBeDiscarded(type3)) {
454  tc.copyRestrictionsAndAttrs(type3, newType);
455  }
456  }
457  myKnownCompoundTypes[type] = newType;
458  type = newType;
459 
460  }
461 
462  }
463  }
464 
465  // otherwise it is not an edge and will be ignored
466  bool ok = true;
467  int numLanesForward = tc.getNumLanes(type);
468  int numLanesBackward = tc.getNumLanes(type);
469  double speed = tc.getSpeed(type);
470  bool defaultsToOneWay = tc.getIsOneWay(type);
471  SVCPermissions forwardPermissions = tc.getPermissions(type);
472  SVCPermissions backwardPermissions = tc.getPermissions(type);
473  double forwardWidth = tc.getWidth(type);
474  double backwardWidth = tc.getWidth(type);
475  const bool addSidewalk = (tc.getSidewalkWidth(type) != NBEdge::UNSPECIFIED_WIDTH);
476  const bool addBikeLane = (tc.getBikeLaneWidth(type) != NBEdge::UNSPECIFIED_WIDTH);
477  // check directions
478  bool addForward = true;
479  bool addBackward = true;
480  if (e->myIsOneWay == "true" || e->myIsOneWay == "yes" || e->myIsOneWay == "1"
481  || (defaultsToOneWay && e->myIsOneWay != "no" && e->myIsOneWay != "false" && e->myIsOneWay != "0" &&
482  e->getParameter("railway:preferred_direction", "") != "both")) {
483  addBackward = false;
484  }
485  if (e->myIsOneWay == "-1" || e->myIsOneWay == "reverse") {
486  // one-way in reversed direction of way
487  addForward = false;
488  addBackward = true;
489  }
490  if (!e->myIsOneWay.empty() && e->myIsOneWay != "false" && e->myIsOneWay != "no" && e->myIsOneWay != "true"
491  && e->myIsOneWay != "yes" && e->myIsOneWay != "-1" && e->myIsOneWay != "1" && e->myIsOneWay != "reverse") {
492  WRITE_WARNING("New value for oneway found: " + e->myIsOneWay);
493  }
494  // if we had been able to extract the number of lanes, override the highway type default
495  if (e->myNoLanes > 0) {
496  if (addForward && !addBackward) {
497  numLanesForward = e->myNoLanes;
498  } else if (!addForward && addBackward) {
499  numLanesBackward = e->myNoLanes;
500  } else {
501  if (e->myNoLanesForward > 0) {
502  numLanesForward = e->myNoLanesForward;
503  } else if (e->myNoLanesForward < 0) {
504  numLanesForward = e->myNoLanes + e->myNoLanesForward;
505  } else {
506  numLanesForward = (int) std::ceil(e->myNoLanes / 2.0);
507  }
508  numLanesBackward = e->myNoLanes - numLanesForward;
509  // sometimes ways are tagged according to their physical width of a single
510  // lane but they are intended for traffic in both directions
511  numLanesForward = MAX2(1, numLanesForward);
512  numLanesBackward = MAX2(1, numLanesBackward);
513  }
514  } else if (e->myNoLanes == 0) {
515  WRITE_WARNING("Skipping edge '" + id + "' because it has zero lanes.");
516  ok = false;
517  }
518  // if we had been able to extract the maximum speed, override the type's default
519  if (e->myMaxSpeed != MAXSPEED_UNGIVEN) {
520  speed = (double)(e->myMaxSpeed / 3.6);
521  }
522  if (speed <= 0) {
523  WRITE_WARNING("Skipping edge '" + id + "' because it has speed " + toString(speed));
524  ok = false;
525  }
526  // deal with cycleways that run in the opposite direction of a one-way street
527  WayType cyclewayType = e->myCyclewayType; // make a copy because we do some temporary modifications
528  if (addBikeLane) {
529  if (!addForward && (cyclewayType & WAY_FORWARD) != 0) {
530  addForward = true;
531  forwardPermissions = SVC_BICYCLE;
532  forwardWidth = tc.getBikeLaneWidth(type);
533  numLanesForward = 1;
534  // do not add an additional cycle lane
535  cyclewayType = (WayType)(cyclewayType & ~WAY_FORWARD); //clang tidy thinks "!WAY_FORWARD" is always false
536  }
537  if (!addBackward && (cyclewayType & WAY_BACKWARD) != 0) {
538  addBackward = true;
539  backwardPermissions = SVC_BICYCLE;
540  backwardWidth = tc.getBikeLaneWidth(type);
541  numLanesBackward = 1;
542  // do not add an additional cycle lane
543  cyclewayType = (WayType)(cyclewayType & ~WAY_BACKWARD); //clang tidy thinks "!WAY_BACKWARD" is always false
544  }
545  }
546  // deal with sidewalks that run in the opposite direction of a one-way street
547  WayType sidewalkType = e->mySidewalkType; // make a copy because we do some temporary modifications
548  if (addSidewalk) {
549  if (!addForward && (sidewalkType & WAY_FORWARD) != 0) {
550  addForward = true;
551  forwardPermissions = SVC_PEDESTRIAN;
552  forwardWidth = tc.getSidewalkWidth(type);
553  numLanesForward = 1;
554  // do not add an additional sidewalk
555  sidewalkType = (WayType)(sidewalkType & ~WAY_FORWARD); //clang tidy thinks "!WAY_FORWARD" is always false
556  }
557  if (!addBackward && (sidewalkType & WAY_BACKWARD) != 0) {
558  addBackward = true;
559  backwardPermissions = SVC_PEDESTRIAN;
560  backwardWidth = tc.getSidewalkWidth(type);
561  numLanesBackward = 1;
562  // do not add an additional cycle lane
563  sidewalkType = (WayType)(sidewalkType & ~WAY_BACKWARD); //clang tidy thinks "!WAY_BACKWARD" is always false
564  }
565  }
566  // deal with busways that run in the opposite direction of a one-way street
567  if (!addForward && (e->myBuswayType & WAY_FORWARD) != 0) {
568  addForward = true;
569  forwardPermissions = SVC_BUS;
570  numLanesForward = 1;
571  }
572  if (!addBackward && (e->myBuswayType & WAY_BACKWARD) != 0) {
573  addBackward = true;
574  backwardPermissions = SVC_BUS;
575  numLanesBackward = 1;
576  }
577 
578  const std::string origID = OptionsCont::getOptions().getBool("output.original-names") ? toString(e->id) : "";
579  if (ok) {
580  LaneSpreadFunction lsf = (addBackward || OptionsCont::getOptions().getBool("osm.oneway-spread-right")) &&
581  e->getParameter("railway:preferred_direction", "") != "both" ? LANESPREAD_RIGHT : LANESPREAD_CENTER;
582 
583  id = StringUtils::escapeXML(id);
584  const std::string reverseID = "-" + id;
585 
586  if (addForward) {
587  assert(numLanesForward > 0);
588  NBEdge* nbe = new NBEdge(id, from, to, type, speed, numLanesForward, tc.getPriority(type),
589  forwardWidth, NBEdge::UNSPECIFIED_OFFSET, shape,
590  StringUtils::escapeXML(e->streetName), origID, lsf, true);
591  nbe->setPermissions(forwardPermissions);
592  if ((e->myBuswayType & WAY_FORWARD) != 0) {
593  nbe->setPermissions(SVC_BUS, 0);
594  }
595  if (addBikeLane && (cyclewayType == WAY_UNKNOWN || (cyclewayType & WAY_FORWARD) != 0)) {
596  nbe->addBikeLane(tc.getBikeLaneWidth(type));
597  } else if (nbe->getPermissions(0) == SVC_BUS) {
598  // bikes drive on buslanes if no separate cycle lane is available
600  }
601  if (addSidewalk && (sidewalkType == WAY_UNKNOWN || (sidewalkType & WAY_FORWARD) != 0)) {
602  nbe->addSidewalk(tc.getSidewalkWidth(type));
603  }
605  if (!ec.insert(nbe)) {
606  delete nbe;
607  throw ProcessError("Could not add edge '" + id + "'.");
608  }
609  }
610  if (addBackward) {
611  assert(numLanesBackward > 0);
612  NBEdge* nbe = new NBEdge(reverseID, to, from, type, speed, numLanesBackward, tc.getPriority(type),
613  backwardWidth, NBEdge::UNSPECIFIED_OFFSET, shape.reverse(),
614  StringUtils::escapeXML(e->streetName), origID, lsf, true);
615  nbe->setPermissions(backwardPermissions);
616  if ((e->myBuswayType & WAY_BACKWARD) != 0) {
617  nbe->setPermissions(SVC_BUS, 0);
618  }
619  if (addBikeLane && (cyclewayType == WAY_UNKNOWN || (cyclewayType & WAY_BACKWARD) != 0)) {
620  nbe->addBikeLane(tc.getBikeLaneWidth(type));
621  } else if (nbe->getPermissions(0) == SVC_BUS) {
622  // bikes drive on buslanes if no separate cycle lane is available
624  }
625  if (addSidewalk && (sidewalkType == WAY_UNKNOWN || (sidewalkType & WAY_BACKWARD) != 0)) {
626  nbe->addSidewalk(tc.getSidewalkWidth(type));
627  }
629  if (!ec.insert(nbe)) {
630  delete nbe;
631  throw ProcessError("Could not add edge '-" + id + "'.");
632  }
633  }
634  if ((e->myParkingType & PARKING_BOTH) != 0 && OptionsCont::getOptions().isSet("parking-output")) {
635  if ((e->myParkingType & PARKING_RIGHT) != 0) {
636  if (addForward) {
637  nb.getParkingCont().push_back(NBParking(id, id));
638  } else {
640  if ((e->myParkingType & PARKING_LEFT) == 0 && !addBackward) {
642  nb.getParkingCont().push_back(NBParking(reverseID, reverseID));
643  }
644  }
645  }
646  if ((e->myParkingType & PARKING_LEFT) != 0) {
647  if (addBackward) {
648  nb.getParkingCont().push_back(NBParking(reverseID, reverseID));
649  } else {
651  if ((e->myParkingType & PARKING_RIGHT) == 0 && !addForward) {
653  nb.getParkingCont().push_back(NBParking(id, id));
654  }
655  }
656  }
657  }
658  }
659  return newIndex;
660 }
661 
662 // ---------------------------------------------------------------------------
663 // definitions of NIImporter_OpenStreetMap::NodesHandler-methods
664 // ---------------------------------------------------------------------------
665 NIImporter_OpenStreetMap::NodesHandler::NodesHandler(std::map<long long int, NIOSMNode*>& toFill,
666  std::set<NIOSMNode*, CompareNodes>& uniqueNodes,
667  const OptionsCont& oc)
668 
669  :
670  SUMOSAXHandler("osm - file"),
671  myToFill(toFill),
672  myLastNodeID(-1),
673  myIsInValidNodeTag(false),
674  myHierarchyLevel(0),
675  myUniqueNodes(uniqueNodes),
676  myImportElevation(oc.getBool("osm.elevation")),
677  myOptionsCont(oc) {
678 }
679 
681 
682 void
685  if (element == SUMO_TAG_NODE) {
686  bool ok = true;
687  if (myHierarchyLevel != 2) {
688  WRITE_ERROR("Node element on wrong XML hierarchy level (id='" + toString(attrs.get<long
689  long
690  int>(SUMO_ATTR_ID,
691  nullptr, ok))
692  + "', level='" + toString(myHierarchyLevel) + "').");
693  return;
694  }
695  const long long int id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
696  const std::string action = attrs.hasAttribute("action") ? attrs.getStringSecure("action", "") : "";
697  if (action == "delete" || !ok) {
698  return;
699  }
700  myLastNodeID = -1;
701  if (myToFill.find(id) == myToFill.end()) {
702  myLastNodeID = id;
703  // assume we are loading multiple files...
704  // ... so we won't report duplicate nodes
705  bool ok2 = true;
706  double tlat, tlon;
707  std::istringstream lon(attrs.get<std::string>(SUMO_ATTR_LON, toString(id).c_str(), ok2));
708  if (!ok2) {
709  return;
710  }
711  lon >> tlon;
712  if (lon.fail()) {
713  WRITE_ERROR("Node's '" + toString(id) + "' lon information is not numeric.");
714  return;
715  }
716  std::istringstream lat(attrs.get<std::string>(SUMO_ATTR_LAT, toString(id).c_str(), ok2));
717  if (!ok2) {
718  return;
719  }
720  lat >> tlat;
721  if (lat.fail()) {
722  WRITE_ERROR("Node's '" + toString(id) + "' lat information is not numeric.");
723  return;
724  }
725  auto* toAdd = new NIOSMNode(id, tlon, tlat);
726  myIsInValidNodeTag = true;
727 
728  auto similarNode = myUniqueNodes.find(toAdd);
729  if (similarNode == myUniqueNodes.end()) {
730  myUniqueNodes.insert(toAdd);
731  } else {
732  delete toAdd;
733  toAdd = *similarNode;
734  WRITE_MESSAGE("Found duplicate nodes. Substituting " + toString(id) + " with " + toString(toAdd->id));
735  }
736  myToFill[id] = toAdd;
737  }
738  }
739  if (element == SUMO_TAG_TAG && myIsInValidNodeTag) {
740  if (myHierarchyLevel != 3) {
741  WRITE_ERROR("Tag element on wrong XML hierarchy level.");
742  return;
743  }
744  bool ok = true;
745  std::string key = attrs.get<std::string>(SUMO_ATTR_K, toString(myLastNodeID).c_str(), ok, false);
746  // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
747  if (key == "highway" || key == "ele" || key == "crossing" || key == "railway" || key == "public_transport"
748  || key == "name" || key == "train" || key == "bus" || key == "tram" || key == "light_rail" || key == "subway" || key == "station" || key == "noexit"
749  || StringUtils::startsWith(key, "railway:signal")) {
750  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myLastNodeID).c_str(), ok, false);
751  if (key == "highway" && value.find("traffic_signal") != std::string::npos) {
752  myToFill[myLastNodeID]->tlsControlled = true;
753  } else if (key == "crossing" && value.find("traffic_signals") != std::string::npos) {
754  myToFill[myLastNodeID]->tlsControlled = true;
755  } else if ((key == "noexit" && value == "yes")
756  || (key == "railway" && value == "buffer_stop")) {
757  myToFill[myLastNodeID]->railwayBufferStop = true;
758  } else if (key == "railway" && value.find("crossing") != std::string::npos) {
759  myToFill[myLastNodeID]->railwayCrossing = true;
760  } else if (StringUtils::startsWith(key, "railway:signal") && (
761  value == "block" || value == "entry" || value == "exit" || value == "intermediate")) {
762  myToFill[myLastNodeID]->railwaySignal = true;
763  } else if ((key == "public_transport" && value == "stop_position") ||
764  (key == "highway" && value == "bus_stop")) {
765  myToFill[myLastNodeID]->ptStopPosition = true;
766  if (myToFill[myLastNodeID]->ptStopLength == 0) {
767  // default length
768  myToFill[myLastNodeID]->ptStopLength = myOptionsCont.getFloat("osm.stop-output.length");
769  }
770  } else if (key == "name") {
771  myToFill[myLastNodeID]->name = value;
772  } else if (key == "train") {
773  myToFill[myLastNodeID]->permissions = SVC_RAIL;
774  myToFill[myLastNodeID]->ptStopLength = myOptionsCont.getFloat("osm.stop-output.length.train");
775  } else if (key == "subway" || key == "light_rail"
776  || (key == "station" && (value == "subway" || value == "light_rail"))) {
777  myToFill[myLastNodeID]->permissions = SVC_RAIL_URBAN;
778  myToFill[myLastNodeID]->ptStopLength = myOptionsCont.getFloat("osm.stop-output.length.train");
779  } else if (key == "bus") {
780  myToFill[myLastNodeID]->permissions = SVC_BUS;
781  myToFill[myLastNodeID]->ptStopLength = myOptionsCont.getFloat("osm.stop-output.length.bus");
782  } else if (key == "tram") {
783  myToFill[myLastNodeID]->permissions = SVC_TRAM;
784  myToFill[myLastNodeID]->ptStopLength = myOptionsCont.getFloat("osm.stop-output.length.tram");
785  } else if (myImportElevation && key == "ele") {
786  try {
787  myToFill[myLastNodeID]->ele = TplConvert::_2double(value.c_str());
788  } catch (...) {
789  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in node '" +
790  toString(myLastNodeID) + "'.");
791  }
792  }
793  }
794  }
795 }
796 
797 void
799  if (element == SUMO_TAG_NODE && myHierarchyLevel == 2) {
800  myLastNodeID = -1;
801  myIsInValidNodeTag = false;
802  }
804 }
805 
806 // ---------------------------------------------------------------------------
807 // definitions of NIImporter_OpenStreetMap::EdgesHandler-methods
808 // ---------------------------------------------------------------------------
810  const std::map<long long int, NIOSMNode*>& osmNodes,
811  std::map<long long int, Edge*>& toFill, std::map<long long int, Edge*>& platformShapes)
812  :
813  SUMOSAXHandler("osm - file"),
814  myOSMNodes(osmNodes),
815  myEdgeMap(toFill),
816  myPlatformShapesMap(platformShapes) {
817  mySpeedMap["signals"] = MAXSPEED_UNGIVEN;
818  mySpeedMap["none"] = 300.;
819  mySpeedMap["no"] = 300.;
820  mySpeedMap["walk"] = 5.;
821  mySpeedMap["DE:rural"] = 100.;
822  mySpeedMap["DE:urban"] = 50.;
823  mySpeedMap["DE:living_street"] = 10.;
824 
825 }
826 
828 
829 void
831  const SUMOSAXAttributes& attrs) {
832  myParentElements.push_back(element);
833  // parse "way" elements
834  if (element == SUMO_TAG_WAY) {
835  bool ok = true;
836  const long long int id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
837  std::string action = attrs.hasAttribute("action") ? attrs.getStringSecure("action", "") : "";
838  if (action == "delete" || !ok) {
839  myCurrentEdge = 0;
840  return;
841  }
842  myCurrentEdge = new Edge(id);
843  }
844  // parse "nd" (node) elements
845  if (element == SUMO_TAG_ND && myCurrentEdge != 0) {
846  bool ok = true;
847  long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, 0, ok);
848  if (ok) {
849  auto node = myOSMNodes.find(ref);
850  if (node == myOSMNodes.end()) {
851  WRITE_WARNING("The referenced geometry information (ref='" + toString(ref) + "') is not known");
852  return;
853  }
854 
855  ref = node->second->id; // node may have been substituted
856  if (myCurrentEdge->myCurrentNodes.empty() ||
857  myCurrentEdge->myCurrentNodes.back() != ref) { // avoid consecutive duplicates
858  myCurrentEdge->myCurrentNodes.push_back(ref);
859  }
860 
861  }
862  }
863  // parse values
864  if (element == SUMO_TAG_TAG && myParentElements.size() > 2
865  && myParentElements[myParentElements.size() - 2] == SUMO_TAG_WAY) {
866  if (myCurrentEdge == 0) {
867  return;
868  }
869  bool ok = true;
870  std::string key = attrs.get<std::string>(SUMO_ATTR_K, toString(myCurrentEdge->id).c_str(), ok, false);
871  if (key.size() > 8 && StringUtils::startsWith(key, "cycleway:")) {
872  // handle special cycleway keys
873  const std::string cyclewaySpec = key.substr(9);
874  key = "cycleway";
875  if (cyclewaySpec == "right") {
877  } else if (cyclewaySpec == "left") {
879  } else if (cyclewaySpec == "both") {
881  } else {
882  key = "ignore";
883  }
884  if ((myCurrentEdge->myCyclewayType & WAY_BOTH) != 0) {
885  // now we have some info on directionality
887  }
888  } else if (key.size() > 6 && StringUtils::startsWith(key, "busway:")) {
889  // handle special busway keys
890  const std::string buswaySpec = key.substr(7);
891  key = "busway";
892  if (buswaySpec == "right") {
894  } else if (buswaySpec == "left") {
896  } else if (buswaySpec == "both") {
898  } else {
899  key = "ignore";
900  }
901  }
902  if ((key == "bridge" || key == "tunnel") && OptionsCont::getOptions().getBool("osm.all-attributes")) {
903  myCurrentEdge->setParameter(key, "true"); // could be differentiated further if necessary
904  }
905  // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
906  if (!StringUtils::endsWith(key, "way") && !StringUtils::startsWith(key, "lanes")
907  && key != "maxspeed" && key != "junction" && key != "name" && key != "tracks" && key != "layer"
908  && key != "route"
909  && key != "sidewalk"
910  && !StringUtils::startsWith(key, "parking")
911  && key != "postal_code" && key != "railway:preferred_direction" && key != "public_transport") {
912  return;
913  }
914  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentEdge->id).c_str(), ok, false);
915 
916  if ((key == "highway" && value != "platform") || key == "railway" || key == "waterway" || key == "cycleway"
917  || key == "busway" || key == "route" || key == "sidewalk") {
919  // special cycleway stuff
920  if (key == "cycleway") {
921  if (value == "no") {
922  return;
923  }
924  if (value == "opposite_track") {
926  } else if (value == "opposite_lane") {
928  }
929  }
930  // special sidewalk stuff
931  if (key == "sidewalk") {
932  if (value == "no" || value == "none") {
934  } else if (value == "both") {
936  } else if (value == "right") {
938  } else if (value == "left") {
940  }
941  // no need to extend the type id
942  return;
943  }
944  // special busway stuff
945  if (key == "busway") {
946  if (value == "no") {
947  return;
948  }
949  if (value == "opposite_track") {
951  } else if (value == "opposite_lane") {
953  }
954  // no need to extend the type id
955  return;
956  }
957  // build type id
958  const std::string singleTypeID = key + "." + value;
959  if (!myCurrentEdge->myHighWayType.empty()) {
960  // osm-ways may be used by more than one mode (eg railway.tram + highway.residential. this is relevant for multimodal traffic)
961  // we create a new type for this kind of situation which must then be resolved in insertEdge()
962  std::vector<std::string> types = StringTokenizer(myCurrentEdge->myHighWayType,
964  types.push_back(singleTypeID);
966  } else {
967  myCurrentEdge->myHighWayType = singleTypeID;
968  }
969  } else if (key == "lanes") {
970  try {
971  myCurrentEdge->myNoLanes = TplConvert::_2int(value.c_str());
972  } catch (NumberFormatException&) {
973  // might be a list of values
974  StringTokenizer st(value, ";", true);
975  std::vector<std::string> list = st.getVector();
976  if (list.size() >= 2) {
977  int minLanes = std::numeric_limits<int>::max();
978  try {
979  for (auto& i : list) {
980  int numLanes = TplConvert::_2int(StringUtils::prune(i).c_str());
981  minLanes = MIN2(minLanes, numLanes);
982  }
983  myCurrentEdge->myNoLanes = minLanes;
985  "Using minimum lane number from list (" + value + ") for edge '"
987  + "'.");
988  } catch (NumberFormatException&) {
989  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
990  toString(myCurrentEdge->id) + "'.");
991  }
992  }
993  } catch (EmptyData&) {
994  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
995  toString(myCurrentEdge->id) + "'.");
996  }
997  } else if (key == "lanes:forward") {
998  try {
1000  } catch (...) {
1001  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
1002  toString(myCurrentEdge->id) + "'.");
1003  }
1004  } else if (key == "lanes:backward") {
1005  try {
1006  // denote backwards count with a negative sign
1008  } catch (...) {
1009  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
1010  toString(myCurrentEdge->id) + "'.");
1011  }
1012  } else if (key == "maxspeed") {
1013  if (mySpeedMap.find(value) != mySpeedMap.end()) {
1015  } else {
1016  double conversion = 1; // OSM default is km/h
1017  if (StringUtils::to_lower_case(value).find("km/h") != std::string::npos) {
1018  value = StringUtils::prune(value.substr(0, value.find_first_not_of("0123456789")));
1019  } else if (StringUtils::to_lower_case(value).find("mph") != std::string::npos) {
1020  value = StringUtils::prune(value.substr(0, value.find_first_not_of("0123456789")));
1021  conversion = 1.609344; // kilometers per mile
1022  }
1023  try {
1024  myCurrentEdge->myMaxSpeed = TplConvert::_2double(value.c_str()) * conversion;
1025  } catch (...) {
1026  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
1027  toString(myCurrentEdge->id) + "'.");
1028  }
1029  }
1030  } else if (key == "junction") {
1031  if ((value == "roundabout") && (myCurrentEdge->myIsOneWay.empty())) {
1032  myCurrentEdge->myIsOneWay = "yes";
1033  }
1034  } else if (key == "oneway") {
1035  myCurrentEdge->myIsOneWay = value;
1036  } else if (key == "name") {
1037  myCurrentEdge->streetName = value;
1038  } else if (key == "layer") {
1039  try {
1040  myCurrentEdge->myLayer = TplConvert::_2int(value.c_str());
1041  } catch (...) {
1042  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
1043  toString(myCurrentEdge->id) + "'.");
1044  }
1045  } else if (key == "tracks") {
1046  try {
1047  if (TplConvert::_2int(value.c_str()) > 1) {
1048  myCurrentEdge->myIsOneWay = "false";
1049  } else {
1050  myCurrentEdge->myIsOneWay = "true";
1051  }
1052  } catch (...) {
1053  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
1054  toString(myCurrentEdge->id) + "'.");
1055  }
1056  } else if (key == "postal_code" && OptionsCont::getOptions().getBool("osm.all-attributes")) {
1057  myCurrentEdge->setParameter(key, value);
1058  } else if (key == "railway:preferred_direction") {
1059  // this param is special because it influences network building (duplicate rail edges)
1060  myCurrentEdge->setParameter(key, value);
1061  } else if (key == "public_transport" && value == "platform") {
1063  } else if (key == "parking:lane:both" && !StringUtils::startsWith(value, "no")) {
1065  } else if (key == "parking:lane:left" && !StringUtils::startsWith(value, "no")) {
1067  } else if (key == "parking:lane:right" && !StringUtils::startsWith(value, "no")) {
1069  }
1070  }
1071 }
1072 
1073 void
1075  myParentElements.pop_back();
1076  if (element == SUMO_TAG_WAY && myCurrentEdge != nullptr) {
1079  } else if (myCurrentEdge->myCurrentIsPlatform) {
1081  } else {
1082  delete myCurrentEdge;
1083  }
1084  myCurrentEdge = nullptr;
1085  }
1086 }
1087 
1088 // ---------------------------------------------------------------------------
1089 // definitions of NIImporter_OpenStreetMap::RelationHandler-methods
1090 // ---------------------------------------------------------------------------
1092  const std::map<long long int, NIOSMNode*>& osmNodes,
1093  const std::map<long long int, Edge*>& osmEdges, NBPTStopCont* nbptStopCont,
1094  const std::map<long long int, Edge*>& platformShapes,
1095  NBPTLineCont* nbptLineCont,
1096  const OptionsCont& oc)
1097  :
1098  SUMOSAXHandler("osm - file"),
1099  myOSMNodes(osmNodes),
1100  myOSMEdges(osmEdges),
1101  myPlatformShapes(platformShapes),
1102  myNBPTStopCont(nbptStopCont),
1103  myNBPTLineCont(nbptLineCont),
1104  myOptionsCont(oc) {
1105  resetValues();
1106 }
1107 
1109 
1110 void
1113  myIsRestriction = false;
1115  myToWay = INVALID_ID;
1117  myViaWay = INVALID_ID;
1119  myPlatforms.clear();
1120  myStops.clear();
1121  myWays.clear();
1122  myIsStopArea = false;
1123  myIsRoute = false;
1124  myPTRouteType = "";
1125 }
1126 
1127 void
1129  const SUMOSAXAttributes& attrs) {
1130  myParentElements.push_back(element);
1131  // parse "way" elements
1132  if (element == SUMO_TAG_RELATION) {
1133  bool ok = true;
1134  myCurrentRelation = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
1135  const std::string action = attrs.hasAttribute("action") ? attrs.getStringSecure("action", "") : "";
1136  if (action == "delete" || !ok) {
1138  }
1139  myName = "";
1140  myRef = "";
1141  myInterval = -1;
1142  myNightService = "";
1143  return;
1144  }
1145  if (myCurrentRelation == INVALID_ID) {
1146  return;
1147  }
1148  // parse member elements
1149  if (element == SUMO_TAG_MEMBER) {
1150  bool ok = true;
1151  std::string role = attrs.hasAttribute("role") ? attrs.getStringSecure("role", "") : "";
1152  auto ref = attrs.get<long
1153  long
1154  int>(SUMO_ATTR_REF, 0, ok);
1155  if (role == "via") {
1156  // u-turns for divided ways may be given with 2 via-nodes or 1 via-way
1157  std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, 0, ok);
1158  if (memberType == "way" && checkEdgeRef(ref)) {
1159  myViaWay = ref;
1160  } else if (memberType == "node") {
1161  if (myOSMNodes.find(ref) != myOSMNodes.end()) {
1162  myViaNode = ref;
1163  } else {
1164  WRITE_WARNING(
1165  "No node found for reference '" + toString(ref) + "' in relation '"
1167  + "'");
1168  }
1169  }
1170  } else if (role == "from" && checkEdgeRef(ref)) {
1171  myFromWay = ref;
1172  } else if (role == "to" && checkEdgeRef(ref)) {
1173  myToWay = ref;
1174  } else if (role == "stop") {
1175  myStops.push_back(ref);
1176  } else if (role == "platform") {
1177  std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, 0, ok);
1178  if (memberType == "way") {
1179  const std::map<long long int,
1180  NIImporter_OpenStreetMap::Edge*>::const_iterator& wayIt = myPlatformShapes.find(ref);
1181  if (wayIt != myPlatformShapes.end()) {
1182 
1183  NIIPTPlatform platform;
1184  platform.isWay = true;
1185  platform.ref = ref;
1186  myPlatforms.push_back(platform);
1187  }
1188  } else if (memberType == "node") {
1189  NIIPTPlatform platform;
1190  platform.isWay = false;
1191  platform.ref = ref;
1192  myPlatforms.push_back(platform);
1193  }
1194 
1195  } else if (role.empty()) {
1196  std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, 0, ok);
1197  if (memberType == "way") {
1198  myWays.push_back(ref);
1199  }
1200  }
1201  return;
1202  }
1203  // parse values
1204  if (element == SUMO_TAG_TAG) {
1205  bool ok = true;
1206  std::string key = attrs.get<std::string>(SUMO_ATTR_K, toString(myCurrentRelation).c_str(), ok, false);
1207  // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
1208  if (key == "type" || key == "restriction") {
1209  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1210  if (key == "type" && value == "restriction") {
1211  myIsRestriction = true;
1212  return;
1213  }
1214  if (key == "type" && value == "route") {
1215  myIsRoute = true;
1216  return;
1217  }
1218  if (key == "restriction") {
1219  // @note: the 'right/left/straight' part is ignored since the information is
1220  // redundantly encoded in the 'from', 'to' and 'via' members
1221  if (value.substr(0, 5) == "only_") {
1223  } else if (value.substr(0, 3) == "no_") {
1225  } else {
1226  WRITE_WARNING(
1227  "Found unknown restriction type '" + value + "' in relation '" + toString(myCurrentRelation)
1228  + "'");
1229  }
1230  return;
1231  }
1232  } else if (key == "public_transport") {
1233  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1234  if (value == "stop_area") {
1235  myIsStopArea = true;
1236  }
1237  } else if (key == "route") {
1238  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1239  if (value == "train" || value == "subway" || value == "light_rail" || value == "monorail" || value == "tram" || value == "bus"
1240  || value == "trolleybus" || value == "arialway" || value == "ferry") {
1241  myPTRouteType = value;
1242  }
1243 
1244  } else if (key == "name") {
1245  myName = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1246  } else if (key == "ref") {
1247  myRef = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1248  } else if (key == "interval" || key == "headway") {
1249  myInterval = attrs.get<int>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1250  } else if (key == "by_night") {
1251  myNightService = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1252  }
1253  }
1254 }
1255 
1256 bool
1258  if (myOSMEdges.find(ref) != myOSMEdges.end()) {
1259  return true;
1260  }
1261 
1262  WRITE_WARNING(
1263  "No way found for reference '" + toString(ref) + "' in relation '" + toString(myCurrentRelation) + "'");
1264  return false;
1265 
1266 }
1267 
1268 void
1270  myParentElements.pop_back();
1271  if (element == SUMO_TAG_RELATION) {
1272  if (myIsRestriction) {
1273  assert(myCurrentRelation != INVALID_ID);
1274  bool ok = true;
1276  WRITE_WARNING("Ignoring restriction relation '" + toString(myCurrentRelation) + "' with unknown type.");
1277  ok = false;
1278  }
1279  if (myFromWay == INVALID_ID) {
1280  WRITE_WARNING(
1281  "Ignoring restriction relation '" + toString(myCurrentRelation) + "' with unknown from-way.");
1282  ok = false;
1283  }
1284  if (myToWay == INVALID_ID) {
1285  WRITE_WARNING(
1286  "Ignoring restriction relation '" + toString(myCurrentRelation) + "' with unknown to-way.");
1287  ok = false;
1288  }
1289  if (myViaNode == INVALID_ID && myViaWay == INVALID_ID) {
1290  WRITE_WARNING("Ignoring restriction relation '" + toString(myCurrentRelation) + "' with unknown via.");
1291  ok = false;
1292  }
1293  if (ok && !applyRestriction()) {
1294  WRITE_WARNING("Ignoring restriction relation '" + toString(myCurrentRelation) + "'.");
1295  }
1296  } else if (myIsStopArea && OptionsCont::getOptions().isSet("ptstop-output")) {
1297  for (long long ref : myStops) {
1298  if (myOSMNodes.find(ref) == myOSMNodes.end()) {
1299  WRITE_WARNING(
1300  "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
1301  + "' does not exist. Probably OSM file is incomplete.");
1302  continue;
1303  }
1304 
1305  NIOSMNode* n = myOSMNodes.find(ref)->second;
1306  NBPTStop* ptStop = myNBPTStopCont->get(toString(n->id));
1307  if (ptStop == 0) {
1308  WRITE_WARNING(
1309  "Relation '" + toString(myCurrentRelation) + "' refers to a non existing pt stop at node: '"
1310  + toString(n->id) + "'. Probably OSM file is incomplete.");
1311  continue;
1312  }
1313  for (NIIPTPlatform& myPlatform : myPlatforms) {
1314  if (myPlatform.isWay) {
1315  assert(myPlatformShapes.find(myPlatform.ref) != myPlatformShapes.end()); //already tested earlier
1316  Edge* edge = (*myPlatformShapes.find(myPlatform.ref)).second;
1317  if (edge->myCurrentNodes[0] == *(edge->myCurrentNodes.end() - 1)) {
1318  WRITE_WARNING("Platform '" + toString(myPlatform.ref) + "' in relation: '" + toString(myCurrentRelation)
1319  + "' is given as polygon, which currently is not supported.");
1320  continue;
1321 
1322  }
1323  PositionVector p;
1324  for (auto nodeRef : edge->myCurrentNodes) {
1325  if (myOSMNodes.find(nodeRef) == myOSMNodes.end()) {
1326  WRITE_WARNING(
1327  "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
1328  + "' does not exist. Probably OSM file is incomplete.");
1329  continue;
1330  }
1331  NIOSMNode* pNode = myOSMNodes.find(nodeRef)->second;
1332  Position pNodePos(pNode->lon, pNode->lat, pNode->ele);
1333  if (!NBNetBuilder::transformCoordinate(pNodePos)) {
1334  WRITE_ERROR("Unable to project coordinates for node '" + toString(pNode->id) + "'.");
1335  continue;
1336  }
1337  p.push_back(pNodePos);
1338  }
1339  if (p.size() == 0) {
1340  WRITE_WARNING(
1341  "Referenced platform: '" + toString(myPlatform.ref) + "' in relation: '" + toString(myCurrentRelation)
1342  + "' is corrupt. Probably OSM file is incomplete.");
1343  continue;
1344  }
1345  NBPTPlatform platform(p[(int)p.size() / 2], p.length());
1346  ptStop->addPlatformCand(platform);
1347  } else {
1348  if (myOSMNodes.find(myPlatform.ref) == myOSMNodes.end()) {
1349  WRITE_WARNING(
1350  "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
1351  + "' does not exist. Probably OSM file is incomplete.");
1352  continue;
1353  }
1354  NIOSMNode* pNode = myOSMNodes.find(myPlatform.ref)->second;
1355  Position platformPos(pNode->lon, pNode->lat, pNode->ele);
1356  if (!NBNetBuilder::transformCoordinate(platformPos)) {
1357  WRITE_ERROR("Unable to project coordinates for node '" + toString(pNode->id) + "'.");
1358  }
1359  NBPTPlatform platform(platformPos, myOptionsCont.getFloat(
1360  "osm.stop-output.length"));
1361  ptStop->addPlatformCand(platform);
1362 
1363  }
1364  }
1365  ptStop->setIsMultipleStopPositions(myStops.size() > 1);;
1366  }
1367  } else if (myPTRouteType != "" && myIsRoute && OptionsCont::getOptions().isSet("ptline-output") && myStops.size() > 1) {
1369  ptLine->setMyNumOfStops((int)myStops.size());
1370  for (long long ref : myStops) {
1371  if (myOSMNodes.find(ref) == myOSMNodes.end()) {
1372  WRITE_WARNING(
1373  "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
1374  + "' does not exist. Probably OSM file is incomplete.");
1375 // resetValues();
1376 // return;
1377  if (!ptLine->getStops().empty()) {
1378  WRITE_WARNING("Done reading first coherent junk of pt stops. Further stops in relation " + toString(myCurrentRelation) + " are ignored");
1379  break;
1380  }
1381  continue;
1382  }
1383 
1384  NIOSMNode* n = myOSMNodes.find(ref)->second;
1385  NBPTStop* ptStop = myNBPTStopCont->get(toString(n->id));
1386  if (ptStop == nullptr) {
1387  WRITE_WARNING("Relation '" + toString(myCurrentRelation)
1388  + "' refers to a non existing pt stop at node: '" + toString(n->id)
1389  + "'. Probably OSM file is incomplete.");
1390 // resetValues();
1391 // return;
1392  if (!ptLine->getStops().empty()) {
1393  WRITE_WARNING("Done reading first coherent junk of pt stops. Further stops in relation " + toString(myCurrentRelation) + " are ignored");
1394  break;
1395  }
1396  continue;
1397  }
1398  ptLine->addPTStop(ptStop);
1399  }
1400  for (long long& myWay : myWays) {
1401  auto entr = myOSMEdges.find(myWay);
1402  if (entr != myOSMEdges.end()) {
1403  Edge* edge = entr->second;
1404  for (long long& myCurrentNode : edge->myCurrentNodes) {
1405  ptLine->addWayNode(myWay, myCurrentNode);
1406  }
1407  }
1408  }
1409  if (ptLine->getStops().empty()) {
1410  WRITE_WARNING("PT line in relation " + toString(myCurrentRelation) + " with no stops ignored. Probably OSM file is incomplete.");
1411  resetValues();
1412  return;
1413  }
1414  myNBPTLineCont->insert(ptLine);
1415  }
1416  // other relations might use similar subelements so reset in any case
1417  resetValues();
1418  }
1419 }
1420 
1421 bool
1423  // since OSM ways are bidirectional we need the via to figure out which direction was meant
1424  if (myViaNode != INVALID_ID) {
1425  NBNode* viaNode = myOSMNodes.find(myViaNode)->second->node;
1426  if (viaNode == 0) {
1427  WRITE_WARNING("Via-node '" + toString(myViaNode) + "' was not instantiated");
1428  return false;
1429  }
1430  NBEdge* from = findEdgeRef(myFromWay, viaNode->getIncomingEdges());
1431  NBEdge* to = findEdgeRef(myToWay, viaNode->getOutgoingEdges());
1432  if (from == 0) {
1433  WRITE_WARNING("from-edge of restriction relation could not be determined");
1434  return false;
1435  }
1436  if (to == 0) {
1437  WRITE_WARNING("to-edge of restriction relation could not be determined");
1438  return false;
1439  }
1441  from->addEdge2EdgeConnection(to);
1442  } else {
1443  from->removeFromConnections(to, -1, -1, true);
1444  }
1445  } else {
1446  // XXX interpreting via-ways or via-node lists not yet implemented
1447  WRITE_WARNING("direction of restriction relation could not be determined");
1448  return false;
1449  }
1450  return true;
1451 }
1452 
1453 NBEdge*
1455  const std::vector<NBEdge*>& candidates) const {
1456  const std::string prefix = toString(wayRef);
1457  const std::string backPrefix = "-" + prefix;
1458  NBEdge* result = 0;
1459  int found = 0;
1460  for (auto candidate : candidates) {
1461  if ((candidate->getID().substr(0, prefix.size()) == prefix) ||
1462  (candidate->getID().substr(0, backPrefix.size()) == backPrefix)) {
1463  result = candidate;
1464  found++;
1465  }
1466  }
1467  if (found > 1) {
1468  WRITE_WARNING("Ambigous way reference '" + prefix + "' in restriction relation");
1469  result = 0;
1470  }
1471  return result;
1472 }
1473 
1474 void
1476  NBNodeCont& nc = nb.getNodeCont();
1477  NBEdgeCont& ec = nb.getEdgeCont();
1478  // reconstruct elevation from layer info
1479  // build a map of raising and lowering forces (attractor and distance)
1480  // for all nodes unknownElevation
1481  std::map<NBNode*, std::vector<std::pair<double, double> > > layerForces;
1482 
1483  // collect all nodes that belong to a way with layer information
1484  std::set<NBNode*> knownElevation;
1485  for (auto& myEdge : myEdges) {
1486  Edge* e = myEdge.second;
1487  if (e->myLayer != 0) {
1488  for (auto j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
1489  NBNode* node = nc.retrieve(toString(*j));
1490  if (node != 0) {
1491  knownElevation.insert(node);
1492  layerForces[node].emplace_back(e->myLayer * layerElevation, POSITION_EPS);
1493  }
1494  }
1495  }
1496  }
1497 #ifdef DEBUG_LAYER_ELEVATION
1498  std::cout << "known elevations:\n";
1499  for (std::set<NBNode*>::iterator it = knownElevation.begin(); it != knownElevation.end(); ++it) {
1500  const std::vector<std::pair<double, double> >& primaryLayers = layerForces[*it];
1501  std::cout << " node=" << (*it)->getID() << " ele=";
1502  for (std::vector<std::pair<double, double> >::const_iterator it_ele = primaryLayers.begin(); it_ele != primaryLayers.end(); ++it_ele) {
1503  std::cout << it_ele->first << " ";
1504  }
1505  std::cout << "\n";
1506  }
1507 #endif
1508  // layer data only provides a lower bound on elevation since it is used to
1509  // resolve the relation among overlapping ways.
1510  // Perform a sanity check for steep inclines and raise the knownElevation if necessary
1511  std::map<NBNode*, double> knownEleMax;
1512  for (auto it : knownElevation) {
1513  double eleMax = -std::numeric_limits<double>::max();
1514  const std::vector<std::pair<double, double> >& primaryLayers = layerForces[it];
1515  for (const auto& primaryLayer : primaryLayers) {
1516  eleMax = MAX2(eleMax, primaryLayer.first);
1517  }
1518  knownEleMax[it] = eleMax;
1519  }
1520  const double gradeThreshold = OptionsCont::getOptions().getFloat("osm.layer-elevation.max-grade") / 100;
1521  bool changed = true;
1522  while (changed) {
1523  changed = false;
1524  for (auto it = knownElevation.begin(); it != knownElevation.end(); ++it) {
1525  std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it,
1526  knownEleMax[*it]
1527  / gradeThreshold * 3,
1528  knownElevation);
1529  for (auto& neighbor : neighbors) {
1530  if (knownElevation.count(neighbor.first) != 0) {
1531  const double grade = fabs(knownEleMax[*it] - knownEleMax[neighbor.first])
1532  / MAX2(POSITION_EPS, neighbor.second.first);
1533 #ifdef DEBUG_LAYER_ELEVATION
1534  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";
1535 #endif
1536  if (grade > gradeThreshold * 50 / 3.6 / neighbor.second.second) {
1537  // raise the lower node to the higher level
1538  const double eleMax = MAX2(knownEleMax[*it], knownEleMax[neighbor.first]);
1539  if (knownEleMax[*it] < eleMax) {
1540  knownEleMax[*it] = eleMax;
1541  } else {
1542  knownEleMax[neighbor.first] = eleMax;
1543  }
1544  changed = true;
1545  }
1546  }
1547  }
1548  }
1549  }
1550 
1551  // collect all nodes within a grade-dependent range around knownElevation-nodes and apply knowElevation forces
1552  std::set<NBNode*> unknownElevation;
1553  for (auto it = knownElevation.begin(); it != knownElevation.end(); ++it) {
1554  const double eleMax = knownEleMax[*it];
1555  const double maxDist = fabs(eleMax) * 100 / layerElevation;
1556  std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it, maxDist, knownElevation);
1557  for (auto& neighbor : neighbors) {
1558  if (knownElevation.count(neighbor.first) == 0) {
1559  unknownElevation.insert(neighbor.first);
1560  layerForces[neighbor.first].emplace_back(eleMax, neighbor.second.first);
1561  }
1562  }
1563  }
1564 
1565  // apply forces to ground-level nodes (neither in knownElevation nor unknownElevation)
1566  for (auto it = unknownElevation.begin(); it != unknownElevation.end(); ++it) {
1567  double eleMax = -std::numeric_limits<double>::max();
1568  const std::vector<std::pair<double, double> >& primaryLayers = layerForces[*it];
1569  for (const auto& primaryLayer : primaryLayers) {
1570  eleMax = MAX2(eleMax, primaryLayer.first);
1571  }
1572  const double maxDist = fabs(eleMax) * 100 / layerElevation;
1573  std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it, maxDist, knownElevation);
1574  for (auto& neighbor : neighbors) {
1575  if (knownElevation.count(neighbor.first) == 0 && unknownElevation.count(neighbor.first) == 0) {
1576  layerForces[*it].emplace_back(0, neighbor.second.first);
1577  }
1578  }
1579  }
1580  // compute the elevation for each node as the weighted average of all forces
1581 #ifdef DEBUG_LAYER_ELEVATION
1582  std::cout << "summation of forces\n";
1583 #endif
1584  std::map<NBNode*, double> nodeElevation;
1585  for (auto& layerForce : layerForces) {
1586  const std::vector<std::pair<double, double> >& forces = layerForce.second;
1587  if (knownElevation.count(layerForce.first) != 0) {
1588  // use the maximum value
1589  /*
1590  double eleMax = -std::numeric_limits<double>::max();
1591  for (std::vector<std::pair<double, double> >::const_iterator it_force = forces.begin(); it_force != forces.end(); ++it_force) {
1592  eleMax = MAX2(eleMax, it_force->first);
1593  }
1594  */
1595 #ifdef DEBUG_LAYER_ELEVATION
1596  std::cout << " node=" << it->first->getID() << " knownElevation=" << knownEleMax[it->first] << "\n";
1597 #endif
1598  nodeElevation[layerForce.first] = knownEleMax[layerForce.first];
1599  } else if (forces.size() == 1) {
1600  nodeElevation[layerForce.first] = forces.front().first;
1601  } else {
1602  // use the weighted sum
1603  double distSum = 0;
1604  for (const auto& force : forces) {
1605  distSum += force.second;
1606  }
1607  double weightSum = 0;
1608  double elevation = 0;
1609 #ifdef DEBUG_LAYER_ELEVATION
1610  std::cout << " node=" << it->first->getID() << " distSum=" << distSum << "\n";
1611 #endif
1612  for (const auto& force : forces) {
1613  const double weight = (distSum - force.second) / distSum;
1614  weightSum += weight;
1615  elevation += force.first * weight;
1616 
1617 #ifdef DEBUG_LAYER_ELEVATION
1618  std::cout << " force=" << it_force->first << " dist=" << it_force->second << " weight=" << weight << " ele=" << elevation << "\n";
1619 #endif
1620  }
1621  nodeElevation[layerForce.first] = elevation / weightSum;
1622  }
1623  }
1624 #ifdef DEBUG_LAYER_ELEVATION
1625  std::cout << "final elevations:\n";
1626  for (std::map<NBNode*, double>::iterator it = nodeElevation.begin(); it != nodeElevation.end(); ++it) {
1627  std::cout << " node=" << (it->first)->getID() << " ele=" << it->second << "\n";;
1628  }
1629 #endif
1630  // apply node elevations
1631  for (auto& it : nodeElevation) {
1632  NBNode* n = it.first;
1633  Position pos = n->getPosition();
1634  n->reinit(n->getPosition() + Position(0, 0, it.second), n->getType());
1635  }
1636 
1637  // apply way elevation to all edges that had layer information
1638  for (const auto& it : ec) {
1639  NBEdge* edge = it.second;
1640  const PositionVector& geom = edge->getGeometry();
1641  const double length = geom.length2D();
1642  const double zFrom = nodeElevation[edge->getFromNode()];
1643  const double zTo = nodeElevation[edge->getToNode()];
1644  // XXX if the from- or to-node was part of multiple ways with
1645  // different layers, reconstruct the layer value from origID
1646  double dist = 0;
1647  PositionVector newGeom;
1648  for (auto it_pos = geom.begin(); it_pos != geom.end(); ++it_pos) {
1649  if (it_pos != geom.begin()) {
1650  dist += (*it_pos).distanceTo2D(*(it_pos - 1));
1651  }
1652  newGeom.push_back((*it_pos) + Position(0, 0, zFrom + (zTo - zFrom) * dist / length));
1653  }
1654  edge->setGeometry(newGeom);
1655  }
1656 }
1657 
1658 std::map<NBNode*, std::pair<double, double> >
1659 NIImporter_OpenStreetMap::getNeighboringNodes(NBNode* node, double maxDist, const std::set<NBNode*>& knownElevation) {
1660  std::map<NBNode*, std::pair<double, double> > result;
1661  std::set<NBNode*> visited;
1662  std::vector<NBNode*> open;
1663  open.push_back(node);
1664  result[node] = std::make_pair(0, 0);
1665  while (!open.empty()) {
1666  NBNode* n = open.back();
1667  open.pop_back();
1668  if (visited.count(n) != 0) {
1669  continue;
1670  }
1671  visited.insert(n);
1672  const EdgeVector& edges = n->getEdges();
1673  for (auto e : edges) {
1674  NBNode* s = 0;
1675  if (n->hasIncoming(e)) {
1676  s = e->getFromNode();
1677  } else {
1678  s = e->getToNode();
1679  }
1680  const double dist = result[n].first + e->getGeometry().length2D();
1681  const double speed = MAX2(e->getSpeed(), result[n].second);
1682  if (result.count(s) == 0) {
1683  result[s] = std::make_pair(dist, speed);
1684  } else {
1685  result[s] = std::make_pair(MIN2(dist, result[s].first), MAX2(speed, result[s].second));
1686  }
1687  if (dist < maxDist && knownElevation.count(s) == 0) {
1688  open.push_back(s);
1689  }
1690  }
1691  }
1692  result.erase(node);
1693  return result;
1694 }
1695 
1696 
1697 /****************************************************************************/
1698 
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:108
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:54
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.
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:174
~EdgesHandler() override
Destructor.
std::string streetName
The edge&#39;s street name.
NBTypeCont & getTypeCont()
Returns a reference to the type container.
Definition: NBNetBuilder.h:160
NBPTLineCont * myNBPTLineCont
PT Line container to be filled.
is a pedestrian
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:47
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:284
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...
vehicle is a bicycle
const double SUMO_const_laneWidth
Definition: StdDefs.h:43
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:65
int getPriority(const std::string &type) const
Returns the priority for the given type.
Definition: NBTypeCont.cpp:180
vehicle is a light rail
static const double UNSPECIFIED_OFFSET
unspecified lane offset
Definition: NBEdge.h:256
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:1249
long long int myCurrentRelation
The currently parsed relation.
bool checkEdgeRef(long long int ref) const
check whether a referenced way has a corresponding edge
void addPTStop(NBPTStop *pStop)
Definition: NBPTLine.cpp:36
T MAX2(T a, T b)
Definition: StdDefs.h:68
NBPTStopCont & getPTStopCont()
Returns a reference to the pt stop container.
Definition: NBNetBuilder.h:176
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:3251
std::vector< NIIPTPlatform > myPlatforms
bus stop platforms
NBPTLineCont & getPTLineCont()
Returns a reference to the pt line container.
Definition: NBNetBuilder.h:181
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:168
bool getShallBeDiscarded(const std::string &type) const
Returns the information whether edges of this type shall be discarded.
Definition: NBTypeCont.cpp:192
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
const std::string & getID() const
Returns the id.
Definition: Named.h:69
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.
The representation of a single pt stop.
Definition: NBPTStop.h:45
std::vector< long long int > myStops
bus stop references
void registerAdditionalEdge(std::string wayId, std::string edgeId)
Definition: NBPTStop.cpp:174
NBParkingCont & getParkingCont()
Definition: NBNetBuilder.h:186
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:113
void addSidewalk(double width)
add a pedestrian sidewalk of the given width and shift existing connctions
Definition: NBEdge.cpp:3406
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:552
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:253
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:242
bool railwaySignal
Whether this is a railway (main) signal.
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:58
double getWidth(const std::string &type) const
Returns the lane width for the given type [m].
Definition: NBTypeCont.cpp:210
std::set< NIOSMNode *, CompareNodes > & myUniqueNodes
the set of unique nodes (used for duplicate detection/substitution)
NBNode * node
the NBNode that was instantiated
vehicle is a city rail
const EdgeVector & getOutgoingEdges() const
Returns this node&#39;s outgoing edges (The edges which start at this node)
Definition: NBNode.h:254
std::vector< long long int > myWays
ways in pt line references
const OptionsCont & myOptionsCont
the options cont
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.
The representation of a single pt stop.
Definition: NBParking.h:44
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:942
const std::map< long long int, Edge * > & myPlatformShapes
The previously parsed platform shapes.
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:68
double getBikeLaneWidth(const std::string &type) const
Returns the lane width for a bike lane to be added [m].
Definition: NBTypeCont.cpp:222
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:100
void setMyNumOfStops(int numStops)
Definition: NBPTLine.cpp:123
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:152
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:49
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:216
void updateParameter(const std::map< std::string, std::string > &mapArg)
Adds or updates all given parameters from the map.
bool ptStopPosition
Whether this is a public transport stop position.
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:39
classes which drive on tracks
void myEndElement(int element) override
Called when a closing tag occurs.
NBEdgeCont & getEdgeCont()
Definition: NBNetBuilder.h:150
A list of positions.
T get(const std::string &str) const
const EdgeVector & getEdges() const
Returns all edges which participate in this node (Edges that start or end at this node) ...
Definition: NBNode.h:259
Storage for edges, including some functionality operating on multiple edges.
Definition: NBEdgeCont.h:61
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:62
#define PROGRESS_BEGIN_MESSAGE(msg)
Definition: MsgHandler.h:244
void cleanupDeleted(NBEdgeCont &cont)
remove stops on non existing (removed) edges
#define POSITION_EPS
Definition: config.h:172
bool operator()(const Edge *e1, const Edge *e2) const
void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
int myParkingType
Information about road-side parking.
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.
void setIsMultipleStopPositions(bool multipleStopPositions)
Definition: NBPTStop.cpp:155
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.
~NodesHandler() override
Destructor.
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:3279
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:1319
void myEndElement(int element) override
Called when a closing tag occurs.
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:617
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:248
int myNoLanes
number of lanes, or -1 if unknown
bool railwayBufferStop
Whether this is a railway buffer stop.
vehicle is a bus
static std::string to_lower_case(std::string str)
Transfers the content to lower case.
Definition: StringUtils.cpp:56
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.
EdgesHandler(const std::map< long long int, NIOSMNode *> &osmNodes, std::map< long long int, Edge *> &toFill, std::map< long long int, Edge *> &platformShapes)
Constructor.
void myStartElement(int element, const SUMOSAXAttributes &attrs) override
Called on the opening of a tag;.
WayType mySidewalkType
Information about the kind of sidwalk along this road.
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:45
double length() const
Returns the length.
std::map< long long int, Edge * > & myEdgeMap
A map of built edges.
bool myCurrentIsPlatform
Information whether this is a pt platform.
const EdgeVector & getIncomingEdges() const
Returns this node&#39;s incoming edges (The edges which yield in this node)
Definition: NBNode.h:249
NBNodeCont & getNodeCont()
Returns a reference to the node container.
Definition: NBNetBuilder.h:155
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:109
std::string myPTRouteType
indicates whether current relation is a pt route
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition: NBCont.h:34
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:92
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:246
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:107
static double _2double(const E *const data)
converts a char-type array into the double value described by it
Definition: TplConvert.h:305
SumoXMLNodeType getType() const
Returns the type of this node.
Definition: NBNode.h:266
const std::string getParameter(const std::string &key, const std::string &defaultValue="") const
Returns the value for a given key.
void addBikeLane(double width)
add a bicycle lane of the given width and shift existing connctions
Definition: NBEdge.cpp:3418
bool insert(const std::string &id, const Position &position, NBDistrict *district=0)
Inserts a node into the map.
Definition: NBNodeCont.cpp:79
NBTrafficLightLogicCont & getTLLogicCont()
Returns a reference to the traffic light logics container.
Definition: NBNetBuilder.h:165
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:241
int myInterval
service interval of the pt line in seconds
Represents a single node (junction) during network building.
Definition: NBNode.h:68
void resetValues()
reset members to their defaults for parsing a new relation
const std::map< std::string, std::string > & getParametersMap() const
Returns the inner key/value map.
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.
std::string myNightService
night service information of the pt line
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
bool myCurrentIsRoad
Information whether this is a road.
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:49
SVCPermissions permissions
type of pt stop
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:429
Container for nodes during the netbuilding process.
Definition: NBNodeCont.h:60
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:245
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:47
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:186
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:243
std::set< NIOSMNode *, CompareNodes > myUniqueNodes
the set of unique nodes used in NodesHandler, used when freeing memory
void addPlatformCand(NBPTPlatform platform)
Definition: NBPTStop.cpp:137
static const double MAXSPEED_UNGIVEN
const OptionsCont & myOptionsCont
the options
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:436
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:230
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:204
A storage for available types of edges.
Definition: NBTypeCont.h:55
NBPTStopCont * myNBPTStopCont
The previously filled pt stop container.