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