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.dev/sumo
3 // Copyright (C) 2001-2024 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 /****************************************************************************/
23 // Importer for networks stored in OpenStreetMap format
24 /****************************************************************************/
25 #include <config.h>
26 #include <algorithm>
27 #include <set>
28 #include <functional>
29 #include <sstream>
30 #include <limits>
33 #include <utils/common/ToString.h>
44 #include <utils/xml/XMLSubSys.h>
45 #include <netbuild/NBEdge.h>
46 #include <netbuild/NBEdgeCont.h>
47 #include <netbuild/NBNode.h>
48 #include <netbuild/NBNodeCont.h>
49 #include <netbuild/NBNetBuilder.h>
50 #include <netbuild/NBOwnTLDef.h>
51 #include <netbuild/NBPTLine.h>
52 #include <netbuild/NBPTLineCont.h>
53 #include <netbuild/NBPTPlatform.h>
54 #include <netbuild/NBPTStop.h>
55 #include "NILoader.h"
57 
58 #define KM_PER_MILE 1.609344
59 
60 //#define DEBUG_LAYER_ELEVATION
61 //#define DEBUG_RAIL_DIRECTION
62 
63 // ---------------------------------------------------------------------------
64 // static members
65 // ---------------------------------------------------------------------------
67 
68 const long long int NIImporter_OpenStreetMap::INVALID_ID = std::numeric_limits<long long int>::max();
71 
72 // ===========================================================================
73 // Private classes
74 // ===========================================================================
75 
79 public:
80  bool operator()(const Edge* e1, const Edge* e2) const {
81  if (e1->myHighWayType != e2->myHighWayType) {
82  return e1->myHighWayType > e2->myHighWayType;
83  }
84  if (e1->myNoLanes != e2->myNoLanes) {
85  return e1->myNoLanes > e2->myNoLanes;
86  }
87  if (e1->myNoLanesForward != e2->myNoLanesForward) {
88  return e1->myNoLanesForward > e2->myNoLanesForward;
89  }
90  if (e1->myMaxSpeed != e2->myMaxSpeed) {
91  return e1->myMaxSpeed > e2->myMaxSpeed;
92  }
93  if (e1->myIsOneWay != e2->myIsOneWay) {
94  return e1->myIsOneWay > e2->myIsOneWay;
95  }
96  return e1->myCurrentNodes > e2->myCurrentNodes;
97  }
98 };
99 
100 // ===========================================================================
101 // method definitions
102 // ===========================================================================
103 // ---------------------------------------------------------------------------
104 // static methods
105 // ---------------------------------------------------------------------------
106 const std::string NIImporter_OpenStreetMap::compoundTypeSeparator("|"); //clang-tidy says: "compundTypeSeparator with
107 // static storage duration my throw an exception that cannot be caught
108 
109 void
111  NIImporter_OpenStreetMap importer;
112  importer.load(oc, nb);
113 }
114 
116 
118  // delete nodes
119  for (auto myUniqueNode : myUniqueNodes) {
120  delete myUniqueNode;
121  }
122  // delete edges
123  for (auto& myEdge : myEdges) {
124  delete myEdge.second;
125  }
126  // delete platform shapes
127  for (auto& myPlatformShape : myPlatformShapes) {
128  delete myPlatformShape.second;
129  }
130 }
131 
132 void
134  if (!oc.isSet("osm-files")) {
135  return;
136  }
137  const std::vector<std::string> files = oc.getStringVector("osm-files");
138  std::vector<SUMOSAXReader*> readers;
139 
140  myImportLaneAccess = oc.getBool("osm.lane-access");
141  myImportTurnSigns = oc.getBool("osm.turn-lanes");
142  myImportSidewalks = oc.getBool("osm.sidewalks");
143  myImportBikeAccess = oc.getBool("osm.bike-access");
144  myImportCrossings = oc.getBool("osm.crossings");
145 
146  myAllAttributes = OptionsCont::getOptions().getBool("osm.all-attributes");
147  std::vector<std::string> extra = OptionsCont::getOptions().getStringVector("osm.extra-attributes");
148  myExtraAttributes.insert(extra.begin(), extra.end());
149  if (myExtraAttributes.count("all") != 0) {
150  // import all
151  myExtraAttributes.clear();
152  }
153 
154  // load nodes, first
155  NodesHandler nodesHandler(myOSMNodes, myUniqueNodes, oc);
156  for (const std::string& file : files) {
157  if (!FileHelpers::isReadable(file)) {
158  WRITE_ERRORF(TL("Could not open osm-file '%'."), file);
159  return;
160  }
161  nodesHandler.setFileName(file);
162  nodesHandler.resetHierarchy();
163  const long before = PROGRESS_BEGIN_TIME_MESSAGE("Parsing nodes from osm-file '" + file + "'");
164  readers.push_back(XMLSubSys::getSAXReader(nodesHandler));
165  if (!readers.back()->parseFirst(file) || !readers.back()->parseSection(SUMO_TAG_NODE) ||
167  return;
168  }
169  if (nodesHandler.getDuplicateNodes() > 0) {
170  WRITE_MESSAGEF(TL("Found and substituted % osm nodes."), toString(nodesHandler.getDuplicateNodes()));
171  }
172  PROGRESS_TIME_MESSAGE(before);
173  }
174 
175  // load edges, then
177  int idx = 0;
178  for (const std::string& file : files) {
179  edgesHandler.setFileName(file);
180  readers[idx]->setHandler(edgesHandler);
181  const long before = PROGRESS_BEGIN_TIME_MESSAGE("Parsing edges from osm-file '" + file + "'");
182  if (!readers[idx]->parseSection(SUMO_TAG_WAY)) {
183  // eof already reached, no relations
184  delete readers[idx];
185  readers[idx] = nullptr;
186  }
187  PROGRESS_TIME_MESSAGE(before);
188  idx++;
189  }
190 
191  /* Remove duplicate edges with the same shape and attributes */
192  if (!oc.getBool("osm.skip-duplicates-check")) {
193  int numRemoved = 0;
194  PROGRESS_BEGIN_MESSAGE(TL("Removing duplicate edges"));
195  if (myEdges.size() > 1) {
196  std::set<const Edge*, CompareEdges> dupsFinder;
197  for (auto it = myEdges.begin(); it != myEdges.end();) {
198  if (dupsFinder.count(it->second) > 0) {
199  numRemoved++;
200  delete it->second;
201  myEdges.erase(it++);
202  } else {
203  dupsFinder.insert(it->second);
204  it++;
205  }
206  }
207  }
208  if (numRemoved > 0) {
209  WRITE_MESSAGEF(TL("Removed % duplicate osm edges."), toString(numRemoved));
210  }
212  }
213 
214  /* Mark which nodes are used (by edges or traffic lights).
215  * This is necessary to detect which OpenStreetMap nodes are for
216  * geometry only */
217  std::map<long long int, int> nodeUsage;
218  // Mark which nodes are used by edges (begin and end)
219  for (const auto& edgeIt : myEdges) {
220  assert(edgeIt.second->myCurrentIsRoad);
221  for (const long long int node : edgeIt.second->myCurrentNodes) {
222  nodeUsage[node]++;
223  }
224  }
225  // Mark which nodes are used by traffic lights or are pedestrian crossings
226  for (const auto& nodesIt : myOSMNodes) {
227  if (nodesIt.second->tlsControlled || nodesIt.second->railwaySignal || (nodesIt.second->pedestrianCrossing && myImportCrossings) /* || nodesIt->second->railwayCrossing*/) {
228  // If the key is not found in the map, the value is automatically
229  // initialized with 0.
230  nodeUsage[nodesIt.first]++;
231  }
232  }
233 
234  /* Instantiate edges
235  * Only those nodes in the middle of an edge which are used by more than
236  * one edge are instantiated. Other nodes are considered as geometry nodes. */
237  NBNodeCont& nc = nb.getNodeCont();
239  for (const auto& edgeIt : myEdges) {
240  Edge* const e = edgeIt.second;
241  assert(e->myCurrentIsRoad);
242  if (e->myCurrentNodes.size() < 2) {
243  WRITE_WARNINGF(TL("Discarding way '%' because it has only % node(s)"), e->id, e->myCurrentNodes.size());
244  continue;
245  }
247  // build nodes;
248  // - the from- and to-nodes must be built in any case
249  // - the in-between nodes are only built if more than one edge references them
250  NBNode* first = insertNodeChecking(e->myCurrentNodes.front(), nc, tlsc);
251  NBNode* last = insertNodeChecking(e->myCurrentNodes.back(), nc, tlsc);
252  NBNode* currentFrom = first;
253  int running = 0;
254  std::vector<long long int> passed;
255  for (auto j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
256  passed.push_back(*j);
257  if (nodeUsage[*j] > 1 && j != e->myCurrentNodes.end() - 1 && j != e->myCurrentNodes.begin()) {
258  NBNode* currentTo = insertNodeChecking(*j, nc, tlsc);
259  running = insertEdge(e, running, currentFrom, currentTo, passed, nb, first, last);
260  currentFrom = currentTo;
261  passed.clear();
262  passed.push_back(*j);
263  }
264  }
265  if (running == 0) {
266  running = -1;
267  }
268  insertEdge(e, running, currentFrom, last, passed, nb, first, last);
269  }
270 
271  /* Collect edges which explictly are part of a roundabout and store the edges of each
272  * detected roundabout */
274 
275  if (myImportCrossings) {
276  /* After edges are instantiated
277  * nodes are parsed again to add pedestrian crossings to them
278  * This is only executed if crossings are imported and not guessed */
279  const double crossingWidth = OptionsCont::getOptions().getFloat("default.crossing-width");
280 
281  for (const auto& nodeIt : nc) {
282  NBNode* const n = nodeIt.second;
283  if (n->hasParameter("computePedestrianCrossing")) {
284  EdgeVector incomingEdges = n->getIncomingEdges();
285  EdgeVector outgoingEdges = n->getOutgoingEdges();
286  size_t incomingEdgesNo = incomingEdges.size();
287  size_t outgoingEdgesNo = outgoingEdges.size();
288 
289  for (size_t i = 0; i < incomingEdgesNo; i++) {
290  /* Check if incoming edge has driving lanes(and sidewalks)
291  * if not, ignore
292  * if yes, check if there is a corresponding outgoing edge for the opposite direction
293  * -> if yes, check if it has driving lanes
294  * --> if yes, do the crossing
295  * --> if no, only do the crossing with the incoming edge (usually one lane roads with two sidewalks)
296  * -> if not, do nothing as we don't have a sidewalk in the opposite direction */
297  auto const iEdge = incomingEdges[i];
298 
299  if (iEdge->getFirstNonPedestrianLaneIndex(NBNode::FORWARD) > -1
300  && iEdge->getSpecialLane(SVC_PEDESTRIAN) > -1) {
301  std::string const& iEdgeId = iEdge->getID();
302  std::size_t const m = iEdgeId.find_first_of("#");
303  std::string const& iWayId = iEdgeId.substr(0, m);
304  for (size_t j = 0; j < outgoingEdgesNo; j++) {
305  auto const oEdge = outgoingEdges[j];
306  // Searching for a corresponding outgoing edge (based on OSM way identifier)
307  // with at least a pedestrian lane, going in the opposite direction
308  if (oEdge->getID().find(iWayId) != std::string::npos
309  && oEdge->getSpecialLane(SVC_PEDESTRIAN) > -1
310  && oEdge->getID().rfind(iWayId, 0) != 0) {
311  EdgeVector edgeVector = EdgeVector{ iEdge };
312  if (oEdge->getFirstNonPedestrianLaneIndex(NBNode::FORWARD) > -1) {
313  edgeVector.push_back(oEdge);
314  }
315 
316  if (!n->checkCrossingDuplicated(edgeVector)) {
317  n->addCrossing(edgeVector, crossingWidth, false);
318  }
319  }
320  }
321  }
322  }
323  for (size_t i = 0; i < outgoingEdgesNo; i++) {
324  // Same checks as above for loop, but for outgoing edges
325  auto const oEdge = outgoingEdges[i];
326 
327  if (oEdge->getFirstNonPedestrianLaneIndex(NBNode::FORWARD) > -1
328  && oEdge->getSpecialLane(SVC_PEDESTRIAN) > -1) {
329  std::string const& oEdgeId = oEdge->getID();
330  std::size_t const m = oEdgeId.find_first_of("#");
331  std::string const& iWayId = oEdgeId.substr(0, m);
332  for (size_t j = 0; j < incomingEdgesNo; j++) {
333  auto const iEdge = incomingEdges[j];
334  if (iEdge->getID().find(iWayId) != std::string::npos
335  && iEdge->getSpecialLane(SVC_PEDESTRIAN) > -1
336  && iEdge->getID().rfind(iWayId, 0) != 0) {
337  EdgeVector edgeVector = EdgeVector{ oEdge };
338  if (iEdge->getFirstNonPedestrianLaneIndex(NBNode::FORWARD) > -1) {
339  edgeVector.push_back(iEdge);
340  }
341 
342  if (!n->checkCrossingDuplicated(edgeVector)) {
343  n->addCrossing(edgeVector, crossingWidth, false);
344  }
345  }
346  }
347  }
348  }
349  n->unsetParameter("computePedestrianCrossing");
350  }
351  }
352  }
353 
354  const double layerElevation = oc.getFloat("osm.layer-elevation");
355  if (layerElevation > 0) {
356  reconstructLayerElevation(layerElevation, nb);
357  }
358 
359  // revise pt stops; remove stops on deleted edges
361 
362  // load relations (after edges are built since we want to apply
363  // turn-restrictions directly to NBEdges)
365  &nb.getPTLineCont(), oc);
366  idx = 0;
367  for (const std::string& file : files) {
368  if (readers[idx] != nullptr) {
369  relationHandler.setFileName(file);
370  readers[idx]->setHandler(relationHandler);
371  const long before = PROGRESS_BEGIN_TIME_MESSAGE("Parsing relations from osm-file '" + file + "'");
372  readers[idx]->parseSection(SUMO_TAG_RELATION);
373  PROGRESS_TIME_MESSAGE(before);
374  delete readers[idx];
375  }
376  idx++;
377  }
378 
379  // declare additional stops that are not anchored to a (road)-way or route relation
380  std::set<std::string> stopNames;
381  for (const auto& item : nb.getPTStopCont().getStops()) {
382  stopNames.insert(item.second->getName());
383  }
384  for (const auto& item : myOSMNodes) {
385  const NIOSMNode* n = item.second;
386  if (n->ptStopPosition && stopNames.count(n->name) == 0) {
387  Position ptPos(n->lon, n->lat, n->ele);
388  if (!NBNetBuilder::transformCoordinate(ptPos)) {
389  WRITE_ERRORF("Unable to project coordinates for node '%'.", n->id);
390  }
391  std::shared_ptr<NBPTStop> ptStop = std::make_shared<NBPTStop>(toString(n->id), ptPos, "", "", n->ptStopLength, n->name, n->permissions);
392  nb.getPTStopCont().insert(ptStop, true);
393  }
394  }
395 }
396 
397 
398 NBNode*
400  NBNode* node = nc.retrieve(toString(id));
401  if (node == nullptr) {
402  NIOSMNode* n = myOSMNodes.find(id)->second;
403  Position pos(n->lon, n->lat, n->ele);
404  if (!NBNetBuilder::transformCoordinate(pos, true)) {
405  WRITE_ERRORF("Unable to project coordinates for junction '%'.", id);
406  return nullptr;
407  }
408  node = new NBNode(toString(id), pos);
409  if (!nc.insert(node)) {
410  WRITE_ERRORF(TL("Could not insert junction '%'."), toString(id));
411  delete node;
412  return nullptr;
413  }
414  n->node = node;
415  if (n->railwayCrossing) {
416  if (n->getParameter("crossing:barrier") != "no") {
418  } else if (n->getParameter("crossing.light") == "yes") {
420  }
421  } else if (n->railwaySignal) {
423  } else if (n->tlsControlled) {
424  // ok, this node is a traffic light node where no other nodes
425  // participate
426  // @note: The OSM-community has not settled on a schema for differentiating between fixed and actuated lights
428  OptionsCont::getOptions().getString("tls.default-type"));
429  NBOwnTLDef* tlDef = new NBOwnTLDef(toString(id), node, 0, type);
430  if (!tlsc.insert(tlDef)) {
431  // actually, nothing should fail here
432  delete tlDef;
433  throw ProcessError(TLF("Could not allocate tls '%'.", toString(id)));
434  }
435  } else if (n->pedestrianCrossing && myImportCrossings) {
436  node->setParameter("computePedestrianCrossing", "true");
437  }
438  if (n->railwayBufferStop) {
439  node->setParameter("buffer_stop", "true");
441  }
442  if (n->railwaySignal) {
443  if (n->myRailDirection == WAY_FORWARD) {
445  } else if (n->myRailDirection == WAY_BACKWARD) {
447  }
448  }
450  }
451  return node;
452 }
453 
454 
455 int
457  const std::vector<long long int>& passed, NBNetBuilder& nb,
458  const NBNode* first, const NBNode* last) {
459  NBNodeCont& nc = nb.getNodeCont();
460  NBEdgeCont& ec = nb.getEdgeCont();
461  NBTypeCont& tc = nb.getTypeCont();
462  NBPTStopCont& sc = nb.getPTStopCont();
463 
465  // patch the id
466  std::string id = toString(e->id);
467  if (from == nullptr || to == nullptr) {
468  WRITE_ERRORF("Discarding edge '%' because the nodes could not be built.", id);
469  return index;
470  }
471  if (index >= 0) {
472  id = id + "#" + toString(index);
473  } else {
474  index = 0;
475  }
476  if (from == to) {
477  assert(passed.size() >= 2);
478  if (passed.size() == 2) {
479  WRITE_WARNINGF(TL("Discarding edge '%' which connects two identical nodes without geometry."), id);
480  return index;
481  }
482  // in the special case of a looped way split again using passed
483  int intermediateIndex = (int) passed.size() / 2;
484  NBNode* intermediate = insertNodeChecking(passed[intermediateIndex], nc, tlsc);
485  std::vector<long long int> part1(passed.begin(), passed.begin() + intermediateIndex + 1);
486  std::vector<long long int> part2(passed.begin() + intermediateIndex, passed.end());
487  index = insertEdge(e, index, from, intermediate, part1, nb, first, last);
488  return insertEdge(e, index, intermediate, to, part2, nb, first, last);
489  }
490  const int newIndex = index + 1;
491  const std::string type = usableType(e->myHighWayType, id, tc);
492  if (type == "") { // we do not want to import it
493  return newIndex;
494  }
495 
496  int numLanesForward = tc.getEdgeTypeNumLanes(type);
497  int numLanesBackward = tc.getEdgeTypeNumLanes(type);
498  double speed = tc.getEdgeTypeSpeed(type);
499  bool defaultsToOneWay = tc.getEdgeTypeIsOneWay(type);
500  const SVCPermissions defaultPermissions = tc.getEdgeTypePermissions(type);
503  // extra permissions are more specific than extra prohibitions
504  SVCPermissions permissions = (defaultPermissions & ~extraDis) | extra;
505  if (defaultPermissions == SVC_SHIP) {
506  // extra permission apply to the ships operating on the route rather than the waterway
507  permissions = defaultPermissions;
508  }
509  if (defaultsToOneWay && defaultPermissions == SVC_PEDESTRIAN && (permissions & (~SVC_PEDESTRIAN)) != 0) {
510  defaultsToOneWay = false;
511  }
512  if ((permissions & SVC_RAIL) != 0 && e->myExtraTags.count("electrified") != 0) {
513  permissions |= (SVC_RAIL_ELECTRIC | SVC_RAIL_FAST);
514  }
515 
516  // convert the shape
517  PositionVector shape;
518  double distanceStart = myOSMNodes[passed.front()]->positionMeters;
519  double distanceEnd = myOSMNodes[passed.back()]->positionMeters;
520  const bool useDistance = distanceStart != std::numeric_limits<double>::max() && distanceEnd != std::numeric_limits<double>::max();
521  if (useDistance) {
522  // negative sign denotes counting in the other direction
523  if (distanceStart < distanceEnd) {
524  distanceStart *= -1;
525  } else {
526  distanceEnd *= -1;
527  }
528  } else {
529  distanceStart = 0;
530  distanceEnd = 0;
531  }
532  // get additional direction information
533  int nodeDirection = myOSMNodes.find(StringUtils::toLong(from->getID()))->second->myRailDirection |
534  myOSMNodes.find(StringUtils::toLong(to->getID()))->second->myRailDirection;
535 
536  std::vector<std::shared_ptr<NBPTStop> > ptStops;
537  for (long long i : passed) {
538  NIOSMNode* n = myOSMNodes.find(i)->second;
539  // recheck permissions, maybe they got assigned to a strange edge, see #11656
540  if (n->ptStopPosition && (n->permissions == 0 || (permissions & n->permissions) != 0)) {
541  std::shared_ptr<NBPTStop> existingPtStop = sc.get(toString(n->id));
542  if (existingPtStop != nullptr) {
543  existingPtStop->registerAdditionalEdge(toString(e->id), id);
544  } else {
545  Position ptPos(n->lon, n->lat, n->ele);
546  if (!NBNetBuilder::transformCoordinate(ptPos)) {
547  WRITE_ERRORF("Unable to project coordinates for node '%'.", n->id);
548  }
549  ptStops.push_back(std::make_shared<NBPTStop>(toString(n->id), ptPos, id, toString(e->id), n->ptStopLength, n->name, n->permissions));
550  sc.insert(ptStops.back());
551  }
552  }
553  if (n->railwaySignal) {
554  nodeDirection |= n->myRailDirection;
555  }
556  Position pos(n->lon, n->lat, n->ele);
557  shape.push_back(pos);
558  }
559 #ifdef DEBUG_LAYER_ELEVATION
560  if (e->id == "DEBUGID") {
561  std::cout
562  << " id=" << id << " from=" << from->getID() << " fromRailDirection=" << myOSMNodes.find(StringUtils::toLong(from->getID()))->second->myRailDirection
563  << " to=" << to->getID() << " toRailDirection=" << myOSMNodes.find(StringUtils::toLong(to->getID()))->second->myRailDirection
564  << " origRailDirection=" << e->myRailDirection
565  << " nodeDirection=" << nodeDirection
566  << "\n";
567  }
568 #endif
569  if (e->myRailDirection == WAY_UNKNOWN && nodeDirection != WAY_UNKNOWN && nodeDirection != WAY_FORWARD
570  && nodeDirection != (WAY_FORWARD | WAY_UNKNOWN)) {
571  //std::cout << "way " << e->id << " nodeDirection=" << nodeDirection << " origDirection=" << e->myRailDirection << "\n";
572  // heuristc: assume that the mapped way direction indicates
573  // potential driving direction
575  }
577  WRITE_ERRORF("Unable to project coordinates for edge '%'.", id);
578  }
579 
580  SVCPermissions forwardPermissions = permissions;
581  SVCPermissions backwardPermissions = permissions;
582  const std::string streetName = isRailway(permissions) && e->ref != "" ? e->ref : e->streetName;
583  if (streetName == e->ref) {
584  e->unsetParameter("ref"); // avoid superfluous param for railways
585  }
586  double forwardWidth = tc.getEdgeTypeWidth(type);
587  double backwardWidth = tc.getEdgeTypeWidth(type);
588  double sidewalkWidth = tc.getEdgeTypeSidewalkWidth(type);
589  bool addSidewalk = sidewalkWidth != NBEdge::UNSPECIFIED_WIDTH;
590  if (myImportSidewalks) {
591  if (addSidewalk) {
592  // only use sidewalk width from typemap but don't add sidewalks
593  // unless OSM specifies them
594  addSidewalk = false;
595  } else {
596  sidewalkWidth = OptionsCont::getOptions().getFloat("default.sidewalk-width");
597  }
598  }
599  double bikeLaneWidth = tc.getEdgeTypeBikeLaneWidth(type);
600  const std::string& onewayBike = e->myExtraTags["oneway:bicycle"];
601  if (onewayBike == "false" || onewayBike == "no" || onewayBike == "0") {
603  }
604 
605  const bool addBikeLane = bikeLaneWidth != NBEdge::UNSPECIFIED_WIDTH ||
606  (myImportBikeAccess && (((e->myCyclewayType & WAY_BOTH) != 0 || e->myExtraTags.count("segregated") != 0) &&
607  !(e->myCyclewayType == WAY_BACKWARD && (e->myBuswayType & WAY_BOTH) != 0)));
608  if (addBikeLane && bikeLaneWidth == NBEdge::UNSPECIFIED_WIDTH) {
609  bikeLaneWidth = OptionsCont::getOptions().getFloat("default.bikelane-width");
610  }
611  // check directions
612  bool addForward = true;
613  bool addBackward = true;
614  const bool explicitTwoWay = e->myIsOneWay == "no";
615  if ((e->myIsOneWay == "true" || e->myIsOneWay == "yes" || e->myIsOneWay == "1"
616  || (defaultsToOneWay && e->myIsOneWay != "no" && e->myIsOneWay != "false" && e->myIsOneWay != "0"))
617  && e->myRailDirection != WAY_BOTH) {
618  addBackward = false;
619  }
620  if (e->myIsOneWay == "-1" || e->myIsOneWay == "reverse" || e->myRailDirection == WAY_BACKWARD) {
621  // one-way in reversed direction of way
622  addForward = false;
623  addBackward = true;
624  }
625  if (!e->myIsOneWay.empty() && e->myIsOneWay != "false" && e->myIsOneWay != "no" && e->myIsOneWay != "true"
626  && e->myIsOneWay != "yes" && e->myIsOneWay != "-1" && e->myIsOneWay != "1" && e->myIsOneWay != "reverse") {
627  WRITE_WARNINGF(TL("New value for oneway found: %"), e->myIsOneWay);
628  }
629  if ((permissions == SVC_BICYCLE || permissions == (SVC_BICYCLE | SVC_PEDESTRIAN) || permissions == SVC_PEDESTRIAN)) {
630  if (addBackward && (onewayBike == "true" || onewayBike == "yes" || onewayBike == "1")) {
631  addBackward = false;
632  }
633  if (addForward && (onewayBike == "reverse" || onewayBike == "-1")) {
634  addForward = false;
635  }
636  if (!addBackward && (onewayBike == "false" || onewayBike == "no" || onewayBike == "0")) {
637  addBackward = true;
638  }
639  }
640  bool ok = true;
641  // if we had been able to extract the number of lanes, override the highway type default
642  if (e->myNoLanes > 0) {
643  if (addForward && !addBackward) {
644  numLanesForward = e->myNoLanesForward > 0 ? e->myNoLanesForward : e->myNoLanes;
645  } else if (!addForward && addBackward) {
646  numLanesBackward = e->myNoLanesForward < 0 ? -e->myNoLanesForward : e->myNoLanes;
647  } else {
648  if (e->myNoLanesForward > 0) {
649  numLanesForward = e->myNoLanesForward;
650  } else if (e->myNoLanesForward < 0) {
651  numLanesForward = e->myNoLanes + e->myNoLanesForward;
652  } else {
653  numLanesForward = (int) std::ceil(e->myNoLanes / 2.0);
654  }
655  numLanesBackward = e->myNoLanes - numLanesForward;
656  // sometimes ways are tagged according to their physical width of a single
657  // lane but they are intended for traffic in both directions
658  numLanesForward = MAX2(1, numLanesForward);
659  numLanesBackward = MAX2(1, numLanesBackward);
660  }
661  } else if (e->myNoLanes == 0) {
662  WRITE_WARNINGF(TL("Skipping edge '%' because it has zero lanes."), id);
663  ok = false;
664  } else {
665  // the total number of lanes is not known but at least one direction
666  if (e->myNoLanesForward > 0) {
667  numLanesForward = e->myNoLanesForward;
668  }
669  if (e->myNoLanesForward < 0) {
670  numLanesBackward = -e->myNoLanesForward;
671  }
672  }
673  // deal with busways that run in the opposite direction of a one-way street
674  if (!addForward && (e->myBuswayType & WAY_FORWARD) != 0) {
675  addForward = true;
676  forwardPermissions = SVC_BUS;
677  numLanesForward = 1;
678  }
679  if (!addBackward && (e->myBuswayType & WAY_BACKWARD) != 0) {
680  addBackward = true;
681  backwardPermissions = SVC_BUS;
682  numLanesBackward = 1;
683  }
684  // with is meant for raw lane count before adding sidewalks or cycleways
685  const int taggedLanes = (addForward ? numLanesForward : 0) + (addBackward ? numLanesBackward : 0);
686  if (e->myWidth > 0 && e->myWidthLanesForward.size() == 0 && e->myWidthLanesBackward.size() == 0 && taggedLanes != 0
687  && !OptionsCont::getOptions().getBool("ignore-widths")) {
688  // width is tagged excluding sidewalks and cycleways
689  forwardWidth = e->myWidth / taggedLanes;
690  backwardWidth = forwardWidth;
691  }
692 
693  // if we had been able to extract the maximum speed, override the type's default
694  if (e->myMaxSpeed != MAXSPEED_UNGIVEN) {
695  speed = e->myMaxSpeed / 3.6;
696  }
697  double speedBackward = speed;
699  speedBackward = e->myMaxSpeedBackward / 3.6;
700  }
701  if (speed <= 0 || speedBackward <= 0) {
702  WRITE_WARNINGF(TL("Skipping edge '%' because it has speed %."), id, speed);
703  ok = false;
704  }
705  // deal with cycleways that run in the opposite direction of a one-way street
706  WayType cyclewayType = e->myCyclewayType; // make a copy because we do some temporary modifications
707  if (addBikeLane) {
708  if (!addForward && (cyclewayType & WAY_FORWARD) != 0) {
709  addForward = true;
710  forwardPermissions = SVC_BICYCLE;
711  forwardWidth = bikeLaneWidth;
712  numLanesForward = 1;
713  // do not add an additional cycle lane
714  cyclewayType = (WayType)(cyclewayType & ~WAY_FORWARD);
715  }
716  if (!addBackward && (cyclewayType & WAY_BACKWARD) != 0) {
717  addBackward = true;
718  backwardPermissions = SVC_BICYCLE;
719  backwardWidth = bikeLaneWidth;
720  numLanesBackward = 1;
721  // do not add an additional cycle lane
722  cyclewayType = (WayType)(cyclewayType & ~WAY_BACKWARD);
723  }
724  }
725  // deal with sidewalks that run in the opposite direction of a one-way street
726  WayType sidewalkType = e->mySidewalkType; // make a copy because we do some temporary modifications
727  if (sidewalkType == WAY_UNKNOWN && (e->myExtraAllowed & SVC_PEDESTRIAN) != 0 && (permissions & SVC_PASSENGER) != 0) {
728  // do not assume shared space unless sidewalk is actively disabled
729  sidewalkType = WAY_BOTH;
730  }
731  if (addSidewalk || (myImportSidewalks && (permissions & SVC_ROAD_CLASSES) != 0 && defaultPermissions != SVC_PEDESTRIAN)) {
732  if (!addForward && (sidewalkType & WAY_FORWARD) != 0) {
733  addForward = true;
734  forwardPermissions = SVC_PEDESTRIAN;
735  forwardWidth = tc.getEdgeTypeSidewalkWidth(type);
736  numLanesForward = 1;
737  // do not add an additional sidewalk
738  sidewalkType = (WayType)(sidewalkType & ~WAY_FORWARD); //clang tidy thinks "!WAY_FORWARD" is always false
739  } else if (addSidewalk && addForward && (sidewalkType & WAY_BOTH) == 0
740  && numLanesForward == 1 && numLanesBackward <= 1
741  && (e->myExtraDisallowed & SVC_PEDESTRIAN) == 0) {
742  // our typemap says pedestrians should walk here but the data says
743  // there is no sidewalk at all. If the road is small, pedestrians can just walk
744  // on the road
745  forwardPermissions |= SVC_PEDESTRIAN;
746  }
747  if (!addBackward && (sidewalkType & WAY_BACKWARD) != 0) {
748  addBackward = true;
749  backwardPermissions = SVC_PEDESTRIAN;
750  backwardWidth = tc.getEdgeTypeSidewalkWidth(type);
751  numLanesBackward = 1;
752  // do not add an additional cycle lane
753  sidewalkType = (WayType)(sidewalkType & ~WAY_BACKWARD); //clang tidy thinks "!WAY_BACKWARD" is always false
754  } else if (addSidewalk && addBackward && (sidewalkType & WAY_BOTH) == 0
755  && numLanesBackward == 1 && numLanesForward <= 1
756  && (e->myExtraDisallowed & SVC_PEDESTRIAN) == 0) {
757  // our typemap says pedestrians should walk here but the data says
758  // there is no sidewalk at all. If the road is small, pedestrians can just walk
759  // on the road
760  backwardPermissions |= SVC_PEDESTRIAN;
761  }
762  }
763 
764  const std::string origID = OptionsCont::getOptions().getBool("output.original-names") ? toString(e->id) : "";
765  if (ok) {
766  const bool lefthand = OptionsCont::getOptions().getBool("lefthand");
767  const int offsetFactor = lefthand ? -1 : 1;
768  LaneSpreadFunction lsf = (addBackward || OptionsCont::getOptions().getBool("osm.oneway-spread-right")) &&
770  if (addBackward && lsf == LaneSpreadFunction::RIGHT && OptionsCont::getOptions().getString("default.spreadtype") == toString(LaneSpreadFunction::ROADCENTER)) {
772  }
774  // user defined value overrides defaults
775  lsf = tc.getEdgeTypeSpreadType(type);
776  }
777 
778  id = StringUtils::escapeXML(id);
779  const std::string reverseID = "-" + id;
780  const bool markOSMDirection = from->getType() == SumoXMLNodeType::RAIL_SIGNAL || to->getType() == SumoXMLNodeType::RAIL_SIGNAL;
781  if (addForward) {
782  assert(numLanesForward > 0);
783  NBEdge* nbe = new NBEdge(id, from, to, type, speed, NBEdge::UNSPECIFIED_FRICTION, numLanesForward, tc.getEdgeTypePriority(type),
784  forwardWidth, NBEdge::UNSPECIFIED_OFFSET, shape, lsf,
785  StringUtils::escapeXML(streetName), origID, true);
786  if (markOSMDirection) {
788  }
789  nbe->setPermissions(forwardPermissions, -1);
790  if ((e->myBuswayType & WAY_FORWARD) != 0) {
791  nbe->setPermissions(SVC_BUS, 0);
792  }
794  applyLaneUse(nbe, e, true);
796  nbe->setTurnSignTarget(last->getID());
797  if (addBikeLane && (cyclewayType == WAY_UNKNOWN || (cyclewayType & WAY_FORWARD) != 0)) {
798  nbe->addBikeLane(bikeLaneWidth * offsetFactor);
799  } else if (nbe->getPermissions(0) == SVC_BUS) {
800  // bikes drive on buslanes if no separate cycle lane is available
802  }
803  if ((addSidewalk && (sidewalkType == WAY_UNKNOWN || (sidewalkType & WAY_FORWARD) != 0))
804  || (myImportSidewalks && (sidewalkType & WAY_FORWARD) != 0 && defaultPermissions != SVC_PEDESTRIAN)) {
805  nbe->addSidewalk(sidewalkWidth * offsetFactor);
806  }
807  if (!addBackward && (e->myExtraAllowed & SVC_PEDESTRIAN) != 0 && (nbe->getPermissions(0) & SVC_PEDESTRIAN) == 0) {
808  // Pedestrians are explicitly allowed (maybe through foot="yes") but did not get a sidewalk (maybe through sidewalk="no").
809  // Since we do not have a backward edge, we need to make sure they can at least walk somewhere, see #14124
810  nbe->setPermissions(nbe->getPermissions(0) | SVC_PEDESTRIAN, 0);
811  }
813  nbe->setDistance(distanceStart);
814  if (e->myAmInRoundabout) {
815  // ensure roundabout edges have the precedence
816  nbe->setJunctionPriority(to, NBEdge::JunctionPriority::ROUNDABOUT);
817  nbe->setJunctionPriority(from, NBEdge::JunctionPriority::ROUNDABOUT);
818  }
819 
820  // process forward lanes width
821  const int numForwardLanesFromWidthKey = (int)e->myWidthLanesForward.size();
822  if (numForwardLanesFromWidthKey > 0 && !OptionsCont::getOptions().getBool("ignore-widths")) {
823  if ((int)nbe->getLanes().size() != numForwardLanesFromWidthKey) {
824  WRITE_WARNINGF(TL("Forward lanes count for edge '%' ('%') is not matching the number of lanes defined in width:lanes:forward key ('%'). Using default width values."),
825  id, nbe->getLanes().size(), numForwardLanesFromWidthKey);
826  } else {
827  for (int i = 0; i < numForwardLanesFromWidthKey; i++) {
828  const double actualWidth = e->myWidthLanesForward[i] <= 0 ? forwardWidth : e->myWidthLanesForward[i];
829  const int laneIndex = lefthand ? i : numForwardLanesFromWidthKey - i - 1;
830  nbe->setLaneWidth(laneIndex, actualWidth);
831  }
832  }
833  }
834 
835  if (!ec.insert(nbe)) {
836  delete nbe;
837  throw ProcessError(TLF("Could not add edge '%'.", id));
838  }
839  }
840  if (addBackward) {
841  assert(numLanesBackward > 0);
842  NBEdge* nbe = new NBEdge(reverseID, to, from, type, speedBackward, NBEdge::UNSPECIFIED_FRICTION, numLanesBackward, tc.getEdgeTypePriority(type),
843  backwardWidth, NBEdge::UNSPECIFIED_OFFSET, shape.reverse(), lsf,
844  StringUtils::escapeXML(streetName), origID, true);
845  if (markOSMDirection) {
847  }
848  nbe->setPermissions(backwardPermissions);
849  if ((e->myBuswayType & WAY_BACKWARD) != 0) {
850  nbe->setPermissions(SVC_BUS, 0);
851  }
853  applyLaneUse(nbe, e, false);
855  nbe->setTurnSignTarget(first->getID());
856  if (addBikeLane && (cyclewayType == WAY_UNKNOWN || (cyclewayType & WAY_BACKWARD) != 0)) {
857  nbe->addBikeLane(bikeLaneWidth * offsetFactor);
858  } else if (nbe->getPermissions(0) == SVC_BUS) {
859  // bikes drive on buslanes if no separate cycle lane is available
861  }
862  if ((addSidewalk && (sidewalkType == WAY_UNKNOWN || (sidewalkType & WAY_BACKWARD) != 0))
863  || (myImportSidewalks && (sidewalkType & WAY_BACKWARD) != 0 && defaultPermissions != SVC_PEDESTRIAN)) {
864  nbe->addSidewalk(sidewalkWidth * offsetFactor);
865  }
867  nbe->setDistance(distanceEnd);
868  if (e->myAmInRoundabout) {
869  // ensure roundabout edges have the precedence
870  nbe->setJunctionPriority(from, NBEdge::JunctionPriority::ROUNDABOUT);
871  nbe->setJunctionPriority(to, NBEdge::JunctionPriority::ROUNDABOUT);
872  }
873  // process backward lanes width
874  const int numBackwardLanesFromWidthKey = (int)e->myWidthLanesBackward.size();
875  if (numBackwardLanesFromWidthKey > 0 && !OptionsCont::getOptions().getBool("ignore-widths")) {
876  if ((int)nbe->getLanes().size() != numBackwardLanesFromWidthKey) {
877  WRITE_WARNINGF(TL("Backward lanes count for edge '%' ('%') is not matching the number of lanes defined in width:lanes:backward key ('%'). Using default width values."),
878  id, nbe->getLanes().size(), numBackwardLanesFromWidthKey);
879  } else {
880  for (int i = 0; i < numBackwardLanesFromWidthKey; i++) {
881  const double actualWidth = e->myWidthLanesBackward[i] <= 0 ? backwardWidth : e->myWidthLanesBackward[i];
882  const int laneIndex = lefthand ? i : numBackwardLanesFromWidthKey - i - 1;
883  nbe->setLaneWidth(laneIndex, actualWidth);
884  }
885  }
886  }
887 
888  if (!ec.insert(nbe)) {
889  delete nbe;
890  throw ProcessError(TLF("Could not add edge '-%'.", id));
891  }
892  }
893  if ((e->myParkingType & PARKING_BOTH) != 0 && OptionsCont::getOptions().isSet("parking-output")) {
894  if ((e->myParkingType & PARKING_RIGHT) != 0) {
895  if (addForward) {
896  nb.getParkingCont().push_back(NBParking(id, id));
897  } else {
899  if ((e->myParkingType & PARKING_LEFT) == 0 && !addBackward) {
901  nb.getParkingCont().push_back(NBParking(reverseID, reverseID));
902  }
903  }
904  }
905  if ((e->myParkingType & PARKING_LEFT) != 0) {
906  if (addBackward) {
907  nb.getParkingCont().push_back(NBParking(reverseID, reverseID));
908  } else {
910  if ((e->myParkingType & PARKING_RIGHT) == 0 && !addForward) {
912  nb.getParkingCont().push_back(NBParking(id, id));
913  }
914  }
915  }
916  }
917  }
918  return newIndex;
919 }
920 
921 
922 // ---------------------------------------------------------------------------
923 // definitions of NIImporter_OpenStreetMap::NodesHandler-methods
924 // ---------------------------------------------------------------------------
925 NIImporter_OpenStreetMap::NodesHandler::NodesHandler(std::map<long long int, NIOSMNode*>& toFill,
926  std::set<NIOSMNode*, CompareNodes>& uniqueNodes, const OptionsCont& oc) :
927  SUMOSAXHandler("osm - file"),
928  myToFill(toFill),
929  myCurrentNode(nullptr),
930  myHierarchyLevel(0),
931  myUniqueNodes(uniqueNodes),
932  myImportElevation(oc.getBool("osm.elevation")),
933  myDuplicateNodes(0),
934  myOptionsCont(oc) {
935  // init rail signal rules
936  for (std::string kv : oc.getStringVector("osm.railsignals")) {
937  if (kv == "DEFAULT") {
938  myRailSignalRules.push_back("railway:signal:main=");
939  myRailSignalRules.push_back("railway:signal:combined=");
940  } else if (kv == "ALL") {
941  myRailSignalRules.push_back("railway=signal");
942  } else {
943  myRailSignalRules.push_back("railway:signal:" + kv);
944  }
945  }
946 }
947 
948 
950 
951 void
953  ++myHierarchyLevel;
954  if (element == SUMO_TAG_NODE) {
955  bool ok = true;
956  myLastNodeID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
957  if (myHierarchyLevel != 2) {
958  WRITE_ERROR("Node element on wrong XML hierarchy level (id='" + myLastNodeID +
959  "', level='" + toString(myHierarchyLevel) + "').");
960  return;
961  }
962  const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, myLastNodeID.c_str(), ok);
963  if (action == "delete" || !ok) {
964  return;
965  }
966  try {
967  // we do not use attrs.get here to save some time on parsing
968  const long long int id = StringUtils::toLong(myLastNodeID);
969  myCurrentNode = nullptr;
970  const auto insertionIt = myToFill.lower_bound(id);
971  if (insertionIt == myToFill.end() || insertionIt->first != id) {
972  // assume we are loading multiple files, so we won't report duplicate nodes
973  const double tlon = attrs.get<double>(SUMO_ATTR_LON, myLastNodeID.c_str(), ok);
974  const double tlat = attrs.get<double>(SUMO_ATTR_LAT, myLastNodeID.c_str(), ok);
975  if (!ok) {
976  return;
977  }
978  myCurrentNode = new NIOSMNode(id, tlon, tlat);
979  auto similarNode = myUniqueNodes.find(myCurrentNode);
980  if (similarNode == myUniqueNodes.end()) {
981  myUniqueNodes.insert(myCurrentNode);
982  } else {
983  delete myCurrentNode;
984  myCurrentNode = *similarNode;
985  myDuplicateNodes++;
986  }
987  myToFill.emplace_hint(insertionIt, id, myCurrentNode);
988  }
989  } catch (FormatException&) {
990  WRITE_ERROR(TL("Attribute 'id' in the definition of a node is not of type long long int."));
991  return;
992  }
993  }
994  if (element == SUMO_TAG_TAG && myCurrentNode != nullptr) {
995  if (myHierarchyLevel != 3) {
996  WRITE_ERROR(TL("Tag element on wrong XML hierarchy level."));
997  return;
998  }
999  bool ok = true;
1000  const std::string& key = attrs.get<std::string>(SUMO_ATTR_K, myLastNodeID.c_str(), ok, false);
1001  // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
1002  if (key == "highway" || key == "ele" || key == "crossing" || key == "railway" || key == "public_transport"
1003  || key == "name" || key == "train" || key == "bus" || key == "tram" || key == "light_rail" || key == "subway" || key == "station" || key == "noexit"
1004  || key == "crossing:barrier"
1005  || key == "crossing:light"
1006  || StringUtils::startsWith(key, "railway:signal")
1007  || StringUtils::startsWith(key, "railway:position")
1008  ) {
1009  const std::string& value = attrs.get<std::string>(SUMO_ATTR_V, myLastNodeID.c_str(), ok, false);
1010  if (key == "highway" && value.find("traffic_signal") != std::string::npos) {
1011  myCurrentNode->tlsControlled = true;
1012  } else if (key == "crossing" && value.find("traffic_signals") != std::string::npos) {
1013  myCurrentNode->tlsControlled = true;
1014  } else if (key == "highway" && value.find("crossing") != std::string::npos) {
1015  myCurrentNode->pedestrianCrossing = true;
1016  } else if ((key == "noexit" && value == "yes")
1017  || (key == "railway" && value == "buffer_stop")) {
1018  myCurrentNode->railwayBufferStop = true;
1019  } else if (key == "railway" && value.find("crossing") != std::string::npos) {
1020  myCurrentNode->railwayCrossing = true;
1021  } else if (key == "crossing:barrier") {
1022  myCurrentNode->setParameter("crossing:barrier", value);
1023  } else if (key == "crossing:light") {
1024  myCurrentNode->setParameter("crossing:light", value);
1025  } else if (key == "railway:signal:direction") {
1026  if (value == "both") {
1027  myCurrentNode->myRailDirection = WAY_BOTH;
1028  } else if (value == "backward") {
1029  myCurrentNode->myRailDirection = WAY_BACKWARD;
1030  } else if (value == "forward") {
1031  myCurrentNode->myRailDirection = WAY_FORWARD;
1032  }
1033  } else if (StringUtils::startsWith(key, "railway:signal") || (key == "railway" && value == "signal")) {
1034  std::string kv = key + "=" + value;
1035  std::string kglob = key + "=";
1036  if ((std::find(myRailSignalRules.begin(), myRailSignalRules.end(), kv) != myRailSignalRules.end())
1037  || (std::find(myRailSignalRules.begin(), myRailSignalRules.end(), kglob) != myRailSignalRules.end())) {
1038  myCurrentNode->railwaySignal = true;
1039  }
1040  } else if (StringUtils::startsWith(key, "railway:position") && value.size() > myCurrentNode->position.size()) {
1041  // use the entry with the highest precision (more digits)
1042  myCurrentNode->position = value;
1043  } else if ((key == "public_transport" && value == "stop_position") ||
1044  (key == "highway" && value == "bus_stop")) {
1045  myCurrentNode->ptStopPosition = true;
1046  if (myCurrentNode->ptStopLength == 0) {
1047  // default length
1048  myCurrentNode->ptStopLength = myOptionsCont.getFloat("osm.stop-output.length");
1049  }
1050  } else if (key == "name") {
1051  myCurrentNode->name = value;
1052  } else if (myImportElevation && key == "ele") {
1053  try {
1054  const double elevation = StringUtils::toDouble(value);
1055  if (std::isnan(elevation)) {
1056  WRITE_WARNINGF(TL("Value of key '%' is invalid ('%') in node '%'."), key, value, myLastNodeID);
1057  } else {
1058  myCurrentNode->ele = elevation;
1059  }
1060  } catch (...) {
1061  WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in node '%'."), key, value, myLastNodeID);
1062  }
1063  } else if (key == "station") {
1064  interpretTransportType(value, myCurrentNode);
1065  } else {
1066  // v="yes"
1067  interpretTransportType(key, myCurrentNode);
1068  }
1069  }
1070  if (myAllAttributes && (myExtraAttributes.count(key) != 0 || myExtraAttributes.size() == 0)) {
1071  const std::string info = "node=" + toString(myCurrentNode->id) + ", k=" + key;
1072  myCurrentNode->setParameter(key, attrs.get<std::string>(SUMO_ATTR_V, info.c_str(), ok, false));
1073  }
1074  }
1075 }
1076 
1077 
1078 void
1080  if (element == SUMO_TAG_NODE && myHierarchyLevel == 2) {
1081  myCurrentNode = nullptr;
1082  }
1083  --myHierarchyLevel;
1084 }
1085 
1086 
1087 // ---------------------------------------------------------------------------
1088 // definitions of NIImporter_OpenStreetMap::EdgesHandler-methods
1089 // ---------------------------------------------------------------------------
1091  const std::map<long long int, NIOSMNode*>& osmNodes,
1092  std::map<long long int, Edge*>& toFill, std::map<long long int, Edge*>& platformShapes):
1093  SUMOSAXHandler("osm - file"),
1094  myOSMNodes(osmNodes),
1095  myEdgeMap(toFill),
1096  myPlatformShapesMap(platformShapes) {
1097 
1098  const double unlimitedSpeed = OptionsCont::getOptions().getFloat("osm.speedlimit-none") * 3.6;
1099 
1100  mySpeedMap["nan"] = MAXSPEED_UNGIVEN;
1101  mySpeedMap["sign"] = MAXSPEED_UNGIVEN;
1102  mySpeedMap["signals"] = MAXSPEED_UNGIVEN;
1103  mySpeedMap["none"] = unlimitedSpeed;
1104  mySpeedMap["no"] = unlimitedSpeed;
1105  mySpeedMap["walk"] = 5.;
1106  // https://wiki.openstreetmap.org/wiki/Key:source:maxspeed#Commonly_used_values
1107  mySpeedMap["AT:urban"] = 50;
1108  mySpeedMap["AT:rural"] = 100;
1109  mySpeedMap["AT:trunk"] = 100;
1110  mySpeedMap["AT:motorway"] = 130;
1111  mySpeedMap["AU:urban"] = 50;
1112  mySpeedMap["BE:urban"] = 50;
1113  mySpeedMap["BE:zone"] = 30;
1114  mySpeedMap["BE:motorway"] = 120;
1115  mySpeedMap["BE:zone30"] = 30;
1116  mySpeedMap["BE-VLG:rural"] = 70;
1117  mySpeedMap["BE-WAL:rural"] = 90;
1118  mySpeedMap["BE:school"] = 30;
1119  mySpeedMap["CZ:motorway"] = 130;
1120  mySpeedMap["CZ:trunk"] = 110;
1121  mySpeedMap["CZ:rural"] = 90;
1122  mySpeedMap["CZ:urban_motorway"] = 80;
1123  mySpeedMap["CZ:urban_trunk"] = 80;
1124  mySpeedMap["CZ:urban"] = 50;
1125  mySpeedMap["DE:motorway"] = unlimitedSpeed;
1126  mySpeedMap["DE:rural"] = 100;
1127  mySpeedMap["DE:urban"] = 50;
1128  mySpeedMap["DE:bicycle_road"] = 30;
1129  mySpeedMap["DK:motorway"] = 130;
1130  mySpeedMap["DK:rural"] = 80;
1131  mySpeedMap["DK:urban"] = 50;
1132  mySpeedMap["EE:urban"] = 50;
1133  mySpeedMap["EE:rural"] = 90;
1134  mySpeedMap["ES:urban"] = 50;
1135  mySpeedMap["ES:zone30"] = 30;
1136  mySpeedMap["FR:motorway"] = 130; // 110 (raining)
1137  mySpeedMap["FR:rural"] = 80;
1138  mySpeedMap["FR:urban"] = 50;
1139  mySpeedMap["FR:zone30"] = 30;
1140  mySpeedMap["HU:living_street"] = 20;
1141  mySpeedMap["HU:motorway"] = 130;
1142  mySpeedMap["HU:rural"] = 90;
1143  mySpeedMap["HU:trunk"] = 110;
1144  mySpeedMap["HU:urban"] = 50;
1145  mySpeedMap["IT:rural"] = 90;
1146  mySpeedMap["IT:motorway"] = 130;
1147  mySpeedMap["IT:urban"] = 50;
1148  mySpeedMap["JP:nsl"] = 60;
1149  mySpeedMap["JP:express"] = 100;
1150  mySpeedMap["LT:rural"] = 90;
1151  mySpeedMap["LT:urban"] = 50;
1152  mySpeedMap["NO:rural"] = 80;
1153  mySpeedMap["NO:urban"] = 50;
1154  mySpeedMap["ON:urban"] = 50;
1155  mySpeedMap["ON:rural"] = 80;
1156  mySpeedMap["PT:motorway"] = 120;
1157  mySpeedMap["PT:rural"] = 90;
1158  mySpeedMap["PT:trunk"] = 100;
1159  mySpeedMap["PT:urban"] = 50;
1160  mySpeedMap["RO:motorway"] = 130;
1161  mySpeedMap["RO:rural"] = 90;
1162  mySpeedMap["RO:trunk"] = 100;
1163  mySpeedMap["RO:urban"] = 50;
1164  mySpeedMap["RS:living_street"] = 30;
1165  mySpeedMap["RS:motorway"] = 130;
1166  mySpeedMap["RS:rural"] = 80;
1167  mySpeedMap["RS:trunk"] = 100;
1168  mySpeedMap["RS:urban"] = 50;
1169  mySpeedMap["RU:living_street"] = 20;
1170  mySpeedMap["RU:urban"] = 60;
1171  mySpeedMap["RU:rural"] = 90;
1172  mySpeedMap["RU:motorway"] = 110;
1173  mySpeedMap["GB:motorway"] = 70 * KM_PER_MILE;
1174  mySpeedMap["GB:nsl_dual"] = 70 * KM_PER_MILE;
1175  mySpeedMap["GB:nsl_single"] = 60 * KM_PER_MILE;
1176  mySpeedMap["UK:motorway"] = 70 * KM_PER_MILE;
1177  mySpeedMap["UK:nsl_dual"] = 70 * KM_PER_MILE;
1178  mySpeedMap["UK:nsl_single"] = 60 * KM_PER_MILE;
1179  mySpeedMap["UZ:living_street"] = 30;
1180  mySpeedMap["UZ:urban"] = 70;
1181  mySpeedMap["UZ:rural"] = 100;
1182  mySpeedMap["UZ:motorway"] = 110;
1183 }
1184 
1186 
1187 void
1189  if (element == SUMO_TAG_WAY) {
1190  bool ok = true;
1191  const long long int id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
1192  const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, nullptr, ok);
1193  if (action == "delete" || !ok) {
1194  myCurrentEdge = nullptr;
1195  return;
1196  }
1197  myCurrentEdge = new Edge(id);
1198  }
1199  // parse "nd" (node) elements
1200  if (element == SUMO_TAG_ND && myCurrentEdge != nullptr) {
1201  bool ok = true;
1202  long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, nullptr, ok);
1203  if (ok) {
1204  auto node = myOSMNodes.find(ref);
1205  if (node == myOSMNodes.end()) {
1206  WRITE_WARNINGF(TL("The referenced geometry information (ref='%') is not known"), toString(ref));
1207  return;
1208  }
1209 
1210  ref = node->second->id; // node may have been substituted
1211  if (myCurrentEdge->myCurrentNodes.empty() ||
1212  myCurrentEdge->myCurrentNodes.back() != ref) { // avoid consecutive duplicates
1213  myCurrentEdge->myCurrentNodes.push_back(ref);
1214  }
1215 
1216  }
1217  }
1218  if (element == SUMO_TAG_TAG && myCurrentEdge != nullptr) {
1219  bool ok = true;
1220  std::string key = attrs.get<std::string>(SUMO_ATTR_K, toString(myCurrentEdge->id).c_str(), ok, false);
1221  if (key.size() > 6 && StringUtils::startsWith(key, "busway:")) {
1222  // handle special busway keys
1223  const std::string buswaySpec = key.substr(7);
1224  key = "busway";
1225  if (buswaySpec == "right") {
1226  myCurrentEdge->myBuswayType = (WayType)(myCurrentEdge->myBuswayType | WAY_FORWARD);
1227  } else if (buswaySpec == "left") {
1228  myCurrentEdge->myBuswayType = (WayType)(myCurrentEdge->myBuswayType | WAY_BACKWARD);
1229  } else if (buswaySpec == "both") {
1230  myCurrentEdge->myBuswayType = (WayType)(myCurrentEdge->myBuswayType | WAY_BOTH);
1231  } else {
1232  key = "ignore";
1233  }
1234  }
1235  if (myAllAttributes && (myExtraAttributes.count(key) != 0 || myExtraAttributes.size() == 0)) {
1236  const std::string info = "way=" + toString(myCurrentEdge->id) + ", k=" + key;
1237  myCurrentEdge->setParameter(key, attrs.get<std::string>(SUMO_ATTR_V, info.c_str(), ok, false));
1238  }
1239  // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
1240  if (!StringUtils::endsWith(key, "way")
1241  && !StringUtils::startsWith(key, "lanes")
1242  && key != "maxspeed" && key != "maxspeed:type"
1243  && key != "zone:maxspeed"
1244  && key != "maxspeed:forward" && key != "maxspeed:backward"
1245  && key != "junction" && key != "name" && key != "tracks" && key != "layer"
1246  && key != "route"
1247  && !StringUtils::startsWith(key, "cycleway")
1248  && !StringUtils::startsWith(key, "sidewalk")
1249  && key != "ref"
1250  && key != "highspeed"
1251  && !StringUtils::startsWith(key, "parking")
1252  && !StringUtils::startsWith(key, "change")
1253  && !StringUtils::startsWith(key, "vehicle:lanes")
1254  && key != "postal_code"
1255  && key != "railway:preferred_direction"
1256  && key != "railway:bidirectional"
1257  && key != "railway:track_ref"
1258  && key != "usage"
1259  && key != "access"
1260  && key != "emergency"
1261  && key != "service"
1262  && key != "electrified"
1263  && key != "segregated"
1264  && key != "bus"
1265  && key != "psv"
1266  && key != "foot"
1267  && key != "bicycle"
1268  && key != "oneway:bicycle"
1269  && key != "oneway:bus"
1270  && key != "bus:lanes"
1271  && key != "bus:lanes:forward"
1272  && key != "bus:lanes:backward"
1273  && key != "psv:lanes"
1274  && key != "psv:lanes:forward"
1275  && key != "psv:lanes:backward"
1276  && key != "bicycle:lanes"
1277  && key != "bicycle:lanes:forward"
1278  && key != "bicycle:lanes:backward"
1279  && !StringUtils::startsWith(key, "width")
1280  && !(StringUtils::startsWith(key, "turn:") && key.find(":lanes") != std::string::npos)
1281  && key != "public_transport") {
1282  return;
1283  }
1284  const std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentEdge->id).c_str(), ok, false);
1285 
1286  if ((key == "highway" && value != "platform") || key == "railway" || key == "waterway" || StringUtils::startsWith(key, "cycleway")
1287  || key == "busway" || key == "route" || StringUtils::startsWith(key, "sidewalk") || key == "highspeed"
1288  || key == "aeroway" || key == "aerialway" || key == "usage" || key == "service") {
1289  // build type id
1290  myCurrentEdge->myCurrentIsRoad = true;
1291  // special cycleway stuff https://wiki.openstreetmap.org/wiki/Key:cycleway
1292  if (key == "cycleway") {
1293  if (value == "no" || value == "none" || value == "separate") {
1294  myCurrentEdge->myCyclewayType = WAY_NONE;
1295  } else if (value == "both") {
1296  myCurrentEdge->myCyclewayType = WAY_BOTH;
1297  } else if (value == "right") {
1298  myCurrentEdge->myCyclewayType = WAY_FORWARD;
1299  } else if (value == "left") {
1300  myCurrentEdge->myCyclewayType = WAY_BACKWARD;
1301  } else if (value == "opposite_track") {
1302  myCurrentEdge->myCyclewayType = WAY_BACKWARD;
1303  } else if (value == "opposite_lane") {
1304  myCurrentEdge->myCyclewayType = WAY_BACKWARD;
1305  } else if (value == "opposite") {
1306  // according to the wiki ref above, this should rather be a bidi lane, see #13438
1307  myCurrentEdge->myCyclewayType = WAY_BACKWARD;
1308  }
1309  }
1310  if (key == "cycleway:left") {
1311  if (myCurrentEdge->myCyclewayType == WAY_UNKNOWN) {
1312  myCurrentEdge->myCyclewayType = WAY_NONE;
1313  }
1314  if (value == "yes" || value == "lane" || value == "track") {
1315  myCurrentEdge->myCyclewayType = (WayType)(myCurrentEdge->myCyclewayType | WAY_BACKWARD);
1316  }
1317  key = "cycleway"; // for type adaption
1318  }
1319  if (key == "cycleway:right") {
1320  if (myCurrentEdge->myCyclewayType == WAY_UNKNOWN) {
1321  myCurrentEdge->myCyclewayType = WAY_NONE;
1322  }
1323  if (value == "yes" || value == "lane" || value == "track") {
1324  myCurrentEdge->myCyclewayType = (WayType)(myCurrentEdge->myCyclewayType | WAY_FORWARD);
1325  }
1326  key = "cycleway"; // for type adaption
1327  }
1328  if (key == "cycleway:both") {
1329  if (myCurrentEdge->myCyclewayType == WAY_UNKNOWN) {
1330  if (value == "no" || value == "none" || value == "separate") {
1331  myCurrentEdge->myCyclewayType = WAY_NONE;
1332  }
1333  if (value == "yes" || value == "lane" || value == "track") {
1334  myCurrentEdge->myCyclewayType = WAY_BOTH;
1335  }
1336  }
1337  key = "cycleway"; // for type adaption
1338  }
1339  if (key == "cycleway" && value != "lane" && value != "track" && value != "opposite_track" && value != "opposite_lane") {
1340  // typemap covers only the lane and track cases
1341  return;
1342  }
1343  if (StringUtils::startsWith(key, "cycleway:")) {
1344  // no need to extend the type id for other cycleway sub tags
1345  return;
1346  }
1347  // special sidewalk stuff
1348  if (key == "sidewalk") {
1349  if (value == "no" || value == "none" || value == "separate") {
1350  myCurrentEdge->mySidewalkType = WAY_NONE;
1351  } else if (value == "both") {
1352  myCurrentEdge->mySidewalkType = WAY_BOTH;
1353  } else if (value == "right") {
1354  myCurrentEdge->mySidewalkType = WAY_FORWARD;
1355  } else if (value == "left") {
1356  myCurrentEdge->mySidewalkType = WAY_BACKWARD;
1357  }
1358  }
1359  if (key == "sidewalk:left") {
1360  if (myCurrentEdge->mySidewalkType == WAY_UNKNOWN) {
1361  myCurrentEdge->mySidewalkType = WAY_NONE;
1362  }
1363  if (value == "yes") {
1364  myCurrentEdge->mySidewalkType = (WayType)(myCurrentEdge->mySidewalkType | WAY_BACKWARD);
1365  }
1366  }
1367  if (key == "sidewalk:right") {
1368  if (myCurrentEdge->mySidewalkType == WAY_UNKNOWN) {
1369  myCurrentEdge->mySidewalkType = WAY_NONE;
1370  }
1371  if (value == "yes") {
1372  myCurrentEdge->mySidewalkType = (WayType)(myCurrentEdge->mySidewalkType | WAY_FORWARD);
1373  }
1374  }
1375  if (key == "sidewalk:both") {
1376  if (myCurrentEdge->mySidewalkType == WAY_UNKNOWN) {
1377  if (value == "no" || value == "none" || value == "separate") {
1378  myCurrentEdge->mySidewalkType = WAY_NONE;
1379  }
1380  if (value == "yes") {
1381  myCurrentEdge->mySidewalkType = WAY_BOTH;
1382  }
1383  }
1384  }
1385  if (StringUtils::startsWith(key, "sidewalk")) {
1386  // no need to extend the type id
1387  return;
1388  }
1389  // special busway stuff
1390  if (key == "busway") {
1391  if (value == "no") {
1392  return;
1393  }
1394  if (value == "opposite_track") {
1395  myCurrentEdge->myBuswayType = WAY_BACKWARD;
1396  } else if (value == "opposite_lane") {
1397  myCurrentEdge->myBuswayType = WAY_BACKWARD;
1398  }
1399  // no need to extend the type id
1400  return;
1401  }
1402  std::string singleTypeID = key + "." + value;
1403  if (key == "highspeed") {
1404  if (value == "no") {
1405  return;
1406  }
1407  singleTypeID = "railway.highspeed";
1408  }
1409  // special case: never build compound type for highspeed rail
1410  if (!myCurrentEdge->myHighWayType.empty() && singleTypeID != "railway.highspeed") {
1411  if (myCurrentEdge->myHighWayType == "railway.highspeed") {
1412  return;
1413  }
1414  // osm-ways may be used by more than one mode (eg railway.tram + highway.residential. this is relevant for multimodal traffic)
1415  // we create a new type for this kind of situation which must then be resolved in insertEdge()
1416  std::vector<std::string> types = StringTokenizer(myCurrentEdge->myHighWayType,
1418  types.push_back(singleTypeID);
1419  myCurrentEdge->myHighWayType = joinToStringSorting(types, compoundTypeSeparator);
1420  } else {
1421  myCurrentEdge->myHighWayType = singleTypeID;
1422  }
1423  } else if (key == "bus" || key == "psv") {
1424  // 'psv' includes taxi in the UK but not in germany
1425  try {
1426  if (StringUtils::toBool(value)) {
1427  myCurrentEdge->myExtraAllowed |= SVC_BUS;
1428  } else {
1429  myCurrentEdge->myExtraDisallowed |= SVC_BUS;
1430  }
1431  } catch (const BoolFormatException&) {
1432  myCurrentEdge->myExtraAllowed |= SVC_BUS;
1433  }
1434  } else if (key == "emergency") {
1435  try {
1436  if (StringUtils::toBool(value)) {
1437  myCurrentEdge->myExtraAllowed |= SVC_AUTHORITY | SVC_EMERGENCY;
1438  }
1439  } catch (const BoolFormatException&) {
1440  myCurrentEdge->myExtraAllowed |= SVC_AUTHORITY | SVC_EMERGENCY;
1441  }
1442  } else if (key == "access") {
1443  if (value == "no") {
1444  myCurrentEdge->myExtraDisallowed |= ~(SVC_PUBLIC_CLASSES | SVC_EMERGENCY | SVC_AUTHORITY);
1445  }
1446  } else if (StringUtils::startsWith(key, "width:lanes")) {
1447  try {
1448  const std::vector<std::string> values = StringTokenizer(value, "|").getVector();
1449  std::vector<double> widthLanes;
1450  for (std::string width : values) {
1451  double parsedWidth = width == ""
1452  ? -1
1453  : StringUtils::toDouble(width);
1454  widthLanes.push_back(parsedWidth);
1455  }
1456 
1457  if (key == "width:lanes" || key == "width:lanes:forward") {
1458  myCurrentEdge->myWidthLanesForward = widthLanes;
1459  } else if (key == "width:lanes:backward") {
1460  myCurrentEdge->myWidthLanesBackward = widthLanes;
1461  } else {
1462  WRITE_WARNINGF(TL("Using default lane width for edge '%' as key '%' could not be parsed."), toString(myCurrentEdge->id), key);
1463  }
1464  } catch (const NumberFormatException&) {
1465  WRITE_WARNINGF(TL("Using default lane width for edge '%' as value '%' could not be parsed."), toString(myCurrentEdge->id), value);
1466  }
1467  } else if (key == "width") {
1468  try {
1469  myCurrentEdge->myWidth = StringUtils::toDouble(value);
1470  } catch (const NumberFormatException&) {
1471  WRITE_WARNINGF(TL("Using default width for edge '%' as value '%' could not be parsed."), toString(myCurrentEdge->id), value);
1472  }
1473  } else if (key == "foot") {
1474  if (value == "use_sidepath" || value == "no") {
1475  myCurrentEdge->myExtraDisallowed |= SVC_PEDESTRIAN;
1476  } else if (value == "yes" || value == "designated" || value == "permissive") {
1477  myCurrentEdge->myExtraAllowed |= SVC_PEDESTRIAN;
1478  }
1479  } else if (key == "bicycle") {
1480  if (value == "use_sidepath" || value == "no") {
1481  myCurrentEdge->myExtraDisallowed |= SVC_BICYCLE;
1482  } else if (value == "yes" || value == "designated" || value == "permissive") {
1483  myCurrentEdge->myExtraAllowed |= SVC_BICYCLE;
1484  }
1485  } else if (key == "oneway:bicycle") {
1486  myCurrentEdge->myExtraTags["oneway:bicycle"] = value;
1487  } else if (key == "oneway:bus") {
1488  if (value == "no") {
1489  // need to add a bus way in reversed direction of way
1490  myCurrentEdge->myBuswayType = WAY_BACKWARD;
1491  }
1492  } else if (key == "lanes") {
1493  try {
1494  myCurrentEdge->myNoLanes = StringUtils::toInt(value);
1495  } catch (NumberFormatException&) {
1496  // might be a list of values
1497  StringTokenizer st(value, ";", true);
1498  std::vector<std::string> list = st.getVector();
1499  if (list.size() >= 2) {
1500  int minLanes = std::numeric_limits<int>::max();
1501  try {
1502  for (auto& i : list) {
1503  const int numLanes = StringUtils::toInt(StringUtils::prune(i));
1504  minLanes = MIN2(minLanes, numLanes);
1505  }
1506  myCurrentEdge->myNoLanes = minLanes;
1507  WRITE_WARNINGF(TL("Using minimum lane number from list (%) for edge '%'."), value, toString(myCurrentEdge->id));
1508  } catch (NumberFormatException&) {
1509  WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
1510  }
1511  }
1512  } catch (EmptyData&) {
1513  WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
1514  }
1515  } else if (key == "lanes:forward") {
1516  try {
1517  const int numLanes = StringUtils::toInt(value);
1518  if (myCurrentEdge->myNoLanesForward < 0 && myCurrentEdge->myNoLanes < 0) {
1519  // fix lane count in case only lanes:forward and lanes:backward are set
1520  myCurrentEdge->myNoLanes = numLanes - myCurrentEdge->myNoLanesForward;
1521  }
1522  myCurrentEdge->myNoLanesForward = numLanes;
1523  } catch (...) {
1524  WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
1525  }
1526  } else if (key == "lanes:backward") {
1527  try {
1528  const int numLanes = StringUtils::toInt(value);
1529  if (myCurrentEdge->myNoLanesForward > 0 && myCurrentEdge->myNoLanes < 0) {
1530  // fix lane count in case only lanes:forward and lanes:backward are set
1531  myCurrentEdge->myNoLanes = numLanes + myCurrentEdge->myNoLanesForward;
1532  }
1533  // denote backwards count with a negative sign
1534  myCurrentEdge->myNoLanesForward = -numLanes;
1535  } catch (...) {
1536  WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
1537  }
1538  } else if (myCurrentEdge->myMaxSpeed == MAXSPEED_UNGIVEN &&
1539  (key == "maxspeed" || key == "maxspeed:type" || key == "maxspeed:forward" || key == "zone:maxspeed")) {
1540  // both 'maxspeed' and 'maxspeed:type' may be given so we must take care not to overwrite an already seen value
1541  myCurrentEdge->myMaxSpeed = interpretSpeed(key, value);
1542  } else if (key == "maxspeed:backward" && myCurrentEdge->myMaxSpeedBackward == MAXSPEED_UNGIVEN) {
1543  myCurrentEdge->myMaxSpeedBackward = interpretSpeed(key, value);
1544  } else if (key == "junction") {
1545  if ((value == "roundabout" || value == "circular") && myCurrentEdge->myIsOneWay.empty()) {
1546  myCurrentEdge->myIsOneWay = "yes";
1547  }
1548  if (value == "roundabout") {
1549  myCurrentEdge->myAmInRoundabout = true;
1550  }
1551  } else if (key == "oneway") {
1552  myCurrentEdge->myIsOneWay = value;
1553  } else if (key == "name") {
1554  myCurrentEdge->streetName = value;
1555  } else if (key == "ref") {
1556  myCurrentEdge->ref = value;
1557  myCurrentEdge->setParameter("ref", value);
1558  } else if (key == "layer") {
1559  try {
1560  myCurrentEdge->myLayer = StringUtils::toInt(value);
1561  } catch (...) {
1562  WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
1563  }
1564  } else if (key == "tracks") {
1565  try {
1566  if (StringUtils::toInt(value) == 1) {
1567  myCurrentEdge->myIsOneWay = "true";
1568  } else {
1569  WRITE_WARNINGF(TL("Ignoring track count % for edge '%'."), value, myCurrentEdge->id);
1570  }
1571  } catch (...) {
1572  WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
1573  }
1574  } else if (key == "railway:preferred_direction") {
1575  if (value == "both") {
1576  myCurrentEdge->myRailDirection = WAY_BOTH;
1577  } else if (myCurrentEdge->myRailDirection == WAY_UNKNOWN) {
1578  if (value == "backward") {
1579  myCurrentEdge->myRailDirection = WAY_BACKWARD;
1580  } else if (value == "forward") {
1581  myCurrentEdge->myRailDirection = WAY_FORWARD;
1582  }
1583  }
1584  } else if (key == "railway:bidirectional") {
1585  if (value == "regular") {
1586  myCurrentEdge->myRailDirection = WAY_BOTH;
1587  }
1588  } else if (key == "electrified" || key == "segregated") {
1589  if (value != "no") {
1590  myCurrentEdge->myExtraTags[key] = value;
1591  }
1592  } else if (key == "railway:track_ref") {
1593  myCurrentEdge->setParameter(key, value);
1594  } else if (key == "public_transport" && value == "platform") {
1595  myCurrentEdge->myExtraTags["platform"] = "yes";
1596  } else if (key == "parking:lane:both" && !StringUtils::startsWith(value, "no")) {
1597  myCurrentEdge->myParkingType |= PARKING_BOTH;
1598  } else if (key == "parking:lane:left" && !StringUtils::startsWith(value, "no")) {
1599  myCurrentEdge->myParkingType |= PARKING_LEFT;
1600  } else if (key == "parking:lane:right" && !StringUtils::startsWith(value, "no")) {
1601  myCurrentEdge->myParkingType |= PARKING_RIGHT;
1602  } else if (key == "change" || key == "change:lanes") {
1603  myCurrentEdge->myChangeForward = myCurrentEdge->myChangeBackward = interpretChangeType(value);
1604  } else if (key == "change:forward" || key == "change:lanes:forward") {
1605  myCurrentEdge->myChangeForward = interpretChangeType(value);
1606  } else if (key == "change:backward" || key == "change:lanes:backward") {
1607  myCurrentEdge->myChangeBackward = interpretChangeType(value);
1608  } else if (key == "vehicle:lanes" || key == "vehicle:lanes:forward") {
1609  interpretLaneUse(value, SVC_PASSENGER, true);
1610  interpretLaneUse(value, SVC_PRIVATE, true);
1611  } else if (key == "vehicle:lanes:backward") {
1612  interpretLaneUse(value, SVC_PASSENGER, false);
1613  interpretLaneUse(value, SVC_PRIVATE, false);
1614  } else if (key == "bus:lanes" || key == "bus:lanes:forward") {
1615  interpretLaneUse(value, SVC_BUS, true);
1616  } else if (key == "bus:lanes:backward") {
1617  interpretLaneUse(value, SVC_BUS, false);
1618  } else if (key == "psv:lanes" || key == "psv:lanes:forward") {
1619  interpretLaneUse(value, SVC_BUS, true);
1620  interpretLaneUse(value, SVC_TAXI, true);
1621  } else if (key == "psv:lanes:backward") {
1622  interpretLaneUse(value, SVC_BUS, false);
1623  interpretLaneUse(value, SVC_TAXI, false);
1624  } else if (key == "bicycle:lanes" || key == "bicycle:lanes:forward") {
1625  interpretLaneUse(value, SVC_BICYCLE, true);
1626  } else if (key == "bicycle:lanes:backward") {
1627  interpretLaneUse(value, SVC_BICYCLE, false);
1628  } else if (StringUtils::startsWith(key, "turn:") && key.find(":lanes") != std::string::npos) {
1629  int shift = 0;
1630  // use the first 8 bit to encode permitted directions for all classes
1631  // and the successive 8 bit blocks for selected classes
1632  if (StringUtils::startsWith(key, "turn:bus") || StringUtils::startsWith(key, "turn:psv:")) {
1634  } else if (StringUtils::startsWith(key, "turn:taxi")) {
1636  } else if (StringUtils::startsWith(key, "turn:bicycle")) {
1638  }
1639  const std::vector<std::string> values = StringTokenizer(value, "|").getVector();
1640  std::vector<int> turnCodes;
1641  for (std::string codeList : values) {
1642  const std::vector<std::string> codes = StringTokenizer(codeList, ";").getVector();
1643  int turnCode = 0;
1644  if (codes.size() == 0) {
1645  turnCode = (int)LinkDirection::STRAIGHT;
1646  }
1647  for (std::string code : codes) {
1648  if (code == "" || code == "none" || code == "through") {
1649  turnCode |= (int)LinkDirection::STRAIGHT << shift ;
1650  } else if (code == "left" || code == "sharp_left") {
1651  turnCode |= (int)LinkDirection::LEFT << shift;
1652  } else if (code == "right" || code == "sharp_right") {
1653  turnCode |= (int)LinkDirection::RIGHT << shift;
1654  } else if (code == "slight_left") {
1655  turnCode |= (int)LinkDirection::PARTLEFT << shift;
1656  } else if (code == "slight_right") {
1657  turnCode |= (int)LinkDirection::PARTRIGHT << shift;
1658  } else if (code == "reverse") {
1659  turnCode |= (int)LinkDirection::TURN << shift;
1660  } else if (code == "merge_to_left" || code == "merge_to_right") {
1661  turnCode |= (int)LinkDirection::NODIR << shift;
1662  }
1663  }
1664  turnCodes.push_back(turnCode);
1665  }
1666  if (StringUtils::endsWith(key, "lanes") || StringUtils::endsWith(key, "lanes:forward")) {
1667  mergeTurnSigns(myCurrentEdge->myTurnSignsForward, turnCodes);
1668  } else if (StringUtils::endsWith(key, "lanes:backward")) {
1669  mergeTurnSigns(myCurrentEdge->myTurnSignsBackward, turnCodes);
1670  } else if (StringUtils::endsWith(key, "lanes:both_ways")) {
1671  mergeTurnSigns(myCurrentEdge->myTurnSignsForward, turnCodes);
1672  mergeTurnSigns(myCurrentEdge->myTurnSignsBackward, turnCodes);
1673  }
1674  }
1675  }
1676 }
1677 
1678 
1679 double
1680 NIImporter_OpenStreetMap::EdgesHandler::interpretSpeed(const std::string& key, std::string value) {
1681  if (mySpeedMap.find(value) != mySpeedMap.end()) {
1682  return mySpeedMap[value];
1683  } else {
1684  // handle symbolic names of the form DE:30 / DE:zone30
1685  if (value.size() > 3 && value[2] == ':') {
1686  if (value.substr(3, 4) == "zone") {
1687  value = value.substr(7);
1688  } else {
1689  value = value.substr(3);
1690  }
1691  }
1692  double conversion = 1; // OSM default is km/h
1693  if (StringUtils::to_lower_case(value).find("km/h") != std::string::npos) {
1694  value = StringUtils::prune(value.substr(0, value.find_first_not_of("0123456789")));
1695  } else if (StringUtils::to_lower_case(value).find("mph") != std::string::npos) {
1696  value = StringUtils::prune(value.substr(0, value.find_first_not_of("0123456789")));
1697  conversion = KM_PER_MILE;
1698  }
1699  try {
1700  return StringUtils::toDouble(value) * conversion;
1701  } catch (...) {
1702  WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
1703  toString(myCurrentEdge->id) + "'.");
1704  return MAXSPEED_UNGIVEN;
1705  }
1706  }
1707 }
1708 
1709 
1710 int
1712  int result = 0;
1713  const std::vector<std::string> values = StringTokenizer(value, "|").getVector();
1714  for (const std::string& val : values) {
1715  if (val == "no") {
1716  result += CHANGE_NO;
1717  } else if (val == "not_left") {
1718  result += CHANGE_NO_LEFT;
1719  } else if (val == "not_right") {
1720  result += CHANGE_NO_RIGHT;
1721  }
1722  result = result << 2;
1723  }
1724  // last shift was superfluous
1725  result = result >> 2;
1726 
1727  if (values.size() > 1) {
1728  result += 2 << 29; // mark multi-value input
1729  }
1730  //std::cout << " way=" << myCurrentEdge->id << " value=" << value << " result=" << std::bitset<32>(result) << "\n";
1731  return result;
1732 }
1733 
1734 
1735 void
1736 NIImporter_OpenStreetMap::EdgesHandler::interpretLaneUse(const std::string& value, SUMOVehicleClass svc, const bool forward) const {
1737  const std::vector<std::string> values = StringTokenizer(value, "|").getVector();
1738  std::vector<bool>& designated = forward ? myCurrentEdge->myDesignatedLaneForward : myCurrentEdge->myDesignatedLaneBackward;
1739  std::vector<SVCPermissions>& allowed = forward ? myCurrentEdge->myAllowedLaneForward : myCurrentEdge->myAllowedLaneBackward;
1740  std::vector<SVCPermissions>& disallowed = forward ? myCurrentEdge->myDisallowedLaneForward : myCurrentEdge->myDisallowedLaneBackward;
1741  designated.resize(MAX2(designated.size(), values.size()), false);
1742  allowed.resize(MAX2(allowed.size(), values.size()), SVC_IGNORING);
1743  disallowed.resize(MAX2(disallowed.size(), values.size()), SVC_IGNORING);
1744  int i = 0;
1745  for (const std::string& val : values) {
1746  if (val == "yes" || val == "permissive") {
1747  allowed[i] |= svc;
1748  } else if (val == "lane" || val == "designated") {
1749  allowed[i] |= svc;
1750  designated[i] = true;
1751  } else if (val == "no") {
1752  disallowed[i] |= svc;
1753  } else {
1754  WRITE_WARNINGF(TL("Unknown lane use specifier '%' ignored for way '%'"), val, myCurrentEdge->id);
1755  }
1756  i++;
1757  }
1758 }
1759 
1760 
1761 void
1763  if (element == SUMO_TAG_WAY && myCurrentEdge != nullptr) {
1764  if (myCurrentEdge->myCurrentIsRoad) {
1765  const auto insertionIt = myEdgeMap.lower_bound(myCurrentEdge->id);
1766  if (insertionIt == myEdgeMap.end() || insertionIt->first != myCurrentEdge->id) {
1767  // assume we are loading multiple files, so we won't report duplicate edges
1768  myEdgeMap.emplace_hint(insertionIt, myCurrentEdge->id, myCurrentEdge);
1769  } else {
1770  delete myCurrentEdge;
1771  }
1772  } else if (myCurrentEdge->myExtraTags.count("platform") != 0) {
1773  const auto insertionIt = myPlatformShapesMap.lower_bound(myCurrentEdge->id);
1774  if (insertionIt == myPlatformShapesMap.end() || insertionIt->first != myCurrentEdge->id) {
1775  // assume we are loading multiple files, so we won't report duplicate platforms
1776  myPlatformShapesMap.emplace_hint(insertionIt, myCurrentEdge->id, myCurrentEdge);
1777  } else {
1778  delete myCurrentEdge;
1779  }
1780  } else {
1781  delete myCurrentEdge;
1782  }
1783  myCurrentEdge = nullptr;
1784  }
1785 }
1786 
1787 
1788 // ---------------------------------------------------------------------------
1789 // definitions of NIImporter_OpenStreetMap::RelationHandler-methods
1790 // ---------------------------------------------------------------------------
1792  const std::map<long long int, NIOSMNode*>& osmNodes,
1793  const std::map<long long int, Edge*>& osmEdges, NBPTStopCont* nbptStopCont,
1794  const std::map<long long int, Edge*>& platformShapes,
1795  NBPTLineCont* nbptLineCont,
1796  const OptionsCont& oc) :
1797  SUMOSAXHandler("osm - file"),
1798  myOSMNodes(osmNodes),
1799  myOSMEdges(osmEdges),
1800  myPlatformShapes(platformShapes),
1801  myNBPTStopCont(nbptStopCont),
1802  myNBPTLineCont(nbptLineCont),
1803  myOptionsCont(oc) {
1804  resetValues();
1805 }
1806 
1807 
1809 
1810 
1811 void
1813  myCurrentRelation = INVALID_ID;
1814  myIsRestriction = false;
1815  myRestrictionException = SVC_IGNORING;
1816  myFromWay = INVALID_ID;
1817  myToWay = INVALID_ID;
1818  myViaNode = INVALID_ID;
1819  myViaWay = INVALID_ID;
1820  myRestrictionType = RestrictionType::UNKNOWN;
1821  myPlatforms.clear();
1822  myStops.clear();
1823  myPlatformStops.clear();
1824  myWays.clear();
1825  myIsStopArea = false;
1826  myIsRoute = false;
1827  myPTRouteType = "";
1828  myRouteColor.setValid(false);
1829 }
1830 
1831 
1832 void
1834  if (element == SUMO_TAG_RELATION) {
1835  bool ok = true;
1836  myCurrentRelation = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
1837  const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, nullptr, ok);
1838  if (action == "delete" || !ok) {
1839  myCurrentRelation = INVALID_ID;
1840  }
1841  myName = "";
1842  myRef = "";
1843  myInterval = -1;
1844  myNightService = "";
1845  return;
1846  }
1847  if (myCurrentRelation == INVALID_ID) {
1848  return;
1849  }
1850  if (element == SUMO_TAG_MEMBER) {
1851  bool ok = true;
1852  std::string role = attrs.hasAttribute("role") ? attrs.getStringSecure("role", "") : "";
1853  const long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, nullptr, ok);
1854  if (role == "via") {
1855  // u-turns for divided ways may be given with 2 via-nodes or 1 via-way
1856  std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
1857  if (memberType == "way" && checkEdgeRef(ref)) {
1858  myViaWay = ref;
1859  } else if (memberType == "node") {
1860  if (myOSMNodes.find(ref) != myOSMNodes.end()) {
1861  myViaNode = ref;
1862  } else {
1863  WRITE_WARNINGF(TL("No node found for reference '%' in relation '%'."), toString(ref), toString(myCurrentRelation));
1864  }
1865  }
1866  } else if (role == "from" && checkEdgeRef(ref)) {
1867  myFromWay = ref;
1868  } else if (role == "to" && checkEdgeRef(ref)) {
1869  myToWay = ref;
1870  } else if (role == "stop") {
1871  myStops.push_back(ref);
1872  } else if (role == "platform") {
1873  std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
1874  if (memberType == "way") {
1875  const std::map<long long int, NIImporter_OpenStreetMap::Edge*>::const_iterator& wayIt = myPlatformShapes.find(ref);
1876  if (wayIt != myPlatformShapes.end()) {
1877  NIIPTPlatform platform;
1878  platform.isWay = true;
1879  platform.ref = ref;
1880  myPlatforms.push_back(platform);
1881  }
1882  } else if (memberType == "node") {
1883  // myIsStopArea may not be set yet
1884  myStops.push_back(ref);
1885  myPlatformStops.insert(ref);
1886  NIIPTPlatform platform;
1887  platform.isWay = false;
1888  platform.ref = ref;
1889  myPlatforms.push_back(platform);
1890  }
1891 
1892  } else if (role.empty()) {
1893  std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
1894  if (memberType == "way") {
1895  myWays.push_back(ref);
1896  } else if (memberType == "node") {
1897  myStops.push_back(ref);
1898  }
1899  }
1900  return;
1901  }
1902  // parse values
1903  if (element == SUMO_TAG_TAG) {
1904  bool ok = true;
1905  std::string key = attrs.get<std::string>(SUMO_ATTR_K, toString(myCurrentRelation).c_str(), ok, false);
1906  // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
1907  if (key == "type" || key == "restriction") {
1908  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1909  if (key == "type" && value == "restriction") {
1910  myIsRestriction = true;
1911  return;
1912  }
1913  if (key == "type" && value == "route") {
1914  myIsRoute = true;
1915  return;
1916  }
1917  if (key == "restriction") {
1918  // @note: the 'right/left/straight' part is ignored since the information is
1919  // redundantly encoded in the 'from', 'to' and 'via' members
1920  if (value.substr(0, 5) == "only_") {
1921  myRestrictionType = RestrictionType::ONLY;
1922  } else if (value.substr(0, 3) == "no_") {
1923  myRestrictionType = RestrictionType::NO;
1924  } else {
1925  WRITE_WARNINGF(TL("Found unknown restriction type '%' in relation '%'"), value, toString(myCurrentRelation));
1926  }
1927  return;
1928  }
1929  } else if (key == "except") {
1930  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1931  for (const std::string& v : StringTokenizer(value, ";").getVector()) {
1932  if (v == "psv") {
1933  myRestrictionException |= SVC_BUS;
1934  } else if (v == "bicycle") {
1935  myRestrictionException |= SVC_BICYCLE;
1936  } else if (v == "hgv") {
1937  myRestrictionException |= SVC_TRUCK | SVC_TRAILER;
1938  } else if (v == "motorcar") {
1939  myRestrictionException |= SVC_PASSENGER | SVC_TAXI;
1940  } else if (v == "emergency") {
1941  myRestrictionException |= SVC_EMERGENCY;
1942  }
1943  }
1944  } else if (key == "public_transport") {
1945  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1946  if (value == "stop_area") {
1947  myIsStopArea = true;
1948  }
1949  } else if (key == "route") {
1950  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1951  if (value == "train" || value == "subway" || value == "light_rail" || value == "monorail" || value == "tram" || value == "bus"
1952  || value == "trolleybus" || value == "aerialway" || value == "ferry" || value == "share_taxi" || value == "minibus") {
1953  myPTRouteType = value;
1954  }
1955 
1956  } else if (key == "name") {
1957  myName = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1958  } else if (key == "colour") {
1959  std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1960  try {
1961  myRouteColor = RGBColor::parseColor(value);
1962  } catch (...) {
1963  WRITE_WARNINGF(TL("Invalid color value '%' in relation %"), value, myCurrentRelation);
1964  }
1965  } else if (key == "ref") {
1966  myRef = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1967  } else if (key == "interval" || key == "headway") {
1968  myInterval = attrs.get<int>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1969  } else if (key == "by_night") {
1970  myNightService = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1971  }
1972  }
1973 }
1974 
1975 
1976 bool
1978  if (myOSMEdges.find(ref) != myOSMEdges.end()) {
1979  return true;
1980  }
1981  WRITE_WARNINGF(TL("No way found for reference '%' in relation '%'"), toString(ref), toString(myCurrentRelation));
1982  return false;
1983 }
1984 
1985 
1986 void
1988  if (element == SUMO_TAG_RELATION) {
1989  if (myIsRestriction) {
1990  assert(myCurrentRelation != INVALID_ID);
1991  bool ok = true;
1992  if (myRestrictionType == RestrictionType::UNKNOWN) {
1993  WRITE_WARNINGF(TL("Ignoring restriction relation '%' with unknown type."), toString(myCurrentRelation));
1994  ok = false;
1995  }
1996  if (myFromWay == INVALID_ID) {
1997  WRITE_WARNINGF(TL("Ignoring restriction relation '%' with unknown from-way."), toString(myCurrentRelation));
1998  ok = false;
1999  }
2000  if (myToWay == INVALID_ID) {
2001  WRITE_WARNINGF(TL("Ignoring restriction relation '%' with unknown to-way."), toString(myCurrentRelation));
2002  ok = false;
2003  }
2004  if (myViaNode == INVALID_ID && myViaWay == INVALID_ID) {
2005  WRITE_WARNINGF(TL("Ignoring restriction relation '%' with unknown via."), toString(myCurrentRelation));
2006  ok = false;
2007  }
2008  if (ok && !applyRestriction()) {
2009  WRITE_WARNINGF(TL("Ignoring restriction relation '%'."), toString(myCurrentRelation));
2010  }
2011  } else if (myIsStopArea) {
2012  for (long long ref : myStops) {
2013  myStopAreas[ref] = myCurrentRelation;
2014  if (myOSMNodes.find(ref) == myOSMNodes.end()) {
2015  //WRITE_WARNING(
2016  // "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
2017  // + "' does not exist. Probably OSM file is incomplete.");
2018  continue;
2019  }
2020 
2021  NIOSMNode* n = myOSMNodes.find(ref)->second;
2022  std::shared_ptr<NBPTStop> ptStop = myNBPTStopCont->get(toString(n->id));
2023  if (ptStop == nullptr) {
2024  //WRITE_WARNING(
2025  // "Relation '" + toString(myCurrentRelation) + "' refers to a non existing pt stop at node: '"
2026  // + toString(n->id) + "'. Probably OSM file is incomplete.");
2027  continue;
2028  }
2029  for (NIIPTPlatform& myPlatform : myPlatforms) {
2030  if (myPlatform.isWay) {
2031  assert(myPlatformShapes.find(myPlatform.ref) != myPlatformShapes.end()); //already tested earlier
2032  Edge* edge = (*myPlatformShapes.find(myPlatform.ref)).second;
2033  if (edge->myCurrentNodes.size() > 1 && edge->myCurrentNodes[0] == *(edge->myCurrentNodes.end() - 1)) {
2034  WRITE_WARNINGF(TL("Platform '%' in relation: '%' is given as polygon, which currently is not supported."), myPlatform.ref, myCurrentRelation);
2035  continue;
2036 
2037  }
2038  PositionVector p;
2039  for (auto nodeRef : edge->myCurrentNodes) {
2040  if (myOSMNodes.find(nodeRef) == myOSMNodes.end()) {
2041  //WRITE_WARNING(
2042  // "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
2043  // + "' does not exist. Probably OSM file is incomplete.");
2044  continue;
2045  }
2046  NIOSMNode* pNode = myOSMNodes.find(nodeRef)->second;
2047  Position pNodePos(pNode->lon, pNode->lat, pNode->ele);
2048  if (!NBNetBuilder::transformCoordinate(pNodePos)) {
2049  WRITE_ERRORF("Unable to project coordinates for node '%'.", pNode->id);
2050  continue;
2051  }
2052  p.push_back(pNodePos);
2053  }
2054  if (p.size() == 0) {
2055  WRITE_WARNINGF(TL("Referenced platform: '%' in relation: '%' is corrupt. Probably OSM file is incomplete."),
2056  toString(myPlatform.ref), toString(myCurrentRelation));
2057  continue;
2058  }
2059  NBPTPlatform platform(p[(int)p.size() / 2], p.length());
2060  ptStop->addPlatformCand(platform);
2061  } else {
2062  if (myOSMNodes.find(myPlatform.ref) == myOSMNodes.end()) {
2063  //WRITE_WARNING(
2064  // "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
2065  // + "' does not exist. Probably OSM file is incomplete.");
2066  continue;
2067  }
2068  NIOSMNode* pNode = myOSMNodes.find(myPlatform.ref)->second;
2069  Position platformPos(pNode->lon, pNode->lat, pNode->ele);
2070  if (!NBNetBuilder::transformCoordinate(platformPos)) {
2071  WRITE_ERRORF("Unable to project coordinates for node '%'.", pNode->id);
2072  }
2073  NBPTPlatform platform(platformPos, myOptionsCont.getFloat("osm.stop-output.length"));
2074  ptStop->addPlatformCand(platform);
2075 
2076  }
2077  }
2078  ptStop->setIsMultipleStopPositions(myStops.size() > 1, myCurrentRelation);
2079  }
2080  } else if (myPTRouteType != "" && myIsRoute) {
2081  NBPTLine* ptLine = new NBPTLine(toString(myCurrentRelation), myName, myPTRouteType, myRef, myInterval, myNightService,
2082  interpretTransportType(myPTRouteType), myRouteColor);
2083  bool hadGap = false;
2084  int missingBefore = 0;
2085  int missingAfter = 0;
2086  int stopIndex = 0;
2087  for (long long ref : myStops) {
2088  stopIndex++;
2089  const auto& nodeIt = myOSMNodes.find(ref);
2090  if (nodeIt == myOSMNodes.end()) {
2091  if (ptLine->getStops().empty()) {
2092  missingBefore++;
2093  } else {
2094  missingAfter++;
2095  if (!hadGap) {
2096  hadGap = true;
2097  }
2098  }
2099  continue;
2100  }
2101  if (hadGap) {
2102  WRITE_WARNINGF(TL("PT line '%' in relation % seems to be split, only keeping first part."), myName, myCurrentRelation);
2103  missingAfter = (int)myStops.size() - missingBefore - (int)ptLine->getStops().size();
2104  break;
2105  }
2106 
2107  const NIOSMNode* const n = nodeIt->second;
2108  std::shared_ptr<NBPTStop> ptStop = myNBPTStopCont->get(toString(n->id));
2109  if (ptStop == nullptr) {
2110  // loose stop, which must later be mapped onto a line way
2111  Position ptPos(n->lon, n->lat, n->ele);
2112  if (!NBNetBuilder::transformCoordinate(ptPos)) {
2113  WRITE_ERRORF("Unable to project coordinates for node '%'.", n->id);
2114  }
2115  ptStop = std::make_shared<NBPTStop>(toString(n->id), ptPos, "", "", n->ptStopLength, n->name, n->permissions);
2116  myNBPTStopCont->insert(ptStop);
2117  if (myStopAreas.count(n->id)) {
2118  ptStop->setIsMultipleStopPositions(false, myStopAreas[n->id]);
2119  }
2120  if (myPlatformStops.count(n->id) > 0) {
2121  ptStop->setIsPlatform();
2122  }
2123  }
2124  ptLine->addPTStop(ptStop);
2125  }
2126  for (long long& myWay : myWays) {
2127  auto entr = myOSMEdges.find(myWay);
2128  if (entr != myOSMEdges.end()) {
2129  Edge* edge = entr->second;
2130  for (long long& myCurrentNode : edge->myCurrentNodes) {
2131  ptLine->addWayNode(myWay, myCurrentNode);
2132  }
2133  }
2134  }
2135  ptLine->setNumOfStops((int)myStops.size(), missingBefore, missingAfter);
2136  if (ptLine->getStops().empty()) {
2137  WRITE_WARNINGF(TL("PT line in relation % with no stops ignored. Probably OSM file is incomplete."), myCurrentRelation);
2138  delete ptLine;
2139  resetValues();
2140  return;
2141  }
2142  if (!myNBPTLineCont->insert(ptLine)) {
2143  WRITE_WARNINGF(TL("Ignoring duplicate PT line '%'."), myCurrentRelation);
2144  delete ptLine;
2145  }
2146  }
2147  // other relations might use similar subelements so reset in any case
2148  resetValues();
2149  }
2150 }
2151 
2152 bool
2154  // since OSM ways are bidirectional we need the via to figure out which direction was meant
2155  if (myViaNode != INVALID_ID) {
2156  NBNode* viaNode = myOSMNodes.find(myViaNode)->second->node;
2157  if (viaNode == nullptr) {
2158  WRITE_WARNINGF(TL("Via-node '%' was not instantiated"), toString(myViaNode));
2159  return false;
2160  }
2161  NBEdge* from = findEdgeRef(myFromWay, viaNode->getIncomingEdges());
2162  NBEdge* to = findEdgeRef(myToWay, viaNode->getOutgoingEdges());
2163  if (from == nullptr) {
2164  WRITE_WARNINGF(TL("from-edge '%' of restriction relation could not be determined"), toString(myFromWay));
2165  return false;
2166  }
2167  if (to == nullptr) {
2168  WRITE_WARNINGF(TL("to-edge '%' of restriction relation could not be determined"), toString(myToWay));
2169  return false;
2170  }
2171  if (myRestrictionType == RestrictionType::ONLY) {
2172  from->addEdge2EdgeConnection(to, true);
2173  // make sure that these connections remain disabled even if network
2174  // modifications (ramps.guess) reset existing connections
2175  for (NBEdge* cand : from->getToNode()->getOutgoingEdges()) {
2176  if (!from->isConnectedTo(cand)) {
2177  if (myRestrictionException == SVC_IGNORING) {
2178  from->removeFromConnections(cand, -1, -1, true);
2179  } else {
2180  from->addEdge2EdgeConnection(cand, true, myRestrictionException);
2181  }
2182  }
2183  }
2184  } else {
2185  if (myRestrictionException == SVC_IGNORING) {
2186  from->removeFromConnections(to, -1, -1, true);
2187  } else {
2188  from->addEdge2EdgeConnection(to, true, myRestrictionException);
2189  for (NBEdge* cand : from->getToNode()->getOutgoingEdges()) {
2190  if (!from->isConnectedTo(cand)) {
2191  from->addEdge2EdgeConnection(cand, true);
2192  }
2193  }
2194  }
2195  }
2196  } else {
2197  // XXX interpreting via-ways or via-node lists not yet implemented
2198  WRITE_WARNINGF(TL("direction of restriction relation could not be determined%"), "");
2199  return false;
2200  }
2201  return true;
2202 }
2203 
2204 NBEdge*
2206  const std::vector<NBEdge*>& candidates) const {
2207  const std::string prefix = toString(wayRef);
2208  const std::string backPrefix = "-" + prefix;
2209  NBEdge* result = nullptr;
2210  int found = 0;
2211  for (auto candidate : candidates) {
2212  if ((candidate->getID().substr(0, prefix.size()) == prefix) ||
2213  (candidate->getID().substr(0, backPrefix.size()) == backPrefix)) {
2214  result = candidate;
2215  found++;
2216  }
2217  }
2218  if (found > 1) {
2219  WRITE_WARNINGF(TL("Ambiguous way reference '%' in restriction relation"), prefix);
2220  result = nullptr;
2221  }
2222  return result;
2223 }
2224 
2225 
2226 void
2228  NBNodeCont& nc = nb.getNodeCont();
2229  NBEdgeCont& ec = nb.getEdgeCont();
2230  // reconstruct elevation from layer info
2231  // build a map of raising and lowering forces (attractor and distance)
2232  // for all nodes unknownElevation
2233  std::map<NBNode*, std::vector<std::pair<double, double> > > layerForces;
2234 
2235  // collect all nodes that belong to a way with layer information
2236  std::set<NBNode*> knownElevation;
2237  for (auto& myEdge : myEdges) {
2238  Edge* e = myEdge.second;
2239  if (e->myLayer != 0) {
2240  for (auto j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
2241  NBNode* node = nc.retrieve(toString(*j));
2242  if (node != nullptr) {
2243  knownElevation.insert(node);
2244  layerForces[node].emplace_back(e->myLayer * layerElevation, POSITION_EPS);
2245  }
2246  }
2247  }
2248  }
2249 #ifdef DEBUG_LAYER_ELEVATION
2250  std::cout << "known elevations:\n";
2251  for (std::set<NBNode*>::iterator it = knownElevation.begin(); it != knownElevation.end(); ++it) {
2252  const std::vector<std::pair<double, double> >& primaryLayers = layerForces[*it];
2253  std::cout << " node=" << (*it)->getID() << " ele=";
2254  for (std::vector<std::pair<double, double> >::const_iterator it_ele = primaryLayers.begin(); it_ele != primaryLayers.end(); ++it_ele) {
2255  std::cout << it_ele->first << " ";
2256  }
2257  std::cout << "\n";
2258  }
2259 #endif
2260  // layer data only provides a lower bound on elevation since it is used to
2261  // resolve the relation among overlapping ways.
2262  // Perform a sanity check for steep inclines and raise the knownElevation if necessary
2263  std::map<NBNode*, double> knownEleMax;
2264  for (auto it : knownElevation) {
2265  double eleMax = -std::numeric_limits<double>::max();
2266  const std::vector<std::pair<double, double> >& primaryLayers = layerForces[it];
2267  for (const auto& primaryLayer : primaryLayers) {
2268  eleMax = MAX2(eleMax, primaryLayer.first);
2269  }
2270  knownEleMax[it] = eleMax;
2271  }
2272  const double gradeThreshold = OptionsCont::getOptions().getFloat("osm.layer-elevation.max-grade") / 100;
2273  bool changed = true;
2274  while (changed) {
2275  changed = false;
2276  for (auto it = knownElevation.begin(); it != knownElevation.end(); ++it) {
2277  std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it,
2278  knownEleMax[*it]
2279  / gradeThreshold * 3,
2280  knownElevation);
2281  for (auto& neighbor : neighbors) {
2282  if (knownElevation.count(neighbor.first) != 0) {
2283  const double grade = fabs(knownEleMax[*it] - knownEleMax[neighbor.first])
2284  / MAX2(POSITION_EPS, neighbor.second.first);
2285 #ifdef DEBUG_LAYER_ELEVATION
2286  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";
2287 #endif
2288  if (grade > gradeThreshold * 50 / 3.6 / neighbor.second.second) {
2289  // raise the lower node to the higher level
2290  const double eleMax = MAX2(knownEleMax[*it], knownEleMax[neighbor.first]);
2291  if (knownEleMax[*it] < eleMax) {
2292  knownEleMax[*it] = eleMax;
2293  } else {
2294  knownEleMax[neighbor.first] = eleMax;
2295  }
2296  changed = true;
2297  }
2298  }
2299  }
2300  }
2301  }
2302 
2303  // collect all nodes within a grade-dependent range around knownElevation-nodes and apply knowElevation forces
2304  std::set<NBNode*> unknownElevation;
2305  for (auto it = knownElevation.begin(); it != knownElevation.end(); ++it) {
2306  const double eleMax = knownEleMax[*it];
2307  const double maxDist = fabs(eleMax) * 100 / layerElevation;
2308  std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it, maxDist, knownElevation);
2309  for (auto& neighbor : neighbors) {
2310  if (knownElevation.count(neighbor.first) == 0) {
2311  unknownElevation.insert(neighbor.first);
2312  layerForces[neighbor.first].emplace_back(eleMax, neighbor.second.first);
2313  }
2314  }
2315  }
2316 
2317  // apply forces to ground-level nodes (neither in knownElevation nor unknownElevation)
2318  for (auto it = unknownElevation.begin(); it != unknownElevation.end(); ++it) {
2319  double eleMax = -std::numeric_limits<double>::max();
2320  const std::vector<std::pair<double, double> >& primaryLayers = layerForces[*it];
2321  for (const auto& primaryLayer : primaryLayers) {
2322  eleMax = MAX2(eleMax, primaryLayer.first);
2323  }
2324  const double maxDist = fabs(eleMax) * 100 / layerElevation;
2325  std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it, maxDist, knownElevation);
2326  for (auto& neighbor : neighbors) {
2327  if (knownElevation.count(neighbor.first) == 0 && unknownElevation.count(neighbor.first) == 0) {
2328  layerForces[*it].emplace_back(0, neighbor.second.first);
2329  }
2330  }
2331  }
2332  // compute the elevation for each node as the weighted average of all forces
2333 #ifdef DEBUG_LAYER_ELEVATION
2334  std::cout << "summation of forces\n";
2335 #endif
2336  std::map<NBNode*, double> nodeElevation;
2337  for (auto& layerForce : layerForces) {
2338  const std::vector<std::pair<double, double> >& forces = layerForce.second;
2339  if (knownElevation.count(layerForce.first) != 0) {
2340  // use the maximum value
2341  /*
2342  double eleMax = -std::numeric_limits<double>::max();
2343  for (std::vector<std::pair<double, double> >::const_iterator it_force = forces.begin(); it_force != forces.end(); ++it_force) {
2344  eleMax = MAX2(eleMax, it_force->first);
2345  }
2346  */
2347 #ifdef DEBUG_LAYER_ELEVATION
2348  std::cout << " node=" << it->first->getID() << " knownElevation=" << knownEleMax[it->first] << "\n";
2349 #endif
2350  nodeElevation[layerForce.first] = knownEleMax[layerForce.first];
2351  } else if (forces.size() == 1) {
2352  nodeElevation[layerForce.first] = forces.front().first;
2353  } else {
2354  // use the weighted sum
2355  double distSum = 0;
2356  for (const auto& force : forces) {
2357  distSum += force.second;
2358  }
2359  double weightSum = 0;
2360  double elevation = 0;
2361 #ifdef DEBUG_LAYER_ELEVATION
2362  std::cout << " node=" << it->first->getID() << " distSum=" << distSum << "\n";
2363 #endif
2364  for (const auto& force : forces) {
2365  const double weight = (distSum - force.second) / distSum;
2366  weightSum += weight;
2367  elevation += force.first * weight;
2368 
2369 #ifdef DEBUG_LAYER_ELEVATION
2370  std::cout << " force=" << it_force->first << " dist=" << it_force->second << " weight=" << weight << " ele=" << elevation << "\n";
2371 #endif
2372  }
2373  nodeElevation[layerForce.first] = elevation / weightSum;
2374  }
2375  }
2376 #ifdef DEBUG_LAYER_ELEVATION
2377  std::cout << "final elevations:\n";
2378  for (std::map<NBNode*, double>::iterator it = nodeElevation.begin(); it != nodeElevation.end(); ++it) {
2379  std::cout << " node=" << (it->first)->getID() << " ele=" << it->second << "\n";
2380  }
2381 #endif
2382  // apply node elevations
2383  for (auto& it : nodeElevation) {
2384  NBNode* n = it.first;
2385  Position pos = n->getPosition();
2386  n->reinit(n->getPosition() + Position(0, 0, it.second), n->getType());
2387  }
2388 
2389  // apply way elevation to all edges that had layer information
2390  for (const auto& it : ec) {
2391  NBEdge* edge = it.second;
2392  const PositionVector& geom = edge->getGeometry();
2393  const double length = geom.length2D();
2394  const double zFrom = nodeElevation[edge->getFromNode()];
2395  const double zTo = nodeElevation[edge->getToNode()];
2396  // XXX if the from- or to-node was part of multiple ways with
2397  // different layers, reconstruct the layer value from origID
2398  double dist = 0;
2399  PositionVector newGeom;
2400  for (auto it_pos = geom.begin(); it_pos != geom.end(); ++it_pos) {
2401  if (it_pos != geom.begin()) {
2402  dist += (*it_pos).distanceTo2D(*(it_pos - 1));
2403  }
2404  newGeom.push_back((*it_pos) + Position(0, 0, zFrom + (zTo - zFrom) * dist / length));
2405  }
2406  edge->setGeometry(newGeom);
2407  }
2408 }
2409 
2410 std::map<NBNode*, std::pair<double, double> >
2411 NIImporter_OpenStreetMap::getNeighboringNodes(NBNode* node, double maxDist, const std::set<NBNode*>& knownElevation) {
2412  std::map<NBNode*, std::pair<double, double> > result;
2413  std::set<NBNode*> visited;
2414  std::vector<NBNode*> open;
2415  open.push_back(node);
2416  result[node] = std::make_pair(0, 0);
2417  while (!open.empty()) {
2418  NBNode* n = open.back();
2419  open.pop_back();
2420  if (visited.count(n) != 0) {
2421  continue;
2422  }
2423  visited.insert(n);
2424  const EdgeVector& edges = n->getEdges();
2425  for (auto e : edges) {
2426  NBNode* s = nullptr;
2427  if (n->hasIncoming(e)) {
2428  s = e->getFromNode();
2429  } else {
2430  s = e->getToNode();
2431  }
2432  const double dist = result[n].first + e->getGeometry().length2D();
2433  const double speed = MAX2(e->getSpeed(), result[n].second);
2434  if (result.count(s) == 0) {
2435  result[s] = std::make_pair(dist, speed);
2436  } else {
2437  result[s] = std::make_pair(MIN2(dist, result[s].first), MAX2(speed, result[s].second));
2438  }
2439  if (dist < maxDist && knownElevation.count(s) == 0) {
2440  open.push_back(s);
2441  }
2442  }
2443  }
2444  result.erase(node);
2445  return result;
2446 }
2447 
2448 
2449 std::string
2450 NIImporter_OpenStreetMap::usableType(const std::string& type, const std::string& id, NBTypeCont& tc) {
2451  if (tc.knows(type)) {
2452  return type;
2453  }
2454  if (myUnusableTypes.count(type) > 0) {
2455  return "";
2456  }
2457  if (myKnownCompoundTypes.count(type) > 0) {
2458  return myKnownCompoundTypes[type];
2459  }
2460  // this edge has a type which does not yet exist in the TypeContainer
2462  std::vector<std::string> types;
2463  while (tok.hasNext()) {
2464  std::string t = tok.next();
2465  if (tc.knows(t)) {
2466  if (std::find(types.begin(), types.end(), t) == types.end()) {
2467  types.push_back(t);
2468  }
2469  } else if (tok.size() > 1) {
2470  if (!StringUtils::startsWith(t, "service.")) {
2471  WRITE_WARNINGF(TL("Discarding unknown compound '%' in type '%' (first occurrence for edge '%')."), t, type, id);
2472  }
2473  }
2474  }
2475  if (types.empty()) {
2476  if (!StringUtils::startsWith(type, "service.")) {
2477  WRITE_WARNINGF(TL("Discarding unusable type '%' (first occurrence for edge '%')."), type, id);
2478  }
2479  myUnusableTypes.insert(type);
2480  return "";
2481  }
2482  const std::string newType = joinToString(types, "|");
2483  if (tc.knows(newType)) {
2484  myKnownCompoundTypes[type] = newType;
2485  return newType;
2486  } else if (myKnownCompoundTypes.count(newType) > 0) {
2487  return myKnownCompoundTypes[newType];
2488  } else {
2489  // build a new type by merging all values
2490  int numLanes = 0;
2491  double maxSpeed = 0;
2492  int prio = 0;
2493  double width = NBEdge::UNSPECIFIED_WIDTH;
2494  double sidewalkWidth = NBEdge::UNSPECIFIED_WIDTH;
2495  double bikelaneWidth = NBEdge::UNSPECIFIED_WIDTH;
2496  bool defaultIsOneWay = true;
2497  SVCPermissions permissions = 0;
2499  bool discard = true;
2500  bool hadDiscard = false;
2501  for (auto& type2 : types) {
2502  if (!tc.getEdgeTypeShallBeDiscarded(type2)) {
2503  numLanes = MAX2(numLanes, tc.getEdgeTypeNumLanes(type2));
2504  maxSpeed = MAX2(maxSpeed, tc.getEdgeTypeSpeed(type2));
2505  prio = MAX2(prio, tc.getEdgeTypePriority(type2));
2506  defaultIsOneWay &= tc.getEdgeTypeIsOneWay(type2);
2507  //std::cout << "merging component " << type2 << " into type " << newType << " allows=" << getVehicleClassNames(tc.getPermissions(type2)) << " oneway=" << defaultIsOneWay << "\n";
2508  permissions |= tc.getEdgeTypePermissions(type2);
2509  spreadType = tc.getEdgeTypeSpreadType(type2);
2510  width = MAX2(width, tc.getEdgeTypeWidth(type2));
2511  sidewalkWidth = MAX2(sidewalkWidth, tc.getEdgeTypeSidewalkWidth(type2));
2512  bikelaneWidth = MAX2(bikelaneWidth, tc.getEdgeTypeBikeLaneWidth(type2));
2513  discard = false;
2514  } else {
2515  hadDiscard = true;
2516  }
2517  }
2518  if (hadDiscard && permissions == 0) {
2519  discard = true;
2520  }
2521  if (discard) {
2522  WRITE_WARNINGF(TL("Discarding compound type '%' (first occurrence for edge '%')."), newType, id);
2523  myUnusableTypes.insert(newType);
2524  return "";
2525  }
2526  if (width != NBEdge::UNSPECIFIED_WIDTH) {
2527  width = MAX2(width, SUMO_const_laneWidth);
2528  }
2529  // ensure pedestrians don't run into trains
2530  if (sidewalkWidth == NBEdge::UNSPECIFIED_WIDTH
2531  && (permissions & SVC_PEDESTRIAN) != 0
2532  && (permissions & SVC_RAIL_CLASSES) != 0) {
2533  //std::cout << "patching sidewalk for type '" << newType << "' which allows=" << getVehicleClassNames(permissions) << "\n";
2534  sidewalkWidth = OptionsCont::getOptions().getFloat("default.sidewalk-width");
2535  }
2536 
2537  WRITE_MESSAGEF(TL("Adding new type '%' (first occurrence for edge '%')."), type, id);
2538  tc.insertEdgeType(newType, numLanes, maxSpeed, prio, permissions, spreadType, width,
2539  defaultIsOneWay, sidewalkWidth, bikelaneWidth, 0, 0, 0);
2540  for (auto& type3 : types) {
2541  if (!tc.getEdgeTypeShallBeDiscarded(type3)) {
2542  tc.copyEdgeTypeRestrictionsAndAttrs(type3, newType);
2543  }
2544  }
2545  myKnownCompoundTypes[type] = newType;
2546  return newType;
2547  }
2548 }
2549 
2550 void
2552  const std::string id = toString(e->id);
2553  std::string type = usableType(e->myHighWayType, id, tc);
2554  if (type != "" && isRailway(tc.getEdgeTypePermissions(type))) {
2555  std::vector<NIOSMNode*> nodes;
2556  std::vector<double> usablePositions;
2557  std::vector<int> usableIndex;
2558  for (long long int n : e->myCurrentNodes) {
2559  NIOSMNode* node = myOSMNodes[n];
2560  node->positionMeters = interpretDistance(node);
2561  if (node->positionMeters != std::numeric_limits<double>::max()) {
2562  usablePositions.push_back(node->positionMeters);
2563  usableIndex.push_back((int)nodes.size());
2564  }
2565  nodes.push_back(node);
2566  }
2567  if (usablePositions.size() == 0) {
2568  return;
2569  } else {
2570  bool forward = true;
2571  if (usablePositions.size() == 1) {
2572  WRITE_WARNINGF(TL("Ambiguous railway kilometrage direction for way '%' (assuming forward)"), id);
2573  } else {
2574  forward = usablePositions.front() < usablePositions.back();
2575  }
2576  // check for consistency
2577  for (int i = 1; i < (int)usablePositions.size(); i++) {
2578  if ((usablePositions[i - 1] < usablePositions[i]) != forward) {
2579  WRITE_WARNINGF(TL("Inconsistent railway kilometrage direction for way '%': % (skipping)"), id, toString(usablePositions));
2580  return;
2581  }
2582  }
2583  if (nodes.size() > usablePositions.size()) {
2584  // complete missing values
2585  PositionVector shape;
2586  for (NIOSMNode* node : nodes) {
2587  shape.push_back(Position(node->lon, node->lat, 0));
2588  }
2589  if (!NBNetBuilder::transformCoordinates(shape)) {
2590  return; // error will be given later
2591  }
2592  double sign = forward ? 1 : -1;
2593  // extend backward before first usable value
2594  for (int i = usableIndex.front() - 1; i >= 0; i--) {
2595  nodes[i]->positionMeters = nodes[i + 1]->positionMeters - sign * shape[i].distanceTo2D(shape[i + 1]);
2596  }
2597  // extend forward
2598  for (int i = usableIndex.front() + 1; i < (int)nodes.size(); i++) {
2599  if (nodes[i]->positionMeters == std::numeric_limits<double>::max()) {
2600  nodes[i]->positionMeters = nodes[i - 1]->positionMeters + sign * shape[i].distanceTo2D(shape[i - 1]);
2601  }
2602  }
2603  //std::cout << " way=" << id << " usable=" << toString(usablePositions) << "\n indices=" << toString(usableIndex)
2604  // << " final:\n";
2605  //for (auto n : nodes) {
2606  // std::cout << " " << n->id << " " << n->positionMeters << " " << n->position<< "\n";
2607  //}
2608  }
2609  }
2610  }
2611 }
2612 
2613 
2614 double
2616  if (node->position.size() > 0) {
2617  try {
2618  if (StringUtils::startsWith(node->position, "mi:")) {
2619  return StringUtils::toDouble(node->position.substr(3)) * 1609.344; // meters per mile
2620  } else {
2621  return StringUtils::toDouble(node->position) * 1000;
2622  }
2623  } catch (...) {
2624  WRITE_WARNINGF(TL("Value of railway:position is not numeric ('%') in node '%'."), node->position, toString(node->id));
2625  }
2626  }
2627  return std::numeric_limits<double>::max();
2628 }
2629 
2632  SUMOVehicleClass result = SVC_IGNORING;
2633  if (type == "train") {
2634  result = SVC_RAIL;
2635  } else if (type == "subway") {
2636  result = SVC_SUBWAY;
2637  } else if (type == "aerialway") {
2638  result = SVC_CABLE_CAR;
2639  } else if (type == "light_rail" || type == "monorail") {
2640  result = SVC_RAIL_URBAN;
2641  } else if (type == "share_taxi") {
2642  result = SVC_TAXI;
2643  } else if (type == "minibus") {
2644  result = SVC_BUS;
2645  } else if (SumoVehicleClassStrings.hasString(type)) {
2646  result = SumoVehicleClassStrings.get(type);
2647  }
2648  std::string stop = "";
2649  if (result == SVC_TRAM) {
2650  stop = ".tram";
2651  } else if (result == SVC_BUS) {
2652  stop = ".bus";
2653  } else if (isRailway(result)) {
2654  stop = ".train";
2655  }
2656  if (toSet != nullptr && result != SVC_IGNORING) {
2657  toSet->permissions |= result;
2658  toSet->ptStopLength = OptionsCont::getOptions().getFloat("osm.stop-output.length" + stop);
2659  }
2660  return result;
2661 }
2662 
2663 
2664 void
2666  bool multiLane = changeProhibition > 3;
2667  //std::cout << "applyChangeProhibition e=" << e->getID() << " changeProhibition=" << std::bitset<32>(changeProhibition) << " val=" << changeProhibition << "\n";
2668  for (int lane = 0; changeProhibition > 0 && lane < e->getNumLanes(); lane++) {
2669  int code = changeProhibition % 4; // only look at the last 2 bits
2670  SVCPermissions changeLeft = (code & CHANGE_NO_LEFT) == 0 ? SVCAll : (SVCPermissions)SVC_AUTHORITY;
2671  SVCPermissions changeRight = (code & CHANGE_NO_RIGHT) == 0 ? SVCAll : (SVCPermissions)SVC_AUTHORITY;
2672  e->setPermittedChanging(lane, changeLeft, changeRight);
2673  if (multiLane) {
2674  changeProhibition = changeProhibition >> 2;
2675  }
2676  }
2677 }
2678 
2679 
2680 void
2682  if (myImportLaneAccess) {
2683  const int numLanes = e->getNumLanes();
2684  const bool lefthand = OptionsCont::getOptions().getBool("lefthand");
2685  const std::vector<bool>& designated = forward ? nie->myDesignatedLaneForward : nie->myDesignatedLaneBackward;
2686  const std::vector<SVCPermissions>& allowed = forward ? nie->myAllowedLaneForward : nie->myAllowedLaneBackward;
2687  const std::vector<SVCPermissions>& disallowed = forward ? nie->myDisallowedLaneForward : nie->myDisallowedLaneBackward;
2688  for (int lane = 0; lane < numLanes; lane++) {
2689  // laneUse stores from left to right
2690  const int i = lefthand ? lane : numLanes - 1 - lane;
2691  // Extra allowed SVCs for this lane or none if no info was present for the lane
2692  const SVCPermissions extraAllowed = i < (int)allowed.size() ? allowed[i] : (SVCPermissions)SVC_IGNORING;
2693  // Extra disallowed SVCs for this lane or none if no info was present for the lane
2694  const SVCPermissions extraDisallowed = i < (int)disallowed.size() ? disallowed[i] : (SVCPermissions)SVC_IGNORING;
2695  if (i < (int)designated.size() && designated[i]) {
2696  // if designated, delete all permissions
2697  e->setPermissions(SVC_IGNORING, lane);
2698  e->preferVehicleClass(lane, extraAllowed);
2699  }
2700  e->setPermissions((e->getPermissions(lane) | extraAllowed) & (~extraDisallowed), lane);
2701  }
2702  }
2703 }
2704 
2705 void
2706 NIImporter_OpenStreetMap::mergeTurnSigns(std::vector<int>& signs, std::vector<int> signs2) {
2707  if (signs.empty()) {
2708  signs.insert(signs.begin(), signs2.begin(), signs2.end());
2709  } else {
2710  for (int i = 0; i < (int)MIN2(signs.size(), signs2.size()); i++) {
2711  signs[i] |= signs2[i];
2712  }
2713  }
2714 }
2715 
2716 
2717 void
2718 NIImporter_OpenStreetMap::applyTurnSigns(NBEdge* e, const std::vector<int>& turnSigns) {
2719  if (myImportTurnSigns && turnSigns.size() > 0) {
2720  // no sidewalks and bike lanes have been added yet
2721  if ((int)turnSigns.size() == e->getNumLanes()) {
2722  //std::cout << "apply turnSigns for " << e->getID() << " turnSigns=" << toString(turnSigns) << "\n";
2723  for (int i = 0; i < (int)turnSigns.size(); i++) {
2724  // laneUse stores from left to right
2725  const int laneIndex = e->getNumLanes() - 1 - i;
2726  NBEdge::Lane& lane = e->getLaneStruct(laneIndex);
2727  lane.turnSigns = turnSigns[i];
2728  }
2729  } else {
2730  WRITE_WARNINGF(TL("Ignoring turn sign information for % lanes on edge % with % driving lanes"), turnSigns.size(), e->getID(), e->getNumLanes());
2731  }
2732  }
2733 }
2734 
2735 
2736 /****************************************************************************/
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:296
#define WRITE_MESSAGEF(...)
Definition: MsgHandler.h:298
#define WRITE_ERRORF(...)
Definition: MsgHandler.h:305
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:304
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:295
#define PROGRESS_BEGIN_TIME_MESSAGE(msg)
Definition: MsgHandler.h:301
#define TL(string)
Definition: MsgHandler.h:315
#define PROGRESS_TIME_MESSAGE(before)
Definition: MsgHandler.h:302
#define PROGRESS_DONE_MESSAGE()
Definition: MsgHandler.h:300
#define TLF(string,...)
Definition: MsgHandler.h:317
#define PROGRESS_BEGIN_MESSAGE(msg)
Definition: MsgHandler.h:299
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition: NBCont.h:35
#define KM_PER_MILE
SVCPermissions extraDisallowed(SVCPermissions disallowed, const MMVersion &networkVersion)
Interprets disallowed vehicles depending on network version.
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)
long long int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types.
@ SVC_SHIP
is an arbitrary ship
@ SVC_PRIVATE
private vehicles
@ SVC_TRUCK
vehicle is a large transport vehicle
@ 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_CABLE_CAR
@ 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_TRAILER
vehicle is a large transport vehicle
@ SVC_RAIL_ELECTRIC
rail vehicle that requires electrified tracks
@ SVC_RAIL_URBAN
vehicle is a city rail
@ SVC_EMERGENCY
public emergency vehicles
@ SVC_AUTHORITY
authorities vehicles
@ SVC_TRAM
vehicle is a light rail
@ SVC_PUBLIC_CLASSES
public transport
@ SVC_TAXI
vehicle is a taxi
@ SVC_BUS
vehicle is a bus
@ SVC_SUBWAY
@ SVC_PEDESTRIAN
pedestrian
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_ACTION
@ SUMO_ATTR_K
const double SUMO_const_laneWidth
Definition: StdDefs.h:48
T MIN2(T a, T b)
Definition: StdDefs.h:76
T MAX2(T a, T b)
Definition: StdDefs.h:82
std::string joinToStringSorting(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:299
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:283
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:51
void setFileName(const std::string &name)
Sets the current file name.
bool wasInformed() const
Returns the information whether any messages were added.
Definition: MsgHandler.cpp:416
static MsgHandler * getErrorInstance()
Returns the instance to add errors to.
Definition: MsgHandler.cpp:92
Storage for edges, including some functionality operating on multiple edges.
Definition: NBEdgeCont.h:59
int extractRoundabouts()
Determines which edges have been marked as roundabouts and stores them internally.
bool insert(NBEdge *edge, bool ignorePrunning=false)
Adds an edge to the dictionary.
Definition: NBEdgeCont.cpp:182
The representation of a single edge during network building.
Definition: NBEdge.h:92
static const int TURN_SIGN_SHIFT_BUS
shift values for decoding turn signs
Definition: NBEdge.h:375
static const int TURN_SIGN_SHIFT_BICYCLE
Definition: NBEdge.h:377
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:4297
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:4306
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:4269
void addBikeLane(double width)
add a bicycle lane of the given width and shift existing connctions
Definition: NBEdge.cpp:4512
static const double UNSPECIFIED_FRICTION
unspecified lane friction
Definition: NBEdge.h:351
bool addEdge2EdgeConnection(NBEdge *dest, bool overrideRemoval=false, SVCPermissions permission=SVC_UNSPECIFIED)
Adds a connection to another edge.
Definition: NBEdge.cpp:1063
void setTurnSignTarget(const std::string &target)
Definition: NBEdge.h:1551
void setDistance(double distance)
set kilometrage at start of edge (negative value implies couting down along the edge)
Definition: NBEdge.h:1407
const std::string & getID() const
Definition: NBEdge.h:1522
const std::vector< NBEdge::Lane > & getLanes() const
Returns the lane definitions.
Definition: NBEdge.h:726
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:542
void setLaneWidth(int lane, double width)
set lane specific width (negative lane implies set for all lanes)
Definition: NBEdge.cpp:4092
void addSidewalk(double width)
add a pedestrian sidewalk of the given width and shift existing connctions
Definition: NBEdge.cpp:4500
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:516
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition: NBEdge.h:779
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:1413
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:1296
static const int TURN_SIGN_SHIFT_TAXI
Definition: NBEdge.h:376
void preferVehicleClass(int lane, SVCPermissions vclasses)
prefer certain vehicle classes for the given lane or for all lanes if -1 is given (ensures also permi...
Definition: NBEdge.cpp:4078
static const double UNSPECIFIED_WIDTH
unspecified lane width
Definition: NBEdge.h:342
static const double UNSPECIFIED_OFFSET
unspecified lane offset
Definition: NBEdge.h:345
Lane & getLaneStruct(int lane)
Definition: NBEdge.h:1422
void setJunctionPriority(const NBNode *const node, int prio)
Sets the junction priority of the edge.
Definition: NBEdge.cpp:2092
void setGeometry(const PositionVector &g, bool inner=false)
(Re)sets the edge's geometry
Definition: NBEdge.cpp:618
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:535
Instance responsible for building networks.
Definition: NBNetBuilder.h:107
static bool transformCoordinates(PositionVector &from, bool includeInBoundary=true, GeoConvHelper *from_srs=nullptr)
NBTypeCont & getTypeCont()
Returns a reference to the type container.
Definition: NBNetBuilder.h:149
NBParkingCont & getParkingCont()
Definition: NBNetBuilder.h:173
NBPTLineCont & getPTLineCont()
Returns a reference to the pt line container.
Definition: NBNetBuilder.h:169
NBEdgeCont & getEdgeCont()
Definition: NBNetBuilder.h:139
NBPTStopCont & getPTStopCont()
Returns a reference to the pt stop container.
Definition: NBNetBuilder.h:164
static bool transformCoordinate(Position &from, bool includeInBoundary=true, GeoConvHelper *from_srs=nullptr)
transforms loaded coordinates handles projections, offsets (using GeoConvHelper) and import of height...
NBNodeCont & getNodeCont()
Returns a reference to the node container.
Definition: NBNetBuilder.h:144
NBTrafficLightLogicCont & getTLLogicCont()
Returns a reference to the traffic light logics container.
Definition: NBNetBuilder.h:154
Container for nodes during the netbuilding process.
Definition: NBNodeCont.h:57
bool insert(const std::string &id, const Position &position, NBDistrict *district=0)
Inserts a node into the map.
Definition: NBNodeCont.cpp:87
NBNode * retrieve(const std::string &id) const
Returns the node with the given name.
Definition: NBNodeCont.cpp:116
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:1847
NBNode::Crossing * addCrossing(EdgeVector edges, double width, bool priority, int tlIndex=-1, int tlIndex2=-1, const PositionVector &customShape=PositionVector::EMPTY, bool fromSumoNet=false, const Parameterised *params=nullptr)
add a pedestrian crossing to this node
Definition: NBNode.cpp:3809
void reinit(const Position &position, SumoXMLNodeType type, bool updateEdgeGeometries=false)
Resets initial values.
Definition: NBNode.cpp:338
SumoXMLNodeType getType() const
Returns the type of this node.
Definition: NBNode.h:285
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges (The edges which start at this node)
Definition: NBNode.h:273
const EdgeVector & getEdges() const
Returns all edges which participate in this node (Edges that start or end at this node)
Definition: NBNode.h:278
bool checkCrossingDuplicated(EdgeVector edges)
return true if there already exist a crossing with the same edges as the input
Definition: NBNode.cpp:2841
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges (The edges which yield in this node)
Definition: NBNode.h:268
const Position & getPosition() const
Definition: NBNode.h:260
static const int FORWARD
edge directions (for pedestrian related stuff)
Definition: NBNode.h:216
void setFringeType(FringeType fringeType)
set method for computing right-of-way
Definition: NBNode.h:574
A traffic light logics which must be computed (only nodes/edges are given)
Definition: NBOwnTLDef.h:44
void setNumOfStops(int numStops, int missingBefore, int missingAfter)
Definition: NBPTLine.cpp:166
void addWayNode(long long int way, long long int node)
Definition: NBPTLine.cpp:121
const std::vector< std::shared_ptr< NBPTStop > > & getStops()
Definition: NBPTLine.cpp:68
void addPTStop(std::shared_ptr< NBPTStop > pStop)
Definition: NBPTLine.cpp:54
Container for public transport stops during the net building process.
Definition: NBPTStopCont.h:44
int cleanupDeleted(NBEdgeCont &cont)
remove stops on non existing (removed) edges
const std::map< std::string, std::shared_ptr< NBPTStop > > & getStops() const
Returns an unmodifiable reference to the stored pt stops.
Definition: NBPTStopCont.h:62
std::shared_ptr< NBPTStop > get(std::string id) const
Retrieve a previously inserted pt stop.
bool insert(std::shared_ptr< NBPTStop > ptStop, bool floating=false)
Inserts a node into the map.
The representation of an imported parking area.
Definition: NBParking.h:42
static const std::string OSM_DIRECTION
processing parameter for rail signal edges and nodes
static const std::string OSM_SIGNAL_DIRECTION
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:526
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:204
bool copyEdgeTypeRestrictionsAndAttrs(const std::string &fromId, const std::string &toId)
Copy restrictions to a edgeType.
Definition: NBTypeCont.cpp:342
double getEdgeTypeSpeed(const std::string &edgeType) const
Returns the maximal velocity for the given edgeType [m/s].
Definition: NBTypeCont.cpp:503
int getEdgeTypePriority(const std::string &edgeType) const
Returns the priority for the given edgeType.
Definition: NBTypeCont.cpp:514
int getEdgeTypeNumLanes(const std::string &edgeType) const
Returns the number of lanes for the given edgeType.
Definition: NBTypeCont.cpp:497
double getEdgeTypeWidth(const std::string &edgeType) const
Returns the lane width for the given edgeType [m].
Definition: NBTypeCont.cpp:564
SVCPermissions getEdgeTypePermissions(const std::string &edgeType) const
Returns allowed vehicle classes for the given edgeType.
Definition: NBTypeCont.cpp:552
bool knows(const std::string &edgeType) const
Returns whether the named edgeType is in the container.
Definition: NBTypeCont.cpp:303
double getEdgeTypeSidewalkWidth(const std::string &edgeType) const
Returns the lane width for a sidewalk to be added [m].
Definition: NBTypeCont.cpp:570
LaneSpreadFunction getEdgeTypeSpreadType(const std::string &edgeType) const
Returns spreadType for the given edgeType.
Definition: NBTypeCont.cpp:558
double getEdgeTypeBikeLaneWidth(const std::string &edgeType) const
Returns the lane width for a bike lane to be added [m].
Definition: NBTypeCont.cpp:576
bool getEdgeTypeIsOneWay(const std::string &edgeType) const
Returns whether edges are one-way per default for the given edgeType.
Definition: NBTypeCont.cpp:520
bool operator()(const Edge *e1, const Edge *e2) const
An internal definition of a loaded edge.
std::vector< SVCPermissions > myDisallowedLaneBackward
(optional) information about additional disallowed SVCs on backward lane(s)
std::map< std::string, std::string > myExtraTags
Additionally tagged information.
std::vector< double > myWidthLanesForward
Information on lane width.
WayType mySidewalkType
Information about the kind of sidwalk along this road.
std::vector< SVCPermissions > myDisallowedLaneForward
(optional) information about additional disallowed SVCs on forward lane(s)
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
std::string ref
The edge's track name.
std::vector< SVCPermissions > myAllowedLaneForward
(optional) information about additional allowed SVCs on forward lane(s)
std::string myHighWayType
The type, stored in "highway" key.
const long long int id
The edge's id.
bool myAmInRoundabout
Information whether this road is part of a roundabout.
int myLayer
Information about the relative z-ordering of ways.
std::vector< bool > myDesignatedLaneBackward
(optional) information about whether the backward lanes are designated to some SVCs
SVCPermissions myExtraDisallowed
Extra permissions prohibited from tags instead of highway type.
std::vector< SVCPermissions > myAllowedLaneBackward
(optional) information about additional allowed SVCs on backward lane(s)
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::vector< bool > myDesignatedLaneForward
(optional) information about whether the forward lanes are designated to some SVCs
std::string myIsOneWay
Information whether this is an one-way road.
A class which extracts OSM-edges from a parsed OSM-file.
void interpretLaneUse(const std::string &value, SUMOVehicleClass svc, const bool forward) const
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
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;.
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)
Constructor.
void myEndElement(int element) override
Called when a closing tag occurs.
StringVector myRailSignalRules
custom requirements for rail signal tagging
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
bool myImportCrossings
import crossings
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
void applyLaneUse(NBEdge *e, NIImporter_OpenStreetMap::Edge *nie, const bool forward)
Applies lane use information from nie to e.
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
static bool myAllAttributes
whether additional way and node attributes shall be imported
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 std::set< std::string > myExtraAttributes
extra attributes to import
bool myImportBikeAccess
import bike path specific permissions and directions
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.
static void mergeTurnSigns(std::vector< int > &signs, std::vector< int > signs2)
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
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:60
void unsetParameter(const std::string &key)
Removes a parameter.
bool hasParameter(const std::string &key) const
Returns whether the parameter is set.
virtual const std::string getParameter(const std::string &key, const std::string defaultValue="") const
Returns the value for a given key.
const Parameterised::Map & getParametersMap() const
Returns the inner key/value map.
virtual void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
void updateParameters(const Parameterised::Map &mapArg)
Adds or updates all given parameters from the 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:239
Encapsulated SAX-Attributes.
T getOpt(int attr, const char *objectid, bool &ok, T defaultValue=T(), bool report=true) const
Tries to read given attribute assuming it is an int.
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 long long int toLong(const std::string &sData)
converts a string into the long value described by it by calling the char-type converter,...
static std::string to_lower_case(const std::string &str)
Transfers the content to lower case.
Definition: StringUtils.cpp:77
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 prune(const std::string &str)
Removes trailing and leading whitechars.
Definition: StringUtils.cpp:56
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 SUMOSAXReader * getSAXReader(SUMOSAXHandler &handler, const bool isNet=false, const bool isRoute=false)
Builds a reader and assigns the handler to it.
Definition: XMLSubSys.cpp:141
An (internal) definition of a single lane of an edge.
Definition: NBEdge.h:143
int turnSigns
turning signs printed on the road, bitset of LinkDirection (imported from OSM)
Definition: NBEdge.h:195
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 pedestrianCrossing
Whether this is a pedestrian crossing.
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.
WayType myRailDirection
Information about the direction(s) of railway usage.