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