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-2022 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
22 // Importer for networks stored in OpenStreetMap format
23 /****************************************************************************/
24 #include <config.h>
25 #include <algorithm>
26 #include <set>
27 #include <functional>
28 #include <sstream>
29 #include <limits>
33 #include <utils/common/ToString.h>
37 #include <netbuild/NBEdge.h>
38 #include <netbuild/NBEdgeCont.h>
39 #include <netbuild/NBNode.h>
40 #include <netbuild/NBNodeCont.h>
41 #include <netbuild/NBNetBuilder.h>
42 #include <netbuild/NBOwnTLDef.h>
48 #include <utils/xml/XMLSubSys.h>
49 #include <netbuild/NBPTLine.h>
50 #include <netbuild/NBPTLineCont.h>
51 #include "NILoader.h"
53 
54 #define KM_PER_MILE 1.609344
55 
56 //#define DEBUG_LAYER_ELEVATION
57 
58 // ---------------------------------------------------------------------------
59 // static members
60 // ---------------------------------------------------------------------------
62 
63 const long long int NIImporter_OpenStreetMap::INVALID_ID = std::numeric_limits<long long int>::max();
64 
65 // ===========================================================================
66 // Private classes
67 // ===========================================================================
68 
72 public:
73  bool operator()(const Edge* e1, const Edge* e2) const {
74  if (e1->myHighWayType != e2->myHighWayType) {
75  return e1->myHighWayType > e2->myHighWayType;
76  }
77  if (e1->myNoLanes != e2->myNoLanes) {
78  return e1->myNoLanes > e2->myNoLanes;
79  }
80  if (e1->myNoLanesForward != e2->myNoLanesForward) {
81  return e1->myNoLanesForward > e2->myNoLanesForward;
82  }
83  if (e1->myMaxSpeed != e2->myMaxSpeed) {
84  return e1->myMaxSpeed > e2->myMaxSpeed;
85  }
86  if (e1->myIsOneWay != e2->myIsOneWay) {
87  return e1->myIsOneWay > e2->myIsOneWay;
88  }
89  return e1->myCurrentNodes > e2->myCurrentNodes;
90  }
91 };
92 
93 // ===========================================================================
94 // method definitions
95 // ===========================================================================
96 // ---------------------------------------------------------------------------
97 // static methods
98 // ---------------------------------------------------------------------------
99 const std::string NIImporter_OpenStreetMap::compoundTypeSeparator("|"); //clang-tidy says: "compundTypeSeparator with
100 // static storage duration my throw an exception that cannot be caught
101 
102 void
104  NIImporter_OpenStreetMap importer;
105  importer.load(oc, nb);
106 }
107 
109 
111  // delete nodes
112  for (auto myUniqueNode : myUniqueNodes) {
113  delete myUniqueNode;
114  }
115  // delete edges
116  for (auto& myEdge : myEdges) {
117  delete myEdge.second;
118  }
119  // delete platform shapes
120  for (auto& myPlatformShape : myPlatformShapes) {
121  delete myPlatformShape.second;
122  }
123 }
124 
125 void
127  // check whether the option is set (properly)
128  if (!oc.isSet("osm-files")) {
129  return;
130  }
131  /* Parse file(s)
132  * Each file is parsed twice: first for nodes, second for edges. */
133  std::vector<std::string> files = oc.getStringVector("osm-files");
134 
135  myImportLaneAccess = oc.getBool("osm.lane-access");
136  myImportTurnSigns = oc.getBool("osm.turn-lanes");
138 
139  // load nodes, first
140  NodesHandler nodesHandler(myOSMNodes, myUniqueNodes, oc);
141  for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
142  // nodes
143  if (!FileHelpers::isReadable(*file)) {
144  WRITE_ERROR("Could not open osm-file '" + *file + "'.");
145  return;
146  }
147  nodesHandler.setFileName(*file);
148  PROGRESS_BEGIN_MESSAGE("Parsing nodes from osm-file '" + *file + "'");
149  if (!XMLSubSys::runParser(nodesHandler, *file)) {
150  return;
151  }
152  if (nodesHandler.getDuplicateNodes() > 0) {
153  WRITE_MESSAGE("Found and substituted " + toString(nodesHandler.getDuplicateNodes()) + " osm nodes.");
154  }
156  }
157  // load edges, then
159  for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
160  // edges
161  edgesHandler.setFileName(*file);
162  PROGRESS_BEGIN_MESSAGE("Parsing edges from osm-file '" + *file + "'");
163  XMLSubSys::runParser(edgesHandler, *file);
165  }
166 
167  /* Remove duplicate edges with the same shape and attributes */
168  if (!oc.getBool("osm.skip-duplicates-check")) {
169  int numRemoved = 0;
170  PROGRESS_BEGIN_MESSAGE("Removing duplicate edges");
171  if (myEdges.size() > 1) {
172  std::set<const Edge*, CompareEdges> dupsFinder;
173  for (auto it = myEdges.begin(); it != myEdges.end();) {
174  if (dupsFinder.count(it->second) > 0) {
175  numRemoved++;
176  delete it->second;
177  myEdges.erase(it++);
178  } else {
179  dupsFinder.insert(it->second);
180  it++;
181  }
182  }
183  }
184  if (numRemoved > 0) {
185  WRITE_MESSAGE("Removed " + toString(numRemoved) + " duplicate osm edges.");
186  }
188  }
189 
190  /* Mark which nodes are used (by edges or traffic lights).
191  * This is necessary to detect which OpenStreetMap nodes are for
192  * geometry only */
193  std::map<long long int, int> nodeUsage;
194  // Mark which nodes are used by edges (begin and end)
195  for (std::map<long long int, Edge*>::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
196  Edge* e = (*i).second;
197  assert(e->myCurrentIsRoad);
198  for (std::vector<long long int>::const_iterator j = e->myCurrentNodes.begin();
199  j != e->myCurrentNodes.end();
200  ++j) {
201  if (nodeUsage.find(*j) == nodeUsage.end()) {
202  nodeUsage[*j] = 0;
203  }
204  nodeUsage[*j] = nodeUsage[*j] + 1;
205  }
206  }
207  // Mark which nodes are used by traffic lights
208  for (std::map<long long int, NIOSMNode*>::const_iterator nodesIt = myOSMNodes.begin();
209  nodesIt != myOSMNodes.end();
210  ++nodesIt) {
211  if (nodesIt->second->tlsControlled || nodesIt->second->railwaySignal /* || nodesIt->second->railwayCrossing*/) {
212  // If the key is not found in the map, the value is automatically
213  // initialized with 0.
214  nodeUsage[nodesIt->first] += 1;
215  }
216  }
217 
218  /* Instantiate edges
219  * Only those nodes in the middle of an edge which are used by more than
220  * one edge are instantiated. Other nodes are considered as geometry nodes. */
221  NBNodeCont& nc = nb.getNodeCont();
223  for (auto& myEdge : myEdges) {
224  Edge* e = myEdge.second;
225  assert(e->myCurrentIsRoad);
226  if (e->myCurrentNodes.size() < 2) {
227  WRITE_WARNINGF("Discarding way '%' because it has only % node(s)", e->id, e->myCurrentNodes.size());
228  continue;
229  }
231  // build nodes;
232  // - the from- and to-nodes must be built in any case
233  // - the in-between nodes are only built if more than one edge references them
234  NBNode* first = insertNodeChecking(*e->myCurrentNodes.begin(), nc, tlsc);
235  NBNode* last = insertNodeChecking(*(e->myCurrentNodes.end() - 1), nc, tlsc);
236  NBNode* currentFrom = first;
237  int running = 0;
238  std::vector<long long int> passed;
239  for (auto j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
240  passed.push_back(*j);
241  if (nodeUsage[*j] > 1 && j != e->myCurrentNodes.end() - 1 && j != e->myCurrentNodes.begin()) {
242  NBNode* currentTo = insertNodeChecking(*j, nc, tlsc);
243  running = insertEdge(e, running, currentFrom, currentTo, passed, nb, first, last);
244  currentFrom = currentTo;
245  passed.clear();
246  passed.push_back(*j);
247  }
248  }
249  if (running == 0) {
250  running = -1;
251  }
252  insertEdge(e, running, currentFrom, last, passed, nb, first, last);
253  }
254 
255  const double layerElevation = oc.getFloat("osm.layer-elevation");
256  if (layerElevation > 0) {
257  reconstructLayerElevation(layerElevation, nb);
258  }
259 
260  //revise pt stops; remove stops on deleted edges
261  if (OptionsCont::getOptions().isSet("ptstop-output")) {
263  }
264 
265  // load relations (after edges are built since we want to apply
266  // turn-restrictions directly to NBEdges)
268  &nb.getPTLineCont(), oc);
269  for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
270  // relations
271  relationHandler.setFileName(*file);
272  PROGRESS_BEGIN_MESSAGE("Parsing relations from osm-file '" + *file + "'");
273  XMLSubSys::runParser(relationHandler, *file);
275  }
276 }
277 
278 NBNode*
280  NBNode* node = nc.retrieve(toString(id));
281  if (node == nullptr) {
282  NIOSMNode* n = myOSMNodes.find(id)->second;
283  Position pos(n->lon, n->lat, n->ele);
284  if (!NBNetBuilder::transformCoordinate(pos, true)) {
285  WRITE_ERROR("Unable to project coordinates for junction '" + toString(id) + "'.");
286  return nullptr;
287  }
288  node = new NBNode(toString(id), pos);
289  if (!nc.insert(node)) {
290  WRITE_ERROR("Could not insert junction '" + toString(id) + "'.");
291  delete node;
292  return nullptr;
293  }
294  n->node = node;
295  if (n->railwayCrossing) {
297  } else if (n->railwaySignal) {
299  } else if (n->tlsControlled) {
300  // ok, this node is a traffic light node where no other nodes
301  // participate
302  // @note: The OSM-community has not settled on a schema for differentiating between fixed and actuated lights
304  OptionsCont::getOptions().getString("tls.default-type"));
305  NBOwnTLDef* tlDef = new NBOwnTLDef(toString(id), node, 0, type);
306  if (!tlsc.insert(tlDef)) {
307  // actually, nothing should fail here
308  delete tlDef;
309  throw ProcessError("Could not allocate tls '" + toString(id) + "'.");
310  }
311  }
312  if (n->railwayBufferStop) {
313  node->setParameter("buffer_stop", "true");
314  }
315  }
316  return node;
317 }
318 
319 int
321  const std::vector<long long int>& passed, NBNetBuilder& nb,
322  const NBNode* first, const NBNode* last) {
323  NBNodeCont& nc = nb.getNodeCont();
324  NBEdgeCont& ec = nb.getEdgeCont();
325  NBTypeCont& tc = nb.getTypeCont();
326  NBPTStopCont& sc = nb.getPTStopCont();
327 
329  // patch the id
330  std::string id = toString(e->id);
331  if (from == nullptr || to == nullptr) {
332  WRITE_ERROR("Discarding edge '" + id + "' because the nodes could not be built.");
333  return index;
334  }
335  if (index >= 0) {
336  id = id + "#" + toString(index);
337  } else {
338  index = 0;
339  }
340  if (from == to) {
341  assert(passed.size() >= 2);
342  if (passed.size() == 2) {
343  WRITE_WARNINGF("Discarding edge '%' which connects two identical nodes without geometry.", id);
344  return index;
345  }
346  // in the special case of a looped way split again using passed
347  int intermediateIndex = (int) passed.size() / 2;
348  NBNode* intermediate = insertNodeChecking(passed[intermediateIndex], nc, tlsc);
349  std::vector<long long int> part1(passed.begin(), passed.begin() + intermediateIndex + 1);
350  std::vector<long long int> part2(passed.begin() + intermediateIndex, passed.end());
351  index = insertEdge(e, index, from, intermediate, part1, nb, first, last);
352  return insertEdge(e, index, intermediate, to, part2, nb, first, last);
353  }
354  const int newIndex = index + 1;
355 
356  // convert the shape
357  PositionVector shape;
358  double distanceStart = myOSMNodes[passed.front()]->positionMeters;
359  double distanceEnd = myOSMNodes[passed.back()]->positionMeters;
360  const bool useDistance = distanceStart != std::numeric_limits<double>::max() && distanceEnd != std::numeric_limits<double>::max();
361  if (useDistance) {
362  // negative sign denotes counting in the other direction
363  if (distanceStart < distanceEnd) {
364  distanceStart *= -1;
365  } else {
366  distanceEnd *= -1;
367  }
368  } else {
369  distanceStart = 0;
370  distanceEnd = 0;
371  }
372  for (long long i : passed) {
373  NIOSMNode* n = myOSMNodes.find(i)->second;
374  if (n->ptStopPosition) {
375  NBPTStop* existingPtStop = sc.get(toString(n->id));
376  if (existingPtStop != nullptr) {
377  existingPtStop->registerAdditionalEdge(toString(e->id), id);
378  } else {
379  Position ptPos(n->lon, n->lat, n->ele);
380  if (!NBNetBuilder::transformCoordinate(ptPos)) {
381  WRITE_ERROR("Unable to project coordinates for node '" + toString(n->id) + "'.");
382  }
383  NBPTStop* ptStop = new NBPTStop(toString(n->id), ptPos, id, toString(e->id), n->ptStopLength, n->name,
384  n->permissions);
385 
386  sc.insert(ptStop);
387  }
388  }
389  Position pos(n->lon, n->lat, n->ele);
390  shape.push_back(pos);
391  }
393  WRITE_ERROR("Unable to project coordinates for edge '" + id + "'.");
394  }
395  std::string type = usableType(e->myHighWayType, id, tc);
396  if (type == "") {
397  return newIndex;
398  }
399 
400  // otherwise it is not an edge and will be ignored
401  bool ok = true;
402  int numLanesForward = tc.getEdgeTypeNumLanes(type);
403  int numLanesBackward = tc.getEdgeTypeNumLanes(type);
404  double speed = tc.getEdgeTypeSpeed(type);
405  bool defaultsToOneWay = tc.getEdgeTypeIsOneWay(type);
406  SVCPermissions defaultPermissions = tc.getEdgeTypePermissions(type);
407  SVCPermissions permissions = defaultPermissions | e->myExtraAllowed;
408  permissions &= ~e->myExtraDisallowed;
409  if (defaultsToOneWay && defaultPermissions == SVC_PEDESTRIAN && (permissions & (~SVC_PEDESTRIAN)) != 0) {
410  defaultsToOneWay = false;
411  }
412  if (e->myCurrentIsElectrified && (permissions & SVC_RAIL) != 0) {
413  permissions |= (SVC_RAIL_ELECTRIC | SVC_RAIL_FAST);
414  }
415  SVCPermissions forwardPermissions = permissions;
416  SVCPermissions backwardPermissions = permissions;
417  const std::string streetName = isRailway(permissions) && e->ref != "" ? e->ref : e->streetName;
418  if (streetName == e->ref) {
419  e->unsetParameter("ref"); // avoid superfluous param for railways
420  }
421  double forwardWidth = tc.getEdgeTypeWidth(type);
422  double backwardWidth = tc.getEdgeTypeWidth(type);
423  double sidewalkWidth = tc.getEdgeTypeSidewalkWidth(type);
424  bool addSidewalk = sidewalkWidth != NBEdge::UNSPECIFIED_WIDTH;
425  const bool addBikeLane = (tc.getEdgeTypeBikeLaneWidth(type) != NBEdge::UNSPECIFIED_WIDTH);
426  if (myImportSidewalks) {
427  if (addSidewalk) {
428  // only use sidewalk width from typemap but don't add sidewalks
429  // unless OSM specifies them
430  addSidewalk = false;
431  } else {
432  sidewalkWidth = OptionsCont::getOptions().getFloat("default.sidewalk-width");
433  }
434  }
435  // check directions
436  bool addForward = true;
437  bool addBackward = true;
438  if ((e->myIsOneWay == "true" || e->myIsOneWay == "yes" || e->myIsOneWay == "1"
439  || (defaultsToOneWay && e->myIsOneWay != "no" && e->myIsOneWay != "false" && e->myIsOneWay != "0"))
440  && e->myRailDirection != WAY_BOTH) {
441  addBackward = false;
442  }
443  if (e->myIsOneWay == "-1" || e->myIsOneWay == "reverse" || e->myRailDirection == WAY_BACKWARD) {
444  // one-way in reversed direction of way
445  addForward = false;
446  addBackward = true;
447  }
448  if (!e->myIsOneWay.empty() && e->myIsOneWay != "false" && e->myIsOneWay != "no" && e->myIsOneWay != "true"
449  && e->myIsOneWay != "yes" && e->myIsOneWay != "-1" && e->myIsOneWay != "1" && e->myIsOneWay != "reverse") {
450  WRITE_WARNINGF("New value for oneway found: %", e->myIsOneWay);
451  }
452  if (isBikepath(permissions) && e->myCyclewayType != WAY_UNKNOWN) {
453  if ((e->myCyclewayType & WAY_BACKWARD) == 0) {
454  addBackward = false;
455  }
456  if ((e->myCyclewayType & WAY_FORWARD) == 0) {
457  addForward = false;
458  }
459  }
460  // if we had been able to extract the number of lanes, override the highway type default
461  if (e->myNoLanes > 0) {
462  if (addForward && !addBackward) {
463  numLanesForward = e->myNoLanes;
464  } else if (!addForward && addBackward) {
465  numLanesBackward = e->myNoLanes;
466  } else {
467  if (e->myNoLanesForward > 0) {
468  numLanesForward = e->myNoLanesForward;
469  } else if (e->myNoLanesForward < 0) {
470  numLanesForward = e->myNoLanes + e->myNoLanesForward;
471  } else {
472  numLanesForward = (int) std::ceil(e->myNoLanes / 2.0);
473  }
474  numLanesBackward = e->myNoLanes - numLanesForward;
475  // sometimes ways are tagged according to their physical width of a single
476  // lane but they are intended for traffic in both directions
477  numLanesForward = MAX2(1, numLanesForward);
478  numLanesBackward = MAX2(1, numLanesBackward);
479  }
480  } else if (e->myNoLanes == 0) {
481  WRITE_WARNINGF("Skipping edge '%' because it has zero lanes.", id);
482  ok = false;
483  } else {
484  // the total number of lanes is not known but at least one direction
485  if (e->myNoLanesForward > 0) {
486  numLanesForward = e->myNoLanesForward;
487  }
488  if (e->myNoLanesForward < 0) {
489  numLanesBackward = -e->myNoLanesForward;
490  }
491  }
492  // if we had been able to extract the maximum speed, override the type's default
493  if (e->myMaxSpeed != MAXSPEED_UNGIVEN) {
494  speed = e->myMaxSpeed / 3.6;
495  }
496  double speedBackward = speed;
498  speedBackward = e->myMaxSpeedBackward / 3.6;
499  }
500  if (speed <= 0 || speedBackward <= 0) {
501  WRITE_WARNINGF("Skipping edge '%' because it has speed %.", id, speed);
502  ok = false;
503  }
504  // deal with cycleways that run in the opposite direction of a one-way street
505  WayType cyclewayType = e->myCyclewayType; // make a copy because we do some temporary modifications
506  if (addBikeLane) {
507  if (!addForward && (cyclewayType & WAY_FORWARD) != 0) {
508  addForward = true;
509  forwardPermissions = SVC_BICYCLE;
510  forwardWidth = tc.getEdgeTypeBikeLaneWidth(type);
511  numLanesForward = 1;
512  // do not add an additional cycle lane
513  cyclewayType = (WayType)(cyclewayType & ~WAY_FORWARD); //clang tidy thinks "!WAY_FORWARD" is always false
514  }
515  if (!addBackward && (cyclewayType & WAY_BACKWARD) != 0) {
516  addBackward = true;
517  backwardPermissions = SVC_BICYCLE;
518  backwardWidth = tc.getEdgeTypeBikeLaneWidth(type);
519  numLanesBackward = 1;
520  // do not add an additional cycle lane
521  cyclewayType = (WayType)(cyclewayType & ~WAY_BACKWARD); //clang tidy thinks "!WAY_BACKWARD" is always false
522  }
523  }
524  // deal with sidewalks that run in the opposite direction of a one-way street
525  WayType sidewalkType = e->mySidewalkType; // make a copy because we do some temporary modifications
526  if (sidewalkType == WAY_UNKNOWN && (e->myExtraAllowed & SVC_PEDESTRIAN) != 0 && (permissions & SVC_PASSENGER) != 0) {
527  // do not assume shared space unless sidewalk is actively disabled
528  sidewalkType = WAY_BOTH;
529  }
530  if (addSidewalk || (myImportSidewalks && (permissions & SVC_ROAD_CLASSES) != 0 && defaultPermissions != SVC_PEDESTRIAN)) {
531  if (!addForward && (sidewalkType & WAY_FORWARD) != 0) {
532  addForward = true;
533  forwardPermissions = SVC_PEDESTRIAN;
534  forwardWidth = tc.getEdgeTypeSidewalkWidth(type);
535  numLanesForward = 1;
536  // do not add an additional sidewalk
537  sidewalkType = (WayType)(sidewalkType & ~WAY_FORWARD); //clang tidy thinks "!WAY_FORWARD" is always false
538  } else if (addSidewalk && addForward && (sidewalkType & WAY_BOTH) == 0
539  && numLanesForward == 1 && numLanesBackward <= 1
540  && (e->myExtraDisallowed & SVC_PEDESTRIAN) == 0) {
541  // our typemap says pedestrians should walk here but the data says
542  // there is no sidewalk at all. If the road is small, pedestrians can just walk
543  // on the road
544  forwardPermissions |= SVC_PEDESTRIAN;
545  }
546  if (!addBackward && (sidewalkType & WAY_BACKWARD) != 0) {
547  addBackward = true;
548  backwardPermissions = SVC_PEDESTRIAN;
549  backwardWidth = tc.getEdgeTypeSidewalkWidth(type);
550  numLanesBackward = 1;
551  // do not add an additional cycle lane
552  sidewalkType = (WayType)(sidewalkType & ~WAY_BACKWARD); //clang tidy thinks "!WAY_BACKWARD" is always false
553  } else if (addSidewalk && addBackward && (sidewalkType & WAY_BOTH) == 0
554  && numLanesBackward == 1 && numLanesForward <= 1
555  && (e->myExtraDisallowed & SVC_PEDESTRIAN) == 0) {
556  // our typemap says pedestrians should walk here but the data says
557  // there is no sidewalk at all. If the road is small, pedestrians can just walk
558  // on the road
559  backwardPermissions |= SVC_PEDESTRIAN;
560  }
561  }
562  // deal with busways that run in the opposite direction of a one-way street
563  if (!addForward && (e->myBuswayType & WAY_FORWARD) != 0) {
564  addForward = true;
565  forwardPermissions = SVC_BUS;
566  numLanesForward = 1;
567  }
568  if (!addBackward && (e->myBuswayType & WAY_BACKWARD) != 0) {
569  addBackward = true;
570  backwardPermissions = SVC_BUS;
571  numLanesBackward = 1;
572  }
573 
574  const std::string origID = OptionsCont::getOptions().getBool("output.original-names") ? toString(e->id) : "";
575  if (ok) {
576  const int offsetFactor = OptionsCont::getOptions().getBool("lefthand") ? -1 : 1;
577  LaneSpreadFunction lsf = (addBackward || OptionsCont::getOptions().getBool("osm.oneway-spread-right")) &&
579  if (addBackward && lsf == LaneSpreadFunction::RIGHT && OptionsCont::getOptions().getString("default.spreadtype") == toString(LaneSpreadFunction::ROADCENTER)) {
581  }
582 
583  id = StringUtils::escapeXML(id);
584  const std::string reverseID = "-" + id;
585 
586  if (addForward) {
587  assert(numLanesForward > 0);
588  NBEdge* nbe = new NBEdge(id, from, to, type, speed, numLanesForward, tc.getEdgeTypePriority(type),
589  forwardWidth, NBEdge::UNSPECIFIED_OFFSET, shape, lsf,
590  StringUtils::escapeXML(streetName), origID, true);
591  nbe->setPermissions(forwardPermissions);
592  if ((e->myBuswayType & WAY_FORWARD) != 0) {
593  nbe->setPermissions(SVC_BUS, 0);
594  }
598  nbe->setTurnSignTarget(last->getID());
599  if (addBikeLane && (cyclewayType == WAY_UNKNOWN || (cyclewayType & WAY_FORWARD) != 0)) {
600  nbe->addBikeLane(tc.getEdgeTypeBikeLaneWidth(type) * offsetFactor);
601  } else if (nbe->getPermissions(0) == SVC_BUS) {
602  // bikes drive on buslanes if no separate cycle lane is available
604  }
605  if ((addSidewalk && (sidewalkType == WAY_UNKNOWN || (sidewalkType & WAY_FORWARD) != 0))
606  || (myImportSidewalks && (sidewalkType & WAY_FORWARD) != 0 && defaultPermissions != SVC_PEDESTRIAN)) {
607  nbe->addSidewalk(sidewalkWidth * offsetFactor);
608  }
610  nbe->setDistance(distanceStart);
611  if (!ec.insert(nbe)) {
612  delete nbe;
613  throw ProcessError("Could not add edge '" + id + "'.");
614  }
615  }
616  if (addBackward) {
617  assert(numLanesBackward > 0);
618  NBEdge* nbe = new NBEdge(reverseID, to, from, type, speedBackward, numLanesBackward, tc.getEdgeTypePriority(type),
619  backwardWidth, NBEdge::UNSPECIFIED_OFFSET, shape.reverse(), lsf,
620  StringUtils::escapeXML(streetName), origID, true);
621  nbe->setPermissions(backwardPermissions);
622  if ((e->myBuswayType & WAY_BACKWARD) != 0) {
623  nbe->setPermissions(SVC_BUS, 0);
624  }
628  nbe->setTurnSignTarget(first->getID());
629  if (addBikeLane && (cyclewayType == WAY_UNKNOWN || (cyclewayType & WAY_BACKWARD) != 0)) {
630  nbe->addBikeLane(tc.getEdgeTypeBikeLaneWidth(type) * offsetFactor);
631  } else if (nbe->getPermissions(0) == SVC_BUS) {
632  // bikes drive on buslanes if no separate cycle lane is available
634  }
635  if ((addSidewalk && (sidewalkType == WAY_UNKNOWN || (sidewalkType & WAY_BACKWARD) != 0))
636  || (myImportSidewalks && (sidewalkType & WAY_BACKWARD) != 0 && defaultPermissions != SVC_PEDESTRIAN)) {
637  nbe->addSidewalk(sidewalkWidth * offsetFactor);
638  }
640  nbe->setDistance(distanceEnd);
641  if (!ec.insert(nbe)) {
642  delete nbe;
643  throw ProcessError("Could not add edge '-" + id + "'.");
644  }
645  }
646  if ((e->myParkingType & PARKING_BOTH) != 0 && OptionsCont::getOptions().isSet("parking-output")) {
647  if ((e->myParkingType & PARKING_RIGHT) != 0) {
648  if (addForward) {
649  nb.getParkingCont().push_back(NBParking(id, id));
650  } else {
652  if ((e->myParkingType & PARKING_LEFT) == 0 && !addBackward) {
654  nb.getParkingCont().push_back(NBParking(reverseID, reverseID));
655  }
656  }
657  }
658  if ((e->myParkingType & PARKING_LEFT) != 0) {
659  if (addBackward) {
660  nb.getParkingCont().push_back(NBParking(reverseID, reverseID));
661  } else {
663  if ((e->myParkingType & PARKING_RIGHT) == 0 && !addForward) {
665  nb.getParkingCont().push_back(NBParking(id, id));
666  }
667  }
668  }
669  }
670  }
671  return newIndex;
672 }
673 
674 // ---------------------------------------------------------------------------
675 // definitions of NIImporter_OpenStreetMap::NodesHandler-methods
676 // ---------------------------------------------------------------------------
677 NIImporter_OpenStreetMap::NodesHandler::NodesHandler(std::map<long long int, NIOSMNode*>& toFill,
678  std::set<NIOSMNode*, CompareNodes>& uniqueNodes,
679  const OptionsCont& oc)
680 
681  :
682  SUMOSAXHandler("osm - file"),
683  myToFill(toFill),
684  myLastNodeID(-1),
685  myIsInValidNodeTag(false),
686  myHierarchyLevel(0),
687  myUniqueNodes(uniqueNodes),
688  myImportElevation(oc.getBool("osm.elevation")),
689  myDuplicateNodes(0),
690  myOptionsCont(oc) {
691 }
692 
694 
695 void
697  ++myHierarchyLevel;
698  if (element == SUMO_TAG_NODE) {
699  bool ok = true;
700  if (myHierarchyLevel != 2) {
701  WRITE_ERROR("Node element on wrong XML hierarchy level (id='" + toString(attrs.get<long
702  long
703  int>(SUMO_ATTR_ID,
704  nullptr, ok))
705  + "', level='" + toString(myHierarchyLevel) + "').");
706  return;
707  }
708  const long long int id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
709  const std::string action = attrs.hasAttribute("action") ? attrs.getStringSecure("action", "") : "";
710  if (action == "delete" || !ok) {
711  return;
712  }
713  myLastNodeID = -1;
714  if (myToFill.find(id) == myToFill.end()) {
715  myLastNodeID = id;
716  // assume we are loading multiple files...
717  // ... so we won't report duplicate nodes
718  bool ok2 = true;
719  double tlat, tlon;
720  std::istringstream lon(attrs.get<std::string>(SUMO_ATTR_LON, toString(id).c_str(), ok2));
721  if (!ok2) {
722  return;
723  }
724  lon >> tlon;
725  if (lon.fail()) {
726  WRITE_ERROR("Node's '" + toString(id) + "' lon information is not numeric.");
727  return;
728  }
729  std::istringstream lat(attrs.get<std::string>(SUMO_ATTR_LAT, toString(id).c_str(), ok2));
730  if (!ok2) {
731  return;
732  }
733  lat >> tlat;
734  if (lat.fail()) {
735  WRITE_ERROR("Node's '" + toString(id) + "' lat information is not numeric.");
736  return;
737  }
738  auto* toAdd = new NIOSMNode(id, tlon, tlat);
739  myIsInValidNodeTag = true;
740 
741  auto similarNode = myUniqueNodes.find(toAdd);
742  if (similarNode == myUniqueNodes.end()) {
743  myUniqueNodes.insert(toAdd);
744  } else {
745  delete toAdd;
746  toAdd = *similarNode;
747  myDuplicateNodes++;
748  }
749  myToFill[id] = toAdd;
750  }
751  }
752  if (element == SUMO_TAG_TAG && myIsInValidNodeTag) {
753  if (myHierarchyLevel != 3) {
754  WRITE_ERROR("Tag element on wrong XML hierarchy level.");
755  return;
756  }
757  bool ok = true;
758  std::string key = attrs.get<std::string>(SUMO_ATTR_K, toString(myLastNodeID).c_str(), ok, false);
759  // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
760  if (key == "highway" || key == "ele" || key == "crossing" || key == "railway" || key == "public_transport"
761  || key == "name" || key == "train" || key == "bus" || key == "tram" || key == "light_rail" || key == "subway" || key == "station" || key == "noexit"
762  || StringUtils::startsWith(key, "railway:signal")
763  || StringUtils::startsWith(key, "railway:position")
764  ) {
765  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myLastNodeID).c_str(), ok, false);
766  if (key == "highway" && value.find("traffic_signal") != std::string::npos) {
767  myToFill[myLastNodeID]->tlsControlled = true;
768  } else if (key == "crossing" && value.find("traffic_signals") != std::string::npos) {
769  myToFill[myLastNodeID]->tlsControlled = true;
770  } else if ((key == "noexit" && value == "yes")
771  || (key == "railway" && value == "buffer_stop")) {
772  myToFill[myLastNodeID]->railwayBufferStop = true;
773  } else if (key == "railway" && value.find("crossing") != std::string::npos) {
774  myToFill[myLastNodeID]->railwayCrossing = true;
775  } else if (StringUtils::startsWith(key, "railway:signal") && (
776  value == "block" || value == "entry" || value == "exit" || value == "intermediate")) {
777  myToFill[myLastNodeID]->railwaySignal = true;
778  } else if (StringUtils::startsWith(key, "railway:position") && value.size() > myToFill[myLastNodeID]->position.size()) {
779  // use the entry with the highest precision (more digits)
780  myToFill[myLastNodeID]->position = value;
781  } else if ((key == "public_transport" && value == "stop_position") ||
782  (key == "highway" && value == "bus_stop")) {
783  myToFill[myLastNodeID]->ptStopPosition = true;
784  if (myToFill[myLastNodeID]->ptStopLength == 0) {
785  // default length
786  myToFill[myLastNodeID]->ptStopLength = myOptionsCont.getFloat("osm.stop-output.length");
787  }
788  } else if (key == "name") {
789  myToFill[myLastNodeID]->name = value;
790  } else if (myImportElevation && key == "ele") {
791  try {
792  const double elevation = StringUtils::toDouble(value);
793  if (ISNAN(elevation)) {
794  WRITE_WARNINGF("Value of key '%' is invalid ('%') in node '%'.", key, value, toString(myLastNodeID));
795  } else {
796  myToFill[myLastNodeID]->ele = elevation;
797  }
798  } catch (...) {
799  WRITE_WARNINGF("Value of key '%' is not numeric ('%') in node '%'.", key, value, toString(myLastNodeID));
800  }
801  } else if (key == "station") {
802  interpretTransportType(value, myToFill[myLastNodeID]);
803  } else {
804  // v="yes"
805  interpretTransportType(key, myToFill[myLastNodeID]);
806  }
807  }
808  }
809 }
810 
811 void
813  if (element == SUMO_TAG_NODE && myHierarchyLevel == 2) {
814  myLastNodeID = -1;
815  myIsInValidNodeTag = false;
816  }
817  --myHierarchyLevel;
818 }
819 
820 // ---------------------------------------------------------------------------
821 // definitions of NIImporter_OpenStreetMap::EdgesHandler-methods
822 // ---------------------------------------------------------------------------
824  const std::map<long long int, NIOSMNode*>& osmNodes,
825  std::map<long long int, Edge*>& toFill, std::map<long long int, Edge*>& platformShapes):
826  SUMOSAXHandler("osm - file"),
827  myOSMNodes(osmNodes),
828  myEdgeMap(toFill),
829  myPlatformShapesMap(platformShapes) {
830  mySpeedMap["nan"] = MAXSPEED_UNGIVEN;
831  mySpeedMap["sign"] = MAXSPEED_UNGIVEN;
832  mySpeedMap["signals"] = MAXSPEED_UNGIVEN;
833  mySpeedMap["none"] = 142.; // Auswirkungen eines allgemeinen Tempolimits auf Autobahnen im Land Brandeburg (2007)
834  mySpeedMap["no"] = 142.;
835  mySpeedMap["walk"] = 5.;
836  // https://wiki.openstreetmap.org/wiki/Key:source:maxspeed#Commonly_used_values
837  mySpeedMap["AT:urban"] = 50;
838  mySpeedMap["AT:rural"] = 100;
839  mySpeedMap["AT:trunk"] = 100;
840  mySpeedMap["AT:motorway"] = 130;
841  mySpeedMap["AU:urban"] = 50;
842  mySpeedMap["BE:urban"] = 50;
843  mySpeedMap["BE:zone"] = 30;
844  mySpeedMap["BE:motorway"] = 120;
845  mySpeedMap["BE:zone30"] = 30;
846  mySpeedMap["BE-VLG:rural"] = 70;
847  mySpeedMap["BE-WAL:rural"] = 90;
848  mySpeedMap["BE:school"] = 30;
849  mySpeedMap["CZ:motorway"] = 130;
850  mySpeedMap["CZ:trunk"] = 110;
851  mySpeedMap["CZ:rural"] = 90;
852  mySpeedMap["CZ:urban_motorway"] = 80;
853  mySpeedMap["CZ:urban_trunk"] = 80;
854  mySpeedMap["CZ:urban"] = 50;
855  mySpeedMap["DE:motorway"] = mySpeedMap["none"];
856  mySpeedMap["DE:rural"] = 100;
857  mySpeedMap["DE:urban"] = 50;
858  mySpeedMap["DE:bicycle_road"] = 30;
859  mySpeedMap["DK:motorway"] = 130;
860  mySpeedMap["DK:rural"] = 80;
861  mySpeedMap["DK:urban"] = 50;
862  mySpeedMap["EE:urban"] = 50;
863  mySpeedMap["EE:rural"] = 90;
864  mySpeedMap["ES:urban"] = 50;
865  mySpeedMap["ES:zone30"] = 30;
866  mySpeedMap["FR:motorway"] = 130; // 110 (raining)
867  mySpeedMap["FR:rural"] = 80;
868  mySpeedMap["FR:urban"] = 50;
869  mySpeedMap["FR:zone30"] = 30;
870  mySpeedMap["HU:living_street"] = 20;
871  mySpeedMap["HU:motorway"] = 130;
872  mySpeedMap["HU:rural"] = 90;
873  mySpeedMap["HU:trunk"] = 110;
874  mySpeedMap["HU:urban"] = 50;
875  mySpeedMap["IT:rural"] = 90;
876  mySpeedMap["IT:motorway"] = 130;
877  mySpeedMap["IT:urban"] = 50;
878  mySpeedMap["JP:nsl"] = 60;
879  mySpeedMap["JP:express"] = 100;
880  mySpeedMap["LT:rural"] = 90;
881  mySpeedMap["LT:urban"] = 50;
882  mySpeedMap["NO:rural"] = 80;
883  mySpeedMap["NO:urban"] = 50;
884  mySpeedMap["ON:urban"] = 50;
885  mySpeedMap["ON:rural"] = 80;
886  mySpeedMap["PT:motorway"] = 120;
887  mySpeedMap["PT:rural"] = 90;
888  mySpeedMap["PT:trunk"] = 100;
889  mySpeedMap["PT:urban"] = 50;
890  mySpeedMap["RO:motorway"] = 130;
891  mySpeedMap["RO:rural"] = 90;
892  mySpeedMap["RO:trunk"] = 100;
893  mySpeedMap["RO:urban"] = 50;
894  mySpeedMap["RS:living_street"] = 30;
895  mySpeedMap["RS:motorway"] = 130;
896  mySpeedMap["RS:rural"] = 80;
897  mySpeedMap["RS:trunk"] = 100;
898  mySpeedMap["RS:urban"] = 50;
899  mySpeedMap["RU:living_street"] = 20;
900  mySpeedMap["RU:urban"] = 60;
901  mySpeedMap["RU:rural"] = 90;
902  mySpeedMap["RU:motorway"] = 110;
903  mySpeedMap["GB:motorway"] = 70 * KM_PER_MILE;
904  mySpeedMap["GB:nsl_dual"] = 70 * KM_PER_MILE;
905  mySpeedMap["GB:nsl_single"] = 60 * KM_PER_MILE;
906  mySpeedMap["UK:motorway"] = 70 * KM_PER_MILE;
907  mySpeedMap["UK:nsl_dual"] = 70 * KM_PER_MILE;
908  mySpeedMap["UK:nsl_single"] = 60 * KM_PER_MILE;
909  mySpeedMap["UZ:living_street"] = 30;
910  mySpeedMap["UZ:urban"] = 70;
911  mySpeedMap["UZ:rural"] = 100;
912  mySpeedMap["UZ:motorway"] = 110;
913  myAllAttributes = OptionsCont::getOptions().getBool("osm.all-attributes");
914  std::vector<std::string> extra = OptionsCont::getOptions().getStringVector("osm.extra-attributes");
915  myExtraAttributes.insert(extra.begin(), extra.end());
916  if (myExtraAttributes.count("all") != 0) {
917  // import all
918  myExtraAttributes.clear();
919  }
920  myImportBikeAccess = OptionsCont::getOptions().getBool("osm.bike-access");
921 }
922 
924 
925 void
927  const SUMOSAXAttributes& attrs) {
928  myParentElements.push_back(element);
929  // parse "way" elements
930  if (element == SUMO_TAG_WAY) {
931  bool ok = true;
932  const long long int id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
933  std::string action = attrs.hasAttribute("action") ? attrs.getStringSecure("action", "") : "";
934  if (action == "delete" || !ok) {
935  myCurrentEdge = nullptr;
936  return;
937  }
938  myCurrentEdge = new Edge(id);
939  }
940  // parse "nd" (node) elements
941  if (element == SUMO_TAG_ND && myCurrentEdge != nullptr) {
942  bool ok = true;
943  long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, nullptr, ok);
944  if (ok) {
945  auto node = myOSMNodes.find(ref);
946  if (node == myOSMNodes.end()) {
947  WRITE_WARNINGF("The referenced geometry information (ref='%') is not known", toString(ref));
948  return;
949  }
950 
951  ref = node->second->id; // node may have been substituted
952  if (myCurrentEdge->myCurrentNodes.empty() ||
953  myCurrentEdge->myCurrentNodes.back() != ref) { // avoid consecutive duplicates
954  myCurrentEdge->myCurrentNodes.push_back(ref);
955  }
956 
957  }
958  }
959  // parse values
960  if (element == SUMO_TAG_TAG && myParentElements.size() > 2
961  && myParentElements[myParentElements.size() - 2] == SUMO_TAG_WAY) {
962  if (myCurrentEdge == nullptr) {
963  return;
964  }
965  bool ok = true;
966  std::string key = attrs.get<std::string>(SUMO_ATTR_K, toString(myCurrentEdge->id).c_str(), ok, false);
967  if (key.size() > 8 && StringUtils::startsWith(key, "cycleway:")) {
968  // handle special cycleway keys
969  const std::string cyclewaySpec = key.substr(9);
970  key = "cycleway";
971  if (cyclewaySpec == "right") {
972  myCurrentEdge->myCyclewayType = (WayType)(myCurrentEdge->myCyclewayType | WAY_FORWARD);
973  } else if (cyclewaySpec == "left") {
974  myCurrentEdge->myCyclewayType = (WayType)(myCurrentEdge->myCyclewayType | WAY_BACKWARD);
975  } else if (cyclewaySpec == "both") {
976  myCurrentEdge->myCyclewayType = (WayType)(myCurrentEdge->myCyclewayType | WAY_BOTH);
977  } else {
978  key = "ignore";
979  }
980  if ((myCurrentEdge->myCyclewayType & WAY_BOTH) != 0) {
981  // now we have some info on directionality
982  myCurrentEdge->myCyclewayType = (WayType)(myCurrentEdge->myCyclewayType & ~WAY_UNKNOWN);
983  }
984  } else if (key.size() > 6 && StringUtils::startsWith(key, "busway:")) {
985  // handle special busway keys
986  const std::string buswaySpec = key.substr(7);
987  key = "busway";
988  if (buswaySpec == "right") {
989  myCurrentEdge->myBuswayType = (WayType)(myCurrentEdge->myBuswayType | WAY_FORWARD);
990  } else if (buswaySpec == "left") {
991  myCurrentEdge->myBuswayType = (WayType)(myCurrentEdge->myBuswayType | WAY_BACKWARD);
992  } else if (buswaySpec == "both") {
993  myCurrentEdge->myBuswayType = (WayType)(myCurrentEdge->myBuswayType | WAY_BOTH);
994  } else {
995  key = "ignore";
996  }
997  }
998  if (myAllAttributes && (myExtraAttributes.count(key) != 0 || myExtraAttributes.size() == 0)) {
999  const std::string info = "way=" + toString(myCurrentEdge->id) + ", k=" + key;
1000  myCurrentEdge->setParameter(key, attrs.get<std::string>(SUMO_ATTR_V, info.c_str(), ok, false));
1001  }
1002  // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
1003  if (!StringUtils::endsWith(key, "way") && !StringUtils::startsWith(key, "lanes")
1004  && key != "maxspeed" && key != "maxspeed:type"
1005  && key != "maxspeed:forward" && key != "maxspeed:backward"
1006  && key != "junction" && key != "name" && key != "tracks" && key != "layer"
1007  && key != "route"
1008  && key != "sidewalk"
1009  && key != "ref"
1010  && key != "highspeed"
1011  && !StringUtils::startsWith(key, "parking")
1012  && !StringUtils::startsWith(key, "change")
1013  && !StringUtils::startsWith(key, "vehicle:lanes")
1014  && key != "postal_code"
1015  && key != "railway:preferred_direction"
1016  && key != "railway:bidirectional"
1017  && key != "railway:track_ref"
1018  && key != "usage"
1019  && key != "electrified"
1020  && key != "bus"
1021  && key != "psv"
1022  && key != "foot"
1023  && key != "bicycle"
1024  && key != "oneway:bicycle"
1025  && !StringUtils::startsWith(key, "turn:lanes")
1026  && key != "public_transport") {
1027  return;
1028  }
1029  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentEdge->id).c_str(), ok, false);
1030 
1031  if ((key == "highway" && value != "platform") || key == "railway" || key == "waterway" || key == "cycleway"
1032  || key == "busway" || key == "route" || key == "sidewalk" || key == "highspeed"
1033  || key == "aeroway" || key == "usage") {
1034  // build type id
1035  std::string singleTypeID = key + "." + value;
1036  myCurrentEdge->myCurrentIsRoad = true;
1037  // special cycleway stuff
1038  if (key == "cycleway") {
1039  if (value == "no") {
1040  return;
1041  }
1042  if (value == "opposite_track") {
1043  myCurrentEdge->myCyclewayType = WAY_BACKWARD;
1044  } else if (value == "opposite_lane") {
1045  myCurrentEdge->myCyclewayType = WAY_BACKWARD;
1046  }
1047  }
1048  // special sidewalk stuff
1049  if (key == "sidewalk") {
1050  if (value == "no" || value == "none") {
1051  myCurrentEdge->mySidewalkType = WAY_NONE;
1052  } else if (value == "both") {
1053  myCurrentEdge->mySidewalkType = WAY_BOTH;
1054  } else if (value == "right") {
1055  myCurrentEdge->mySidewalkType = WAY_FORWARD;
1056  } else if (value == "left") {
1057  myCurrentEdge->mySidewalkType = WAY_BACKWARD;
1058  }
1059  // no need to extend the type id
1060  return;
1061  }
1062  // special busway stuff
1063  if (key == "busway") {
1064  if (value == "no") {
1065  return;
1066  }
1067  if (value == "opposite_track") {
1068  myCurrentEdge->myBuswayType = WAY_BACKWARD;
1069  } else if (value == "opposite_lane") {
1070  myCurrentEdge->myBuswayType = WAY_BACKWARD;
1071  }
1072  // no need to extend the type id
1073  return;
1074  }
1075  if (key == "highspeed") {
1076  if (value == "no") {
1077  return;
1078  }
1079  singleTypeID = "railway.highspeed";
1080  }
1081  // special case: never build compound type for highspeed rail
1082  if (!myCurrentEdge->myHighWayType.empty() && singleTypeID != "railway.highspeed") {
1083  if (myCurrentEdge->myHighWayType == "railway.highspeed") {
1084  return;
1085  }
1086  // osm-ways may be used by more than one mode (eg railway.tram + highway.residential. this is relevant for multimodal traffic)
1087  // we create a new type for this kind of situation which must then be resolved in insertEdge()
1088  std::vector<std::string> types = StringTokenizer(myCurrentEdge->myHighWayType,
1090  types.push_back(singleTypeID);
1091  myCurrentEdge->myHighWayType = joinToStringSorting(types, compoundTypeSeparator);
1092  } else {
1093  myCurrentEdge->myHighWayType = singleTypeID;
1094  }
1095  } else if (key == "bus" || key == "psv") {
1096  // 'psv' includes taxi in the UK but not in germany
1097  try {
1098  if (StringUtils::toBool(value)) {
1099  myCurrentEdge->myExtraAllowed |= SVC_BUS;
1100  } else {
1101  myCurrentEdge->myExtraDisallowed |= SVC_BUS;
1102  }
1103  } catch (const BoolFormatException&) {
1104  myCurrentEdge->myExtraAllowed |= SVC_BUS;
1105  }
1106  } else if (key == "foot") {
1107  if (value == "use_sidepath" || value == "no") {
1108  myCurrentEdge->myExtraDisallowed |= SVC_PEDESTRIAN;
1109  } else if (value == "yes" || value == "designated" || value == "permissive") {
1110  myCurrentEdge->myExtraAllowed |= SVC_PEDESTRIAN;
1111  }
1112  } else if (key == "bicycle") {
1113  if (myImportBikeAccess) {
1114  if (value == "use_sidepath" || value == "no") {
1115  myCurrentEdge->myExtraDisallowed |= SVC_BICYCLE;
1116  } else if (value == "yes" || value == "designated" || value == "permissive") {
1117  myCurrentEdge->myExtraAllowed |= SVC_BICYCLE;
1118  }
1119  }
1120  } else if (key == "oneway:bicycle") {
1121  if (myImportBikeAccess) {
1122  if (value == "true" || value == "yes" || value == "1") {
1123  myCurrentEdge->myCyclewayType = WAY_FORWARD;
1124  }
1125  if (value == "-1" || value == "reverse") {
1126  // one-way in reversed direction of way
1127  myCurrentEdge->myCyclewayType = WAY_BACKWARD;
1128  }
1129  if (value == "no" || value == "false" || value == "0") {
1130  myCurrentEdge->myCyclewayType = WAY_BOTH;
1131  }
1132  }
1133  } else if (key == "lanes") {
1134  try {
1135  myCurrentEdge->myNoLanes = StringUtils::toInt(value);
1136  } catch (NumberFormatException&) {
1137  // might be a list of values
1138  StringTokenizer st(value, ";", true);
1139  std::vector<std::string> list = st.getVector();
1140  if (list.size() >= 2) {
1141  int minLanes = std::numeric_limits<int>::max();
1142  try {
1143  for (auto& i : list) {
1144  const int numLanes = StringUtils::toInt(StringUtils::prune(i));
1145  minLanes = MIN2(minLanes, numLanes);
1146  }
1147  myCurrentEdge->myNoLanes = minLanes;
1148  WRITE_WARNINGF("Using minimum lane number from list (%) for edge '%'.", value, toString(myCurrentEdge->id));
1149  } catch (NumberFormatException&) {
1150  WRITE_WARNINGF("Value of key '%' is not numeric ('%') in edge '%'.", key, value, myCurrentEdge->id);
1151  }
1152  }
1153  } catch (EmptyData&) {
1154  WRITE_WARNINGF("Value of key '%' is not numeric ('%') in edge '%'.", key, value, myCurrentEdge->id);
1155  }
1156  } else if (key == "lanes:forward") {
1157  try {
1158  const int numLanes = StringUtils::toInt(value);
1159  if (myCurrentEdge->myNoLanesForward < 0 && myCurrentEdge->myNoLanes < 0) {
1160  // fix lane count in case only lanes:forward and lanes:backward are set
1161  myCurrentEdge->myNoLanes = numLanes - myCurrentEdge->myNoLanesForward;
1162  }
1163  myCurrentEdge->myNoLanesForward = numLanes;
1164  } catch (...) {
1165  WRITE_WARNINGF("Value of key '%' is not numeric ('%') in edge '%'.", key, value, myCurrentEdge->id);
1166  }
1167  } else if (key == "lanes:backward") {
1168  try {
1169  const int numLanes = StringUtils::toInt(value);
1170  if (myCurrentEdge->myNoLanesForward > 0 && myCurrentEdge->myNoLanes < 0) {
1171  // fix lane count in case only lanes:forward and lanes:backward are set
1172  myCurrentEdge->myNoLanes = numLanes + myCurrentEdge->myNoLanesForward;
1173  }
1174  // denote backwards count with a negative sign
1175  myCurrentEdge->myNoLanesForward = -numLanes;
1176  } catch (...) {
1177  WRITE_WARNINGF("Value of key '%' is not numeric ('%') in edge '%'.", key, value, myCurrentEdge->id);
1178  }
1179  } else if (myCurrentEdge->myMaxSpeed == MAXSPEED_UNGIVEN &&
1180  (key == "maxspeed" || key == "maxspeed:type" || key == "maxspeed:forward")) {
1181  // both 'maxspeed' and 'maxspeed:type' may be given so we must take care not to overwrite an already seen value
1182  myCurrentEdge->myMaxSpeed = interpretSpeed(key, value);
1183  } else if (key == "maxspeed:backward" && myCurrentEdge->myMaxSpeedBackward == MAXSPEED_UNGIVEN) {
1184  myCurrentEdge->myMaxSpeedBackward = interpretSpeed(key, value);
1185  } else if (key == "junction") {
1186  if ((value == "roundabout") && (myCurrentEdge->myIsOneWay.empty())) {
1187  myCurrentEdge->myIsOneWay = "yes";
1188  }
1189  } else if (key == "oneway") {
1190  myCurrentEdge->myIsOneWay = value;
1191  } else if (key == "name") {
1192  myCurrentEdge->streetName = value;
1193  } else if (key == "ref") {
1194  myCurrentEdge->ref = value;
1195  myCurrentEdge->setParameter("ref", value);
1196  } else if (key == "layer") {
1197  try {
1198  myCurrentEdge->myLayer = StringUtils::toInt(value);
1199  } catch (...) {
1200  WRITE_WARNINGF("Value of key '%' is not numeric ('%') in edge '%'.", key, value, myCurrentEdge->id);
1201  }
1202  } else if (key == "tracks") {
1203  try {
1204  if (StringUtils::toInt(value) == 1) {
1205  myCurrentEdge->myIsOneWay = "true";
1206  } else {
1207  WRITE_WARNINGF("Ignoring track count % for edge '%'.", value, myCurrentEdge->id);
1208  }
1209  } catch (...) {
1210  WRITE_WARNINGF("Value of key '%' is not numeric ('%') in edge '%'.", key, value, myCurrentEdge->id);
1211  }
1212  } else if (key == "railway:preferred_direction") {
1213  if (value == "both") {
1214  myCurrentEdge->myRailDirection = WAY_BOTH;
1215  } else if (value == "backward") {
1216  myCurrentEdge->myRailDirection = WAY_BACKWARD;
1217  }
1218  } else if (key == "railway:bidirectional") {
1219  if (value == "regular") {
1220  myCurrentEdge->myRailDirection = WAY_BOTH;
1221  }
1222  } else if (key == "electrified") {
1223  if (value != "no") {
1224  myCurrentEdge->myCurrentIsElectrified = true;
1225  }
1226  } else if (key == "railway:track_ref") {
1227  myCurrentEdge->setParameter(key, value);
1228  } else if (key == "public_transport" && value == "platform") {
1229  myCurrentEdge->myCurrentIsPlatform = true;
1230  } else if (key == "parking:lane:both" && !StringUtils::startsWith(value, "no")) {
1231  myCurrentEdge->myParkingType |= PARKING_BOTH;
1232  } else if (key == "parking:lane:left" && !StringUtils::startsWith(value, "no")) {
1233  myCurrentEdge->myParkingType |= PARKING_LEFT;
1234  } else if (key == "parking:lane:right" && !StringUtils::startsWith(value, "no")) {
1235  myCurrentEdge->myParkingType |= PARKING_RIGHT;
1236  } else if (key == "change") {
1237  myCurrentEdge->myChangeForward = interpretChangeType(value);
1238  myCurrentEdge->myChangeBackward = myCurrentEdge->myChangeForward;
1239  } else if (key == "change:forward") {
1240  myCurrentEdge->myChangeForward = interpretChangeType(value);
1241  } else if (key == "change:backward") {
1242  myCurrentEdge->myChangeBackward = interpretChangeType(value);
1243  } else if (key == "change:lanes") {
1244  myCurrentEdge->myChangeForward = interpretChangeType(value);
1245  } else if (key == "change:lanes:forward") {
1246  myCurrentEdge->myChangeForward = interpretChangeType(value);
1247  } else if (key == "change:lanes:backward") {
1248  myCurrentEdge->myChangeBackward = interpretChangeType(value);
1249  } else if (key == "vehicle:lanes" || key == "vehicle:lanes:forward") {
1250  interpretLaneUse(value, SVC_PASSENGER, myCurrentEdge->myLaneUseForward);
1251  } else if (key == "vehicle:lanes:backward") {
1252  interpretLaneUse(value, SVC_PASSENGER, myCurrentEdge->myLaneUseBackward);
1253  } else if (StringUtils::startsWith(key, "turn:lanes")) {
1254  const std::vector<std::string> values = StringTokenizer(value, "|").getVector();
1255  std::vector<int> turnCodes;
1256  for (std::string codeList : values) {
1257  const std::vector<std::string> codes = StringTokenizer(codeList, ";").getVector();
1258  int turnCode = 0;
1259  for (std::string code : codes) {
1260  if (code == "" || code == "none" || code == "through") {
1261  turnCode |= (int)LinkDirection::STRAIGHT;
1262  } else if (code == "left" || code == "sharp_left") {
1263  turnCode |= (int)LinkDirection::LEFT;
1264  } else if (code == "right" || code == "sharp_right") {
1265  turnCode |= (int)LinkDirection::RIGHT;
1266  } else if (code == "slight_left") {
1267  turnCode |= (int)LinkDirection::PARTLEFT;
1268  } else if (code == "slight_right") {
1269  turnCode |= (int)LinkDirection::PARTRIGHT;
1270  } else if (code == "reverse") {
1271  turnCode |= (int)LinkDirection::TURN;
1272  } else if (code == "merge_to_left" || code == "merge_to_right") {
1273  turnCode |= (int)LinkDirection::NODIR;
1274  }
1275  }
1276  turnCodes.push_back(turnCode);
1277  }
1278  if (key == "turn:lanes" || key == "turn:lanes:forward") {
1279  myCurrentEdge->myTurnSignsForward = turnCodes;
1280  } else if (key == "turn:lanes:backward") {
1281  myCurrentEdge->myTurnSignsBackward = turnCodes;
1282  } else if (key == "turn:lanes:both_ways") {
1283  myCurrentEdge->myTurnSignsForward = turnCodes;
1284  myCurrentEdge->myTurnSignsBackward = turnCodes;
1285  }
1286  }
1287  }
1288 }
1289 
1290 
1291 double
1292 NIImporter_OpenStreetMap::EdgesHandler::interpretSpeed(const std::string& key, std::string value) {
1293  if (mySpeedMap.find(value) != mySpeedMap.end()) {
1294  return mySpeedMap[value];
1295  } else {
1296  double conversion = 1; // OSM default is km/h
1297  if (StringUtils::to_lower_case(value).find("km/h") != std::string::npos) {
1298  value = StringUtils::prune(value.substr(0, value.find_first_not_of("0123456789")));
1299  } else if (StringUtils::to_lower_case(value).find("mph") != std::string::npos) {
1300  value = StringUtils::prune(value.substr(0, value.find_first_not_of("0123456789")));
1301  conversion = KM_PER_MILE;
1302  }
1303  try {
1304  return StringUtils::toDouble(value) * conversion;
1305  } catch (...) {
1306  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
1307  toString(myCurrentEdge->id) + "'.");
1308  return MAXSPEED_UNGIVEN;
1309  }
1310  }
1311 }
1312 
1313 int
1315  int result = 0;
1316  const std::vector<std::string> values = StringTokenizer(value, "|").getVector();
1317  for (const std::string& val : values) {
1318  if (val == "no") {
1319  result += CHANGE_NO;
1320  } else if (val == "not_left") {
1321  result += CHANGE_NO_LEFT;
1322  } else if (val == "not_right") {
1323  result += CHANGE_NO_RIGHT;
1324  }
1325  result = result << 2;
1326  };
1327  // last shift was superfluous
1328  result = result >> 2;
1329 
1330  if (values.size() > 1) {
1331  result += 2 << 29; // mark multi-value input
1332  }
1333  //std::cout << " way=" << myCurrentEdge->id << " value=" << value << " result=" << std::bitset<32>(result) << "\n";
1334  return result;
1335 }
1336 
1337 
1338 void
1339 NIImporter_OpenStreetMap::EdgesHandler::interpretLaneUse(const std::string& value, SUMOVehicleClass svc, std::vector<SVCPermissions>& result) const {
1340  const std::vector<std::string> values = StringTokenizer(value, "|").getVector();
1341  int i = 0;
1342  for (const std::string& val : values) {
1344  if (val == "yes" || val == "lane" || val == "designated") {
1345  use = svc;
1346  } else if (val != "no") {
1347  WRITE_WARNINGF("Unknown lane use specifier '%' treated as 'no' for way '%'", val, myCurrentEdge->id);
1348  }
1349  if (i >= (int)result.size()) {
1350  result.push_back(use);
1351  } else {
1352  result[i] |= use;
1353  }
1354  i++;
1355  };
1356 }
1357 
1358 
1359 void
1361  myParentElements.pop_back();
1362  if (element == SUMO_TAG_WAY && myCurrentEdge != nullptr) {
1363  if (myCurrentEdge->myCurrentIsRoad) {
1364  myEdgeMap[myCurrentEdge->id] = myCurrentEdge;
1365  } else if (myCurrentEdge->myCurrentIsPlatform) {
1366  myPlatformShapesMap[myCurrentEdge->id] = myCurrentEdge;
1367  } else {
1368  delete myCurrentEdge;
1369  }
1370  myCurrentEdge = nullptr;
1371  }
1372 }
1373 
1374 // ---------------------------------------------------------------------------
1375 // definitions of NIImporter_OpenStreetMap::RelationHandler-methods
1376 // ---------------------------------------------------------------------------
1378  const std::map<long long int, NIOSMNode*>& osmNodes,
1379  const std::map<long long int, Edge*>& osmEdges, NBPTStopCont* nbptStopCont,
1380  const std::map<long long int, Edge*>& platformShapes,
1381  NBPTLineCont* nbptLineCont,
1382  const OptionsCont& oc) :
1383  SUMOSAXHandler("osm - file"),
1384  myOSMNodes(osmNodes),
1385  myOSMEdges(osmEdges),
1386  myPlatformShapes(platformShapes),
1387  myNBPTStopCont(nbptStopCont),
1388  myNBPTLineCont(nbptLineCont),
1389  myOptionsCont(oc) {
1390  resetValues();
1391 }
1392 
1394 
1395 void
1397  myCurrentRelation = INVALID_ID;
1398  myIsRestriction = false;
1399  myFromWay = INVALID_ID;
1400  myToWay = INVALID_ID;
1401  myViaNode = INVALID_ID;
1402  myViaWay = INVALID_ID;
1403  myRestrictionType = RestrictionType::UNKNOWN;
1404  myPlatforms.clear();
1405  myStops.clear();
1406  myPlatformStops.clear();
1407  myWays.clear();
1408  myIsStopArea = false;
1409  myIsRoute = false;
1410  myPTRouteType = "";
1411  myRouteColor.setValid(false);
1412 }
1413 
1414 void
1416  const SUMOSAXAttributes& attrs) {
1417  myParentElements.push_back(element);
1418  // parse "way" elements
1419  if (element == SUMO_TAG_RELATION) {
1420  bool ok = true;
1421  myCurrentRelation = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
1422  const std::string action = attrs.hasAttribute("action") ? attrs.getStringSecure("action", "") : "";
1423  if (action == "delete" || !ok) {
1424  myCurrentRelation = INVALID_ID;
1425  }
1426  myName = "";
1427  myRef = "";
1428  myInterval = -1;
1429  myNightService = "";
1430  return;
1431  }
1432  if (myCurrentRelation == INVALID_ID) {
1433  return;
1434  }
1435  // parse member elements
1436  if (element == SUMO_TAG_MEMBER) {
1437  bool ok = true;
1438  std::string role = attrs.hasAttribute("role") ? attrs.getStringSecure("role", "") : "";
1439  auto ref = attrs.get<long
1440  long
1441  int>(SUMO_ATTR_REF, nullptr, ok);
1442  if (role == "via") {
1443  // u-turns for divided ways may be given with 2 via-nodes or 1 via-way
1444  std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
1445  if (memberType == "way" && checkEdgeRef(ref)) {
1446  myViaWay = ref;
1447  } else if (memberType == "node") {
1448  if (myOSMNodes.find(ref) != myOSMNodes.end()) {
1449  myViaNode = ref;
1450  } else {
1451  WRITE_WARNINGF("No node found for reference '%' in relation '%'.", toString(ref), toString(myCurrentRelation));
1452  }
1453  }
1454  } else if (role == "from" && checkEdgeRef(ref)) {
1455  myFromWay = ref;
1456  } else if (role == "to" && checkEdgeRef(ref)) {
1457  myToWay = ref;
1458  } else if (role == "stop") {
1459  myStops.push_back(ref);
1460  } else if (role == "platform") {
1461  std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
1462  if (memberType == "way") {
1463  const std::map<long long int,
1464  NIImporter_OpenStreetMap::Edge*>::const_iterator& wayIt = myPlatformShapes.find(ref);
1465  if (wayIt != myPlatformShapes.end()) {
1466 
1467  NIIPTPlatform platform;
1468  platform.isWay = true;
1469  platform.ref = ref;
1470  myPlatforms.push_back(platform);
1471  }
1472  } else if (memberType == "node") {
1473  // myIsStopArea may not be set yet
1474  myStops.push_back(ref);
1475  myPlatformStops.insert(ref);
1476  NIIPTPlatform platform;
1477  platform.isWay = false;
1478  platform.ref = ref;
1479  myPlatforms.push_back(platform);
1480  }
1481 
1482  } else if (role.empty()) {
1483  std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
1484  if (memberType == "way") {
1485  myWays.push_back(ref);
1486  } else if (memberType == "node") {
1487  myStops.push_back(ref);
1488  }
1489  }
1490  return;
1491  }
1492  // parse values
1493  if (element == SUMO_TAG_TAG) {
1494  bool ok = true;
1495  std::string key = attrs.get<std::string>(SUMO_ATTR_K, toString(myCurrentRelation).c_str(), ok, false);
1496  // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
1497  if (key == "type" || key == "restriction") {
1498  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1499  if (key == "type" && value == "restriction") {
1500  myIsRestriction = true;
1501  return;
1502  }
1503  if (key == "type" && value == "route") {
1504  myIsRoute = true;
1505  return;
1506  }
1507  if (key == "restriction") {
1508  // @note: the 'right/left/straight' part is ignored since the information is
1509  // redundantly encoded in the 'from', 'to' and 'via' members
1510  if (value.substr(0, 5) == "only_") {
1511  myRestrictionType = RestrictionType::ONLY;
1512  } else if (value.substr(0, 3) == "no_") {
1513  myRestrictionType = RestrictionType::NO;
1514  } else {
1515  WRITE_WARNINGF("Found unknown restriction type '%' in relation '%'", value, toString(myCurrentRelation));
1516  }
1517  return;
1518  }
1519  } else if (key == "public_transport") {
1520  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1521  if (value == "stop_area") {
1522  myIsStopArea = true;
1523  }
1524  } else if (key == "route") {
1525  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1526  if (value == "train" || value == "subway" || value == "light_rail" || value == "monorail" || value == "tram" || value == "bus"
1527  || value == "trolleybus" || value == "arialway" || value == "ferry" || value == "share_taxi" || value == "minibus") {
1528  myPTRouteType = value;
1529  }
1530 
1531  } else if (key == "name") {
1532  myName = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1533  } else if (key == "colour") {
1534  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1535  try {
1536  myRouteColor = RGBColor::parseColor(value);
1537  } catch (...) {
1538  WRITE_WARNINGF("Invalid color value '%' in relation %", value, myCurrentRelation);
1539  }
1540  } else if (key == "ref") {
1541  myRef = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1542  } else if (key == "interval" || key == "headway") {
1543  myInterval = attrs.get<int>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1544  } else if (key == "by_night") {
1545  myNightService = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1546  }
1547  }
1548 }
1549 
1550 bool
1552  if (myOSMEdges.find(ref) != myOSMEdges.end()) {
1553  return true;
1554  }
1555 
1556  WRITE_WARNINGF("No way found for reference '%' in relation '%'", toString(ref), toString(myCurrentRelation));
1557  return false;
1558 
1559 }
1560 
1561 void
1563  myParentElements.pop_back();
1564  if (element == SUMO_TAG_RELATION) {
1565  if (myIsRestriction) {
1566  assert(myCurrentRelation != INVALID_ID);
1567  bool ok = true;
1568  if (myRestrictionType == RestrictionType::UNKNOWN) {
1569  WRITE_WARNINGF("Ignoring restriction relation '%' with unknown type.", toString(myCurrentRelation));
1570  ok = false;
1571  }
1572  if (myFromWay == INVALID_ID) {
1573  WRITE_WARNINGF("Ignoring restriction relation '%' with unknown from-way.", toString(myCurrentRelation));
1574  ok = false;
1575  }
1576  if (myToWay == INVALID_ID) {
1577  WRITE_WARNINGF("Ignoring restriction relation '%' with unknown to-way.", toString(myCurrentRelation));
1578  ok = false;
1579  }
1580  if (myViaNode == INVALID_ID && myViaWay == INVALID_ID) {
1581  WRITE_WARNINGF("Ignoring restriction relation '%' with unknown via.", toString(myCurrentRelation));
1582  ok = false;
1583  }
1584  if (ok && !applyRestriction()) {
1585  WRITE_WARNINGF("Ignoring restriction relation '%'.", toString(myCurrentRelation));
1586  }
1587  } else if (myIsStopArea && OptionsCont::getOptions().isSet("ptstop-output")) {
1588  for (long long ref : myStops) {
1589  myStopAreas[ref] = myCurrentRelation;
1590  if (myOSMNodes.find(ref) == myOSMNodes.end()) {
1591  //WRITE_WARNING(
1592  // "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
1593  // + "' does not exist. Probably OSM file is incomplete.");
1594  continue;
1595  }
1596 
1597  NIOSMNode* n = myOSMNodes.find(ref)->second;
1598  NBPTStop* ptStop = myNBPTStopCont->get(toString(n->id));
1599  if (ptStop == nullptr) {
1600  //WRITE_WARNING(
1601  // "Relation '" + toString(myCurrentRelation) + "' refers to a non existing pt stop at node: '"
1602  // + toString(n->id) + "'. Probably OSM file is incomplete.");
1603  continue;
1604  }
1605  for (NIIPTPlatform& myPlatform : myPlatforms) {
1606  if (myPlatform.isWay) {
1607  assert(myPlatformShapes.find(myPlatform.ref) != myPlatformShapes.end()); //already tested earlier
1608  Edge* edge = (*myPlatformShapes.find(myPlatform.ref)).second;
1609  if (edge->myCurrentNodes[0] == *(edge->myCurrentNodes.end() - 1)) {
1610  WRITE_WARNINGF("Platform '%' in relation: '%' is given as polygon, which currently is not supported.", myPlatform.ref, myCurrentRelation);
1611  continue;
1612 
1613  }
1614  PositionVector p;
1615  for (auto nodeRef : edge->myCurrentNodes) {
1616  if (myOSMNodes.find(nodeRef) == myOSMNodes.end()) {
1617  //WRITE_WARNING(
1618  // "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
1619  // + "' does not exist. Probably OSM file is incomplete.");
1620  continue;
1621  }
1622  NIOSMNode* pNode = myOSMNodes.find(nodeRef)->second;
1623  Position pNodePos(pNode->lon, pNode->lat, pNode->ele);
1624  if (!NBNetBuilder::transformCoordinate(pNodePos)) {
1625  WRITE_ERROR("Unable to project coordinates for node '" + toString(pNode->id) + "'.");
1626  continue;
1627  }
1628  p.push_back(pNodePos);
1629  }
1630  if (p.size() == 0) {
1631  WRITE_WARNINGF("Referenced platform: '%' in relation: '%' is corrupt. Probably OSM file is incomplete.",
1632  toString(myPlatform.ref), toString(myCurrentRelation));
1633  continue;
1634  }
1635  NBPTPlatform platform(p[(int)p.size() / 2], p.length());
1636  ptStop->addPlatformCand(platform);
1637  } else {
1638  if (myOSMNodes.find(myPlatform.ref) == myOSMNodes.end()) {
1639  //WRITE_WARNING(
1640  // "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
1641  // + "' does not exist. Probably OSM file is incomplete.");
1642  continue;
1643  }
1644  NIOSMNode* pNode = myOSMNodes.find(myPlatform.ref)->second;
1645  Position platformPos(pNode->lon, pNode->lat, pNode->ele);
1646  if (!NBNetBuilder::transformCoordinate(platformPos)) {
1647  WRITE_ERROR("Unable to project coordinates for node '" + toString(pNode->id) + "'.");
1648  }
1649  NBPTPlatform platform(platformPos, myOptionsCont.getFloat(
1650  "osm.stop-output.length"));
1651  ptStop->addPlatformCand(platform);
1652 
1653  }
1654  }
1655  ptStop->setIsMultipleStopPositions(myStops.size() > 1, myCurrentRelation);
1656  }
1657  } else if (myPTRouteType != "" && myIsRoute && OptionsCont::getOptions().isSet("ptline-output")) {
1658  NBPTLine* ptLine = new NBPTLine(toString(myCurrentRelation), myName, myPTRouteType, myRef, myInterval, myNightService,
1659  interpretTransportType(myPTRouteType), myRouteColor);
1660  ptLine->setMyNumOfStops((int)myStops.size());
1661  for (long long ref : myStops) {
1662  if (myOSMNodes.find(ref) == myOSMNodes.end()) {
1663  //WRITE_WARNING(
1664  // "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
1665  // + "' does not exist. Probably OSM file is incomplete.");
1666 // resetValues();
1667 // return;
1668  if (!ptLine->getStops().empty()) {
1669  WRITE_WARNINGF("Done reading first coherent chunk of pt stops. Further stops in relation % are ignored", myCurrentRelation);
1670  break;
1671  }
1672  continue;
1673  }
1674 
1675  NIOSMNode* n = myOSMNodes.find(ref)->second;
1676  NBPTStop* ptStop = myNBPTStopCont->get(toString(n->id));
1677  if (ptStop == nullptr) {
1678  // loose stop, which must later be mapped onto a line way
1679  Position ptPos(n->lon, n->lat, n->ele);
1680  if (!NBNetBuilder::transformCoordinate(ptPos)) {
1681  WRITE_ERROR("Unable to project coordinates for node '" + toString(n->id) + "'.");
1682  }
1683  ptStop = new NBPTStop(toString(n->id), ptPos, "", "", n->ptStopLength, n->name, n->permissions);
1684  myNBPTStopCont->insert(ptStop);
1685  if (myStopAreas.count(n->id)) {
1686  ptStop->setIsMultipleStopPositions(false, myStopAreas[n->id]);
1687  }
1688  if (myPlatformStops.count(n->id) > 0) {
1689  ptStop->setIsPlatform();
1690  }
1691  }
1692  ptLine->addPTStop(ptStop);
1693  }
1694  for (long long& myWay : myWays) {
1695  auto entr = myOSMEdges.find(myWay);
1696  if (entr != myOSMEdges.end()) {
1697  Edge* edge = entr->second;
1698  for (long long& myCurrentNode : edge->myCurrentNodes) {
1699  ptLine->addWayNode(myWay, myCurrentNode);
1700  }
1701  }
1702  }
1703  if (ptLine->getStops().empty()) {
1704  WRITE_WARNINGF("PT line in relation % with no stops ignored. Probably OSM file is incomplete.", myCurrentRelation);
1705  resetValues();
1706  return;
1707  }
1708  if (myNBPTLineCont->getLines().count(ptLine->getLineID()) == 0) {
1709  myNBPTLineCont->insert(ptLine);
1710  } else {
1711  WRITE_WARNINGF("Ignoring duplicate PT line '%'.", toString(myCurrentRelation));
1712  delete ptLine;
1713  }
1714  }
1715  // other relations might use similar subelements so reset in any case
1716  resetValues();
1717  }
1718 }
1719 
1720 bool
1722  // since OSM ways are bidirectional we need the via to figure out which direction was meant
1723  if (myViaNode != INVALID_ID) {
1724  NBNode* viaNode = myOSMNodes.find(myViaNode)->second->node;
1725  if (viaNode == nullptr) {
1726  WRITE_WARNINGF("Via-node '%' was not instantiated", toString(myViaNode));
1727  return false;
1728  }
1729  NBEdge* from = findEdgeRef(myFromWay, viaNode->getIncomingEdges());
1730  NBEdge* to = findEdgeRef(myToWay, viaNode->getOutgoingEdges());
1731  if (from == nullptr) {
1732  WRITE_WARNINGF("from-edge '%' of restriction relation could not be determined", toString(myFromWay));
1733  return false;
1734  }
1735  if (to == nullptr) {
1736  WRITE_WARNINGF("to-edge '%' of restriction relation could not be determined", toString(myToWay));
1737  return false;
1738  }
1739  if (myRestrictionType == RestrictionType::ONLY) {
1740  from->addEdge2EdgeConnection(to, true);
1741  // make sure that these connections remain disabled even if network
1742  // modifications (ramps.guess) reset existing connections
1743  for (NBEdge* cand : from->getToNode()->getOutgoingEdges()) {
1744  if (!from->isConnectedTo(cand)) {
1745  from->removeFromConnections(cand, -1, -1, true);
1746  }
1747  }
1748  } else {
1749  from->removeFromConnections(to, -1, -1, true);
1750  }
1751  } else {
1752  // XXX interpreting via-ways or via-node lists not yet implemented
1753  WRITE_WARNINGF("direction of restriction relation could not be determined%", "");
1754  return false;
1755  }
1756  return true;
1757 }
1758 
1759 NBEdge*
1761  const std::vector<NBEdge*>& candidates) const {
1762  const std::string prefix = toString(wayRef);
1763  const std::string backPrefix = "-" + prefix;
1764  NBEdge* result = nullptr;
1765  int found = 0;
1766  for (auto candidate : candidates) {
1767  if ((candidate->getID().substr(0, prefix.size()) == prefix) ||
1768  (candidate->getID().substr(0, backPrefix.size()) == backPrefix)) {
1769  result = candidate;
1770  found++;
1771  }
1772  }
1773  if (found > 1) {
1774  WRITE_WARNINGF("Ambiguous way reference '%' in restriction relation", prefix);
1775  result = nullptr;
1776  }
1777  return result;
1778 }
1779 
1780 
1781 void
1783  NBNodeCont& nc = nb.getNodeCont();
1784  NBEdgeCont& ec = nb.getEdgeCont();
1785  // reconstruct elevation from layer info
1786  // build a map of raising and lowering forces (attractor and distance)
1787  // for all nodes unknownElevation
1788  std::map<NBNode*, std::vector<std::pair<double, double> > > layerForces;
1789 
1790  // collect all nodes that belong to a way with layer information
1791  std::set<NBNode*> knownElevation;
1792  for (auto& myEdge : myEdges) {
1793  Edge* e = myEdge.second;
1794  if (e->myLayer != 0) {
1795  for (auto j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
1796  NBNode* node = nc.retrieve(toString(*j));
1797  if (node != nullptr) {
1798  knownElevation.insert(node);
1799  layerForces[node].emplace_back(e->myLayer * layerElevation, POSITION_EPS);
1800  }
1801  }
1802  }
1803  }
1804 #ifdef DEBUG_LAYER_ELEVATION
1805  std::cout << "known elevations:\n";
1806  for (std::set<NBNode*>::iterator it = knownElevation.begin(); it != knownElevation.end(); ++it) {
1807  const std::vector<std::pair<double, double> >& primaryLayers = layerForces[*it];
1808  std::cout << " node=" << (*it)->getID() << " ele=";
1809  for (std::vector<std::pair<double, double> >::const_iterator it_ele = primaryLayers.begin(); it_ele != primaryLayers.end(); ++it_ele) {
1810  std::cout << it_ele->first << " ";
1811  }
1812  std::cout << "\n";
1813  }
1814 #endif
1815  // layer data only provides a lower bound on elevation since it is used to
1816  // resolve the relation among overlapping ways.
1817  // Perform a sanity check for steep inclines and raise the knownElevation if necessary
1818  std::map<NBNode*, double> knownEleMax;
1819  for (auto it : knownElevation) {
1820  double eleMax = -std::numeric_limits<double>::max();
1821  const std::vector<std::pair<double, double> >& primaryLayers = layerForces[it];
1822  for (const auto& primaryLayer : primaryLayers) {
1823  eleMax = MAX2(eleMax, primaryLayer.first);
1824  }
1825  knownEleMax[it] = eleMax;
1826  }
1827  const double gradeThreshold = OptionsCont::getOptions().getFloat("osm.layer-elevation.max-grade") / 100;
1828  bool changed = true;
1829  while (changed) {
1830  changed = false;
1831  for (auto it = knownElevation.begin(); it != knownElevation.end(); ++it) {
1832  std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it,
1833  knownEleMax[*it]
1834  / gradeThreshold * 3,
1835  knownElevation);
1836  for (auto& neighbor : neighbors) {
1837  if (knownElevation.count(neighbor.first) != 0) {
1838  const double grade = fabs(knownEleMax[*it] - knownEleMax[neighbor.first])
1839  / MAX2(POSITION_EPS, neighbor.second.first);
1840 #ifdef DEBUG_LAYER_ELEVATION
1841  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";
1842 #endif
1843  if (grade > gradeThreshold * 50 / 3.6 / neighbor.second.second) {
1844  // raise the lower node to the higher level
1845  const double eleMax = MAX2(knownEleMax[*it], knownEleMax[neighbor.first]);
1846  if (knownEleMax[*it] < eleMax) {
1847  knownEleMax[*it] = eleMax;
1848  } else {
1849  knownEleMax[neighbor.first] = eleMax;
1850  }
1851  changed = true;
1852  }
1853  }
1854  }
1855  }
1856  }
1857 
1858  // collect all nodes within a grade-dependent range around knownElevation-nodes and apply knowElevation forces
1859  std::set<NBNode*> unknownElevation;
1860  for (auto it = knownElevation.begin(); it != knownElevation.end(); ++it) {
1861  const double eleMax = knownEleMax[*it];
1862  const double maxDist = fabs(eleMax) * 100 / layerElevation;
1863  std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it, maxDist, knownElevation);
1864  for (auto& neighbor : neighbors) {
1865  if (knownElevation.count(neighbor.first) == 0) {
1866  unknownElevation.insert(neighbor.first);
1867  layerForces[neighbor.first].emplace_back(eleMax, neighbor.second.first);
1868  }
1869  }
1870  }
1871 
1872  // apply forces to ground-level nodes (neither in knownElevation nor unknownElevation)
1873  for (auto it = unknownElevation.begin(); it != unknownElevation.end(); ++it) {
1874  double eleMax = -std::numeric_limits<double>::max();
1875  const std::vector<std::pair<double, double> >& primaryLayers = layerForces[*it];
1876  for (const auto& primaryLayer : primaryLayers) {
1877  eleMax = MAX2(eleMax, primaryLayer.first);
1878  }
1879  const double maxDist = fabs(eleMax) * 100 / layerElevation;
1880  std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it, maxDist, knownElevation);
1881  for (auto& neighbor : neighbors) {
1882  if (knownElevation.count(neighbor.first) == 0 && unknownElevation.count(neighbor.first) == 0) {
1883  layerForces[*it].emplace_back(0, neighbor.second.first);
1884  }
1885  }
1886  }
1887  // compute the elevation for each node as the weighted average of all forces
1888 #ifdef DEBUG_LAYER_ELEVATION
1889  std::cout << "summation of forces\n";
1890 #endif
1891  std::map<NBNode*, double> nodeElevation;
1892  for (auto& layerForce : layerForces) {
1893  const std::vector<std::pair<double, double> >& forces = layerForce.second;
1894  if (knownElevation.count(layerForce.first) != 0) {
1895  // use the maximum value
1896  /*
1897  double eleMax = -std::numeric_limits<double>::max();
1898  for (std::vector<std::pair<double, double> >::const_iterator it_force = forces.begin(); it_force != forces.end(); ++it_force) {
1899  eleMax = MAX2(eleMax, it_force->first);
1900  }
1901  */
1902 #ifdef DEBUG_LAYER_ELEVATION
1903  std::cout << " node=" << it->first->getID() << " knownElevation=" << knownEleMax[it->first] << "\n";
1904 #endif
1905  nodeElevation[layerForce.first] = knownEleMax[layerForce.first];
1906  } else if (forces.size() == 1) {
1907  nodeElevation[layerForce.first] = forces.front().first;
1908  } else {
1909  // use the weighted sum
1910  double distSum = 0;
1911  for (const auto& force : forces) {
1912  distSum += force.second;
1913  }
1914  double weightSum = 0;
1915  double elevation = 0;
1916 #ifdef DEBUG_LAYER_ELEVATION
1917  std::cout << " node=" << it->first->getID() << " distSum=" << distSum << "\n";
1918 #endif
1919  for (const auto& force : forces) {
1920  const double weight = (distSum - force.second) / distSum;
1921  weightSum += weight;
1922  elevation += force.first * weight;
1923 
1924 #ifdef DEBUG_LAYER_ELEVATION
1925  std::cout << " force=" << it_force->first << " dist=" << it_force->second << " weight=" << weight << " ele=" << elevation << "\n";
1926 #endif
1927  }
1928  nodeElevation[layerForce.first] = elevation / weightSum;
1929  }
1930  }
1931 #ifdef DEBUG_LAYER_ELEVATION
1932  std::cout << "final elevations:\n";
1933  for (std::map<NBNode*, double>::iterator it = nodeElevation.begin(); it != nodeElevation.end(); ++it) {
1934  std::cout << " node=" << (it->first)->getID() << " ele=" << it->second << "\n";
1935  }
1936 #endif
1937  // apply node elevations
1938  for (auto& it : nodeElevation) {
1939  NBNode* n = it.first;
1940  Position pos = n->getPosition();
1941  n->reinit(n->getPosition() + Position(0, 0, it.second), n->getType());
1942  }
1943 
1944  // apply way elevation to all edges that had layer information
1945  for (const auto& it : ec) {
1946  NBEdge* edge = it.second;
1947  const PositionVector& geom = edge->getGeometry();
1948  const double length = geom.length2D();
1949  const double zFrom = nodeElevation[edge->getFromNode()];
1950  const double zTo = nodeElevation[edge->getToNode()];
1951  // XXX if the from- or to-node was part of multiple ways with
1952  // different layers, reconstruct the layer value from origID
1953  double dist = 0;
1954  PositionVector newGeom;
1955  for (auto it_pos = geom.begin(); it_pos != geom.end(); ++it_pos) {
1956  if (it_pos != geom.begin()) {
1957  dist += (*it_pos).distanceTo2D(*(it_pos - 1));
1958  }
1959  newGeom.push_back((*it_pos) + Position(0, 0, zFrom + (zTo - zFrom) * dist / length));
1960  }
1961  edge->setGeometry(newGeom);
1962  }
1963 }
1964 
1965 std::map<NBNode*, std::pair<double, double> >
1966 NIImporter_OpenStreetMap::getNeighboringNodes(NBNode* node, double maxDist, const std::set<NBNode*>& knownElevation) {
1967  std::map<NBNode*, std::pair<double, double> > result;
1968  std::set<NBNode*> visited;
1969  std::vector<NBNode*> open;
1970  open.push_back(node);
1971  result[node] = std::make_pair(0, 0);
1972  while (!open.empty()) {
1973  NBNode* n = open.back();
1974  open.pop_back();
1975  if (visited.count(n) != 0) {
1976  continue;
1977  }
1978  visited.insert(n);
1979  const EdgeVector& edges = n->getEdges();
1980  for (auto e : edges) {
1981  NBNode* s = nullptr;
1982  if (n->hasIncoming(e)) {
1983  s = e->getFromNode();
1984  } else {
1985  s = e->getToNode();
1986  }
1987  const double dist = result[n].first + e->getGeometry().length2D();
1988  const double speed = MAX2(e->getSpeed(), result[n].second);
1989  if (result.count(s) == 0) {
1990  result[s] = std::make_pair(dist, speed);
1991  } else {
1992  result[s] = std::make_pair(MIN2(dist, result[s].first), MAX2(speed, result[s].second));
1993  }
1994  if (dist < maxDist && knownElevation.count(s) == 0) {
1995  open.push_back(s);
1996  }
1997  }
1998  }
1999  result.erase(node);
2000  return result;
2001 }
2002 
2003 
2004 std::string
2005 NIImporter_OpenStreetMap::usableType(const std::string& type, const std::string& id, NBTypeCont& tc) {
2006  if (tc.knows(type)) {
2007  return type;
2008  }
2009  if (myUnusableTypes.count(type) > 0) {
2010  return "";
2011  }
2012  if (myKnownCompoundTypes.count(type) > 0) {
2013  return myKnownCompoundTypes[type];
2014  }
2015  // this edge has a type which does not yet exist in the TypeContainer
2017  std::vector<std::string> types;
2018  while (tok.hasNext()) {
2019  std::string t = tok.next();
2020  if (tc.knows(t)) {
2021  if (std::find(types.begin(), types.end(), t) == types.end()) {
2022  types.push_back(t);
2023  }
2024  } else if (tok.size() > 1) {
2025  WRITE_WARNINGF("Discarding unknown compound '%' in type '%' (first occurence for edge '%').", t, type, id);
2026  }
2027  }
2028  if (types.empty()) {
2029  WRITE_WARNINGF("Discarding unusable type '%' (first occurence for edge '%').", type, id);
2030  myUnusableTypes.insert(type);
2031  return "";
2032  }
2033  const std::string newType = joinToString(types, "|");
2034  if (tc.knows(newType)) {
2035  myKnownCompoundTypes[type] = newType;
2036  return newType;
2037  } else if (myKnownCompoundTypes.count(newType) > 0) {
2038  return myKnownCompoundTypes[newType];
2039  } else {
2040  // build a new type by merging all values
2041  int numLanes = 0;
2042  double maxSpeed = 0;
2043  int prio = 0;
2044  double width = NBEdge::UNSPECIFIED_WIDTH;
2045  double sidewalkWidth = NBEdge::UNSPECIFIED_WIDTH;
2046  double bikelaneWidth = NBEdge::UNSPECIFIED_WIDTH;
2047  bool defaultIsOneWay = true;
2048  SVCPermissions permissions = 0;
2050  bool discard = true;
2051  for (auto& type2 : types) {
2052  if (!tc.getEdgeTypeShallBeDiscarded(type2)) {
2053  numLanes = MAX2(numLanes, tc.getEdgeTypeNumLanes(type2));
2054  maxSpeed = MAX2(maxSpeed, tc.getEdgeTypeSpeed(type2));
2055  prio = MAX2(prio, tc.getEdgeTypePriority(type2));
2056  defaultIsOneWay &= tc.getEdgeTypeIsOneWay(type2);
2057  //std::cout << "merging component " << type2 << " into type " << newType << " allows=" << getVehicleClassNames(tc.getPermissions(type2)) << " oneway=" << defaultIsOneWay << "\n";
2058  permissions |= tc.getEdgeTypePermissions(type2);
2059  spreadType = tc.getEdgeTypeSpreadType(type2);
2060  width = MAX2(width, tc.getEdgeTypeWidth(type2));
2061  sidewalkWidth = MAX2(sidewalkWidth, tc.getEdgeTypeSidewalkWidth(type2));
2062  bikelaneWidth = MAX2(bikelaneWidth, tc.getEdgeTypeBikeLaneWidth(type2));
2063  discard = false;
2064  }
2065  }
2066  if (width != NBEdge::UNSPECIFIED_WIDTH) {
2067  width = MAX2(width, SUMO_const_laneWidth);
2068  }
2069  // ensure pedestrians don't run into trains
2070  if (sidewalkWidth == NBEdge::UNSPECIFIED_WIDTH
2071  && (permissions & SVC_PEDESTRIAN) != 0
2072  && (permissions & SVC_RAIL_CLASSES) != 0) {
2073  //std::cout << "patching sidewalk for type '" << newType << "' which allows=" << getVehicleClassNames(permissions) << "\n";
2074  sidewalkWidth = OptionsCont::getOptions().getFloat("default.sidewalk-width");
2075  }
2076 
2077  if (discard) {
2078  WRITE_WARNINGF("Discarding compound type '%' (first occurence for edge '%').", newType, id);
2079  myUnusableTypes.insert(newType);
2080  return "";
2081  }
2082 
2083  WRITE_MESSAGE("Adding new type '" + type + "' (first occurence for edge '" + id + "').");
2084  tc.insertEdgeType(newType, numLanes, maxSpeed, prio, permissions, spreadType, width,
2085  defaultIsOneWay, sidewalkWidth, bikelaneWidth, 0, 0, 0);
2086  for (auto& type3 : types) {
2087  if (!tc.getEdgeTypeShallBeDiscarded(type3)) {
2088  tc.copyEdgeTypeRestrictionsAndAttrs(type3, newType);
2089  }
2090  }
2091  myKnownCompoundTypes[type] = newType;
2092  return newType;
2093  }
2094 }
2095 
2096 void
2098  const std::string id = toString(e->id);
2099  std::string type = usableType(e->myHighWayType, id, tc);
2100  if (type != "" && isRailway(tc.getEdgeTypePermissions(type))) {
2101  std::vector<NIOSMNode*> nodes;
2102  std::vector<double> usablePositions;
2103  std::vector<int> usableIndex;
2104  for (long long int n : e->myCurrentNodes) {
2105  NIOSMNode* node = myOSMNodes[n];
2106  node->positionMeters = interpretDistance(node);
2107  if (node->positionMeters != std::numeric_limits<double>::max()) {
2108  usablePositions.push_back(node->positionMeters);
2109  usableIndex.push_back((int)nodes.size());
2110  }
2111  nodes.push_back(node);
2112  }
2113  if (usablePositions.size() == 0) {
2114  return;
2115  } else {
2116  bool forward = true;
2117  if (usablePositions.size() == 1) {
2118  WRITE_WARNINGF("Ambiguous railway kilometrage direction for way '%' (assuming forward)", id);
2119  } else {
2120  forward = usablePositions.front() < usablePositions.back();
2121  }
2122  // check for consistency
2123  for (int i = 1; i < (int)usablePositions.size(); i++) {
2124  if ((usablePositions[i - 1] < usablePositions[i]) != forward) {
2125  WRITE_WARNINGF("Inconsistent railway kilometrage direction for way '%': %s (skipping)", id, toString(usablePositions));
2126  return;
2127  }
2128  }
2129  if (nodes.size() > usablePositions.size()) {
2130  // complete missing values
2131  PositionVector shape;
2132  for (NIOSMNode* node : nodes) {
2133  shape.push_back(Position(node->lon, node->lat, 0));
2134  }
2135  if (!NBNetBuilder::transformCoordinates(shape)) {
2136  return; // error will be given later
2137  }
2138  double sign = forward ? 1 : -1;
2139  // extend backward before first usable value
2140  for (int i = usableIndex.front() - 1; i >= 0; i--) {
2141  nodes[i]->positionMeters = nodes[i + 1]->positionMeters - sign * shape[i].distanceTo2D(shape[i + 1]);
2142  }
2143  // extend forward
2144  for (int i = usableIndex.front() + 1; i < (int)nodes.size(); i++) {
2145  if (nodes[i]->positionMeters == std::numeric_limits<double>::max()) {
2146  nodes[i]->positionMeters = nodes[i - 1]->positionMeters + sign * shape[i].distanceTo2D(shape[i - 1]);
2147  }
2148  }
2149  //std::cout << " way=" << id << " usable=" << toString(usablePositions) << "\n indices=" << toString(usableIndex)
2150  // << " final:\n";
2151  //for (auto n : nodes) {
2152  // std::cout << " " << n->id << " " << n->positionMeters << " " << n->position<< "\n";
2153  //}
2154  }
2155  }
2156  }
2157 }
2158 
2159 
2160 double
2162  if (node->position.size() > 0) {
2163  try {
2164  if (StringUtils::startsWith(node->position, "mi:")) {
2165  return StringUtils::toDouble(node->position.substr(3)) * 1609.344; // meters per mile
2166  } else {
2167  return StringUtils::toDouble(node->position) * 1000;
2168  }
2169  } catch (...) {
2170  WRITE_WARNINGF("Value of railway:position is not numeric ('%') in node '%'.", node->position, toString(node->id));
2171  }
2172  }
2173  return std::numeric_limits<double>::max();
2174 }
2175 
2178  SUMOVehicleClass result = SVC_IGNORING;
2179  if (type == "train") {
2180  result = SVC_RAIL;
2181  } else if (type == "subway" || type == "light_rail") {
2182  result = SVC_RAIL_URBAN;
2183  } else if (type == "share_taxi") {
2184  result = SVC_TAXI;
2185  } else if (type == "minibus") {
2186  result = SVC_BUS;
2187  } else if (SumoVehicleClassStrings.hasString(type)) {
2188  result = SumoVehicleClassStrings.get(type);
2189  }
2190  std::string stop = "";
2191  if (result == SVC_TRAM) {
2192  stop = ".tram";
2193  } else if (result == SVC_BUS) {
2194  stop = ".bus";
2195  } else if (isRailway(result)) {
2196  stop = ".train";
2197  }
2198  if (toSet != nullptr && result != SVC_IGNORING) {
2199  toSet->permissions |= result;
2200  toSet->ptStopLength = OptionsCont::getOptions().getFloat("osm.stop-output.length" + stop);
2201  }
2202  return result;
2203 }
2204 
2205 void
2207  bool multiLane = changeProhibition > 3;
2208  //std::cout << "applyChangeProhibition e=" << e->getID() << " changeProhibition=" << std::bitset<32>(changeProhibition) << " val=" << changeProhibition << "\n";
2209  for (int lane = 0; changeProhibition > 0 && lane < e->getNumLanes(); lane++) {
2210  int code = changeProhibition % 4; // only look at the last 2 bits
2211  SVCPermissions changeLeft = (code & CHANGE_NO_LEFT) == 0 ? SVCAll : SVC_AUTHORITY;
2212  SVCPermissions changeRight = (code & CHANGE_NO_RIGHT) == 0 ? SVCAll : SVC_AUTHORITY;
2213  e->setPermittedChanging(lane, changeLeft, changeRight);
2214  if (multiLane) {
2215  changeProhibition = changeProhibition >> 2;
2216  }
2217  }
2218 }
2219 
2220 void
2221 NIImporter_OpenStreetMap::applyLaneUseInformation(NBEdge* e, const std::vector<SVCPermissions>& laneUse) {
2222  if (myImportLaneAccess && laneUse.size() > 0) {
2223  if ((int)laneUse.size() == e->getNumLanes()) {
2224  const bool lefthand = OptionsCont::getOptions().getBool("lefthand");
2225  for (int lane = 0; lane < (int)laneUse.size(); lane++) {
2226  // laneUse stores from left to right
2227  const int i = lefthand ? lane : e->getNumLanes() - 1 - lane;
2228  SVCPermissions svc = e->getPermissions(lane);
2229  if (laneUse[i] == 0) {
2230  svc = SVC_IGNORING;
2231  } else if ((laneUse[i] & SVC_PASSENGER) == 0) {
2232  svc &= ~SVC_PASSENGER;
2233  }
2234  e->setPermissions(svc, lane);
2235  }
2236  } else {
2237  WRITE_WARNINGF("Ignoring lane use information for % lanes on edge % with % lanes", laneUse.size(), e->getID(), e->getNumLanes());
2238  }
2239  }
2240 }
2241 
2242 void
2243 NIImporter_OpenStreetMap::applyTurnSigns(NBEdge* e, const std::vector<int>& turnSigns) {
2244  if (myImportTurnSigns && turnSigns.size() > 0) {
2245  // no sidewalks and bike lanes have been added yet
2246  if ((int)turnSigns.size() == e->getNumLanes()) {
2247  const bool lefthand = OptionsCont::getOptions().getBool("lefthand");
2248  //std::cout << "apply turnSigns for " << e->getID() << " turnSigns=" << toString(turnSigns) << "\n";
2249  for (int i = 0; i < (int)turnSigns.size(); i++) {
2250  // laneUse stores from left to right
2251  const int laneIndex = lefthand ? i : e->getNumLanes() - 1 - i;
2252  NBEdge::Lane& lane = e->getLaneStruct(laneIndex);
2253  lane.turnSigns = turnSigns[i];
2254  }
2255  } else {
2256  WRITE_WARNINGF("Ignoring turn sign information for % lanes on edge % with % driving lanes", turnSigns.size(), e->getID(), e->getNumLanes());
2257  }
2258  }
2259 }
2260 
2261 /****************************************************************************/
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:281
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:282
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:288
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:280
#define PROGRESS_DONE_MESSAGE()
Definition: MsgHandler.h:284
#define PROGRESS_BEGIN_MESSAGE(msg)
Definition: MsgHandler.h:283
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition: NBCont.h:35
#define KM_PER_MILE
const SVCPermissions SVCAll
all VClasses are allowed
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
StringBijection< SUMOVehicleClass > SumoVehicleClassStrings(sumoVehicleClassStringInitializer, SVC_CUSTOM2, false)
bool isBikepath(SVCPermissions permissions)
Returns whether an edge with the given permission is a bicycle edge.
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types.
@ SVC_ROAD_CLASSES
classes which drive on roads
@ SVC_IGNORING
vehicles ignoring classes
@ SVC_RAIL
vehicle is a not electrified rail
@ SVC_RAIL_CLASSES
classes which drive on tracks
@ SVC_PASSENGER
vehicle is a passenger car (a "normal" car)
@ SVC_BICYCLE
vehicle is a bicycle
@ SVC_RAIL_FAST
vehicle that is allowed to drive on high-speed rail tracks
@ SVC_RAIL_ELECTRIC
rail vehicle that requires electrified tracks
@ SVC_RAIL_URBAN
vehicle is a city rail
@ SVC_AUTHORITY
authorities vehicles
@ SVC_TRAM
vehicle is a light rail
@ SVC_TAXI
vehicle is a taxi
@ SVC_BUS
vehicle is a bus
@ SVC_PEDESTRIAN
pedestrian
int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
TrafficLightType
@ SUMO_TAG_MEMBER
@ SUMO_TAG_ND
@ SUMO_TAG_WAY
@ SUMO_TAG_NODE
alternative definition for junction
@ SUMO_TAG_RELATION
@ SUMO_TAG_TAG
LaneSpreadFunction
Numbers representing special SUMO-XML-attribute values Information how the edge's lateral offset shal...
@ PARTLEFT
The link is a partial left direction.
@ RIGHT
The link is a (hard) right direction.
@ TURN
The link is a 180 degree turn.
@ LEFT
The link is a (hard) left direction.
@ STRAIGHT
The link is a straight direction.
@ PARTRIGHT
The link is a partial right direction.
@ NODIR
The link has no direction (is a dead end link)
@ SUMO_ATTR_LON
@ SUMO_ATTR_V
@ SUMO_ATTR_REF
@ SUMO_ATTR_LAT
@ SUMO_ATTR_TYPE
@ SUMO_ATTR_ID
@ SUMO_ATTR_K
const double SUMO_const_laneWidth
Definition: StdDefs.h:48
T MIN2(T a, T b)
Definition: StdDefs.h:74
T ISNAN(T a)
Definition: StdDefs.h:115
T MAX2(T a, T b)
Definition: StdDefs.h:80
std::string joinToStringSorting(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:285
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:269
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
static bool isReadable(std::string path)
Checks whether the given file is readable.
Definition: FileHelpers.cpp:49
void setFileName(const std::string &name)
Sets the current file name.
Storage for edges, including some functionality operating on multiple edges.
Definition: NBEdgeCont.h:59
bool insert(NBEdge *edge, bool ignorePrunning=false)
Adds an edge to the dictionary.
Definition: NBEdgeCont.cpp:178
The representation of a single edge during network building.
Definition: NBEdge.h:91
bool addEdge2EdgeConnection(NBEdge *dest, bool overrideRemoval=false)
Adds a connection to another edge.
Definition: NBEdge.cpp:1026
void setPermittedChanging(int lane, SVCPermissions changeLeft, SVCPermissions changeRight)
set allowed classes for changing to the left and right from the given lane
Definition: NBEdge.cpp:4013
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:4022
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:3985
void addBikeLane(double width)
add a bicycle lane of the given width and shift existing connctions
Definition: NBEdge.cpp:4227
void setTurnSignTarget(const std::string &target)
Definition: NBEdge.h:1494
void setDistance(double distance)
set lane specific speed (negative lane implies set for all lanes)
Definition: NBEdge.h:1363
const std::string & getID() const
Definition: NBEdge.h:1465
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:541
void addSidewalk(double width)
add a pedestrian sidewalk of the given width and shift existing connctions
Definition: NBEdge.cpp:4215
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:515
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition: NBEdge.h:752
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:1372
bool isConnectedTo(const NBEdge *e, const bool ignoreTurnaround=false) const
Returns the information whethe a connection to the given edge has been added (or computed)
Definition: NBEdge.cpp:1255
static const double UNSPECIFIED_WIDTH
unspecified lane width
Definition: NBEdge.h:349
static const double UNSPECIFIED_OFFSET
unspecified lane offset
Definition: NBEdge.h:352
Lane & getLaneStruct(int lane)
Definition: NBEdge.h:1368
void setGeometry(const PositionVector &g, bool inner=false)
(Re)sets the edge's geometry
Definition: NBEdge.cpp:633
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:534
Instance responsible for building networks.
Definition: NBNetBuilder.h:107
static bool transformCoordinates(PositionVector &from, bool includeInBoundary=true, GeoConvHelper *from_srs=0)
NBTypeCont & getTypeCont()
Returns a reference to the type container.
Definition: NBNetBuilder.h:158
NBParkingCont & getParkingCont()
Definition: NBNetBuilder.h:184
NBPTLineCont & getPTLineCont()
Returns a reference to the pt line container.
Definition: NBNetBuilder.h:179
static bool transformCoordinate(Position &from, bool includeInBoundary=true, GeoConvHelper *from_srs=0)
transforms loaded coordinates handles projections, offsets (using GeoConvHelper) and import of height...
NBEdgeCont & getEdgeCont()
Definition: NBNetBuilder.h:148
NBPTStopCont & getPTStopCont()
Returns a reference to the pt stop container.
Definition: NBNetBuilder.h:174
NBNodeCont & getNodeCont()
Returns a reference to the node container.
Definition: NBNetBuilder.h:153
NBTrafficLightLogicCont & getTLLogicCont()
Returns a reference to the traffic light logics container.
Definition: NBNetBuilder.h:163
Container for nodes during the netbuilding process.
Definition: NBNodeCont.h:58
bool insert(const std::string &id, const Position &position, NBDistrict *district=0)
Inserts a node into the map.
Definition: NBNodeCont.cpp:90
NBNode * retrieve(const std::string &id) const
Returns the node with the given name.
Definition: NBNodeCont.cpp:119
Represents a single node (junction) during network building.
Definition: NBNode.h:66
bool hasIncoming(const NBEdge *const e) const
Returns whether the given edge ends at this node.
Definition: NBNode.cpp:1744
void reinit(const Position &position, SumoXMLNodeType type, bool updateEdgeGeometries=false)
Resets initial values.
Definition: NBNode.cpp:307
SumoXMLNodeType getType() const
Returns the type of this node.
Definition: NBNode.h:273
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges (The edges which start at this node)
Definition: NBNode.h:261
const EdgeVector & getEdges() const
Returns all edges which participate in this node (Edges that start or end at this node)
Definition: NBNode.h:266
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges (The edges which yield in this node)
Definition: NBNode.h:256
const Position & getPosition() const
Definition: NBNode.h:248
A traffic light logics which must be computed (only nodes/edges are given)
Definition: NBOwnTLDef.h:44
void addPTStop(NBPTStop *pStop)
Definition: NBPTLine.cpp:44
const std::string & getLineID() const
Definition: NBPTLine.h:47
void addWayNode(long long int way, long long int node)
Definition: NBPTLine.cpp:99
void setMyNumOfStops(int numStops)
Definition: NBPTLine.cpp:142
std::vector< NBPTStop * > getStops()
Definition: NBPTLine.cpp:56
bool insert(NBPTStop *ptStop)
Inserts a node into the map.
int cleanupDeleted(NBEdgeCont &cont)
remove stops on non existing (removed) edges
NBPTStop * get(std::string id) const
Retrieve a previously inserted pt stop.
The representation of a single pt stop.
Definition: NBPTStop.h:46
void registerAdditionalEdge(std::string wayId, std::string edgeId)
Definition: NBPTStop.cpp:195
void addPlatformCand(NBPTPlatform platform)
Definition: NBPTStop.cpp:157
void setIsPlatform()
Definition: NBPTStop.h:104
void setIsMultipleStopPositions(bool multipleStopPositions, long long int areaID)
Definition: NBPTStop.cpp:175
The representation of an imported parking area.
Definition: NBParking.h:42
A container for traffic light definitions and built programs.
bool insert(NBTrafficLightDefinition *logic, bool forceInsert=false)
Adds a logic definition to the dictionary.
A storage for available edgeTypes of edges.
Definition: NBTypeCont.h:52
bool getEdgeTypeShallBeDiscarded(const std::string &edgeType) const
Returns the information whether edges of this edgeType shall be discarded.
Definition: NBTypeCont.cpp:494
void insertEdgeType(const std::string &id, int numLanes, double maxSpeed, int prio, SVCPermissions permissions, LaneSpreadFunction spreadType, double width, bool oneWayIsDefault, double sidewalkWidth, double bikeLaneWidth, double widthResolution, double maxWidth, double minWidth)
Adds a edgeType into the list.
Definition: NBTypeCont.cpp:194
bool copyEdgeTypeRestrictionsAndAttrs(const std::string &fromId, const std::string &toId)
Copy restrictions to a edgeType.
Definition: NBTypeCont.cpp:330
double getEdgeTypeSpeed(const std::string &edgeType) const
Returns the maximal velocity for the given edgeType [m/s].
Definition: NBTypeCont.cpp:476
int getEdgeTypePriority(const std::string &edgeType) const
Returns the priority for the given edgeType.
Definition: NBTypeCont.cpp:482
int getEdgeTypeNumLanes(const std::string &edgeType) const
Returns the number of lanes for the given edgeType.
Definition: NBTypeCont.cpp:470
double getEdgeTypeWidth(const std::string &edgeType) const
Returns the lane width for the given edgeType [m].
Definition: NBTypeCont.cpp:532
SVCPermissions getEdgeTypePermissions(const std::string &edgeType) const
Returns allowed vehicle classes for the given edgeType.
Definition: NBTypeCont.cpp:520
bool knows(const std::string &edgeType) const
Returns whether the named edgeType is in the container.
Definition: NBTypeCont.cpp:291
double getEdgeTypeSidewalkWidth(const std::string &edgeType) const
Returns the lane width for a sidewalk to be added [m].
Definition: NBTypeCont.cpp:538
LaneSpreadFunction getEdgeTypeSpreadType(const std::string &edgeType) const
Returns spreadType for the given edgeType.
Definition: NBTypeCont.cpp:526
double getEdgeTypeBikeLaneWidth(const std::string &edgeType) const
Returns the lane width for a bike lane to be added [m].
Definition: NBTypeCont.cpp:544
bool getEdgeTypeIsOneWay(const std::string &edgeType) const
Returns whether edges are one-way per default for the given edgeType.
Definition: NBTypeCont.cpp:488
bool operator()(const Edge *e1, const Edge *e2) const
An internal definition of a loaded edge.
WayType mySidewalkType
Information about the kind of sidwalk along this road.
std::vector< SVCPermissions > myLaneUseForward
(optional) information about the permitted vehicle classes on each lane
bool myCurrentIsRoad
Information whether this is a road.
WayType myCyclewayType
Information about the kind of cycleway along this road.
int myNoLanesForward
number of lanes in forward direction or 0 if unknown, negative if backwards lanes are meant
double myMaxSpeed
maximum speed in km/h, or MAXSPEED_UNGIVEN
bool myCurrentIsElectrified
Information whether this is railway is electrified.
std::string ref
The edge's track name.
std::string myHighWayType
The type, stored in "highway" key.
const long long int id
The edge's id.
int myLayer
Information about the relative z-ordering of ways.
SVCPermissions myExtraDisallowed
Extra permissions prohibited from tags instead of highway type.
std::vector< SVCPermissions > myLaneUseBackward
int myNoLanes
number of lanes, or -1 if unknown
std::vector< int > myTurnSignsForward
turning direction (arrows printed on the road)
std::vector< long long int > myCurrentNodes
The list of nodes this edge is made of.
int myParkingType
Information about road-side parking.
double myMaxSpeedBackward
maximum speed in km/h, or MAXSPEED_UNGIVEN
WayType myBuswayType
Information about the kind of busway along this road.
int myChangeForward
Information about change prohibitions (forward direction.
SVCPermissions myExtraAllowed
Extra permissions added from tags instead of highway type.
int myChangeBackward
Information about change prohibitions (backward direction.
std::string streetName
The edge's street name.
WayType myRailDirection
Information about the direction(s) of railway usage.
std::string myIsOneWay
Information whether this is an one-way road.
A class which extracts OSM-edges from a parsed OSM-file.
std::set< std::string > myExtraAttributes
extra attributes to import
EdgesHandler(const std::map< long long int, NIOSMNode * > &osmNodes, std::map< long long int, Edge * > &toFill, std::map< long long int, Edge * > &platformShapes)
Constructor.
int interpretChangeType(const std::string &value) const
bool myAllAttributes
whether additional way attributes shall be added to the edge
bool myImportBikeAccess
import bike path specific permissions and directions
void myEndElement(int element) override
Called when a closing tag occurs.
double interpretSpeed(const std::string &key, std::string value)
std::map< std::string, double > mySpeedMap
A map of non-numeric speed descriptions to their numeric values.
void myStartElement(int element, const SUMOSAXAttributes &attrs) override
Called on the opening of a tag;.
void interpretLaneUse(const std::string &value, SUMOVehicleClass svc, std::vector< SVCPermissions > &result) const
A class which extracts OSM-nodes from a parsed OSM-file.
void myStartElement(int element, const SUMOSAXAttributes &attrs) override
Called on the opening of a tag;.
NodesHandler(std::map< long long int, NIOSMNode * > &toFill, std::set< NIOSMNode *, CompareNodes > &uniqueNodes, const OptionsCont &cont)
Contructor.
void myEndElement(int element) override
Called when a closing tag occurs.
A class which extracts relevant relation information from a parsed OSM-file.
void myEndElement(int element) override
Called when a closing tag occurs.
void resetValues()
reset members to their defaults for parsing a new relation
void myStartElement(int element, const SUMOSAXAttributes &attrs) override
Called on the opening of a tag;.
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.
bool checkEdgeRef(long long int ref) const
check whether a referenced way has a corresponding edge
bool applyRestriction() const
try to apply the parsed restriction and return whether successful
NBEdge * findEdgeRef(long long int wayRef, const std::vector< NBEdge * > &candidates) const
try to find the way segment among candidates
Importer for networks stored in OpenStreetMap format.
int insertEdge(Edge *e, int index, NBNode *from, NBNode *to, const std::vector< long long int > &passed, NBNetBuilder &nb, const NBNode *first, const NBNode *last)
Builds an NBEdge.
std::map< long long int, Edge * > myEdges
the map from OSM way ids to edge objects
std::map< long long int, NIOSMNode * > myOSMNodes
the map from OSM node ids to actual nodes
static void loadNetwork(const OptionsCont &oc, NBNetBuilder &nb)
Loads content of the optionally given OSM file.
static const long long int INVALID_ID
static const double MAXSPEED_UNGIVEN
std::map< long long int, Edge * > myPlatformShapes
the map from OSM way ids to platform shapes
void load(const OptionsCont &oc, NBNetBuilder &nb)
void applyTurnSigns(NBEdge *e, const std::vector< int > &turnSigns)
bool myImportSidewalks
import sidewalks
std::set< NIOSMNode *, CompareNodes > myUniqueNodes
the set of unique nodes used in NodesHandler, used when freeing memory
void reconstructLayerElevation(double layerElevation, NBNetBuilder &nb)
reconstruct elevation from layer info
static SUMOVehicleClass interpretTransportType(const std::string &type, NIOSMNode *toSet=nullptr)
translate osm transport designations into sumo vehicle class
bool myImportLaneAccess
import lane specific access restrictions
bool myImportTurnSigns
import turning signals (turn:lanes) to guide connection building
std::map< std::string, std::string > myKnownCompoundTypes
The compound types that have already been mapped to other known types.
static const std::string compoundTypeSeparator
The separator within newly created compound type names.
std::set< std::string > myUnusableTypes
The compounds types that do not contain known types.
std::map< NBNode *, std::pair< double, double > > getNeighboringNodes(NBNode *node, double maxDist, const std::set< NBNode * > &knownElevation)
collect neighboring nodes with their road distance and maximum between-speed. Search does not continu...
static double interpretDistance(NIOSMNode *node)
read distance value from node and return value in m
NBNode * insertNodeChecking(long long int id, NBNodeCont &nc, NBTrafficLightLogicCont &tlsc)
Builds an NBNode.
void extendRailwayDistances(Edge *e, NBTypeCont &tc)
extend kilometrage data for all nodes along railway
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
void applyLaneUseInformation(NBEdge *e, const std::vector< SVCPermissions > &laneUse)
static void applyChangeProhibition(NBEdge *e, int changeProhibition)
const std::string & getID() const
Returns the id.
Definition: Named.h:74
A storage for options typed value containers)
Definition: OptionsCont.h:89
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
const StringVector & getStringVector(const std::string &name) const
Returns the list of string-value of the named option (only for Option_StringVector)
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:58
void unsetParameter(const std::string &key)
Removes a parameter.
virtual void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
void updateParameters(const std::map< std::string, std::string > &mapArg)
Adds or updates all given parameters from the map.
const std::map< std::string, std::string > & getParametersMap() const
Returns the inner key/value map.
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:37
A list of positions.
double length2D() const
Returns the length.
double length() const
Returns the length.
PositionVector reverse() const
reverse position vector
static RGBColor parseColor(std::string coldef)
Parses a color information.
Definition: RGBColor.cpp:236
Encapsulated SAX-Attributes.
virtual std::string getStringSecure(int id, const std::string &def) const =0
Returns the string-value of the named (by its enum-value) attribute.
T get(int attr, const char *objectid, bool &ok, bool report=true) const
Tries to read given attribute assuming it is an int.
virtual bool hasAttribute(int id) const =0
Returns the information whether the named (by its enum-value) attribute is within the current list.
SAX-handler base for SUMO-files.
static StringBijection< TrafficLightType > TrafficLightTypes
traffic light types
T get(const std::string &str) const
int size() const
returns the number of existing substrings
std::vector< std::string > getVector()
return vector of strings
bool hasNext()
returns the information whether further substrings exist
std::string next()
returns the next substring when it exists. Otherwise the behaviour is undefined
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter
static std::string escapeXML(const std::string &orig, const bool maskDoubleHyphen=false)
Replaces the standard escapes by their XML entities.
static std::string to_lower_case(std::string str)
Transfers the content to lower case.
Definition: StringUtils.cpp:59
static std::string prune(const std::string &str)
Removes trailing and leading whitechars.
Definition: StringUtils.cpp:48
static bool startsWith(const std::string &str, const std::string prefix)
Checks whether a given string starts with the prefix.
static bool endsWith(const std::string &str, const std::string suffix)
Checks whether a given string ends with the suffix.
static int toInt(const std::string &sData)
converts a string into the integer value described by it by calling the char-type converter,...
static bool toBool(const std::string &sData)
converts a string into the bool value described by it by calling the char-type converter
static bool runParser(GenericSAXHandler &handler, const std::string &file, const bool isNet=false, const bool isRoute=false)
Runs the given handler on the given file; returns if everything's ok.
Definition: XMLSubSys.cpp:149
An (internal) definition of a single lane of an edge.
Definition: NBEdge.h:142
int turnSigns
turning signs printed on the road, bitset of LinkDirection (imported from OSM)
Definition: NBEdge.h:191
An internal representation of an OSM-node.
SVCPermissions permissions
type of pt stop
NBNode * node
the NBNode that was instantiated
double positionMeters
position converted to m (using highest precision available)
std::string position
kilometrage/mileage
const long long int id
The node's id.
bool tlsControlled
Whether this is a tls controlled junction.
double ptStopLength
The length of the pt stop.
bool ptStopPosition
Whether this is a public transport stop position.
std::string name
The name of the node.
bool railwayCrossing
Whether this is a railway crossing.
double ele
The elevation of this node.
bool railwayBufferStop
Whether this is a railway buffer stop.
const double lon
The longitude the node is located at.
const double lat
The latitude the node is located at.
bool railwaySignal
Whether this is a railway (main) signal.