Eclipse 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-2019 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 /****************************************************************************/
18 // Importer for networks stored in OpenStreetMap format
19 /****************************************************************************/
20 
21 
22 // ===========================================================================
23 // included modules
24 // ===========================================================================
25 #include <config.h>
26 #include <algorithm>
27 #include <set>
28 #include <functional>
29 #include <sstream>
30 #include <limits>
34 #include <utils/common/ToString.h>
38 #include <netbuild/NBEdge.h>
39 #include <netbuild/NBEdgeCont.h>
40 #include <netbuild/NBNode.h>
41 #include <netbuild/NBNodeCont.h>
42 #include <netbuild/NBNetBuilder.h>
43 #include <netbuild/NBOwnTLDef.h>
49 #include <utils/xml/XMLSubSys.h>
50 #include <netbuild/NBPTLine.h>
51 #include <netbuild/NBPTLineCont.h>
52 #include "NILoader.h"
54 
55 //#define DEBUG_LAYER_ELEVATION
56 
57 // ---------------------------------------------------------------------------
58 // static members
59 // ---------------------------------------------------------------------------
61 
62 const long long int NIImporter_OpenStreetMap::INVALID_ID = std::numeric_limits<long long int>::max();
63 
64 // ===========================================================================
65 // Private classes
66 // ===========================================================================
67 
71 public:
72  bool operator()(const Edge* e1, const Edge* e2) const {
73  if (e1->myHighWayType != e2->myHighWayType) {
74  return e1->myHighWayType > e2->myHighWayType;
75  }
76  if (e1->myNoLanes != e2->myNoLanes) {
77  return e1->myNoLanes > e2->myNoLanes;
78  }
79  if (e1->myNoLanesForward != e2->myNoLanesForward) {
80  return e1->myNoLanesForward > e2->myNoLanesForward;
81  }
82  if (e1->myMaxSpeed != e2->myMaxSpeed) {
83  return e1->myMaxSpeed > e2->myMaxSpeed;
84  }
85  if (e1->myIsOneWay != e2->myIsOneWay) {
86  return e1->myIsOneWay > e2->myIsOneWay;
87  }
88  return e1->myCurrentNodes > e2->myCurrentNodes;
89  }
90 };
91 
92 // ===========================================================================
93 // method definitions
94 // ===========================================================================
95 // ---------------------------------------------------------------------------
96 // static methods
97 // ---------------------------------------------------------------------------
98 const std::string NIImporter_OpenStreetMap::compoundTypeSeparator("|"); //clang-tidy says: "compundTypeSeparator with
99 // static storage duration my throw an exception that cannot be caught
100 
101 void
103  NIImporter_OpenStreetMap importer;
104  importer.load(oc, nb);
105 }
106 
108 
110  // delete nodes
111  for (auto myUniqueNode : myUniqueNodes) {
112  delete myUniqueNode;
113  }
114  // delete edges
115  for (auto& myEdge : myEdges) {
116  delete myEdge.second;
117  }
118  // delete platform shapes
119  for (auto& myPlatformShape : myPlatformShapes) {
120  delete myPlatformShape.second;
121  }
122 }
123 
124 void
126  // check whether the option is set (properly)
127  if (!oc.isSet("osm-files")) {
128  return;
129  }
130  /* Parse file(s)
131  * Each file is parsed twice: first for nodes, second for edges. */
132  std::vector<std::string> files = oc.getStringVector("osm-files");
133  // load nodes, first
134  NodesHandler nodesHandler(myOSMNodes, myUniqueNodes, oc);
135  for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
136  // nodes
137  if (!FileHelpers::isReadable(*file)) {
138  WRITE_ERROR("Could not open osm-file '" + *file + "'.");
139  return;
140  }
141  nodesHandler.setFileName(*file);
142  PROGRESS_BEGIN_MESSAGE("Parsing nodes from osm-file '" + *file + "'");
143  if (!XMLSubSys::runParser(nodesHandler, *file)) {
144  return;
145  }
147  }
148  // load edges, then
150  for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
151  // edges
152  edgesHandler.setFileName(*file);
153  PROGRESS_BEGIN_MESSAGE("Parsing edges from osm-file '" + *file + "'");
154  XMLSubSys::runParser(edgesHandler, *file);
156  }
157 
158  /* Remove duplicate edges with the same shape and attributes */
159  if (!oc.getBool("osm.skip-duplicates-check")) {
160  PROGRESS_BEGIN_MESSAGE("Removing duplicate edges");
161  if (myEdges.size() > 1) {
162  std::set<const Edge*, CompareEdges> dupsFinder;
163  for (auto it = myEdges.begin(); it != myEdges.end();) {
164  if (dupsFinder.count(it->second) > 0) {
165  WRITE_MESSAGE("Found duplicate edges. Removing " + toString(it->first));
166  delete it->second;
167  myEdges.erase(it++);
168  } else {
169  dupsFinder.insert(it->second);
170  it++;
171  }
172  }
173  }
175  }
176 
177  /* Mark which nodes are used (by edges or traffic lights).
178  * This is necessary to detect which OpenStreetMap nodes are for
179  * geometry only */
180  std::map<long long int, int> nodeUsage;
181  // Mark which nodes are used by edges (begin and end)
182  for (std::map<long long int, Edge*>::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
183  Edge* e = (*i).second;
184  assert(e->myCurrentIsRoad);
185  for (std::vector<long long int>::const_iterator j = e->myCurrentNodes.begin();
186  j != e->myCurrentNodes.end();
187  ++j) {
188  if (nodeUsage.find(*j) == nodeUsage.end()) {
189  nodeUsage[*j] = 0;
190  }
191  nodeUsage[*j] = nodeUsage[*j] + 1;
192  }
193  }
194  // Mark which nodes are used by traffic lights
195  for (std::map<long long int, NIOSMNode*>::const_iterator nodesIt = myOSMNodes.begin();
196  nodesIt != myOSMNodes.end();
197  ++nodesIt) {
198  if (nodesIt->second->tlsControlled || nodesIt->second->railwaySignal /* || nodesIt->second->railwayCrossing*/) {
199  // If the key is not found in the map, the value is automatically
200  // initialized with 0.
201  nodeUsage[nodesIt->first] += 1;
202  }
203  }
204 
205  /* Instantiate edges
206  * Only those nodes in the middle of an edge which are used by more than
207  * one edge are instantiated. Other nodes are considered as geometry nodes. */
208  NBNodeCont& nc = nb.getNodeCont();
210  for (auto& myEdge : myEdges) {
211  Edge* e = myEdge.second;
212  assert(e->myCurrentIsRoad);
213  if (e->myCurrentNodes.size() < 2) {
214  WRITE_WARNINGF("Discarding way '%' because it has only % node(s)", e->id, e->myCurrentNodes.size());
215  continue;
216  }
218  // build nodes;
219  // - the from- and to-nodes must be built in any case
220  // - the in-between nodes are only built if more than one edge references them
221  NBNode* currentFrom = insertNodeChecking(*e->myCurrentNodes.begin(), nc, tlsc);
222  NBNode* last = insertNodeChecking(*(e->myCurrentNodes.end() - 1), nc, tlsc);
223  int running = 0;
224  std::vector<long long int> passed;
225  for (auto j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
226  passed.push_back(*j);
227  if (nodeUsage[*j] > 1 && j != e->myCurrentNodes.end() - 1 && j != e->myCurrentNodes.begin()) {
228  NBNode* currentTo = insertNodeChecking(*j, nc, tlsc);
229  running = insertEdge(e, running, currentFrom, currentTo, passed, nb);
230  currentFrom = currentTo;
231  passed.clear();
232  passed.push_back(*j);
233  }
234  }
235  if (running == 0) {
236  running = -1;
237  }
238  insertEdge(e, running, currentFrom, last, passed, nb);
239  }
240 
241  const double layerElevation = oc.getFloat("osm.layer-elevation");
242  if (layerElevation > 0) {
243  reconstructLayerElevation(layerElevation, nb);
244  }
245 
246  //revise pt stops; remove stops on deleted edges
247  if (OptionsCont::getOptions().isSet("ptstop-output")) {
249  }
250 
251  // load relations (after edges are built since we want to apply
252  // turn-restrictions directly to NBEdges)
254  &(nb.getPTLineCont()), oc);
255  for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
256  // relations
257  relationHandler.setFileName(*file);
258  PROGRESS_BEGIN_MESSAGE("Parsing relations from osm-file '" + *file + "'");
259  XMLSubSys::runParser(relationHandler, *file);
261  }
262 }
263 
264 NBNode*
266  NBNode* node = nc.retrieve(toString(id));
267  if (node == nullptr) {
268  NIOSMNode* n = myOSMNodes.find(id)->second;
269  Position pos(n->lon, n->lat, n->ele);
270  if (!NBNetBuilder::transformCoordinate(pos, true)) {
271  WRITE_ERROR("Unable to project coordinates for junction '" + toString(id) + "'.");
272  return nullptr;
273  }
274  node = new NBNode(toString(id), pos);
275  if (!nc.insert(node)) {
276  WRITE_ERROR("Could not insert junction '" + toString(id) + "'.");
277  delete node;
278  return nullptr;
279  }
280  n->node = node;
281  if (n->railwayCrossing) {
282  node->reinit(pos, NODETYPE_RAIL_CROSSING);
283  } else if (n->railwaySignal) {
284  node->reinit(pos, NODETYPE_RAIL_SIGNAL);
285  } else if (n->tlsControlled) {
286  // ok, this node is a traffic light node where no other nodes
287  // participate
288  // @note: The OSM-community has not settled on a schema for differentiating between fixed and actuated lights
290  OptionsCont::getOptions().getString("tls.default-type"));
291  NBOwnTLDef* tlDef = new NBOwnTLDef(toString(id), node, 0, type);
292  if (!tlsc.insert(tlDef)) {
293  // actually, nothing should fail here
294  delete tlDef;
295  throw ProcessError("Could not allocate tls '" + toString(id) + "'.");
296  }
297  }
298  if (n->railwayBufferStop) {
299  node->setParameter("buffer_stop", "true");
300  }
301  }
302  return node;
303 }
304 
305 int
307  const std::vector<long long int>& passed, NBNetBuilder& nb) {
308  NBNodeCont& nc = nb.getNodeCont();
309  NBEdgeCont& ec = nb.getEdgeCont();
310  NBTypeCont& tc = nb.getTypeCont();
311  NBPTStopCont& sc = nb.getPTStopCont();
312 
314  // patch the id
315  std::string id = toString(e->id);
316  if (from == nullptr || to == nullptr) {
317  WRITE_ERROR("Discarding edge '" + id + "' because the nodes could not be built.");
318  return index;
319  }
320  if (index >= 0) {
321  id = id + "#" + toString(index);
322  } else {
323  index = 0;
324  }
325  if (from == to) {
326  assert(passed.size() >= 2);
327  if (passed.size() == 2) {
328  WRITE_WARNINGF("Discarding edge '%' which connects two identical nodes without geometry.", id);
329  return index;
330  }
331  // in the special case of a looped way split again using passed
332  int intermediateIndex = (int) passed.size() / 2;
333  NBNode* intermediate = insertNodeChecking(passed[intermediateIndex], nc, tlsc);
334  std::vector<long long int> part1(passed.begin(), passed.begin() + intermediateIndex + 1);
335  std::vector<long long int> part2(passed.begin() + intermediateIndex, passed.end());
336  index = insertEdge(e, index, from, intermediate, part1, nb);
337  return insertEdge(e, index, intermediate, to, part2, nb);
338  }
339  const int newIndex = index + 1;
340 
341  // convert the shape
342  PositionVector shape;
343  double distanceStart = myOSMNodes[passed.front()]->positionMeters;
344  double distanceEnd = myOSMNodes[passed.back()]->positionMeters;
345  const bool useDistance = distanceStart != std::numeric_limits<double>::max() && distanceEnd != std::numeric_limits<double>::max();
346  if (useDistance) {
347  // negative sign denotes counting in the other direction
348  if (distanceStart < distanceEnd) {
349  distanceStart *= -1;
350  } else {
351  distanceEnd *= -1;
352  }
353  } else {
354  distanceStart = 0;
355  distanceEnd = 0;
356  }
357  for (long long i : passed) {
358  NIOSMNode* n = myOSMNodes.find(i)->second;
359  if (n->ptStopPosition) {
360  NBPTStop* existingPtStop = sc.get(toString(n->id));
361  if (existingPtStop != nullptr) {
362  existingPtStop->registerAdditionalEdge(toString(e->id), id);
363  } else {
364  Position ptPos(n->lon, n->lat, n->ele);
365  if (!NBNetBuilder::transformCoordinate(ptPos)) {
366  WRITE_ERROR("Unable to project coordinates for node '" + toString(n->id) + "'.");
367  }
368  NBPTStop* ptStop = new NBPTStop(toString(n->id), ptPos, id, toString(e->id), n->ptStopLength, n->name,
369  n->permissions);
370 
371  sc.insert(ptStop);
372  }
373  }
374  Position pos(n->lon, n->lat, n->ele);
375  shape.push_back(pos);
376  }
378  WRITE_ERROR("Unable to project coordinates for edge '" + id + "'.");
379  }
380  std::string type = usableType(e->myHighWayType, id, tc);
381  if (type == "") {
382  return newIndex;
383  }
384 
385  // otherwise it is not an edge and will be ignored
386  bool ok = true;
387  int numLanesForward = tc.getNumLanes(type);
388  int numLanesBackward = tc.getNumLanes(type);
389  double speed = tc.getSpeed(type);
390  bool defaultsToOneWay = tc.getIsOneWay(type);
391  SVCPermissions permissions = tc.getPermissions(type);
392  if (e->myCurrentIsElectrified && (permissions & SVC_RAIL) != 0) {
393  permissions |= (SVC_RAIL_ELECTRIC | SVC_RAIL_FAST);
394  }
395  SVCPermissions forwardPermissions = permissions;
396  SVCPermissions backwardPermissions = permissions;
397  const std::string streetName = isRailway(forwardPermissions) && e->ref != "" ? e->ref : e->streetName;
398  if (streetName == e->ref) {
399  e->unsetParameter("ref"); // avoid superfluous param for railways
400  }
401  double forwardWidth = tc.getWidth(type);
402  double backwardWidth = tc.getWidth(type);
403  const bool addSidewalk = (tc.getSidewalkWidth(type) != NBEdge::UNSPECIFIED_WIDTH);
404  const bool addBikeLane = (tc.getBikeLaneWidth(type) != NBEdge::UNSPECIFIED_WIDTH);
405  // check directions
406  bool addForward = true;
407  bool addBackward = true;
408  if ((e->myIsOneWay == "true" || e->myIsOneWay == "yes" || e->myIsOneWay == "1"
409  || (defaultsToOneWay && e->myIsOneWay != "no" && e->myIsOneWay != "false" && e->myIsOneWay != "0"))
410  && e->myRailDirection != WAY_BOTH) {
411  addBackward = false;
412  }
413  if (e->myIsOneWay == "-1" || e->myIsOneWay == "reverse" || e->myRailDirection == WAY_BACKWARD) {
414  // one-way in reversed direction of way
415  addForward = false;
416  addBackward = true;
417  }
418  if (!e->myIsOneWay.empty() && e->myIsOneWay != "false" && e->myIsOneWay != "no" && e->myIsOneWay != "true"
419  && e->myIsOneWay != "yes" && e->myIsOneWay != "-1" && e->myIsOneWay != "1" && e->myIsOneWay != "reverse") {
420  WRITE_WARNINGF("New value for oneway found: %", e->myIsOneWay);
421  }
422  // if we had been able to extract the number of lanes, override the highway type default
423  if (e->myNoLanes > 0) {
424  if (addForward && !addBackward) {
425  numLanesForward = e->myNoLanes;
426  } else if (!addForward && addBackward) {
427  numLanesBackward = e->myNoLanes;
428  } else {
429  if (e->myNoLanesForward > 0) {
430  numLanesForward = e->myNoLanesForward;
431  } else if (e->myNoLanesForward < 0) {
432  numLanesForward = e->myNoLanes + e->myNoLanesForward;
433  } else {
434  numLanesForward = (int) std::ceil(e->myNoLanes / 2.0);
435  }
436  numLanesBackward = e->myNoLanes - numLanesForward;
437  // sometimes ways are tagged according to their physical width of a single
438  // lane but they are intended for traffic in both directions
439  numLanesForward = MAX2(1, numLanesForward);
440  numLanesBackward = MAX2(1, numLanesBackward);
441  }
442  } else if (e->myNoLanes == 0) {
443  WRITE_WARNINGF("Skipping edge '%' because it has zero lanes.", id);
444  ok = false;
445  }
446  // if we had been able to extract the maximum speed, override the type's default
447  if (e->myMaxSpeed != MAXSPEED_UNGIVEN) {
448  speed = e->myMaxSpeed / 3.6;
449  }
450  if (speed <= 0) {
451  WRITE_WARNINGF("Skipping edge '%' because it has speed %.", id, speed);
452  ok = false;
453  }
454  // deal with cycleways that run in the opposite direction of a one-way street
455  WayType cyclewayType = e->myCyclewayType; // make a copy because we do some temporary modifications
456  if (addBikeLane) {
457  if (!addForward && (cyclewayType & WAY_FORWARD) != 0) {
458  addForward = true;
459  forwardPermissions = SVC_BICYCLE;
460  forwardWidth = tc.getBikeLaneWidth(type);
461  numLanesForward = 1;
462  // do not add an additional cycle lane
463  cyclewayType = (WayType)(cyclewayType & ~WAY_FORWARD); //clang tidy thinks "!WAY_FORWARD" is always false
464  }
465  if (!addBackward && (cyclewayType & WAY_BACKWARD) != 0) {
466  addBackward = true;
467  backwardPermissions = SVC_BICYCLE;
468  backwardWidth = tc.getBikeLaneWidth(type);
469  numLanesBackward = 1;
470  // do not add an additional cycle lane
471  cyclewayType = (WayType)(cyclewayType & ~WAY_BACKWARD); //clang tidy thinks "!WAY_BACKWARD" is always false
472  }
473  }
474  // deal with sidewalks that run in the opposite direction of a one-way street
475  WayType sidewalkType = e->mySidewalkType; // make a copy because we do some temporary modifications
476  if (addSidewalk) {
477  if (!addForward && (sidewalkType & WAY_FORWARD) != 0) {
478  addForward = true;
479  forwardPermissions = SVC_PEDESTRIAN;
480  forwardWidth = tc.getSidewalkWidth(type);
481  numLanesForward = 1;
482  // do not add an additional sidewalk
483  sidewalkType = (WayType)(sidewalkType & ~WAY_FORWARD); //clang tidy thinks "!WAY_FORWARD" is always false
484  }
485  if (!addBackward && (sidewalkType & WAY_BACKWARD) != 0) {
486  addBackward = true;
487  backwardPermissions = SVC_PEDESTRIAN;
488  backwardWidth = tc.getSidewalkWidth(type);
489  numLanesBackward = 1;
490  // do not add an additional cycle lane
491  sidewalkType = (WayType)(sidewalkType & ~WAY_BACKWARD); //clang tidy thinks "!WAY_BACKWARD" is always false
492  }
493  }
494  // deal with busways that run in the opposite direction of a one-way street
495  if (!addForward && (e->myBuswayType & WAY_FORWARD) != 0) {
496  addForward = true;
497  forwardPermissions = SVC_BUS;
498  numLanesForward = 1;
499  }
500  if (!addBackward && (e->myBuswayType & WAY_BACKWARD) != 0) {
501  addBackward = true;
502  backwardPermissions = SVC_BUS;
503  numLanesBackward = 1;
504  }
505 
506  const std::string origID = OptionsCont::getOptions().getBool("output.original-names") ? toString(e->id) : "";
507  if (ok) {
508  const int offsetFactor = OptionsCont::getOptions().getBool("lefthand") ? -1 : 1;
509  LaneSpreadFunction lsf = (addBackward || OptionsCont::getOptions().getBool("osm.oneway-spread-right")) &&
511 
512  id = StringUtils::escapeXML(id);
513  const std::string reverseID = "-" + id;
514 
515  if (addForward) {
516  assert(numLanesForward > 0);
517  NBEdge* nbe = new NBEdge(id, from, to, type, speed, numLanesForward, tc.getPriority(type),
518  forwardWidth, NBEdge::UNSPECIFIED_OFFSET, shape,
519  StringUtils::escapeXML(streetName), origID, lsf, true);
520  nbe->setPermissions(forwardPermissions);
521  if ((e->myBuswayType & WAY_FORWARD) != 0) {
522  nbe->setPermissions(SVC_BUS, 0);
523  }
524  if (addBikeLane && (cyclewayType == WAY_UNKNOWN || (cyclewayType & WAY_FORWARD) != 0)) {
525  nbe->addBikeLane(tc.getBikeLaneWidth(type) * offsetFactor);
526  } else if (nbe->getPermissions(0) == SVC_BUS) {
527  // bikes drive on buslanes if no separate cycle lane is available
529  }
530  if (addSidewalk && (sidewalkType == WAY_UNKNOWN || (sidewalkType & WAY_FORWARD) != 0)) {
531  nbe->addSidewalk(tc.getSidewalkWidth(type) * offsetFactor);
532  }
534  nbe->setDistance(distanceStart);
535  if (!ec.insert(nbe)) {
536  delete nbe;
537  throw ProcessError("Could not add edge '" + id + "'.");
538  }
539  }
540  if (addBackward) {
541  assert(numLanesBackward > 0);
542  NBEdge* nbe = new NBEdge(reverseID, to, from, type, speed, numLanesBackward, tc.getPriority(type),
543  backwardWidth, NBEdge::UNSPECIFIED_OFFSET, shape.reverse(),
544  StringUtils::escapeXML(streetName), origID, lsf, true);
545  nbe->setPermissions(backwardPermissions);
546  if ((e->myBuswayType & WAY_BACKWARD) != 0) {
547  nbe->setPermissions(SVC_BUS, 0);
548  }
549  if (addBikeLane && (cyclewayType == WAY_UNKNOWN || (cyclewayType & WAY_BACKWARD) != 0)) {
550  nbe->addBikeLane(tc.getBikeLaneWidth(type) * offsetFactor);
551  } else if (nbe->getPermissions(0) == SVC_BUS) {
552  // bikes drive on buslanes if no separate cycle lane is available
554  }
555  if (addSidewalk && (sidewalkType == WAY_UNKNOWN || (sidewalkType & WAY_BACKWARD) != 0)) {
556  nbe->addSidewalk(tc.getSidewalkWidth(type) * offsetFactor);
557  }
559  nbe->setDistance(distanceEnd);
560  if (!ec.insert(nbe)) {
561  delete nbe;
562  throw ProcessError("Could not add edge '-" + id + "'.");
563  }
564  }
565  if ((e->myParkingType & PARKING_BOTH) != 0 && OptionsCont::getOptions().isSet("parking-output")) {
566  if ((e->myParkingType & PARKING_RIGHT) != 0) {
567  if (addForward) {
568  nb.getParkingCont().push_back(NBParking(id, id));
569  } else {
571  if ((e->myParkingType & PARKING_LEFT) == 0 && !addBackward) {
573  nb.getParkingCont().push_back(NBParking(reverseID, reverseID));
574  }
575  }
576  }
577  if ((e->myParkingType & PARKING_LEFT) != 0) {
578  if (addBackward) {
579  nb.getParkingCont().push_back(NBParking(reverseID, reverseID));
580  } else {
582  if ((e->myParkingType & PARKING_RIGHT) == 0 && !addForward) {
584  nb.getParkingCont().push_back(NBParking(id, id));
585  }
586  }
587  }
588  }
589  }
590  return newIndex;
591 }
592 
593 // ---------------------------------------------------------------------------
594 // definitions of NIImporter_OpenStreetMap::NodesHandler-methods
595 // ---------------------------------------------------------------------------
596 NIImporter_OpenStreetMap::NodesHandler::NodesHandler(std::map<long long int, NIOSMNode*>& toFill,
597  std::set<NIOSMNode*, CompareNodes>& uniqueNodes,
598  const OptionsCont& oc)
599 
600  :
601  SUMOSAXHandler("osm - file"),
602  myToFill(toFill),
603  myLastNodeID(-1),
604  myIsInValidNodeTag(false),
605  myHierarchyLevel(0),
606  myUniqueNodes(uniqueNodes),
607  myImportElevation(oc.getBool("osm.elevation")),
608  myOptionsCont(oc) {
609 }
610 
612 
613 void
615  ++myHierarchyLevel;
616  if (element == SUMO_TAG_NODE) {
617  bool ok = true;
618  if (myHierarchyLevel != 2) {
619  WRITE_ERROR("Node element on wrong XML hierarchy level (id='" + toString(attrs.get<long
620  long
621  int>(SUMO_ATTR_ID,
622  nullptr, ok))
623  + "', level='" + toString(myHierarchyLevel) + "').");
624  return;
625  }
626  const long long int id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
627  const std::string action = attrs.hasAttribute("action") ? attrs.getStringSecure("action", "") : "";
628  if (action == "delete" || !ok) {
629  return;
630  }
631  myLastNodeID = -1;
632  if (myToFill.find(id) == myToFill.end()) {
633  myLastNodeID = id;
634  // assume we are loading multiple files...
635  // ... so we won't report duplicate nodes
636  bool ok2 = true;
637  double tlat, tlon;
638  std::istringstream lon(attrs.get<std::string>(SUMO_ATTR_LON, toString(id).c_str(), ok2));
639  if (!ok2) {
640  return;
641  }
642  lon >> tlon;
643  if (lon.fail()) {
644  WRITE_ERROR("Node's '" + toString(id) + "' lon information is not numeric.");
645  return;
646  }
647  std::istringstream lat(attrs.get<std::string>(SUMO_ATTR_LAT, toString(id).c_str(), ok2));
648  if (!ok2) {
649  return;
650  }
651  lat >> tlat;
652  if (lat.fail()) {
653  WRITE_ERROR("Node's '" + toString(id) + "' lat information is not numeric.");
654  return;
655  }
656  auto* toAdd = new NIOSMNode(id, tlon, tlat);
657  myIsInValidNodeTag = true;
658 
659  auto similarNode = myUniqueNodes.find(toAdd);
660  if (similarNode == myUniqueNodes.end()) {
661  myUniqueNodes.insert(toAdd);
662  } else {
663  delete toAdd;
664  toAdd = *similarNode;
665  WRITE_MESSAGE("Found duplicate nodes. Substituting " + toString(id) + " with " + toString(toAdd->id));
666  }
667  myToFill[id] = toAdd;
668  }
669  }
670  if (element == SUMO_TAG_TAG && myIsInValidNodeTag) {
671  if (myHierarchyLevel != 3) {
672  WRITE_ERROR("Tag element on wrong XML hierarchy level.");
673  return;
674  }
675  bool ok = true;
676  std::string key = attrs.get<std::string>(SUMO_ATTR_K, toString(myLastNodeID).c_str(), ok, false);
677  // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
678  if (key == "highway" || key == "ele" || key == "crossing" || key == "railway" || key == "public_transport"
679  || key == "name" || key == "train" || key == "bus" || key == "tram" || key == "light_rail" || key == "subway" || key == "station" || key == "noexit"
680  || StringUtils::startsWith(key, "railway:signal")
681  || StringUtils::startsWith(key, "railway:position")
682  ) {
683  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myLastNodeID).c_str(), ok, false);
684  if (key == "highway" && value.find("traffic_signal") != std::string::npos) {
685  myToFill[myLastNodeID]->tlsControlled = true;
686  } else if (key == "crossing" && value.find("traffic_signals") != std::string::npos) {
687  myToFill[myLastNodeID]->tlsControlled = true;
688  } else if ((key == "noexit" && value == "yes")
689  || (key == "railway" && value == "buffer_stop")) {
690  myToFill[myLastNodeID]->railwayBufferStop = true;
691  } else if (key == "railway" && value.find("crossing") != std::string::npos) {
692  myToFill[myLastNodeID]->railwayCrossing = true;
693  } else if (StringUtils::startsWith(key, "railway:signal") && (
694  value == "block" || value == "entry" || value == "exit" || value == "intermediate")) {
695  myToFill[myLastNodeID]->railwaySignal = true;
696  } else if (StringUtils::startsWith(key, "railway:position") && value.size() > myToFill[myLastNodeID]->position.size()) {
697  // use the entry with the highest precision (more digits)
698  myToFill[myLastNodeID]->position = value;
699  } else if ((key == "public_transport" && value == "stop_position") ||
700  (key == "highway" && value == "bus_stop")) {
701  myToFill[myLastNodeID]->ptStopPosition = true;
702  if (myToFill[myLastNodeID]->ptStopLength == 0) {
703  // default length
704  myToFill[myLastNodeID]->ptStopLength = myOptionsCont.getFloat("osm.stop-output.length");
705  }
706  } else if (key == "name") {
707  myToFill[myLastNodeID]->name = value;
708  } else if (myImportElevation && key == "ele") {
709  try {
710  myToFill[myLastNodeID]->ele = StringUtils::toDouble(value);
711  } catch (...) {
712  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in node '" +
713  toString(myLastNodeID) + "'.");
714  }
715  } else if (key == "station") {
716  interpretTransportType(value, myToFill[myLastNodeID]);
717  } else {
718  // v="yes"
719  interpretTransportType(key, myToFill[myLastNodeID]);
720  }
721  }
722  }
723 }
724 
725 void
727  if (element == SUMO_TAG_NODE && myHierarchyLevel == 2) {
728  myLastNodeID = -1;
729  myIsInValidNodeTag = false;
730  }
731  --myHierarchyLevel;
732 }
733 
734 // ---------------------------------------------------------------------------
735 // definitions of NIImporter_OpenStreetMap::EdgesHandler-methods
736 // ---------------------------------------------------------------------------
738  const std::map<long long int, NIOSMNode*>& osmNodes,
739  std::map<long long int, Edge*>& toFill, std::map<long long int, Edge*>& platformShapes):
740  SUMOSAXHandler("osm - file"),
741  myOSMNodes(osmNodes),
742  myEdgeMap(toFill),
743  myPlatformShapesMap(platformShapes) {
744  mySpeedMap["signals"] = MAXSPEED_UNGIVEN;
745  mySpeedMap["none"] = 142.; // Auswirkungen eines allgemeinen Tempolimits auf Autobahnen im Land Brandeburg (2007)
746  mySpeedMap["no"] = 142.;
747  mySpeedMap["walk"] = 5.;
748  mySpeedMap["DE:rural"] = 100.;
749  mySpeedMap["DE:urban"] = 50.;
750  mySpeedMap["DE:living_street"] = 10.;
751  myAllAttributes = OptionsCont::getOptions().getBool("osm.all-attributes");
752 
753 }
754 
756 
757 void
759  const SUMOSAXAttributes& attrs) {
760  myParentElements.push_back(element);
761  // parse "way" elements
762  if (element == SUMO_TAG_WAY) {
763  bool ok = true;
764  const long long int id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
765  std::string action = attrs.hasAttribute("action") ? attrs.getStringSecure("action", "") : "";
766  if (action == "delete" || !ok) {
767  myCurrentEdge = nullptr;
768  return;
769  }
770  myCurrentEdge = new Edge(id);
771  }
772  // parse "nd" (node) elements
773  if (element == SUMO_TAG_ND && myCurrentEdge != nullptr) {
774  bool ok = true;
775  long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, nullptr, ok);
776  if (ok) {
777  auto node = myOSMNodes.find(ref);
778  if (node == myOSMNodes.end()) {
779  WRITE_WARNING("The referenced geometry information (ref='" + toString(ref) + "') is not known");
780  return;
781  }
782 
783  ref = node->second->id; // node may have been substituted
784  if (myCurrentEdge->myCurrentNodes.empty() ||
785  myCurrentEdge->myCurrentNodes.back() != ref) { // avoid consecutive duplicates
786  myCurrentEdge->myCurrentNodes.push_back(ref);
787  }
788 
789  }
790  }
791  // parse values
792  if (element == SUMO_TAG_TAG && myParentElements.size() > 2
793  && myParentElements[myParentElements.size() - 2] == SUMO_TAG_WAY) {
794  if (myCurrentEdge == nullptr) {
795  return;
796  }
797  bool ok = true;
798  std::string key = attrs.get<std::string>(SUMO_ATTR_K, toString(myCurrentEdge->id).c_str(), ok, false);
799  if (key.size() > 8 && StringUtils::startsWith(key, "cycleway:")) {
800  // handle special cycleway keys
801  const std::string cyclewaySpec = key.substr(9);
802  key = "cycleway";
803  if (cyclewaySpec == "right") {
804  myCurrentEdge->myCyclewayType = (WayType)(myCurrentEdge->myCyclewayType | WAY_FORWARD);
805  } else if (cyclewaySpec == "left") {
806  myCurrentEdge->myCyclewayType = (WayType)(myCurrentEdge->myCyclewayType | WAY_BACKWARD);
807  } else if (cyclewaySpec == "both") {
808  myCurrentEdge->myCyclewayType = (WayType)(myCurrentEdge->myCyclewayType | WAY_BOTH);
809  } else {
810  key = "ignore";
811  }
812  if ((myCurrentEdge->myCyclewayType & WAY_BOTH) != 0) {
813  // now we have some info on directionality
814  myCurrentEdge->myCyclewayType = (WayType)(myCurrentEdge->myCyclewayType & ~WAY_UNKNOWN);
815  }
816  } else if (key.size() > 6 && StringUtils::startsWith(key, "busway:")) {
817  // handle special busway keys
818  const std::string buswaySpec = key.substr(7);
819  key = "busway";
820  if (buswaySpec == "right") {
821  myCurrentEdge->myBuswayType = (WayType)(myCurrentEdge->myBuswayType | WAY_FORWARD);
822  } else if (buswaySpec == "left") {
823  myCurrentEdge->myBuswayType = (WayType)(myCurrentEdge->myBuswayType | WAY_BACKWARD);
824  } else if (buswaySpec == "both") {
825  myCurrentEdge->myBuswayType = (WayType)(myCurrentEdge->myBuswayType | WAY_BOTH);
826  } else {
827  key = "ignore";
828  }
829  }
830  if (myAllAttributes && (key == "bridge" || key == "tunnel")) {
831  myCurrentEdge->setParameter(key, "true"); // could be differentiated further if necessary
832  }
833  // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
834  if (!StringUtils::endsWith(key, "way") && !StringUtils::startsWith(key, "lanes")
835  && key != "maxspeed" && key != "junction" && key != "name" && key != "tracks" && key != "layer"
836  && key != "route"
837  && key != "sidewalk"
838  && key != "ref"
839  && key != "highspeed"
840  && !StringUtils::startsWith(key, "parking")
841  && key != "postal_code"
842  && key != "railway:preferred_direction"
843  && key != "railway:bidirectional"
844  && key != "railway:track_ref"
845  && key != "usage"
846  && key != "electrified"
847  && key != "public_transport") {
848  return;
849  }
850  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentEdge->id).c_str(), ok, false);
851 
852  if ((key == "highway" && value != "platform") || key == "railway" || key == "waterway" || key == "cycleway"
853  || key == "busway" || key == "route" || key == "sidewalk" || key == "highspeed"
854  || key == "usage") {
855  // build type id
856  std::string singleTypeID = key + "." + value;
857  myCurrentEdge->myCurrentIsRoad = true;
858  // special cycleway stuff
859  if (key == "cycleway") {
860  if (value == "no") {
861  return;
862  }
863  if (value == "opposite_track") {
864  myCurrentEdge->myCyclewayType = WAY_BACKWARD;
865  } else if (value == "opposite_lane") {
866  myCurrentEdge->myCyclewayType = WAY_BACKWARD;
867  }
868  }
869  // special sidewalk stuff
870  if (key == "sidewalk") {
871  if (value == "no" || value == "none") {
872  myCurrentEdge->mySidewalkType = WAY_NONE;
873  } else if (value == "both") {
874  myCurrentEdge->mySidewalkType = WAY_BOTH;
875  } else if (value == "right") {
876  myCurrentEdge->mySidewalkType = WAY_FORWARD;
877  } else if (value == "left") {
878  myCurrentEdge->mySidewalkType = WAY_BACKWARD;
879  }
880  // no need to extend the type id
881  return;
882  }
883  // special busway stuff
884  if (key == "busway") {
885  if (value == "no") {
886  return;
887  }
888  if (value == "opposite_track") {
889  myCurrentEdge->myBuswayType = WAY_BACKWARD;
890  } else if (value == "opposite_lane") {
891  myCurrentEdge->myBuswayType = WAY_BACKWARD;
892  }
893  // no need to extend the type id
894  return;
895  }
896  if (key == "highspeed") {
897  if (value == "no") {
898  return;
899  }
900  singleTypeID = "railway.highspeed";
901  }
902  // special case: never build compound type for highspeed rail
903  if (!myCurrentEdge->myHighWayType.empty() && singleTypeID != "railway.highspeed") {
904  if (myCurrentEdge->myHighWayType == "railway.highspeed") {
905  return;
906  }
907  // osm-ways may be used by more than one mode (eg railway.tram + highway.residential. this is relevant for multimodal traffic)
908  // we create a new type for this kind of situation which must then be resolved in insertEdge()
909  std::vector<std::string> types = StringTokenizer(myCurrentEdge->myHighWayType,
911  types.push_back(singleTypeID);
912  myCurrentEdge->myHighWayType = joinToStringSorting(types, compoundTypeSeparator);
913  } else {
914  myCurrentEdge->myHighWayType = singleTypeID;
915  }
916  } else if (key == "lanes") {
917  try {
918  myCurrentEdge->myNoLanes = StringUtils::toInt(value);
919  } catch (NumberFormatException&) {
920  // might be a list of values
921  StringTokenizer st(value, ";", true);
922  std::vector<std::string> list = st.getVector();
923  if (list.size() >= 2) {
924  int minLanes = std::numeric_limits<int>::max();
925  try {
926  for (auto& i : list) {
927  int numLanes = StringUtils::toInt(StringUtils::prune(i));
928  minLanes = MIN2(minLanes, numLanes);
929  }
930  myCurrentEdge->myNoLanes = minLanes;
932  "Using minimum lane number from list (" + value + ") for edge '"
933  + toString(myCurrentEdge->id)
934  + "'.");
935  } catch (NumberFormatException&) {
936  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
937  toString(myCurrentEdge->id) + "'.");
938  }
939  }
940  } catch (EmptyData&) {
941  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
942  toString(myCurrentEdge->id) + "'.");
943  }
944  } else if (key == "lanes:forward") {
945  try {
946  myCurrentEdge->myNoLanesForward = StringUtils::toInt(value);
947  } catch (...) {
948  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
949  toString(myCurrentEdge->id) + "'.");
950  }
951  } else if (key == "lanes:backward") {
952  try {
953  // denote backwards count with a negative sign
954  myCurrentEdge->myNoLanesForward = -StringUtils::toInt(value);
955  } catch (...) {
956  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
957  toString(myCurrentEdge->id) + "'.");
958  }
959  } else if (key == "maxspeed") {
960  if (mySpeedMap.find(value) != mySpeedMap.end()) {
961  myCurrentEdge->myMaxSpeed = mySpeedMap[value];
962  } else {
963  double conversion = 1; // OSM default is km/h
964  if (StringUtils::to_lower_case(value).find("km/h") != std::string::npos) {
965  value = StringUtils::prune(value.substr(0, value.find_first_not_of("0123456789")));
966  } else if (StringUtils::to_lower_case(value).find("mph") != std::string::npos) {
967  value = StringUtils::prune(value.substr(0, value.find_first_not_of("0123456789")));
968  conversion = 1.609344; // kilometers per mile
969  }
970  try {
971  myCurrentEdge->myMaxSpeed = StringUtils::toDouble(value) * conversion;
972  } catch (...) {
973  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
974  toString(myCurrentEdge->id) + "'.");
975  }
976  }
977  } else if (key == "junction") {
978  if ((value == "roundabout") && (myCurrentEdge->myIsOneWay.empty())) {
979  myCurrentEdge->myIsOneWay = "yes";
980  }
981  } else if (key == "oneway") {
982  myCurrentEdge->myIsOneWay = value;
983  } else if (key == "name") {
984  myCurrentEdge->streetName = value;
985  } else if (key == "ref") {
986  myCurrentEdge->ref = value;
987  myCurrentEdge->setParameter("ref", value);
988  } else if (key == "layer") {
989  if (myAllAttributes) {
990  myCurrentEdge->setParameter(key, value);
991  }
992  try {
993  myCurrentEdge->myLayer = StringUtils::toInt(value);
994  } catch (...) {
995  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
996  toString(myCurrentEdge->id) + "'.");
997  }
998  } else if (key == "tracks") {
999  try {
1000  if (StringUtils::toInt(value) == 1) {
1001  myCurrentEdge->myIsOneWay = "true";
1002  } else {
1003  WRITE_WARNING("Ignoring track count " + value + " for edge '" + toString(myCurrentEdge->id) + "'.");
1004  }
1005  } catch (...) {
1006  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
1007  toString(myCurrentEdge->id) + "'.");
1008  }
1009  } else if (myAllAttributes && key == "postal_code") {
1010  myCurrentEdge->setParameter(key, value);
1011  } else if (key == "railway:preferred_direction") {
1012  if (value == "both") {
1013  myCurrentEdge->myRailDirection = WAY_BOTH;
1014  } else if (value == "backward") {
1015  myCurrentEdge->myRailDirection = WAY_BACKWARD;
1016  }
1017  } else if (key == "railway:bidirectional") {
1018  if (value == "regular") {
1019  myCurrentEdge->myRailDirection = WAY_BOTH;
1020  }
1021  } else if (key == "electrified") {
1022  if (value != "no") {
1023  myCurrentEdge->myCurrentIsElectrified = true;
1024  }
1025  } else if (key == "railway:track_ref") {
1026  myCurrentEdge->setParameter(key, value);
1027  } else if (key == "public_transport" && value == "platform") {
1028  myCurrentEdge->myCurrentIsPlatform = true;
1029  } else if (key == "parking:lane:both" && !StringUtils::startsWith(value, "no")) {
1030  myCurrentEdge->myParkingType |= PARKING_BOTH;
1031  } else if (key == "parking:lane:left" && !StringUtils::startsWith(value, "no")) {
1032  myCurrentEdge->myParkingType |= PARKING_LEFT;
1033  } else if (key == "parking:lane:right" && !StringUtils::startsWith(value, "no")) {
1034  myCurrentEdge->myParkingType |= PARKING_RIGHT;
1035  }
1036  }
1037 }
1038 
1039 void
1041  myParentElements.pop_back();
1042  if (element == SUMO_TAG_WAY && myCurrentEdge != nullptr) {
1043  if (myCurrentEdge->myCurrentIsRoad) {
1044  myEdgeMap[myCurrentEdge->id] = myCurrentEdge;
1045  } else if (myCurrentEdge->myCurrentIsPlatform) {
1046  myPlatformShapesMap[myCurrentEdge->id] = myCurrentEdge;
1047  } else {
1048  delete myCurrentEdge;
1049  }
1050  myCurrentEdge = nullptr;
1051  }
1052 }
1053 
1054 // ---------------------------------------------------------------------------
1055 // definitions of NIImporter_OpenStreetMap::RelationHandler-methods
1056 // ---------------------------------------------------------------------------
1058  const std::map<long long int, NIOSMNode*>& osmNodes,
1059  const std::map<long long int, Edge*>& osmEdges, NBPTStopCont* nbptStopCont,
1060  const std::map<long long int, Edge*>& platformShapes,
1061  NBPTLineCont* nbptLineCont,
1062  const OptionsCont& oc)
1063  :
1064  SUMOSAXHandler("osm - file"),
1065  myOSMNodes(osmNodes),
1066  myOSMEdges(osmEdges),
1067  myPlatformShapes(platformShapes),
1068  myNBPTStopCont(nbptStopCont),
1069  myNBPTLineCont(nbptLineCont),
1070  myOptionsCont(oc) {
1071  resetValues();
1072 }
1073 
1075 
1076 void
1078  myCurrentRelation = INVALID_ID;
1079  myIsRestriction = false;
1080  myFromWay = INVALID_ID;
1081  myToWay = INVALID_ID;
1082  myViaNode = INVALID_ID;
1083  myViaWay = INVALID_ID;
1084  myRestrictionType = RESTRICTION_UNKNOWN;
1085  myPlatforms.clear();
1086  myStops.clear();
1087  myWays.clear();
1088  myIsStopArea = false;
1089  myIsRoute = false;
1090  myPTRouteType = "";
1091 }
1092 
1093 void
1095  const SUMOSAXAttributes& attrs) {
1096  myParentElements.push_back(element);
1097  // parse "way" elements
1098  if (element == SUMO_TAG_RELATION) {
1099  bool ok = true;
1100  myCurrentRelation = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
1101  const std::string action = attrs.hasAttribute("action") ? attrs.getStringSecure("action", "") : "";
1102  if (action == "delete" || !ok) {
1103  myCurrentRelation = INVALID_ID;
1104  }
1105  myName = "";
1106  myRef = "";
1107  myInterval = -1;
1108  myNightService = "";
1109  return;
1110  }
1111  if (myCurrentRelation == INVALID_ID) {
1112  return;
1113  }
1114  // parse member elements
1115  if (element == SUMO_TAG_MEMBER) {
1116  bool ok = true;
1117  std::string role = attrs.hasAttribute("role") ? attrs.getStringSecure("role", "") : "";
1118  auto ref = attrs.get<long
1119  long
1120  int>(SUMO_ATTR_REF, nullptr, ok);
1121  if (role == "via") {
1122  // u-turns for divided ways may be given with 2 via-nodes or 1 via-way
1123  std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
1124  if (memberType == "way" && checkEdgeRef(ref)) {
1125  myViaWay = ref;
1126  } else if (memberType == "node") {
1127  if (myOSMNodes.find(ref) != myOSMNodes.end()) {
1128  myViaNode = ref;
1129  } else {
1130  WRITE_WARNING(
1131  "No node found for reference '" + toString(ref) + "' in relation '"
1132  + toString(myCurrentRelation)
1133  + "'");
1134  }
1135  }
1136  } else if (role == "from" && checkEdgeRef(ref)) {
1137  myFromWay = ref;
1138  } else if (role == "to" && checkEdgeRef(ref)) {
1139  myToWay = ref;
1140  } else if (role == "stop") {
1141  myStops.push_back(ref);
1142  } else if (role == "platform") {
1143  std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
1144  if (memberType == "way") {
1145  const std::map<long long int,
1146  NIImporter_OpenStreetMap::Edge*>::const_iterator& wayIt = myPlatformShapes.find(ref);
1147  if (wayIt != myPlatformShapes.end()) {
1148 
1149  NIIPTPlatform platform;
1150  platform.isWay = true;
1151  platform.ref = ref;
1152  myPlatforms.push_back(platform);
1153  }
1154  } else if (memberType == "node") {
1155  NIIPTPlatform platform;
1156  platform.isWay = false;
1157  platform.ref = ref;
1158  myPlatforms.push_back(platform);
1159  }
1160 
1161  } else if (role.empty()) {
1162  std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
1163  if (memberType == "way") {
1164  myWays.push_back(ref);
1165  }
1166  }
1167  return;
1168  }
1169  // parse values
1170  if (element == SUMO_TAG_TAG) {
1171  bool ok = true;
1172  std::string key = attrs.get<std::string>(SUMO_ATTR_K, toString(myCurrentRelation).c_str(), ok, false);
1173  // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
1174  if (key == "type" || key == "restriction") {
1175  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1176  if (key == "type" && value == "restriction") {
1177  myIsRestriction = true;
1178  return;
1179  }
1180  if (key == "type" && value == "route") {
1181  myIsRoute = true;
1182  return;
1183  }
1184  if (key == "restriction") {
1185  // @note: the 'right/left/straight' part is ignored since the information is
1186  // redundantly encoded in the 'from', 'to' and 'via' members
1187  if (value.substr(0, 5) == "only_") {
1188  myRestrictionType = RESTRICTION_ONLY;
1189  } else if (value.substr(0, 3) == "no_") {
1190  myRestrictionType = RESTRICTION_NO;
1191  } else {
1192  WRITE_WARNING(
1193  "Found unknown restriction type '" + value + "' in relation '" + toString(myCurrentRelation)
1194  + "'");
1195  }
1196  return;
1197  }
1198  } else if (key == "public_transport") {
1199  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1200  if (value == "stop_area") {
1201  myIsStopArea = true;
1202  }
1203  } else if (key == "route") {
1204  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1205  if (value == "train" || value == "subway" || value == "light_rail" || value == "monorail" || value == "tram" || value == "bus"
1206  || value == "trolleybus" || value == "arialway" || value == "ferry") {
1207  myPTRouteType = value;
1208  }
1209 
1210  } else if (key == "name") {
1211  myName = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1212  } else if (key == "ref") {
1213  myRef = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1214  } else if (key == "interval" || key == "headway") {
1215  myInterval = attrs.get<int>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1216  } else if (key == "by_night") {
1217  myNightService = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1218  }
1219  }
1220 }
1221 
1222 bool
1224  if (myOSMEdges.find(ref) != myOSMEdges.end()) {
1225  return true;
1226  }
1227 
1228  WRITE_WARNING(
1229  "No way found for reference '" + toString(ref) + "' in relation '" + toString(myCurrentRelation) + "'");
1230  return false;
1231 
1232 }
1233 
1234 void
1236  myParentElements.pop_back();
1237  if (element == SUMO_TAG_RELATION) {
1238  if (myIsRestriction) {
1239  assert(myCurrentRelation != INVALID_ID);
1240  bool ok = true;
1241  if (myRestrictionType == RESTRICTION_UNKNOWN) {
1242  WRITE_WARNING("Ignoring restriction relation '" + toString(myCurrentRelation) + "' with unknown type.");
1243  ok = false;
1244  }
1245  if (myFromWay == INVALID_ID) {
1246  WRITE_WARNING(
1247  "Ignoring restriction relation '" + toString(myCurrentRelation) + "' with unknown from-way.");
1248  ok = false;
1249  }
1250  if (myToWay == INVALID_ID) {
1251  WRITE_WARNING(
1252  "Ignoring restriction relation '" + toString(myCurrentRelation) + "' with unknown to-way.");
1253  ok = false;
1254  }
1255  if (myViaNode == INVALID_ID && myViaWay == INVALID_ID) {
1256  WRITE_WARNING("Ignoring restriction relation '" + toString(myCurrentRelation) + "' with unknown via.");
1257  ok = false;
1258  }
1259  if (ok && !applyRestriction()) {
1260  WRITE_WARNING("Ignoring restriction relation '" + toString(myCurrentRelation) + "'.");
1261  }
1262  } else if (myIsStopArea && OptionsCont::getOptions().isSet("ptstop-output")) {
1263  for (long long ref : myStops) {
1264  if (myOSMNodes.find(ref) == myOSMNodes.end()) {
1265  //WRITE_WARNING(
1266  // "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
1267  // + "' does not exist. Probably OSM file is incomplete.");
1268  continue;
1269  }
1270 
1271  NIOSMNode* n = myOSMNodes.find(ref)->second;
1272  NBPTStop* ptStop = myNBPTStopCont->get(toString(n->id));
1273  if (ptStop == nullptr) {
1274  //WRITE_WARNING(
1275  // "Relation '" + toString(myCurrentRelation) + "' refers to a non existing pt stop at node: '"
1276  // + toString(n->id) + "'. Probably OSM file is incomplete.");
1277  continue;
1278  }
1279  for (NIIPTPlatform& myPlatform : myPlatforms) {
1280  if (myPlatform.isWay) {
1281  assert(myPlatformShapes.find(myPlatform.ref) != myPlatformShapes.end()); //already tested earlier
1282  Edge* edge = (*myPlatformShapes.find(myPlatform.ref)).second;
1283  if (edge->myCurrentNodes[0] == *(edge->myCurrentNodes.end() - 1)) {
1284  WRITE_WARNINGF("Platform '%' in relation: '%' is given as polygon, which currently is not supported.", myPlatform.ref, myCurrentRelation);
1285  continue;
1286 
1287  }
1288  PositionVector p;
1289  for (auto nodeRef : edge->myCurrentNodes) {
1290  if (myOSMNodes.find(nodeRef) == myOSMNodes.end()) {
1291  //WRITE_WARNING(
1292  // "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
1293  // + "' does not exist. Probably OSM file is incomplete.");
1294  continue;
1295  }
1296  NIOSMNode* pNode = myOSMNodes.find(nodeRef)->second;
1297  Position pNodePos(pNode->lon, pNode->lat, pNode->ele);
1298  if (!NBNetBuilder::transformCoordinate(pNodePos)) {
1299  WRITE_ERROR("Unable to project coordinates for node '" + toString(pNode->id) + "'.");
1300  continue;
1301  }
1302  p.push_back(pNodePos);
1303  }
1304  if (p.size() == 0) {
1305  WRITE_WARNING(
1306  "Referenced platform: '" + toString(myPlatform.ref) + "' in relation: '" + toString(myCurrentRelation)
1307  + "' is corrupt. Probably OSM file is incomplete.");
1308  continue;
1309  }
1310  NBPTPlatform platform(p[(int)p.size() / 2], p.length());
1311  ptStop->addPlatformCand(platform);
1312  } else {
1313  if (myOSMNodes.find(myPlatform.ref) == myOSMNodes.end()) {
1314  //WRITE_WARNING(
1315  // "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
1316  // + "' does not exist. Probably OSM file is incomplete.");
1317  continue;
1318  }
1319  NIOSMNode* pNode = myOSMNodes.find(myPlatform.ref)->second;
1320  Position platformPos(pNode->lon, pNode->lat, pNode->ele);
1321  if (!NBNetBuilder::transformCoordinate(platformPos)) {
1322  WRITE_ERROR("Unable to project coordinates for node '" + toString(pNode->id) + "'.");
1323  }
1324  NBPTPlatform platform(platformPos, myOptionsCont.getFloat(
1325  "osm.stop-output.length"));
1326  ptStop->addPlatformCand(platform);
1327 
1328  }
1329  }
1330  ptStop->setIsMultipleStopPositions(myStops.size() > 1);
1331  }
1332  } else if (myPTRouteType != "" && myIsRoute && OptionsCont::getOptions().isSet("ptline-output") && myStops.size() > 1) {
1333  NBPTLine* ptLine = new NBPTLine(toString(myCurrentRelation), myName, myPTRouteType, myRef, myInterval, myNightService, interpretTransportType(myPTRouteType));
1334  ptLine->setMyNumOfStops((int)myStops.size());
1335  for (long long ref : myStops) {
1336  if (myOSMNodes.find(ref) == myOSMNodes.end()) {
1337  //WRITE_WARNING(
1338  // "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
1339  // + "' does not exist. Probably OSM file is incomplete.");
1340 // resetValues();
1341 // return;
1342  if (!ptLine->getStops().empty()) {
1343  WRITE_WARNINGF("Done reading first coherent chunk of pt stops. Further stops in relation % are ignored", myCurrentRelation);
1344  break;
1345  }
1346  continue;
1347  }
1348 
1349  NIOSMNode* n = myOSMNodes.find(ref)->second;
1350  NBPTStop* ptStop = myNBPTStopCont->get(toString(n->id));
1351  if (ptStop == nullptr) {
1352  // loose stop, which must later be mapped onto a line way
1353  Position ptPos(n->lon, n->lat, n->ele);
1354  if (!NBNetBuilder::transformCoordinate(ptPos)) {
1355  WRITE_ERROR("Unable to project coordinates for node '" + toString(n->id) + "'.");
1356  }
1357  ptStop = new NBPTStop(toString(n->id), ptPos, "", "", n->ptStopLength, n->name, n->permissions);
1358  myNBPTStopCont->insert(ptStop);
1359  }
1360  ptLine->addPTStop(ptStop);
1361  }
1362  for (long long& myWay : myWays) {
1363  auto entr = myOSMEdges.find(myWay);
1364  if (entr != myOSMEdges.end()) {
1365  Edge* edge = entr->second;
1366  for (long long& myCurrentNode : edge->myCurrentNodes) {
1367  ptLine->addWayNode(myWay, myCurrentNode);
1368  }
1369  }
1370  }
1371  if (ptLine->getStops().empty()) {
1372  WRITE_WARNINGF("PT line in relation % with no stops ignored. Probably OSM file is incomplete.", myCurrentRelation);
1373  resetValues();
1374  return;
1375  }
1376  if (myNBPTLineCont->getLines().count(ptLine->getLineID()) == 0) {
1377  myNBPTLineCont->insert(ptLine);
1378  } else {
1379  WRITE_WARNING("Ignoring duplicate PT line " + toString(myCurrentRelation) + ".");
1380  delete ptLine;
1381  }
1382  }
1383  // other relations might use similar subelements so reset in any case
1384  resetValues();
1385  }
1386 }
1387 
1388 bool
1390  // since OSM ways are bidirectional we need the via to figure out which direction was meant
1391  if (myViaNode != INVALID_ID) {
1392  NBNode* viaNode = myOSMNodes.find(myViaNode)->second->node;
1393  if (viaNode == nullptr) {
1394  WRITE_WARNING("Via-node '" + toString(myViaNode) + "' was not instantiated");
1395  return false;
1396  }
1397  NBEdge* from = findEdgeRef(myFromWay, viaNode->getIncomingEdges());
1398  NBEdge* to = findEdgeRef(myToWay, viaNode->getOutgoingEdges());
1399  if (from == nullptr) {
1400  WRITE_WARNING("from-edge of restriction relation could not be determined");
1401  return false;
1402  }
1403  if (to == nullptr) {
1404  WRITE_WARNING("to-edge of restriction relation could not be determined");
1405  return false;
1406  }
1407  if (myRestrictionType == RESTRICTION_ONLY) {
1408  from->addEdge2EdgeConnection(to);
1409  } else {
1410  from->removeFromConnections(to, -1, -1, true);
1411  }
1412  } else {
1413  // XXX interpreting via-ways or via-node lists not yet implemented
1414  WRITE_WARNING("direction of restriction relation could not be determined");
1415  return false;
1416  }
1417  return true;
1418 }
1419 
1420 NBEdge*
1422  const std::vector<NBEdge*>& candidates) const {
1423  const std::string prefix = toString(wayRef);
1424  const std::string backPrefix = "-" + prefix;
1425  NBEdge* result = nullptr;
1426  int found = 0;
1427  for (auto candidate : candidates) {
1428  if ((candidate->getID().substr(0, prefix.size()) == prefix) ||
1429  (candidate->getID().substr(0, backPrefix.size()) == backPrefix)) {
1430  result = candidate;
1431  found++;
1432  }
1433  }
1434  if (found > 1) {
1435  WRITE_WARNING("Ambigous way reference '" + prefix + "' in restriction relation");
1436  result = nullptr;
1437  }
1438  return result;
1439 }
1440 
1441 void
1443  NBNodeCont& nc = nb.getNodeCont();
1444  NBEdgeCont& ec = nb.getEdgeCont();
1445  // reconstruct elevation from layer info
1446  // build a map of raising and lowering forces (attractor and distance)
1447  // for all nodes unknownElevation
1448  std::map<NBNode*, std::vector<std::pair<double, double> > > layerForces;
1449 
1450  // collect all nodes that belong to a way with layer information
1451  std::set<NBNode*> knownElevation;
1452  for (auto& myEdge : myEdges) {
1453  Edge* e = myEdge.second;
1454  if (e->myLayer != 0) {
1455  for (auto j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
1456  NBNode* node = nc.retrieve(toString(*j));
1457  if (node != nullptr) {
1458  knownElevation.insert(node);
1459  layerForces[node].emplace_back(e->myLayer * layerElevation, POSITION_EPS);
1460  }
1461  }
1462  }
1463  }
1464 #ifdef DEBUG_LAYER_ELEVATION
1465  std::cout << "known elevations:\n";
1466  for (std::set<NBNode*>::iterator it = knownElevation.begin(); it != knownElevation.end(); ++it) {
1467  const std::vector<std::pair<double, double> >& primaryLayers = layerForces[*it];
1468  std::cout << " node=" << (*it)->getID() << " ele=";
1469  for (std::vector<std::pair<double, double> >::const_iterator it_ele = primaryLayers.begin(); it_ele != primaryLayers.end(); ++it_ele) {
1470  std::cout << it_ele->first << " ";
1471  }
1472  std::cout << "\n";
1473  }
1474 #endif
1475  // layer data only provides a lower bound on elevation since it is used to
1476  // resolve the relation among overlapping ways.
1477  // Perform a sanity check for steep inclines and raise the knownElevation if necessary
1478  std::map<NBNode*, double> knownEleMax;
1479  for (auto it : knownElevation) {
1480  double eleMax = -std::numeric_limits<double>::max();
1481  const std::vector<std::pair<double, double> >& primaryLayers = layerForces[it];
1482  for (const auto& primaryLayer : primaryLayers) {
1483  eleMax = MAX2(eleMax, primaryLayer.first);
1484  }
1485  knownEleMax[it] = eleMax;
1486  }
1487  const double gradeThreshold = OptionsCont::getOptions().getFloat("osm.layer-elevation.max-grade") / 100;
1488  bool changed = true;
1489  while (changed) {
1490  changed = false;
1491  for (auto it = knownElevation.begin(); it != knownElevation.end(); ++it) {
1492  std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it,
1493  knownEleMax[*it]
1494  / gradeThreshold * 3,
1495  knownElevation);
1496  for (auto& neighbor : neighbors) {
1497  if (knownElevation.count(neighbor.first) != 0) {
1498  const double grade = fabs(knownEleMax[*it] - knownEleMax[neighbor.first])
1499  / MAX2(POSITION_EPS, neighbor.second.first);
1500 #ifdef DEBUG_LAYER_ELEVATION
1501  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";
1502 #endif
1503  if (grade > gradeThreshold * 50 / 3.6 / neighbor.second.second) {
1504  // raise the lower node to the higher level
1505  const double eleMax = MAX2(knownEleMax[*it], knownEleMax[neighbor.first]);
1506  if (knownEleMax[*it] < eleMax) {
1507  knownEleMax[*it] = eleMax;
1508  } else {
1509  knownEleMax[neighbor.first] = eleMax;
1510  }
1511  changed = true;
1512  }
1513  }
1514  }
1515  }
1516  }
1517 
1518  // collect all nodes within a grade-dependent range around knownElevation-nodes and apply knowElevation forces
1519  std::set<NBNode*> unknownElevation;
1520  for (auto it = knownElevation.begin(); it != knownElevation.end(); ++it) {
1521  const double eleMax = knownEleMax[*it];
1522  const double maxDist = fabs(eleMax) * 100 / layerElevation;
1523  std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it, maxDist, knownElevation);
1524  for (auto& neighbor : neighbors) {
1525  if (knownElevation.count(neighbor.first) == 0) {
1526  unknownElevation.insert(neighbor.first);
1527  layerForces[neighbor.first].emplace_back(eleMax, neighbor.second.first);
1528  }
1529  }
1530  }
1531 
1532  // apply forces to ground-level nodes (neither in knownElevation nor unknownElevation)
1533  for (auto it = unknownElevation.begin(); it != unknownElevation.end(); ++it) {
1534  double eleMax = -std::numeric_limits<double>::max();
1535  const std::vector<std::pair<double, double> >& primaryLayers = layerForces[*it];
1536  for (const auto& primaryLayer : primaryLayers) {
1537  eleMax = MAX2(eleMax, primaryLayer.first);
1538  }
1539  const double maxDist = fabs(eleMax) * 100 / layerElevation;
1540  std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it, maxDist, knownElevation);
1541  for (auto& neighbor : neighbors) {
1542  if (knownElevation.count(neighbor.first) == 0 && unknownElevation.count(neighbor.first) == 0) {
1543  layerForces[*it].emplace_back(0, neighbor.second.first);
1544  }
1545  }
1546  }
1547  // compute the elevation for each node as the weighted average of all forces
1548 #ifdef DEBUG_LAYER_ELEVATION
1549  std::cout << "summation of forces\n";
1550 #endif
1551  std::map<NBNode*, double> nodeElevation;
1552  for (auto& layerForce : layerForces) {
1553  const std::vector<std::pair<double, double> >& forces = layerForce.second;
1554  if (knownElevation.count(layerForce.first) != 0) {
1555  // use the maximum value
1556  /*
1557  double eleMax = -std::numeric_limits<double>::max();
1558  for (std::vector<std::pair<double, double> >::const_iterator it_force = forces.begin(); it_force != forces.end(); ++it_force) {
1559  eleMax = MAX2(eleMax, it_force->first);
1560  }
1561  */
1562 #ifdef DEBUG_LAYER_ELEVATION
1563  std::cout << " node=" << it->first->getID() << " knownElevation=" << knownEleMax[it->first] << "\n";
1564 #endif
1565  nodeElevation[layerForce.first] = knownEleMax[layerForce.first];
1566  } else if (forces.size() == 1) {
1567  nodeElevation[layerForce.first] = forces.front().first;
1568  } else {
1569  // use the weighted sum
1570  double distSum = 0;
1571  for (const auto& force : forces) {
1572  distSum += force.second;
1573  }
1574  double weightSum = 0;
1575  double elevation = 0;
1576 #ifdef DEBUG_LAYER_ELEVATION
1577  std::cout << " node=" << it->first->getID() << " distSum=" << distSum << "\n";
1578 #endif
1579  for (const auto& force : forces) {
1580  const double weight = (distSum - force.second) / distSum;
1581  weightSum += weight;
1582  elevation += force.first * weight;
1583 
1584 #ifdef DEBUG_LAYER_ELEVATION
1585  std::cout << " force=" << it_force->first << " dist=" << it_force->second << " weight=" << weight << " ele=" << elevation << "\n";
1586 #endif
1587  }
1588  nodeElevation[layerForce.first] = elevation / weightSum;
1589  }
1590  }
1591 #ifdef DEBUG_LAYER_ELEVATION
1592  std::cout << "final elevations:\n";
1593  for (std::map<NBNode*, double>::iterator it = nodeElevation.begin(); it != nodeElevation.end(); ++it) {
1594  std::cout << " node=" << (it->first)->getID() << " ele=" << it->second << "\n";
1595  }
1596 #endif
1597  // apply node elevations
1598  for (auto& it : nodeElevation) {
1599  NBNode* n = it.first;
1600  Position pos = n->getPosition();
1601  n->reinit(n->getPosition() + Position(0, 0, it.second), n->getType());
1602  }
1603 
1604  // apply way elevation to all edges that had layer information
1605  for (const auto& it : ec) {
1606  NBEdge* edge = it.second;
1607  const PositionVector& geom = edge->getGeometry();
1608  const double length = geom.length2D();
1609  const double zFrom = nodeElevation[edge->getFromNode()];
1610  const double zTo = nodeElevation[edge->getToNode()];
1611  // XXX if the from- or to-node was part of multiple ways with
1612  // different layers, reconstruct the layer value from origID
1613  double dist = 0;
1614  PositionVector newGeom;
1615  for (auto it_pos = geom.begin(); it_pos != geom.end(); ++it_pos) {
1616  if (it_pos != geom.begin()) {
1617  dist += (*it_pos).distanceTo2D(*(it_pos - 1));
1618  }
1619  newGeom.push_back((*it_pos) + Position(0, 0, zFrom + (zTo - zFrom) * dist / length));
1620  }
1621  edge->setGeometry(newGeom);
1622  }
1623 }
1624 
1625 std::map<NBNode*, std::pair<double, double> >
1626 NIImporter_OpenStreetMap::getNeighboringNodes(NBNode* node, double maxDist, const std::set<NBNode*>& knownElevation) {
1627  std::map<NBNode*, std::pair<double, double> > result;
1628  std::set<NBNode*> visited;
1629  std::vector<NBNode*> open;
1630  open.push_back(node);
1631  result[node] = std::make_pair(0, 0);
1632  while (!open.empty()) {
1633  NBNode* n = open.back();
1634  open.pop_back();
1635  if (visited.count(n) != 0) {
1636  continue;
1637  }
1638  visited.insert(n);
1639  const EdgeVector& edges = n->getEdges();
1640  for (auto e : edges) {
1641  NBNode* s = nullptr;
1642  if (n->hasIncoming(e)) {
1643  s = e->getFromNode();
1644  } else {
1645  s = e->getToNode();
1646  }
1647  const double dist = result[n].first + e->getGeometry().length2D();
1648  const double speed = MAX2(e->getSpeed(), result[n].second);
1649  if (result.count(s) == 0) {
1650  result[s] = std::make_pair(dist, speed);
1651  } else {
1652  result[s] = std::make_pair(MIN2(dist, result[s].first), MAX2(speed, result[s].second));
1653  }
1654  if (dist < maxDist && knownElevation.count(s) == 0) {
1655  open.push_back(s);
1656  }
1657  }
1658  }
1659  result.erase(node);
1660  return result;
1661 }
1662 
1663 
1664 std::string
1665 NIImporter_OpenStreetMap::usableType(const std::string& type, const std::string& id, NBTypeCont& tc) {
1666  if (tc.knows(type)) {
1667  return type;
1668  }
1669  if (myUnusableTypes.count(type) > 0) {
1670  return "";
1671  }
1672  if (myKnownCompoundTypes.count(type) > 0) {
1673  return myKnownCompoundTypes[type];
1674  }
1675  // this edge has a type which does not yet exist in the TypeContainer
1677  std::vector<std::string> types;
1678  while (tok.hasNext()) {
1679  std::string t = tok.next();
1680  if (tc.knows(t)) {
1681  if (std::find(types.begin(), types.end(), t) == types.end()) {
1682  types.push_back(t);
1683  }
1684  } else if (tok.size() > 1) {
1685  WRITE_WARNINGF("Discarding unknown compound '%' in type '%' (first occurence for edge '%').", t, type, id);
1686  }
1687  }
1688  if (types.empty()) {
1689  WRITE_WARNINGF("Discarding unusable type '%' (first occurence for edge '%').", type, id);
1690  myUnusableTypes.insert(type);
1691  return "";
1692  }
1693  const std::string newType = joinToString(types, "|");
1694  if (tc.knows(newType)) {
1695  myKnownCompoundTypes[type] = newType;
1696  return newType;
1697  } else if (myKnownCompoundTypes.count(newType) > 0) {
1698  return myKnownCompoundTypes[newType];
1699  } else {
1700  // build a new type by merging all values
1701  int numLanes = 0;
1702  double maxSpeed = 0;
1703  int prio = 0;
1704  double width = NBEdge::UNSPECIFIED_WIDTH;
1705  double sidewalkWidth = NBEdge::UNSPECIFIED_WIDTH;
1706  double bikelaneWidth = NBEdge::UNSPECIFIED_WIDTH;
1707  bool defaultIsOneWay = true;
1708  SVCPermissions permissions = 0;
1709  bool discard = true;
1710  for (auto& type2 : types) {
1711  if (!tc.getShallBeDiscarded(type2)) {
1712  numLanes = MAX2(numLanes, tc.getNumLanes(type2));
1713  maxSpeed = MAX2(maxSpeed, tc.getSpeed(type2));
1714  prio = MAX2(prio, tc.getPriority(type2));
1715  defaultIsOneWay &= tc.getIsOneWay(type2);
1716  //std::cout << "merging component " << type2 << " into type " << newType << " allows=" << getVehicleClassNames(tc.getPermissions(type2)) << " oneway=" << defaultIsOneWay << "\n";
1717  permissions |= tc.getPermissions(type2);
1718  width = MAX2(width, tc.getWidth(type2));
1719  sidewalkWidth = MAX2(sidewalkWidth, tc.getSidewalkWidth(type2));
1720  bikelaneWidth = MAX2(bikelaneWidth, tc.getBikeLaneWidth(type2));
1721  discard = false;
1722  }
1723  }
1724  if (width != NBEdge::UNSPECIFIED_WIDTH) {
1725  width = MAX2(width, SUMO_const_laneWidth);
1726  }
1727  // ensure pedestrians don't run into trains
1728  if (sidewalkWidth == NBEdge::UNSPECIFIED_WIDTH
1729  && (permissions & SVC_PEDESTRIAN) != 0
1730  && (permissions & SVC_RAIL_CLASSES) != 0) {
1731  //std::cout << "patching sidewalk for type '" << newType << "' which allows=" << getVehicleClassNames(permissions) << "\n";
1732  sidewalkWidth = OptionsCont::getOptions().getFloat("default.sidewalk-width");
1733  }
1734 
1735  if (discard) {
1736  WRITE_WARNING(
1737  "Discarding compound type '" + newType + "' (first occurence for edge '" + id + "').");
1738  myUnusableTypes.insert(newType);
1739  return "";
1740  }
1741 
1742  WRITE_MESSAGE("Adding new type '" + type + "' (first occurence for edge '" + id + "').");
1743  tc.insert(newType, numLanes, maxSpeed, prio, permissions, width, defaultIsOneWay,
1744  sidewalkWidth, bikelaneWidth, 0, 0, 0);
1745  for (auto& type3 : types) {
1746  if (!tc.getShallBeDiscarded(type3)) {
1747  tc.copyRestrictionsAndAttrs(type3, newType);
1748  }
1749  }
1750  myKnownCompoundTypes[type] = newType;
1751  return newType;
1752  }
1753 }
1754 
1755 void
1757  const std::string id = toString(e->id);
1758  std::string type = usableType(e->myHighWayType, id, tc);
1759  if (type != "" && isRailway(tc.getPermissions(type))) {
1760  std::vector<NIOSMNode*> nodes;
1761  std::vector<double> usablePositions;
1762  std::vector<int> usableIndex;
1763  int i = 0;
1764  for (long long int n : e->myCurrentNodes) {
1765  NIOSMNode* node = myOSMNodes[n];
1766  node->positionMeters = interpretDistance(node);
1767  if (node->positionMeters != std::numeric_limits<double>::max()) {
1768  usablePositions.push_back(node->positionMeters);
1769  usableIndex.push_back(i);
1770  }
1771  i++;
1772  nodes.push_back(node);
1773  }
1774  if (usablePositions.size() == 0) {
1775  return;
1776  } else {
1777  bool forward = true;
1778  if (usablePositions.size() == 1) {
1779  WRITE_WARNING("Ambiguous railway kilometrage direction for way '" + id + "' (assuming forward)");
1780  } else {
1781  forward = usablePositions.front() < usablePositions.back();
1782  }
1783  // check for consistency
1784  for (int i = 1; i < (int)usablePositions.size(); i++) {
1785  if ((usablePositions[i - 1] < usablePositions[i]) != forward) {
1786  WRITE_WARNING("Inconsistent railway kilometrage direction for way '" + id + "': " + toString(usablePositions) + " (skipping)");
1787  return;
1788  }
1789  }
1790  if (nodes.size() > usablePositions.size()) {
1791  // complete missing values
1792  PositionVector shape;
1793  for (NIOSMNode* node : nodes) {
1794  shape.push_back(Position(node->lon, node->lat, 0));
1795  }
1796  if (!NBNetBuilder::transformCoordinates(shape)) {
1797  return; // error will be given later
1798  }
1799  double sign = forward ? 1 : -1;
1800  // extend backward before first usable value
1801  for (int i = usableIndex.front() - 1; i >= 0; i--) {
1802  nodes[i]->positionMeters = nodes[i + 1]->positionMeters - sign * shape[i].distanceTo2D(shape[i + 1]);
1803  }
1804  // extend forward
1805  for (int i = usableIndex.front() + 1; i < (int)nodes.size(); i++) {
1806  if (nodes[i]->positionMeters == std::numeric_limits<double>::max()) {
1807  nodes[i]->positionMeters = nodes[i - 1]->positionMeters + sign * shape[i].distanceTo2D(shape[i - 1]);
1808  }
1809  }
1810  //std::cout << " way=" << id << " usable=" << toString(usablePositions) << "\n indices=" << toString(usableIndex)
1811  // << " final:\n";
1812  //for (auto n : nodes) {
1813  // std::cout << " " << n->id << " " << n->positionMeters << " " << n->position<< "\n";
1814  //}
1815  }
1816  }
1817  }
1818 }
1819 
1820 
1821 double
1823  if (node->position.size() > 0) {
1824  try {
1825  if (StringUtils::startsWith(node->position, "mi:")) {
1826  return StringUtils::toDouble(node->position.substr(3)) * 1609.344; // meters per mile
1827  } else {
1828  return StringUtils::toDouble(node->position) * 1000;
1829  }
1830  } catch (...) {
1831  WRITE_WARNING("Value of railway:position is not numeric ('" + node->position + "') in node '" +
1832  toString(node->id) + "'.");
1833  }
1834  }
1835  return std::numeric_limits<double>::max();
1836 }
1837 
1840  SUMOVehicleClass result = SVC_IGNORING;
1841  std::string stop = type;
1842  if (type == "train") {
1843  result = SVC_RAIL;
1844  } else if (type == "subway" || type == "light_rail") {
1845  result = SVC_RAIL_URBAN;
1846  stop = "train";
1847  } else if (type == "bus") {
1848  result = SVC_BUS;
1849  } else if (type == "tram") {
1850  result = SVC_TRAM;
1851  }
1852  if (toSet != nullptr && result != SVC_IGNORING) {
1853  toSet->permissions |= result;
1854  toSet->ptStopLength = OptionsCont::getOptions().getFloat("osm.stop-output.length." + stop);
1855  }
1856  return result;
1857 }
1858 
1859 
1860 /****************************************************************************/
1861 
SVC_RAIL_FAST
@ SVC_RAIL_FAST
vehicle that is allowed to drive on high-speed rail tracks
Definition: SUMOVehicleClass.h:192
NIImporter_OpenStreetMap::NIOSMNode::name
std::string name
The name of the node.
Definition: NIImporter_OpenStreetMap.h:110
NBTypeCont::copyRestrictionsAndAttrs
bool copyRestrictionsAndAttrs(const std::string &fromId, const std::string &toId)
Copy restrictions to a type.
Definition: NBTypeCont.cpp:110
OptionsCont::isSet
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
Definition: OptionsCont.cpp:135
NIImporter_OpenStreetMap::Edge::myIsOneWay
std::string myIsOneWay
Information whether this is an one-way road.
Definition: NIImporter_OpenStreetMap.h:191
SUMO_ATTR_TYPE
@ SUMO_ATTR_TYPE
Definition: SUMOXMLDefinitions.h:381
NBEdge::UNSPECIFIED_OFFSET
static const double UNSPECIFIED_OFFSET
unspecified lane offset
Definition: NBEdge.h:318
SVC_PEDESTRIAN
@ SVC_PEDESTRIAN
pedestrian
Definition: SUMOVehicleClass.h:156
SUMOVehicleClass
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types.
Definition: SUMOVehicleClass.h:133
NBPTStop::setIsMultipleStopPositions
void setIsMultipleStopPositions(bool multipleStopPositions)
Definition: NBPTStop.cpp:155
NIImporter_OpenStreetMap::myKnownCompoundTypes
std::map< std::string, std::string > myKnownCompoundTypes
The compound types that have already been mapped to other known types.
Definition: NIImporter_OpenStreetMap.h:263
ToString.h
XMLSubSys::runParser
static bool runParser(GenericSAXHandler &handler, const std::string &file, const bool isNet=false)
Runs the given handler on the given file; returns if everything's ok.
Definition: XMLSubSys.cpp:112
SUMOSAXAttributes::hasAttribute
virtual bool hasAttribute(int id) const =0
Returns the information whether the named (by its enum-value) attribute is within the current list.
NIImporter_OpenStreetMap::insertNodeChecking
NBNode * insertNodeChecking(long long int id, NBNodeCont &nc, NBTrafficLightLogicCont &tlsc)
Builds an NBNode.
Definition: NIImporter_OpenStreetMap.cpp:265
MIN2
T MIN2(T a, T b)
Definition: StdDefs.h:73
joinToStringSorting
std::string joinToStringSorting(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:262
NBPTStopCont
Definition: NBPTStopCont.h:27
NIImporter_OpenStreetMap::NIOSMNode
An internal representation of an OSM-node.
Definition: NIImporter_OpenStreetMap.h:76
NIImporter_OpenStreetMap::loadNetwork
static void loadNetwork(const OptionsCont &oc, NBNetBuilder &nb)
Loads content of the optionally given OSM file.
Definition: NIImporter_OpenStreetMap.cpp:102
WRITE_WARNING
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:275
NIImporter_OpenStreetMap::NIOSMNode::ele
double ele
The elevation of this node.
Definition: NIImporter_OpenStreetMap.h:96
NIImporter_OpenStreetMap::Edge::id
const long long int id
The edge's id.
Definition: NIImporter_OpenStreetMap.h:177
NIImporter_OpenStreetMap::Edge::myBuswayType
WayType myBuswayType
Information about the kind of busway along this road.
Definition: NIImporter_OpenStreetMap.h:195
NBEdgeCont
Storage for edges, including some functionality operating on multiple edges.
Definition: NBEdgeCont.h:60
NIImporter_OpenStreetMap::NIOSMNode::ptStopLength
double ptStopLength
The length of the pt stop.
Definition: NIImporter_OpenStreetMap.h:108
NIImporter_OpenStreetMap::PARKING_RIGHT
@ PARKING_RIGHT
Definition: NIImporter_OpenStreetMap.h:148
SUMOSAXHandler
SAX-handler base for SUMO-files.
Definition: SUMOSAXHandler.h:41
NBNetBuilder
Instance responsible for building networks.
Definition: NBNetBuilder.h:109
NBTrafficLightLogicCont
A container for traffic light definitions and built programs.
Definition: NBTrafficLightLogicCont.h:57
GeomConvHelper.h
SUMO_TAG_MEMBER
@ SUMO_TAG_MEMBER
Definition: SUMOXMLDefinitions.h:236
OptionsCont.h
StringTokenizer::hasNext
bool hasNext()
returns the information whether further substrings exist
Definition: StringTokenizer.cpp:94
LANESPREAD_RIGHT
@ LANESPREAD_RIGHT
Definition: SUMOXMLDefinitions.h:1098
StringUtils::toDouble
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter
Definition: StringUtils.cpp:345
SUMOSAXAttributes::get
T get(int attr, const char *objectid, bool &ok, bool report=true) const
Tries to read given attribute assuming it is an int.
Definition: SUMOSAXAttributes.h:492
NBPTLine::getStops
std::vector< NBPTStop * > getStops()
Definition: NBPTLine.cpp:43
NIImporter_OpenStreetMap::Edge::myCurrentIsElectrified
bool myCurrentIsElectrified
Information whether this is railway is electrified.
Definition: NIImporter_OpenStreetMap.h:211
NIImporter_OpenStreetMap::NIOSMNode::railwayCrossing
bool railwayCrossing
Whether this is a railway crossing.
Definition: NIImporter_OpenStreetMap.h:100
MsgHandler.h
NIImporter_OpenStreetMap::RelationHandler::~RelationHandler
~RelationHandler() override
Destructor.
EdgeVector
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition: NBCont.h:34
NIImporter_OpenStreetMap::RelationHandler::resetValues
void resetValues()
reset members to their defaults for parsing a new relation
Definition: NIImporter_OpenStreetMap.cpp:1077
NIImporter_OpenStreetMap.h
NBNodeCont::insert
bool insert(const std::string &id, const Position &position, NBDistrict *district=0)
Inserts a node into the map.
Definition: NBNodeCont.cpp:78
SUMOSAXHandler.h
NBNode::getOutgoingEdges
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges (The edges which start at this node)
Definition: NBNode.h:260
FileHelpers.h
NBPTLine
Definition: NBPTLine.h:33
NBEdge::addEdge2EdgeConnection
bool addEdge2EdgeConnection(NBEdge *dest)
Adds a connection to another edge.
Definition: NBEdge.cpp:960
TrafficLightType
TrafficLightType
Definition: SUMOXMLDefinitions.h:1197
StringUtils::to_lower_case
static std::string to_lower_case(std::string str)
Transfers the content to lower case.
Definition: StringUtils.cpp:59
NBNetBuilder::transformCoordinates
static bool transformCoordinates(PositionVector &from, bool includeInBoundary=true, GeoConvHelper *from_srs=0)
Definition: NBNetBuilder.cpp:660
NIImporter_OpenStreetMap::NIOSMNode::railwayBufferStop
bool railwayBufferStop
Whether this is a railway buffer stop.
Definition: NIImporter_OpenStreetMap.h:104
NBEdgeCont.h
GeoConvHelper.h
OptionsCont::getBool
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
Definition: OptionsCont.cpp:222
NBOwnTLDef
A traffic light logics which must be computed (only nodes/edges are given)
Definition: NBOwnTLDef.h:46
SVC_BICYCLE
@ SVC_BICYCLE
vehicle is a bicycle
Definition: SUMOVehicleClass.h:179
NIImporter_OpenStreetMap::NIOSMNode::tlsControlled
bool tlsControlled
Whether this is a tls controlled junction.
Definition: NIImporter_OpenStreetMap.h:98
EmptyData
Definition: UtilExceptions.h:68
NBTypeCont::insert
void insert(const std::string &id, int numLanes, double maxSpeed, int prio, SVCPermissions permissions, double width, bool oneWayIsDefault, double sidewalkWidth, double bikeLaneWidth, double widthResolution, double maxWidth, double minWidth)
Adds a type into the list.
Definition: NBTypeCont.cpp:53
OptionsCont::getOptions
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:57
NBNode::getType
SumoXMLNodeType getType() const
Returns the type of this node.
Definition: NBNode.h:272
NIImporter_OpenStreetMap::RelationHandler::myStartElement
void myStartElement(int element, const SUMOSAXAttributes &attrs) override
Called on the opening of a tag;.
Definition: NIImporter_OpenStreetMap.cpp:1094
StringTokenizer::next
std::string next()
returns the next substring when it exists. Otherwise the behaviour is undefined
Definition: StringTokenizer.cpp:99
SUMO_TAG_ND
@ SUMO_TAG_ND
Definition: SUMOXMLDefinitions.h:233
NIImporter_OpenStreetMap::Edge
An internal definition of a loaded edge.
Definition: NIImporter_OpenStreetMap.h:159
SUMO_const_laneWidth
const double SUMO_const_laneWidth
Definition: StdDefs.h:49
NIImporter_OpenStreetMap::NodesHandler
A class which extracts OSM-nodes from a parsed OSM-file.
Definition: NIImporter_OpenStreetMap.h:322
NBEdge::setDistance
void setDistance(double distance)
set lane specific speed (negative lane implies set for all lanes)
Definition: NBEdge.h:1279
NBNetBuilder::transformCoordinate
static bool transformCoordinate(Position &from, bool includeInBoundary=true, GeoConvHelper *from_srs=0)
transforms loaded coordinates handles projections, offsets (using GeoConvHelper) and import of height...
Definition: NBNetBuilder.cpp:633
NBEdgeCont::insert
bool insert(NBEdge *edge, bool ignorePrunning=false)
Adds an edge to the dictionary.
Definition: NBEdgeCont.cpp:153
SUMO_ATTR_ID
@ SUMO_ATTR_ID
Definition: SUMOXMLDefinitions.h:378
PositionVector::length
double length() const
Returns the length.
Definition: PositionVector.cpp:484
WRITE_WARNINGF
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:276
NIImporter_OpenStreetMap::Edge::myCurrentNodes
std::vector< long long int > myCurrentNodes
The list of nodes this edge is made of.
Definition: NIImporter_OpenStreetMap.h:205
NBEdge::setPermissions
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:3376
NBEdge::getPermissions
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:3404
NIImporter_OpenStreetMap::WAY_NONE
@ WAY_NONE
Definition: NIImporter_OpenStreetMap.h:138
NIImporter_OpenStreetMap::reconstructLayerElevation
void reconstructLayerElevation(double layerElevation, NBNetBuilder &nb)
reconstruct elevation from layer info
Definition: NIImporter_OpenStreetMap.cpp:1442
NBPTLine::setMyNumOfStops
void setMyNumOfStops(int numStops)
Definition: NBPTLine.cpp:133
PositionVector
A list of positions.
Definition: PositionVector.h:45
SUMO_ATTR_V
@ SUMO_ATTR_V
Definition: SUMOXMLDefinitions.h:820
NIImporter_OpenStreetMap::load
void load(const OptionsCont &oc, NBNetBuilder &nb)
Definition: NIImporter_OpenStreetMap.cpp:125
NBTypeCont::knows
bool knows(const std::string &type) const
Returns whether the named type is in the container.
Definition: NBTypeCont.cpp:71
LANESPREAD_CENTER
@ LANESPREAD_CENTER
Definition: SUMOXMLDefinitions.h:1099
NIImporter_OpenStreetMap::RelationHandler::myEndElement
void myEndElement(int element) override
Called when a closing tag occurs.
Definition: NIImporter_OpenStreetMap.cpp:1235
SVC_RAIL
@ SVC_RAIL
vehicle is a not electrified rail
Definition: SUMOVehicleClass.h:188
NIImporter_OpenStreetMap::NIOSMNode::id
const long long int id
The node's id.
Definition: NIImporter_OpenStreetMap.h:90
NIImporter_OpenStreetMap::WAY_UNKNOWN
@ WAY_UNKNOWN
Definition: NIImporter_OpenStreetMap.h:142
SVC_RAIL_URBAN
@ SVC_RAIL_URBAN
vehicle is a city rail
Definition: SUMOVehicleClass.h:186
NBPTLine::getLineID
const std::string & getLineID() const
Definition: NBPTLine.h:42
NIImporter_OpenStreetMap::RelationHandler::findEdgeRef
NBEdge * findEdgeRef(long long int wayRef, const std::vector< NBEdge * > &candidates) const
try to find the way segment among candidates
Definition: NIImporter_OpenStreetMap.cpp:1421
NIImporter_OpenStreetMap::MAXSPEED_UNGIVEN
static const double MAXSPEED_UNGIVEN
Definition: NIImporter_OpenStreetMap.h:314
NBNetBuilder::getEdgeCont
NBEdgeCont & getEdgeCont()
Definition: NBNetBuilder.h:150
NBNodeCont
Container for nodes during the netbuilding process.
Definition: NBNodeCont.h:59
NIImporter_OpenStreetMap::NodesHandler::NodesHandler
NodesHandler(std::map< long long int, NIOSMNode * > &toFill, std::set< NIOSMNode *, CompareNodes > &uniqueNodes, const OptionsCont &cont)
Contructor.
Definition: NIImporter_OpenStreetMap.cpp:596
NBEdge
The representation of a single edge during network building.
Definition: NBEdge.h:91
OptionsCont::getStringVector
const StringVector & getStringVector(const std::string &name) const
Returns the list of string-value of the named option (only for Option_StringVector)
Definition: OptionsCont.cpp:235
NIImporter_OpenStreetMap::Edge::myNoLanesForward
int myNoLanesForward
number of lanes in forward direction or 0 if unknown, negative if backwards lanes are meant
Definition: NIImporter_OpenStreetMap.h:185
NIImporter_OpenStreetMap::EdgesHandler::myStartElement
void myStartElement(int element, const SUMOSAXAttributes &attrs) override
Called on the opening of a tag;.
Definition: NIImporter_OpenStreetMap.cpp:758
MAX2
T MAX2(T a, T b)
Definition: StdDefs.h:79
SVC_TRAM
@ SVC_TRAM
vehicle is a light rail
Definition: SUMOVehicleClass.h:184
NBNode::getPosition
const Position & getPosition() const
Definition: NBNode.h:247
NIImporter_OpenStreetMap::NodesHandler::myStartElement
void myStartElement(int element, const SUMOSAXAttributes &attrs) override
Called on the opening of a tag;.
Definition: NIImporter_OpenStreetMap.cpp:614
NIImporter_OpenStreetMap::interpretTransportType
static SUMOVehicleClass interpretTransportType(const std::string &type, NIOSMNode *toSet=nullptr)
translate osm transport designations into sumo vehicle class
Definition: NIImporter_OpenStreetMap.cpp:1839
NumberFormatException
Definition: UtilExceptions.h:95
NODETYPE_RAIL_SIGNAL
@ NODETYPE_RAIL_SIGNAL
Definition: SUMOXMLDefinitions.h:1059
Parameterised::getParametersMap
const std::map< std::string, std::string > & getParametersMap() const
Returns the inner key/value map.
Definition: Parameterised.cpp:106
NBTypeCont::getIsOneWay
bool getIsOneWay(const std::string &type) const
Returns whether edges are one-way per default for the given type.
Definition: NBTypeCont.cpp:189
NBEdge::getToNode
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:498
NIImporter_OpenStreetMap::EdgesHandler::mySpeedMap
std::map< std::string, double > mySpeedMap
A map of non-numeric speed descriptions to their numeric values.
Definition: NIImporter_OpenStreetMap.h:456
Parameterised::updateParameters
void updateParameters(const std::map< std::string, std::string > &mapArg)
Adds or updates all given parameters from the map.
Definition: Parameterised.cpp:58
NBEdge::getGeometry
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition: NBEdge.h:692
NBNetBuilder::getPTStopCont
NBPTStopCont & getPTStopCont()
Returns a reference to the pt stop container.
Definition: NBNetBuilder.h:176
NIImporter_OpenStreetMap::CompareEdges::operator()
bool operator()(const Edge *e1, const Edge *e2) const
Definition: NIImporter_OpenStreetMap.cpp:72
NBPTLineCont
Definition: NBPTLineCont.h:26
StringUtils::prune
static std::string prune(const std::string &str)
Removes trailing and leading whitechars.
Definition: StringUtils.cpp:48
NBPTLineCont.h
StringUtils::endsWith
static bool endsWith(const std::string &str, const std::string suffix)
Checks whether a given string ends with the suffix.
Definition: StringUtils.cpp:180
NIImporter_OpenStreetMap::extendRailwayDistances
void extendRailwayDistances(Edge *e, NBTypeCont &tc)
extend kilometrage data for all nodes along railway
Definition: NIImporter_OpenStreetMap.cpp:1756
NBNetBuilder::getPTLineCont
NBPTLineCont & getPTLineCont()
Returns a reference to the pt line container.
Definition: NBNetBuilder.h:181
NIImporter_OpenStreetMap::RelationHandler::RelationHandler
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.
Definition: NIImporter_OpenStreetMap.cpp:1057
SVCPermissions
int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
Definition: SUMOVehicleClass.h:218
SVC_RAIL_CLASSES
@ SVC_RAIL_CLASSES
classes which drive on tracks
Definition: SUMOVehicleClass.h:204
NIImporter_OpenStreetMap::WAY_BOTH
@ WAY_BOTH
Definition: NIImporter_OpenStreetMap.h:141
NIImporter_OpenStreetMap::WayType
WayType
Definition: NIImporter_OpenStreetMap.h:137
NIImporter_OpenStreetMap::RelationHandler::NIIPTPlatform::isWay
bool isWay
Definition: NIImporter_OpenStreetMap.h:593
NBNetBuilder::getParkingCont
NBParkingCont & getParkingCont()
Definition: NBNetBuilder.h:186
NBTypeCont::getSpeed
double getSpeed(const std::string &type) const
Returns the maximal velocity for the given type [m/s].
Definition: NBTypeCont.cpp:177
SUMO_TAG_RELATION
@ SUMO_TAG_RELATION
Definition: SUMOXMLDefinitions.h:235
StringBijection::get
T get(const std::string &str) const
Definition: StringBijection.h:97
NIImporter_OpenStreetMap::Edge::myCyclewayType
WayType myCyclewayType
Information about the kind of cycleway along this road.
Definition: NIImporter_OpenStreetMap.h:193
NBPTStopCont::cleanupDeleted
int cleanupDeleted(NBEdgeCont &cont)
remove stops on non existing (removed) edges
Definition: NBPTStopCont.cpp:299
StringTokenizer
Definition: StringTokenizer.h:61
StringUtils::escapeXML
static std::string escapeXML(const std::string &orig, const bool maskDoubleHyphen=false)
Replaces the standard escapes by their XML entities.
Definition: StringUtils.cpp:190
NIImporter_OpenStreetMap::NIOSMNode::permissions
SVCPermissions permissions
type of pt stop
Definition: NIImporter_OpenStreetMap.h:112
NIImporter_OpenStreetMap::RelationHandler::checkEdgeRef
bool checkEdgeRef(long long int ref) const
check whether a referenced way has a corresponding edge
Definition: NIImporter_OpenStreetMap.cpp:1223
SVC_RAIL_ELECTRIC
@ SVC_RAIL_ELECTRIC
rail vehicle that requires electrified tracks
Definition: SUMOVehicleClass.h:190
NIImporter_OpenStreetMap::insertEdge
int insertEdge(Edge *e, int index, NBNode *from, NBNode *to, const std::vector< long long int > &passed, NBNetBuilder &nb)
Builds an NBEdge.
Definition: NIImporter_OpenStreetMap.cpp:306
NBNetBuilder.h
ProcessError
Definition: UtilExceptions.h:39
NIImporter_OpenStreetMap::myOSMNodes
std::map< long long int, NIOSMNode * > myOSMNodes
the map from OSM node ids to actual nodes
Definition: NIImporter_OpenStreetMap.h:242
NBPTLine::addPTStop
void addPTStop(NBPTStop *pStop)
Definition: NBPTLine.cpp:38
isRailway
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
Definition: SUMOVehicleClass.cpp:363
NIImporter_OpenStreetMap::INVALID_ID
static const long long int INVALID_ID
Definition: NIImporter_OpenStreetMap.h:315
NIImporter_OpenStreetMap::myUnusableTypes
std::set< std::string > myUnusableTypes
The compounds types that do not contain known types.
Definition: NIImporter_OpenStreetMap.h:260
NIImporter_OpenStreetMap::interpretDistance
static double interpretDistance(NIOSMNode *node)
read distance value from node and return value in m
Definition: NIImporter_OpenStreetMap.cpp:1822
Position
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:38
NIImporter_OpenStreetMap::WAY_BACKWARD
@ WAY_BACKWARD
Definition: NIImporter_OpenStreetMap.h:140
NIImporter_OpenStreetMap::Edge::myParkingType
int myParkingType
Information about road-side parking.
Definition: NIImporter_OpenStreetMap.h:201
NIImporter_OpenStreetMap::NIOSMNode::position
std::string position
kilometrage/mileage
Definition: NIImporter_OpenStreetMap.h:114
UtilExceptions.h
NIImporter_OpenStreetMap::EdgesHandler::~EdgesHandler
~EdgesHandler() override
Destructor.
NIImporter_OpenStreetMap::EdgesHandler::myEndElement
void myEndElement(int element) override
Called when a closing tag occurs.
Definition: NIImporter_OpenStreetMap.cpp:1040
OptionsCont
A storage for options typed value containers)
Definition: OptionsCont.h:89
NBTypeCont::getShallBeDiscarded
bool getShallBeDiscarded(const std::string &type) const
Returns the information whether edges of this type shall be discarded.
Definition: NBTypeCont.cpp:195
NBNode::getEdges
const EdgeVector & getEdges() const
Returns all edges which participate in this node (Edges that start or end at this node)
Definition: NBNode.h:265
NBTypeCont::getPriority
int getPriority(const std::string &type) const
Returns the priority for the given type.
Definition: NBTypeCont.cpp:183
StringUtils::startsWith
static bool startsWith(const std::string &str, const std::string prefix)
Checks whether a given string starts with the prefix.
Definition: StringUtils.cpp:174
NIImporter_OpenStreetMap::WAY_FORWARD
@ WAY_FORWARD
Definition: NIImporter_OpenStreetMap.h:139
NIImporter_OpenStreetMap::NIImporter_OpenStreetMap
NIImporter_OpenStreetMap()
NBEdge::addSidewalk
void addSidewalk(double width)
add a pedestrian sidewalk of the given width and shift existing connctions
Definition: NBEdge.cpp:3545
NBEdge::addBikeLane
void addBikeLane(double width)
add a bicycle lane of the given width and shift existing connctions
Definition: NBEdge.cpp:3557
PositionVector::length2D
double length2D() const
Returns the length.
Definition: PositionVector.cpp:497
NIImporter_OpenStreetMap::NIOSMNode::positionMeters
double positionMeters
position converted to m (using highest precision available)
Definition: NIImporter_OpenStreetMap.h:116
NIImporter_OpenStreetMap::Edge::myMaxSpeed
double myMaxSpeed
maximum speed in km/h, or MAXSPEED_UNGIVEN
Definition: NIImporter_OpenStreetMap.h:187
NIImporter_OpenStreetMap::myUniqueNodes
std::set< NIOSMNode *, CompareNodes > myUniqueNodes
the set of unique nodes used in NodesHandler, used when freeing memory
Definition: NIImporter_OpenStreetMap.h:250
NIImporter_OpenStreetMap::PARKING_LEFT
@ PARKING_LEFT
Definition: NIImporter_OpenStreetMap.h:147
NBEdge::removeFromConnections
void removeFromConnections(NBEdge *toEdge, int fromLane=-1, int toLane=-1, bool tryLater=false, const bool adaptToLaneRemoval=false, const bool keepPossibleTurns=false)
Removes the specified connection(s)
Definition: NBEdge.cpp:1266
StringTokenizer::size
int size() const
returns the number of existing substrings
Definition: StringTokenizer.cpp:137
NBPTPlatform
Definition: NBPTPlatform.h:22
NIImporter_OpenStreetMap::Edge::ref
std::string ref
The edge's track name.
Definition: NIImporter_OpenStreetMap.h:181
NODETYPE_RAIL_CROSSING
@ NODETYPE_RAIL_CROSSING
Definition: SUMOXMLDefinitions.h:1060
NIImporter_OpenStreetMap::CompareEdges
Functor which compares two Edges.
Definition: NIImporter_OpenStreetMap.cpp:70
NIImporter_OpenStreetMap::RelationHandler
A class which extracts relevant relation information from a parsed OSM-file.
Definition: NIImporter_OpenStreetMap.h:475
NBNodeCont::retrieve
NBNode * retrieve(const std::string &id) const
Returns the node with the given name.
Definition: NBNodeCont.cpp:107
NIImporter_OpenStreetMap::compoundTypeSeparator
static const std::string compoundTypeSeparator
The separator within newly created compound type names.
Definition: NIImporter_OpenStreetMap.h:240
NIImporter_OpenStreetMap::Edge::mySidewalkType
WayType mySidewalkType
Information about the kind of sidwalk along this road.
Definition: NIImporter_OpenStreetMap.h:197
NIImporter_OpenStreetMap::EdgesHandler::myAllAttributes
bool myAllAttributes
whether additional way attributes shall be added to the edge
Definition: NIImporter_OpenStreetMap.h:459
NIImporter_OpenStreetMap::myPlatformShapes
std::map< long long int, Edge * > myPlatformShapes
the map from OSM way ids to platform shapes
Definition: NIImporter_OpenStreetMap.h:257
OptionsCont::getFloat
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
Definition: OptionsCont.cpp:208
NIImporter_OpenStreetMap::NIOSMNode::ptStopPosition
bool ptStopPosition
Whether this is a public transport stop position.
Definition: NIImporter_OpenStreetMap.h:106
NBNodeCont.h
toString
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:47
StringUtils.h
NIImporter_OpenStreetMap::RelationHandler::applyRestriction
bool applyRestriction() const
try to apply the parsed restriction and return whether successful
Definition: NIImporter_OpenStreetMap.cpp:1389
StringUtils::toInt
static int toInt(const std::string &sData)
converts a string into the integer value described by it by calling the char-type converter,...
Definition: StringUtils.cpp:278
NBPTStop::registerAdditionalEdge
void registerAdditionalEdge(std::string wayId, std::string edgeId)
Definition: NBPTStop.cpp:174
NILoader.h
NIImporter_OpenStreetMap::PARKING_BOTH
@ PARKING_BOTH
Definition: NIImporter_OpenStreetMap.h:149
NIImporter_OpenStreetMap::Edge::myLayer
int myLayer
Information about the relative z-ordering of ways.
Definition: NIImporter_OpenStreetMap.h:203
PROGRESS_BEGIN_MESSAGE
#define PROGRESS_BEGIN_MESSAGE(msg)
Definition: MsgHandler.h:278
NBTypeCont::getPermissions
SVCPermissions getPermissions(const std::string &type) const
Returns allowed vehicle classes for the given type.
Definition: NBTypeCont.cpp:221
NIImporter_OpenStreetMap::usableType
std::string usableType(const std::string &type, const std::string &id, NBTypeCont &tc)
check whether the type is known or consists of known type compounds. return empty string otherwise
Definition: NIImporter_OpenStreetMap.cpp:1665
NIImporter_OpenStreetMap::Edge::myNoLanes
int myNoLanes
number of lanes, or -1 if unknown
Definition: NIImporter_OpenStreetMap.h:183
NIImporter_OpenStreetMap::RelationHandler::NIIPTPlatform::ref
long long int ref
Definition: NIImporter_OpenStreetMap.h:592
NBTypeCont
A storage for available types of edges.
Definition: NBTypeCont.h:54
NBParking
The representation of a single pt stop.
Definition: NBParking.h:43
PositionVector::reverse
PositionVector reverse() const
reverse position vector
Definition: PositionVector.cpp:1086
NBNetBuilder::getTLLogicCont
NBTrafficLightLogicCont & getTLLogicCont()
Returns a reference to the traffic light logics container.
Definition: NBNetBuilder.h:165
Parameterised::unsetParameter
void unsetParameter(const std::string &key)
Removes a parameter.
Definition: Parameterised.cpp:52
NBPTStopCont::get
NBPTStop * get(std::string id)
Retrieve a previously inserted pt stop.
Definition: NBPTStopCont.cpp:50
NIImporter_OpenStreetMap::NIOSMNode::node
NBNode * node
the NBNode that was instantiated
Definition: NIImporter_OpenStreetMap.h:118
SUMO_ATTR_LAT
@ SUMO_ATTR_LAT
Definition: SUMOXMLDefinitions.h:815
SUMO_ATTR_K
@ SUMO_ATTR_K
Definition: SUMOXMLDefinitions.h:819
NBNode::getIncomingEdges
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges (The edges which yield in this node)
Definition: NBNode.h:255
PROGRESS_DONE_MESSAGE
#define PROGRESS_DONE_MESSAGE()
Definition: MsgHandler.h:279
SUMO_TAG_TAG
@ SUMO_TAG_TAG
Definition: SUMOXMLDefinitions.h:234
NBTypeCont::getWidth
double getWidth(const std::string &type) const
Returns the lane width for the given type [m].
Definition: NBTypeCont.cpp:227
NBTypeCont::getNumLanes
int getNumLanes(const std::string &type) const
Returns the number of lanes for the given type.
Definition: NBTypeCont.cpp:171
NIImporter_OpenStreetMap::Edge::myHighWayType
std::string myHighWayType
The type, stored in "highway" key.
Definition: NIImporter_OpenStreetMap.h:189
joinToString
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:246
NBEdge::UNSPECIFIED_WIDTH
static const double UNSPECIFIED_WIDTH
unspecified lane width
Definition: NBEdge.h:315
Parameterised::setParameter
void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
Definition: Parameterised.cpp:46
NIImporter_OpenStreetMap::Edge::myCurrentIsRoad
bool myCurrentIsRoad
Information whether this is a road.
Definition: NIImporter_OpenStreetMap.h:207
SUMOXMLDefinitions::TrafficLightTypes
static StringBijection< TrafficLightType > TrafficLightTypes
traffic light types
Definition: SUMOXMLDefinitions.h:1392
LaneSpreadFunction
LaneSpreadFunction
Numbers representing special SUMO-XML-attribute values Information how the edge's lateral offset shal...
Definition: SUMOXMLDefinitions.h:1097
SUMO_TAG_WAY
@ SUMO_TAG_WAY
Definition: SUMOXMLDefinitions.h:232
NBPTLine.h
FileHelpers::isReadable
static bool isReadable(std::string path)
Checks whether the given file is readable.
Definition: FileHelpers.cpp:49
NIImporter_OpenStreetMap::EdgesHandler
A class which extracts OSM-edges from a parsed OSM-file.
Definition: NIImporter_OpenStreetMap.h:400
NIImporter_OpenStreetMap::NIOSMNode::railwaySignal
bool railwaySignal
Whether this is a railway (main) signal.
Definition: NIImporter_OpenStreetMap.h:102
NBNode::hasIncoming
bool hasIncoming(const NBEdge *const e) const
Returns whether the given edge ends at this node.
Definition: NBNode.cpp:1531
StringTokenizer::getVector
std::vector< std::string > getVector()
return vector of strings
Definition: StringTokenizer.cpp:191
config.h
NIImporter_OpenStreetMap
Importer for networks stored in OpenStreetMap format.
Definition: NIImporter_OpenStreetMap.h:58
NIImporter_OpenStreetMap::EdgesHandler::EdgesHandler
EdgesHandler(const std::map< long long int, NIOSMNode * > &osmNodes, std::map< long long int, Edge * > &toFill, std::map< long long int, Edge * > &platformShapes)
Constructor.
Definition: NIImporter_OpenStreetMap.cpp:737
SVC_BUS
@ SVC_BUS
vehicle is a bus
Definition: SUMOVehicleClass.h:165
NIImporter_OpenStreetMap::NodesHandler::myEndElement
void myEndElement(int element) override
Called when a closing tag occurs.
Definition: NIImporter_OpenStreetMap.cpp:726
StringTokenizer.h
NBPTLine::addWayNode
void addWayNode(long long int way, long long int node)
Definition: NBPTLine.cpp:90
SUMO_ATTR_REF
@ SUMO_ATTR_REF
Definition: SUMOXMLDefinitions.h:821
NIImporter_OpenStreetMap::~NIImporter_OpenStreetMap
~NIImporter_OpenStreetMap()
Definition: NIImporter_OpenStreetMap.cpp:109
NIImporter_OpenStreetMap::NIOSMNode::lat
const double lat
The latitude the node is located at.
Definition: NIImporter_OpenStreetMap.h:94
NBTypeCont::getSidewalkWidth
double getSidewalkWidth(const std::string &type) const
Returns the lane width for a sidewalk to be added [m].
Definition: NBTypeCont.cpp:233
NBNode
Represents a single node (junction) during network building.
Definition: NBNode.h:67
NIImporter_OpenStreetMap::NodesHandler::~NodesHandler
~NodesHandler() override
Destructor.
SUMOSAXAttributes::getStringSecure
virtual std::string getStringSecure(int id, const std::string &def) const =0
Returns the string-value of the named (by its enum-value) attribute.
NBOwnTLDef.h
NBPTStopCont::insert
bool insert(NBPTStop *ptStop)
Inserts a node into the map.
Definition: NBPTStopCont.cpp:38
SUMO_ATTR_LON
@ SUMO_ATTR_LON
Definition: SUMOXMLDefinitions.h:814
NIImporter_OpenStreetMap::RelationHandler::NIIPTPlatform
Definition: NIImporter_OpenStreetMap.h:591
NBNetBuilder::getNodeCont
NBNodeCont & getNodeCont()
Returns a reference to the node container.
Definition: NBNetBuilder.h:155
NBPTStop
The representation of a single pt stop.
Definition: NBPTStop.h:44
NBTrafficLightLogicCont::insert
bool insert(NBTrafficLightDefinition *logic, bool forceInsert=false)
Adds a logic definition to the dictionary.
Definition: NBTrafficLightLogicCont.cpp:73
SVC_IGNORING
@ SVC_IGNORING
vehicles ignoring classes
Definition: SUMOVehicleClass.h:135
NBNetBuilder::getTypeCont
NBTypeCont & getTypeCont()
Returns a reference to the type container.
Definition: NBNetBuilder.h:160
NBNode.h
SUMOSAXAttributes
Encapsulated SAX-Attributes.
Definition: SUMOSAXAttributes.h:56
Named::getID
const std::string & getID() const
Returns the id.
Definition: Named.h:76
POSITION_EPS
#define POSITION_EPS
Definition: config.h:172
WRITE_ERROR
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:283
NIImporter_OpenStreetMap::NIOSMNode::lon
const double lon
The longitude the node is located at.
Definition: NIImporter_OpenStreetMap.h:92
NBTypeCont::getBikeLaneWidth
double getBikeLaneWidth(const std::string &type) const
Returns the lane width for a bike lane to be added [m].
Definition: NBTypeCont.cpp:239
NBEdge::getFromNode
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:491
NIImporter_OpenStreetMap::Edge::myRailDirection
WayType myRailDirection
Information about the direction(s) of railway usage.
Definition: NIImporter_OpenStreetMap.h:199
WRITE_MESSAGE
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:277
NBPTStop::addPlatformCand
void addPlatformCand(NBPTPlatform platform)
Definition: NBPTStop.cpp:137
SUMOXMLDefinitions.h
NIImporter_OpenStreetMap::getNeighboringNodes
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...
Definition: NIImporter_OpenStreetMap.cpp:1626
NBEdge::setGeometry
void setGeometry(const PositionVector &g, bool inner=false)
(Re)sets the edge's geometry
Definition: NBEdge.cpp:582
NBNode::reinit
void reinit(const Position &position, SumoXMLNodeType type, bool updateEdgeGeometries=false)
Resets initial values.
Definition: NBNode.cpp:303
NBEdge.h
GenericSAXHandler::setFileName
void setFileName(const std::string &name)
Sets the current file name.
Definition: GenericSAXHandler.cpp:68
XMLSubSys.h
NIImporter_OpenStreetMap::myEdges
std::map< long long int, Edge * > myEdges
the map from OSM way ids to edge objects
Definition: NIImporter_OpenStreetMap.h:254
NIImporter_OpenStreetMap::Edge::streetName
std::string streetName
The edge's street name.
Definition: NIImporter_OpenStreetMap.h:179
SUMO_TAG_NODE
@ SUMO_TAG_NODE
alternative definition for junction
Definition: SUMOXMLDefinitions.h:208