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