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