diff --git a/src/pfaedle/PfaedleMain.cpp b/src/pfaedle/PfaedleMain.cpp index e0ebec8..9ed4e77 100644 --- a/src/pfaedle/PfaedleMain.cpp +++ b/src/pfaedle/PfaedleMain.cpp @@ -1,12 +1,12 @@ // Copyright 2018, University of Freiburg, // Chair of Algorithms and Data Structures. // Authors: Patrick Brosi -#include #include -#include -#include #include #include +#include +#include +#include #include #include #include @@ -163,14 +163,12 @@ int main(int argc, char** argv) { LOG(INFO) << "Writing filtered XML to " << cfg.writeOsm << " ..."; BBoxIdx box(BOX_PADDING); for (size_t i = 0; i < cfg.feedPaths.size(); i++) { - ShapeBuilder::getGtfsBox(>fs[i], cmdCfgMots, cfg.shapeTripId, true, - &box); + ShapeBuilder::getGtfsBox(>fs[i], cmdCfgMots, cfg.shapeTripId, true, &box); } OsmBuilder osmBuilder; std::vector opts; for (const auto& o : motCfgReader.getConfigs()) { - if (std::find_first_of(o.mots.begin(), o.mots.end(), cmdCfgMots.begin(), - cmdCfgMots.end()) != o.mots.end()) { + if (std::find_first_of(o.mots.begin(), o.mots.end(), cmdCfgMots.begin(), cmdCfgMots.end()) != o.mots.end()) { opts.push_back(o.osmBuildOpts); } } @@ -185,14 +183,12 @@ int main(int argc, char** argv) { } else if (cfg.writeOverpass) { BBoxIdx box(BOX_PADDING); for (size_t i = 0; i < cfg.feedPaths.size(); i++) { - ShapeBuilder::getGtfsBox(>fs[i], cmdCfgMots, cfg.shapeTripId, true, - &box); + ShapeBuilder::getGtfsBox(>fs[i], cmdCfgMots, cfg.shapeTripId, true, &box); } OsmBuilder osmBuilder; std::vector opts; for (const auto& o : motCfgReader.getConfigs()) { - if (std::find_first_of(o.mots.begin(), o.mots.end(), cmdCfgMots.begin(), - cmdCfgMots.end()) != o.mots.end()) { + if (std::find_first_of(o.mots.begin(), o.mots.end(), cmdCfgMots.begin(), cmdCfgMots.end()) != o.mots.end()) { opts.push_back(o.osmBuildOpts); } } @@ -251,8 +247,7 @@ int main(int argc, char** argv) { } } - ShapeBuilder shapeBuilder(>fs[0], &evalFeed, cmdCfgMots, motCfg, &ecoll, - &graph, &fStops, &restr, cfg); + ShapeBuilder shapeBuilder(>fs[0], &evalFeed, cmdCfgMots, motCfg, &ecoll, &graph, &fStops, &restr, cfg); if (cfg.writeGraph) { LOG(INFO) << "Outputting graph.json..."; diff --git a/src/pfaedle/osm/OsmBuilder.cpp b/src/pfaedle/osm/OsmBuilder.cpp index 1f02ec0..65a0734 100644 --- a/src/pfaedle/osm/OsmBuilder.cpp +++ b/src/pfaedle/osm/OsmBuilder.cpp @@ -2,7 +2,10 @@ // Chair of Algorithms and Data Structures. // Authors: Patrick Brosi -#include +#include +#include +#include + #include #include #include @@ -13,12 +16,6 @@ #include #include -#include -#include -#include -#include -#include - #include "pfaedle/Def.h" #include "pfaedle/osm/BBoxIdx.h" #include "pfaedle/osm/Osm.h" @@ -55,442 +52,453 @@ using pfaedle::osm::BlockSearch; using ad::cppgtfs::gtfs::Stop; class NodeHandler : public osmium::handler::Handler { - const pfaedle::osm::OsmFilter& filter; - const pfaedle::osm::BBoxIdx& bbox; - pfaedle::osm::OsmIdSet& bboxNodes; - pfaedle::osm::OsmIdSet& noHupNodes; + const pfaedle::osm::OsmFilter& _filter; + const pfaedle::osm::BBoxIdx& _bbox; + pfaedle::osm::OsmIdSet& _bboxNodes; + pfaedle::osm::OsmIdSet& _noHupNodes; -public: - NodeHandler(const pfaedle::osm::OsmFilter& filter, - const pfaedle::osm::BBoxIdx& bbox, - pfaedle::osm::OsmIdSet& bboxNodes, - pfaedle::osm::OsmIdSet& noHupNodes) : - filter(filter), - bbox(bbox), - bboxNodes(bboxNodes), - noHupNodes(noHupNodes) - { + public: + NodeHandler(const pfaedle::osm::OsmFilter& filter, + const pfaedle::osm::BBoxIdx& bbox, + pfaedle::osm::OsmIdSet& bboxNodes, + pfaedle::osm::OsmIdSet& noHupNodes) : + _filter(filter), + _bbox(bbox), + _bboxNodes(bboxNodes), + _noHupNodes(noHupNodes) + {} - } + void node(const osmium::Node& node) { + bool ignored = false; - void node(const osmium::Node& node) { - bool ignored = false; - for(const auto& tag: node.tags()) { - if (filter.nohup(tag.key(), tag.value())) { - noHupNodes.add(node.id()); - ignored = true; - break; + for (const auto& tag : node.tags()) { + if (_filter.nohup(tag.key(), tag.value())) { + _noHupNodes.add(node.id()); + ignored = true; + break; + } + } + + if (!ignored) { + Point point{node.location().lon(), node.location().lat()}; + if (_bbox.contains(point)) { + _bboxNodes.add(node.id()); + } } } - if(!ignored) { - Point point(node.location().lon(), node.location().lat()); - if (bbox.contains(point)) { - bboxNodes.add(node.id()); - } - } - } - }; class RelationHandler: public osmium::handler::Handler { - const pfaedle::osm::OsmFilter& filter; - const pfaedle::osm::BBoxIdx& bbox; - const pfaedle::osm::AttrKeySet& keepAttrs; - pfaedle::osm::RelLst& rels; - pfaedle::osm::RelMap& nodeRels; - pfaedle::osm::RelMap& wayRels; - pfaedle::osm::Restrictions& restrictions; -public: - RelationHandler(const pfaedle::osm::OsmFilter& filter, - const pfaedle::osm::BBoxIdx& bbox, - const pfaedle::osm::AttrKeySet& keepAttrs, - pfaedle::osm::RelLst& rels, - pfaedle::osm::RelMap& nodeRels, - pfaedle::osm::RelMap& wayRels, - pfaedle::osm::Restrictions& restrictions) : - filter(filter), - bbox(bbox), - keepAttrs(keepAttrs), - rels(rels), - nodeRels(nodeRels), - wayRels(wayRels), - restrictions(restrictions){ + const pfaedle::osm::OsmFilter& _filter; + const pfaedle::osm::BBoxIdx& _bbox; + const pfaedle::osm::AttrKeySet& _keepAttrs; + pfaedle::osm::RelLst& _rels; + pfaedle::osm::RelMap& _nodeRels; + pfaedle::osm::RelMap& _wayRels; + pfaedle::osm::Restrictions& _restrictions; - } + public: + RelationHandler(const pfaedle::osm::OsmFilter& filter, + const pfaedle::osm::BBoxIdx& bbox, + const pfaedle::osm::AttrKeySet& keepAttrs, + pfaedle::osm::RelLst& rels, + pfaedle::osm::RelMap& nodeRels, + pfaedle::osm::RelMap& wayRels, + pfaedle::osm::Restrictions& restrictions) : + _filter(filter), + _bbox(bbox), + _keepAttrs(keepAttrs), + _rels(rels), + _nodeRels(nodeRels), + _wayRels(wayRels), + _restrictions(restrictions) + {} - void relation(const osmium::Relation &relation) { - OsmRel rel; - rel.id = relation.id(); - if(rel.id == 0) return; + void relation(const osmium::Relation &relation) { + OsmRel rel; + rel.id = relation.id(); - for(const auto& tag: relation.tags()) { - if (keepAttrs.count(tag.key())) { - rel.attrs[tag.key()] = tag.value(); + if (rel.id == 0) { + return; } - } - for(const auto& member: relation.members()) { - auto& obj = member.get_object(); - if (member.type() == osmium::item_type::node) { - rel.nodes.push_back(obj.id()); - rel.nodeRoles.emplace_back(member.role()); - } else if (member.type() == osmium::item_type::way) { - rel.ways.push_back(obj.id()); - rel.wayRoles.emplace_back(member.role()); - } - } - for (auto id : rel.nodes) { - nodeRels[id].push_back(rels.rels.size() - 1); - } - for (auto id : rel.ways) { - wayRels[id].push_back(rels.rels.size() - 1); - } - - uint64_t keepFlags = filter.keep(rel.attrs, pfaedle::osm::OsmFilter::REL); - uint64_t dropFlags = filter.drop(rel.attrs, pfaedle::osm::OsmFilter::REL); - if (rel.id && !rel.attrs.empty() && keepFlags && !dropFlags) { - rel.keepFlags = keepFlags; - rel.dropFlags = dropFlags; - } - - rels.rels.push_back(rel.attrs); - if (rel.keepFlags & pfaedle::osm::REL_NO_DOWN) { - rels.flat.insert(rels.rels.size() - 1); - } - { - if (!rel.attrs.count("type")) return; - if (rel.attrs.find("type")->second != "restriction") return; - - bool pos = filter.posRestr(rel.attrs); - bool neg = filter.negRestr(rel.attrs); - - if (!pos && !neg) return; - - uint64_t from = 0; - uint64_t to = 0; - uint64_t via = 0; - - for (size_t i = 0; i < rel.ways.size(); i++) { - if (rel.wayRoles[i] == "from") { - if (from) return; // only one from member supported - from = rel.ways[i]; - } - if (rel.wayRoles[i] == "to") { - if (to) return; // only one to member supported - to = rel.ways[i]; + for (const auto& tag : relation.tags()) { + if (_keepAttrs.count(tag.key())) { + rel.attrs[tag.key()] = tag.value(); } } - for (size_t i = 0; i < rel.nodes.size(); i++) { - if (rel.nodeRoles[i] == "via") { - via = rel.nodes[i]; - break; + for (const auto& member : relation.members()) { + using osmium::item_type; + auto& obj = member.get_object(); + if (member.type() == item_type::node) { + rel.nodes.push_back(obj.id()); + rel.nodeRoles.emplace_back(member.role()); + } else if (member.type() == item_type::way) { + rel.ways.push_back(obj.id()); + rel.wayRoles.emplace_back(member.role()); } } + for (auto id : rel.nodes) { + _nodeRels[id].push_back(_rels.rels.size() - 1); + } - if (from && to && via) { - if (pos) { - restrictions.pos[via].emplace_back(from, to); - } else if (neg) { - restrictions.neg[via].emplace_back(from, to); + for (auto id : rel.ways) { + _wayRels[id].push_back(_rels.rels.size() - 1); + } + + uint64_t keepFlags = _filter.keep(rel.attrs, pfaedle::osm::OsmFilter::REL); + uint64_t dropFlags = _filter.drop(rel.attrs, pfaedle::osm::OsmFilter::REL); + + if (rel.id && !rel.attrs.empty() && keepFlags && !dropFlags) { + rel.keepFlags = keepFlags; + rel.dropFlags = dropFlags; + } + + _rels.rels.push_back(rel.attrs); + if (rel.keepFlags & pfaedle::osm::REL_NO_DOWN) { + _rels.flat.insert(_rels.rels.size() - 1); + } + + // more processing + { + if (!rel.attrs.count("type")) return; + if (rel.attrs.find("type")->second != "restriction") return; + + bool pos = _filter.posRestr(rel.attrs); + bool neg = _filter.negRestr(rel.attrs); + + if (!pos && !neg) return; + + uint64_t from = 0; + uint64_t to = 0; + uint64_t via = 0; + + for (size_t i = 0; i < rel.ways.size(); i++) { + if (rel.wayRoles[i] == "from") { + if (from) return; // only one from member supported + from = rel.ways[i]; + } + if (rel.wayRoles[i] == "to") { + if (to) return; // only one to member supported + to = rel.ways[i]; + } + } + + for (size_t i = 0; i < rel.nodes.size(); i++) { + if (rel.nodeRoles[i] == "via") { + via = rel.nodes[i]; + break; + } + } + + if (from && to && via) { + if (pos) { + _restrictions.pos[via].emplace_back(from, to); + } else if (neg) { + _restrictions.neg[via].emplace_back(from, to); + } } } } - } }; class WayHandler: public osmium::handler::Handler { - Graph &g; - const pfaedle::osm::RelLst &rels; - const pfaedle::osm::RelMap &wayRels; - const pfaedle::osm::OsmFilter &filter; - const pfaedle::osm::OsmIdSet &bBoxNodes; - pfaedle::osm::NIdMap &nodes; - pfaedle::osm::NIdMultMap &multiNodes; - const pfaedle::osm::OsmIdSet &noHupNodes; - const pfaedle::osm::AttrKeySet &keepAttrs; - const pfaedle::osm::Restrictions &rawRests; - pfaedle::osm::Restrictor &restor; - const pfaedle::osm::FlatRels &fl; - pfaedle::osm::EdgTracks &eTracks; - const pfaedle::osm::OsmReadOpts &opts; + pfaedle::trgraph::Graph& _graph; + const pfaedle::osm::RelLst& _rels; + const pfaedle::osm::RelMap& _wayRels; + const pfaedle::osm::OsmFilter& _filter; + const pfaedle::osm::OsmIdSet& _bBoxNodes; + pfaedle::osm::NIdMap& _nodes; + pfaedle::osm::NIdMultMap& _multiNodes; + const pfaedle::osm::OsmIdSet& _noHupNodes; + const pfaedle::osm::AttrKeySet& _keepAttrs; + const pfaedle::osm::Restrictions& _restrictions; + pfaedle::osm::Restrictor& _restrictor; + const pfaedle::osm::FlatRels& _fl; + pfaedle::osm::EdgTracks& _eTracks; + const pfaedle::osm::OsmReadOpts& _opts; - std::map _lines; - std::map _relLines; -public: - WayHandler(Graph &g, - const pfaedle::osm::RelLst &rels, - const pfaedle::osm::RelMap &wayRels, - const pfaedle::osm::OsmFilter &filter, - const pfaedle::osm::OsmIdSet &bBoxNodes, - pfaedle::osm::NIdMap &nodes, - pfaedle::osm::NIdMultMap &multiNodes, - const pfaedle::osm::OsmIdSet &noHupNodes, - const pfaedle::osm::AttrKeySet &keepAttrs, - const pfaedle::osm::Restrictions &rawRests, - pfaedle::osm::Restrictor &restor, - const pfaedle::osm::FlatRels &fl, - pfaedle::osm::EdgTracks &eTracks, - const pfaedle::osm::OsmReadOpts &opts) : - g(g), - rels(rels), - wayRels(wayRels), - filter(filter), - bBoxNodes(bBoxNodes), - nodes(nodes), - multiNodes(multiNodes), - noHupNodes(noHupNodes), - keepAttrs(keepAttrs), - rawRests(rawRests), - restor(restor), - fl(fl), - eTracks(eTracks), - opts(opts) { + std::map _lines; + std::map _relLines; - } + public: + WayHandler(pfaedle::trgraph::Graph &g, + const pfaedle::osm::RelLst &rels, + const pfaedle::osm::RelMap &wayRels, + const pfaedle::osm::OsmFilter &filter, + const pfaedle::osm::OsmIdSet &bBoxNodes, + pfaedle::osm::NIdMap &nodes, + pfaedle::osm::NIdMultMap &multiNodes, + const pfaedle::osm::OsmIdSet &noHupNodes, + const pfaedle::osm::AttrKeySet &keepAttrs, + const pfaedle::osm::Restrictions &rawRests, + pfaedle::osm::Restrictor &restor, + const pfaedle::osm::FlatRels &fl, + pfaedle::osm::EdgTracks &eTracks, + const pfaedle::osm::OsmReadOpts &opts) : + _graph(g), + _rels(rels), + _wayRels(wayRels), + _filter(filter), + _bBoxNodes(bBoxNodes), + _nodes(nodes), + _multiNodes(multiNodes), + _noHupNodes(noHupNodes), + _keepAttrs(keepAttrs), + _restrictions(rawRests), + _restrictor(restor), + _fl(fl), + _eTracks(eTracks), + _opts(opts) + {} - void way(const osmium::Way &way) { - OsmWay w; - w.id = way.id(); - for (const auto &node: way.nodes()) { - w.nodes.emplace_back(node.ref()); - } - for (const auto &tag: way.tags()) { - if (keepAttrs.count(tag.key())) { - w.attrs[tag.key()] = tag.value(); + void way(const osmium::Way &way) { + OsmWay w; + w.id = way.id(); + for (const auto &node : way.nodes()) { + w.nodes.emplace_back(node.ref()); + } + for (const auto &tag : way.tags()) { + if (_keepAttrs.count(tag.key())) { + w.attrs[tag.key()] = tag.value(); + } } - } - bool valid = false; - if (w.id && w.nodes.size() > 1 && - (relKeep(w.id, wayRels, fl) || filter.keep(w.attrs, pfaedle::osm::OsmFilter::WAY)) && - !filter.drop(w.attrs, pfaedle::osm::OsmFilter::WAY)) { - for (auto nid : w.nodes) { - if (bBoxNodes.has(nid)) { - valid = true; - break; + bool valid = false; + if (w.id && w.nodes.size() > 1 && + (relKeep(w.id, _wayRels, _fl) || _filter.keep(w.attrs, pfaedle::osm::OsmFilter::WAY)) && + !_filter.drop(w.attrs, pfaedle::osm::OsmFilter::WAY)) { + for (auto nid : w.nodes) { + if (_bBoxNodes.has(nid)) { + valid = true; + break; + } + } + } + + if (valid) { + Node *last = nullptr; + std::vector lines; + if (_wayRels.count(w.id)) { + lines = getLines(_wayRels.find(w.id)->second, _rels, _opts); + } + std::string track = + getAttrByFirstMatch(_opts.edgePlatformRules, w.id, w.attrs, _wayRels, _rels, _opts.trackNormzer); + + uint64_t lastnid = 0; + + for (auto nid : w.nodes) { + Node *n = nullptr; + + if (_noHupNodes.has(nid)) { + n = _graph.addNd(); + _multiNodes[nid].insert(n); + } else if (!_nodes.count(nid)) { + if (!_bBoxNodes.has(nid)) { + continue; + } + n = _graph.addNd(); + _nodes[nid] = n; + } else { + n = _nodes[nid]; + } + + if (last) { + auto e = _graph.addEdg(last, n, EdgePL()); + if (!e) + continue; + + processRestrictor(nid, w.id, _restrictions, e, n, &_restrictor); + processRestrictor(lastnid, w.id, _restrictions, e, last, &_restrictor); + + e->pl().addLines(lines); + e->pl().setLvl(_filter.level(w.attrs)); + if (!track.empty()) { + _eTracks[e] = track; + } + + if (_filter.oneway(w.attrs)) + e->pl().setOneWay(1); + if (_filter.onewayrev(w.attrs)) + e->pl().setOneWay(2); + } + lastnid = nid; + last = n; } } } - if (valid) { - Node *last = nullptr; - std::vector lines; - if (wayRels.count(w.id)) { - lines = getLines(wayRels.find(w.id)->second, rels, opts); - } - std::string track = - getAttrByFirstMatch(opts.edgePlatformRules, w.id, w.attrs, wayRels, - rels, opts.trackNormzer); + static bool relKeep(uint64_t id, const pfaedle::osm::RelMap &rels, const pfaedle::osm::FlatRels &fl) { + auto it = rels.find(id); - uint64_t lastnid = 0; - for (auto nid : w.nodes) { - Node *n = nullptr; - if (noHupNodes.has(nid)) { - n = g.addNd(); - multiNodes[nid].insert(n); - } else if (!nodes.count(nid)) { - if (!bBoxNodes.has(nid)) { - continue; - } - n = g.addNd(); - nodes[nid] = n; + if (it == rels.end()) + return false; + + return std::any_of(it->second.begin(), it->second.end(), [fl](decltype(*it->second.begin()) relId){ + return !fl.count(relId); + }); + } + + std::vector getLines(const std::vector &edgeRels, + const pfaedle::osm::RelLst &rels, + const pfaedle::osm::OsmReadOpts &ops) + { + std::vector ret; + for (size_t relId : edgeRels) { + TransitEdgeLine* transitEdgeLinePointer = nullptr; + + if (_relLines.count(relId)) { + transitEdgeLinePointer = _relLines[relId]; } else { - n = nodes[nid]; - } - if (last) { - auto e = g.addEdg(last, n, EdgePL()); - if (!e) - continue; + TransitEdgeLine transitEdgeLine; - processRestr(nid, w.id, rawRests, e, n, &restor); - processRestr(lastnid, w.id, rawRests, e, last, &restor); - - e->pl().addLines(lines); - e->pl().setLvl(filter.level(w.attrs)); - if (!track.empty()) { - eTracks[e] = track; + bool found = false; + for (const auto &r : ops.relLinerules.sNameRule) { + for (const auto &relAttr : rels.rels[relId]) { + if (relAttr.first == r) { + transitEdgeLine.shortName = ops.lineNormzer(pfxml::file::decode(relAttr.second)); + if (!transitEdgeLine.shortName.empty()) found = true; + } + } + if (found) break; } - if (filter.oneway(w.attrs)) e->pl().setOneWay(1); - if (filter.onewayrev(w.attrs)) e->pl().setOneWay(2); + found = false; + for (const auto &r : ops.relLinerules.fromNameRule) { + for (const auto &relAttr : rels.rels[relId]) { + if (relAttr.first == r) { + transitEdgeLine.fromStr = ops.statNormzer(pfxml::file::decode(relAttr.second)); + if (!transitEdgeLine.fromStr.empty()) found = true; + } + } + if (found) break; + } + + found = false; + for (const auto &r : ops.relLinerules.toNameRule) { + for (const auto &relAttr : rels.rels[relId]) { + if (relAttr.first == r) { + transitEdgeLine.toStr = ops.statNormzer(pfxml::file::decode(relAttr.second)); + if (!transitEdgeLine.toStr.empty()) found = true; + } + } + if (found) break; + } + + if (transitEdgeLine.shortName.empty() && transitEdgeLine.fromStr.empty() && + transitEdgeLine.toStr.empty()) + continue; + + if (_lines.count(transitEdgeLine)) { + transitEdgeLinePointer = _lines[transitEdgeLine]; + _relLines[relId] = transitEdgeLinePointer; + } else { + transitEdgeLinePointer = new TransitEdgeLine(transitEdgeLine); + _lines[transitEdgeLine] = transitEdgeLinePointer; + _relLines[relId] = transitEdgeLinePointer; + } + } + ret.push_back(transitEdgeLinePointer); + } + + return ret; + } + + static void processRestrictor(uint64_t nid, uint64_t wid, + const pfaedle::osm::Restrictions &rawRests, + Edge *e, + Node *n, + pfaedle::osm::Restrictor *restor) { + if (rawRests.pos.count(nid)) { + for (const auto &kv : rawRests.pos.find(nid)->second) { + if (kv.eFrom == wid) { + e->pl().setRestricted(); + restor->add(e, kv.eTo, n, true); + } else if (kv.eTo == wid) { + e->pl().setRestricted(); + restor->relax(wid, n, e); + } + } + } + + if (rawRests.neg.count(nid)) { + for (const auto &kv : rawRests.neg.find(nid)->second) { + if (kv.eFrom == wid) { + e->pl().setRestricted(); + restor->add(e, kv.eTo, n, false); + } else if (kv.eTo == wid) { + e->pl().setRestricted(); + restor->relax(wid, n, e); + } } - lastnid = nid; - last = n; } } - } - static bool relKeep(uint64_t id, const pfaedle::osm::RelMap &rels, - const pfaedle::osm::FlatRels &fl) { - auto it = rels.find(id); - - if (it == rels.end()) return false; - - for (auto relId : it->second) { - // as soon as any of this entities relations is not flat, return true - if (!fl.count(relId)) return true; - } - - return false; - } - - std::vector getLines( - const std::vector &edgeRels, const pfaedle::osm::RelLst &rels, - const pfaedle::osm::OsmReadOpts &ops) { - std::vector ret; - for (size_t relId : edgeRels) { - TransitEdgeLine *elp = nullptr; - - if (_relLines.count(relId)) { - elp = _relLines[relId]; + static std::string getAttr(const pfaedle::osm::DeepAttrRule &s, uint64_t id, + const pfaedle::osm::AttrMap &attrs, + const pfaedle::osm::RelMap &entRels, + const pfaedle::osm::RelLst &rels) { + if (s.relRule.kv.first.empty()) { + if (attrs.find(s.attr) != attrs.end()) { + return attrs.find(s.attr)->second; + } } else { - TransitEdgeLine el; - - bool found = false; - for (const auto &r : ops.relLinerules.sNameRule) { - for (const auto &relAttr : rels.rels[relId]) { - if (relAttr.first == r) { - el.shortName = ops.lineNormzer(pfxml::file::decode(relAttr.second)); - if (!el.shortName.empty()) found = true; - } - } - if (found) break; - } - - found = false; - for (const auto &r : ops.relLinerules.fromNameRule) { - for (const auto &relAttr : rels.rels[relId]) { - if (relAttr.first == r) { - el.fromStr = ops.statNormzer(pfxml::file::decode(relAttr.second)); - if (!el.fromStr.empty()) found = true; - } - } - if (found) break; - } - - found = false; - for (const auto &r : ops.relLinerules.toNameRule) { - for (const auto &relAttr : rels.rels[relId]) { - if (relAttr.first == r) { - el.toStr = ops.statNormzer(pfxml::file::decode(relAttr.second)); - if (!el.toStr.empty()) found = true; - } - } - if (found) break; - } - - if (!el.shortName.size() && !el.fromStr.size() && !el.toStr.size()) - continue; - - if (_lines.count(el)) { - elp = _lines[el]; - _relLines[relId] = elp; - } else { - elp = new TransitEdgeLine(el); - _lines[el] = elp; - _relLines[relId] = elp; - } - } - ret.push_back(elp); - } - - return ret; - } - - static void processRestr(uint64_t nid, uint64_t wid, - const pfaedle::osm::Restrictions &rawRests, - Edge *e, - Node *n, - pfaedle::osm::Restrictor *restor) { - if (rawRests.pos.count(nid)) { - for (const auto &kv : rawRests.pos.find(nid)->second) { - if (kv.eFrom == wid) { - e->pl().setRestricted(); - restor->add(e, kv.eTo, n, true); - } else if (kv.eTo == wid) { - e->pl().setRestricted(); - restor->relax(wid, n, e); - } - } - } - - if (rawRests.neg.count(nid)) { - for (const auto &kv : rawRests.neg.find(nid)->second) { - if (kv.eFrom == wid) { - e->pl().setRestricted(); - restor->add(e, kv.eTo, n, false); - } else if (kv.eTo == wid) { - e->pl().setRestricted(); - restor->relax(wid, n, e); - } - } - } - } - - static std::string getAttr(const pfaedle::osm::DeepAttrRule &s, uint64_t id, - const pfaedle::osm::AttrMap &attrs, - const pfaedle::osm::RelMap &entRels, - const pfaedle::osm::RelLst &rels) { - if (s.relRule.kv.first.empty()) { - if (attrs.find(s.attr) != attrs.end()) { - return attrs.find(s.attr)->second; - } - } else { - if (entRels.count(id)) { - for (const auto &relId : entRels.find(id)->second) { - if (pfaedle::osm::OsmFilter::contained(rels.rels[relId], s.relRule.kv)) { - if (rels.rels[relId].count(s.attr)) { - return rels.rels[relId].find(s.attr)->second; + if (entRels.count(id)) { + for (const auto &relId : entRels.find(id)->second) { + if (pfaedle::osm::OsmFilter::contained(rels.rels[relId], s.relRule.kv)) { + if (rels.rels[relId].count(s.attr)) { + return rels.rels[relId].find(s.attr)->second; + } } } } } - } - return ""; - } - - static std::string getAttrByFirstMatch(const pfaedle::osm::DeepAttrLst &rule, uint64_t id, - const pfaedle::osm::AttrMap &attrs, - const pfaedle::osm::RelMap &entRels, - const pfaedle::osm::RelLst &rels, - const Normalizer &norm) { - std::string ret; - for (const auto &s : rule) { - ret = norm(pfxml::file::decode(getAttr(s, id, attrs, entRels, rels))); - if (!ret.empty()) return ret; + return ""; } - return ret; - } + static std::string getAttrByFirstMatch(const pfaedle::osm::DeepAttrLst &rule, uint64_t id, + const pfaedle::osm::AttrMap &attrs, + const pfaedle::osm::RelMap &entRels, + const pfaedle::osm::RelLst &rels, + const Normalizer &norm) { + std::string ret; + for (const auto &s : rule) { + ret = norm(pfxml::file::decode(getAttr(s, id, attrs, entRels, rels))); + if (!ret.empty()) return ret; + } + + return ret; + } }; class NodeHandler2: public osmium::handler::Handler { - Graph &g; - const pfaedle::osm::RelLst &rels; - const pfaedle::osm::RelMap &nodeRels; - const pfaedle::osm::OsmFilter &filter; - const pfaedle::osm::OsmIdSet &bBoxNodes; - pfaedle::osm::NIdMap &nodes; - pfaedle::osm::NIdMultMap &multNodes; - pfaedle::osm::NodeSet &orphanStations; - const pfaedle::osm::AttrKeySet &keepAttrs; - const pfaedle::osm::FlatRels &fl; - const pfaedle::osm::OsmReadOpts &opts; -public: - NodeHandler2(Graph &g, - const pfaedle::osm::RelLst &rels, - const pfaedle::osm::RelMap &nodeRels, - const pfaedle::osm::OsmFilter &filter, - const pfaedle::osm::OsmIdSet &bBoxNodes, - pfaedle::osm::NIdMap &nodes, - pfaedle::osm::NIdMultMap &multNodes, - pfaedle::osm::NodeSet &orphanStations, - const pfaedle::osm::AttrKeySet &keepAttrs, - const pfaedle::osm::FlatRels &fl, - const pfaedle::osm::OsmReadOpts &opts) : - g(g), + pfaedle::trgraph::Graph& _graph; + const pfaedle::osm::RelLst& rels; + const pfaedle::osm::RelMap& nodeRels; + const pfaedle::osm::OsmFilter& filter; + const pfaedle::osm::OsmIdSet& bBoxNodes; + pfaedle::osm::NIdMap& nodes; + pfaedle::osm::NIdMultMap& multNodes; + pfaedle::osm::NodeSet& orphanStations; + const pfaedle::osm::AttrKeySet& keepAttrs; + const pfaedle::osm::FlatRels& fl; + const pfaedle::osm::OsmReadOpts& opts; + + public: + NodeHandler2(Graph &g, + const pfaedle::osm::RelLst &rels, + const pfaedle::osm::RelMap &nodeRels, + const pfaedle::osm::OsmFilter &filter, + const pfaedle::osm::OsmIdSet &bBoxNodes, + pfaedle::osm::NIdMap &nodes, + pfaedle::osm::NIdMultMap &multNodes, + pfaedle::osm::NodeSet &orphanStations, + const pfaedle::osm::AttrKeySet &keepAttrs, + const pfaedle::osm::FlatRels &fl, + const pfaedle::osm::OsmReadOpts &opts) : + _graph(g), rels(rels), nodeRels(nodeRels), filter(filter), @@ -500,202 +508,219 @@ public: orphanStations(orphanStations), keepAttrs(keepAttrs), fl(fl), - opts(opts) { + opts(opts) + {} - } + void node(const osmium::Node &node) { + OsmNode nd; + nd.id = node.id(); + nd.lat = node.location().lat(); + nd.lng = node.location().lon(); - void node(const osmium::Node& node) { - OsmNode nd; - for(const auto& tag: node.tags()) - { - if (keepAttrs.count(tag.key())) - nd.attrs[tag.key()] = tag.value(); - } - nd.lat = node.location().lat(); - nd.lng = node.location().lon(); - nd.id = node.id(); + for (const auto &tag : node.tags()) { + if (keepAttrs.count(tag.key())) + nd.attrs[tag.key()] = tag.value(); + } - bool valid = false; - if (nd.id && - (nodes.count(nd.id) || multNodes.count(nd.id) || - relKeep(nd.id, nodeRels, fl) || filter.keep(nd.attrs, pfaedle::osm::OsmFilter::NODE)) && - (nodes.count(nd.id) || bBoxNodes.has(nd.id)) && - (nodes.count(nd.id) || multNodes.count(nd.id) || - !filter.drop(nd.attrs, pfaedle::osm::OsmFilter::NODE))) { - valid = true; - } - pfaedle::osm::StAttrGroups attrGroups; - if(valid) - { - Node* n = nullptr; - auto pos = util::geo::latLngToWebMerc(nd.lat, nd.lng); - if (nodes.count(nd.id)) { - n = (nodes)[nd.id]; - n->pl().setGeom(pos); - if (filter.station(nd.attrs)) { - auto si = getStatInfo(n, nd.id, pos, nd.attrs, &attrGroups, nodeRels, - rels, opts); - if (!si.isNull()) n->pl().setSI(si); - } else if (filter.blocker(nd.attrs)) { - n->pl().setBlocker(); - } - } else if ((multNodes).count(nd.id)) { - for (auto* n : (multNodes)[nd.id]) { + bool valid = false; + if (nd.id && + (nodes.count(nd.id) || multNodes.count(nd.id) || + relKeep(nd.id, nodeRels, fl) || filter.keep(nd.attrs, pfaedle::osm::OsmFilter::NODE)) && + (nodes.count(nd.id) || bBoxNodes.has(nd.id)) && + (nodes.count(nd.id) || multNodes.count(nd.id) || + !filter.drop(nd.attrs, pfaedle::osm::OsmFilter::NODE))) { + valid = true; + } + + pfaedle::osm::StAttrGroups attrGroups; + if (valid) { + Node *n = nullptr; + auto pos = util::geo::latLngToWebMerc(nd.lat, nd.lng); + + if (nodes.count(nd.id)) { + n = nodes[nd.id]; n->pl().setGeom(pos); + if (filter.station(nd.attrs)) { - auto si = getStatInfo(n, nd.id, pos, nd.attrs, &attrGroups, nodeRels, - rels, opts); - if (!si.isNull()) n->pl().setSI(si); + auto si = getStatInfo(n, nd.id, pos, nd.attrs, &attrGroups, nodeRels, rels, opts); + + if (!si.isNull()) + n->pl().setSI(si); } else if (filter.blocker(nd.attrs)) { n->pl().setBlocker(); } - } - } else { - // these are nodes without any connected edges - if (filter.station(nd.attrs)) { - auto tmp = g.addNd(NodePL(pos)); - auto si = getStatInfo(tmp, nd.id, pos, nd.attrs, &attrGroups, nodeRels, - rels, opts); - if (!si.isNull()) tmp->pl().setSI(si); - if (tmp->pl().getSI()) { - tmp->pl().getSI()->setIsFromOsm(false); - orphanStations.insert(tmp); + } else if (multNodes.count(nd.id)) { + for (auto *n : multNodes[nd.id]) { + n->pl().setGeom(pos); + if (filter.station(nd.attrs)) { + auto si = getStatInfo(n, nd.id, pos, nd.attrs, &attrGroups, nodeRels, rels, opts); + + if (!si.isNull()) + n->pl().setSI(si); + } else if (filter.blocker(nd.attrs)) { + n->pl().setBlocker(); + } } - } - } - } - } + } else { + // these are nodes without any connected edges + if (filter.station(nd.attrs)) { + auto tmp = _graph.addNd(NodePL(pos)); + auto si = getStatInfo(tmp, nd.id, pos, nd.attrs, &attrGroups, nodeRels, rels, opts); + if (!si.isNull()) + tmp->pl().setSI(si); - bool relKeep(uint64_t id, const pfaedle::osm::RelMap& rels, const pfaedle::osm::FlatRels& fl) const { - auto it = rels.find(id); - - if (it == rels.end()) return false; - - for (uint64_t relId : it->second) { - // as soon as any of this entities relations is not flat, return true - if (!fl.count(relId)) return true; - } - - return false; - } - - Nullable getStatInfo(Node* node, uint64_t nid, - const POINT& pos, const pfaedle::osm::AttrMap& m, - pfaedle::osm::StAttrGroups* groups, - const pfaedle::osm::RelMap& nodeRels, - const pfaedle::osm::RelLst& rels, - const pfaedle::osm::OsmReadOpts& ops) const { - std::string platform; - std::vector names; - - names = getAttrMatchRanked(ops.statAttrRules.nameRule, nid, m, nodeRels, rels, - ops.statNormzer); - platform = getAttrByFirstMatch(ops.statAttrRules.platformRule, nid, m, - nodeRels, rels, ops.trackNormzer); - - if (!names.size()) return Nullable(); - - auto ret = StatInfo(names[0], platform, true); - -#ifdef PFAEDLE_STATION_IDS - ret.setId(getAttrByFirstMatch(ops.statAttrRules.idRule, nid, m, nodeRels, - rels, ops.idNormzer)); -#endif - - for (size_t i = 1; i < names.size(); i++) ret.addAltName(names[i]); - - bool groupFound = false; - - for (const auto& rule : ops.statGroupNAttrRules) { - if (groupFound) break; - std::string ruleVal = getAttr(rule.attr, nid, m, nodeRels, rels); - if (!ruleVal.empty()) { - // check if a matching group exists - for (auto* group : (*groups)[rule.attr.attr][ruleVal]) { - if (groupFound) break; - for (const auto* member : group->getNodes()) { - if (webMercMeterDist(*member->pl().getGeom(), pos) <= rule.maxDist) { - // ok, group is matching - groupFound = true; - if (node) group->addNode(node); - ret.setGroup(group); - break; + if (tmp->pl().getSI()) { + tmp->pl().getSI()->setIsFromOsm(false); + orphanStations.insert(tmp); } } } } } - if (!groupFound) { - for (const auto& rule : ops.statGroupNAttrRules) { + + static bool relKeep(uint64_t id, const pfaedle::osm::RelMap &rels, const pfaedle::osm::FlatRels &fl) { + auto it = rels.find(id); + + if (it == rels.end()) + return false; + + for (uint64_t relId : it->second) { + // as soon as any of this entities relations is not flat, return true + if (!fl.count(relId)) + return true; + } + + return false; + } + + static Nullable getStatInfo(Node *node, uint64_t nid, + const POINT &pos, + const pfaedle::osm::AttrMap &m, + pfaedle::osm::StAttrGroups *groups, + const pfaedle::osm::RelMap &nodeRels, + const pfaedle::osm::RelLst &rels, + const pfaedle::osm::OsmReadOpts &ops) { + std::vector names = + getAttrMatchRanked(ops.statAttrRules.nameRule, nid, m, nodeRels, rels, ops.statNormzer); + std::string platform = + getAttrByFirstMatch(ops.statAttrRules.platformRule, nid, m, nodeRels, rels, ops.trackNormzer); + + if (names.empty()) { + return Nullable(); + } + + auto ret = StatInfo(names[0], platform, true); + +#ifdef PFAEDLE_STATION_IDS + ret.setId(getAttrByFirstMatch(ops.statAttrRules.idRule, nid, m, nodeRels, rels, ops.idNormzer)); +#endif + + for (size_t i = 1; i < names.size(); i++) { + ret.addAltName(names[i]); + } + bool groupFound = false; + + for (const auto &rule : ops.statGroupNAttrRules) { + if (groupFound) break; std::string ruleVal = getAttr(rule.attr, nid, m, nodeRels, rels); if (!ruleVal.empty()) { - // add new group - auto* g = new StatGroup(); - if (node) g->addNode(node); - ret.setGroup(g); - (*groups)[rule.attr.attr][ruleVal].push_back(g); + // check if a matching group exists + for (auto *group : (*groups)[rule.attr.attr][ruleVal]) { + if (groupFound) break; + for (const auto *member : group->getNodes()) { + if (webMercMeterDist(*member->pl().getGeom(), pos) <= rule.maxDist) { + // ok, group is matching + groupFound = true; + if (node) group->addNode(node); + ret.setGroup(group); + break; + } + } + } + } + } + + if (!groupFound) { + for (const auto &rule : ops.statGroupNAttrRules) { + std::string ruleVal = getAttr(rule.attr, nid, m, nodeRels, rels); + if (!ruleVal.empty()) { + // add new group + auto *group = new StatGroup(); + if (node) group->addNode(node); + ret.setGroup(group); + (*groups)[rule.attr.attr][ruleVal].push_back(group); + break; + } + } + } + + return ret; + } + + static std::string getAttrByFirstMatch(const pfaedle::osm::DeepAttrLst &rule, + uint64_t id, + const pfaedle::osm::AttrMap &attrs, + const pfaedle::osm::RelMap &entRels, + const pfaedle::osm::RelLst &rels, + const Normalizer &norm) { + std::string ret; + for (const auto &s : rule) { + ret = norm(pfxml::file::decode(getAttr(s, id, attrs, entRels, rels))); + if (!ret.empty()) { break; } } + + return ret; } - return ret; - } - - std::string getAttrByFirstMatch(const pfaedle::osm::DeepAttrLst& rule, uint64_t id, - const pfaedle::osm::AttrMap& attrs, - const pfaedle::osm::RelMap& entRels, - const pfaedle::osm::RelLst& rels, - const Normalizer& norm) const { - std::string ret; - for (const auto& s : rule) { - ret = norm(pfxml::file::decode(getAttr(s, id, attrs, entRels, rels))); - if (!ret.empty()) return ret; - } - - return ret; - } - - std::vector getAttrMatchRanked( - const pfaedle::osm::DeepAttrLst& rule, uint64_t id, const pfaedle::osm::AttrMap& attrs, - const pfaedle::osm::RelMap& entRels, const pfaedle::osm::RelLst& rels, const Normalizer& norm) const { - std::vector ret; - for (const auto& s : rule) { - std::string tmp = - norm(pfxml::file::decode(getAttr(s, id, attrs, entRels, rels))); - if (!tmp.empty()) ret.push_back(tmp); - } - - return ret; - } - - std::string getAttr(const pfaedle::osm::DeepAttrRule& s, uint64_t id, - const pfaedle::osm::AttrMap& attrs, const pfaedle::osm::RelMap& entRels, - const pfaedle::osm::RelLst& rels) const { - if (s.relRule.kv.first.empty()) { - if (attrs.find(s.attr) != attrs.end()) { - return attrs.find(s.attr)->second; + static std::vector getAttrMatchRanked(const pfaedle::osm::DeepAttrLst &rule, + uint64_t id, + const pfaedle::osm::AttrMap &attrs, + const pfaedle::osm::RelMap &entRels, + const pfaedle::osm::RelLst &rels, + const Normalizer &norm) { + std::vector ret; + for (const auto &s : rule) { + std::string tmp = norm(pfxml::file::decode(getAttr(s, id, attrs, entRels, rels))); + if (!tmp.empty()) { + ret.push_back(tmp); + } } - } else { - if (entRels.count(id)) { - for (const auto& relId : entRels.find(id)->second) { - if (pfaedle::osm::OsmFilter::contained(rels.rels[relId], s.relRule.kv)) { - if (rels.rels[relId].count(s.attr)) { - return rels.rels[relId].find(s.attr)->second; + + return ret; + } + + static std::string getAttr(const pfaedle::osm::DeepAttrRule &s, + uint64_t id, + const pfaedle::osm::AttrMap &attrs, + const pfaedle::osm::RelMap &entRels, + const pfaedle::osm::RelLst &rels) { + if (s.relRule.kv.first.empty()) { + if (attrs.find(s.attr) != attrs.end()) { + return attrs.find(s.attr)->second; + } + } else { + if (entRels.count(id)) { + for (const auto &relId : entRels.find(id)->second) { + if (pfaedle::osm::OsmFilter::contained(rels.rels[relId], s.relRule.kv)) { + if (rels.rels[relId].count(s.attr)) { + return rels.rels[relId].find(s.attr)->second; + } } } } } + return ""; } - return ""; - } }; + // _____________________________________________________________________________ bool EqSearch::operator()(const Node* cand, const StatInfo* si) const { if (orphanSnap && cand->pl().getSI() && - (!cand->pl().getSI()->getGroup() || cand->pl().getSI()->getGroup()->getStops().empty())) { + (!cand->pl().getSI()->getGroup() || cand->pl().getSI()->getGroup()->getStops().empty())) { return true; } return cand->pl().getSI() && cand->pl().getSI()->simi(si) > minSimi; @@ -708,265 +733,267 @@ OsmBuilder::OsmBuilder() = default; void OsmBuilder::read(const std::string& path, const OsmReadOpts& opts, Graph* g, const BBoxIdx& bbox, size_t gridSize, router::FeedStops* fs, Restrictor* res) { - if (!bbox.size()) return; + if (!bbox.size()) return; - LOG(INFO) << "Reading OSM file " << path << " ... "; + LOG(INFO) << "Reading OSM file " << path << " ... "; - NodeSet orphanStations; - EdgTracks eTracks; - { - OsmIdSet bboxNodes, noHupNodes; + NodeSet orphanStations; + EdgTracks eTracks; + { + OsmIdSet bboxNodes, noHupNodes; - NIdMap nodes; - NIdMultMap multNodes; - RelLst intmRels; - RelMap nodeRels, wayRels; + NIdMap nodes; + NIdMultMap multNodes; + RelLst intmRels; + RelMap nodeRels, wayRels; - Restrictions rawRests; + Restrictions rawRests; - AttrKeySet attrKeys[3] = {}; - getKeptAttrKeys(opts, attrKeys); + AttrKeySet attrKeys[3] = {}; + getKeptAttrKeys(opts, attrKeys); - OsmFilter filter(opts); + OsmFilter filter(opts); - osmium::io::Reader reader{path, osmium::osm_entity_bits::node | osmium::osm_entity_bits::way |osmium::osm_entity_bits::relation}; + osmium::io::Reader reader {path, + osmium::osm_entity_bits::node | + osmium::osm_entity_bits::way | + osmium::osm_entity_bits::relation}; + osmium::io::Reader reader_nodes{path, + osmium::osm_entity_bits::node}; - NodeHandler nodeHandler(filter, bbox, bboxNodes, noHupNodes); - RelationHandler relationHandler(filter, bbox, attrKeys[2],intmRels, nodeRels, wayRels, rawRests); - WayHandler wayHandler(*g, intmRels, wayRels, filter, bboxNodes, nodes, multNodes, - noHupNodes, attrKeys[1], rawRests, *res, - intmRels.flat, eTracks, opts); + NodeHandler nodeHandler(filter, bbox, bboxNodes, noHupNodes); + RelationHandler relationHandler(filter, bbox, attrKeys[2], intmRels, nodeRels, wayRels, rawRests); + WayHandler wayHandler(*g, intmRels, wayRels, filter, bboxNodes, nodes, multNodes, noHupNodes, + attrKeys[1], rawRests, *res, intmRels.flat, eTracks, opts); - osmium::apply(reader, nodeHandler, relationHandler, wayHandler); + osmium::apply(reader, nodeHandler, relationHandler, wayHandler); + NodeHandler2 nodeHandler2(*g, intmRels, nodeRels, filter, bboxNodes, nodes, multNodes, orphanStations, + attrKeys[0], intmRels.flat, opts); + osmium::apply(reader_nodes, nodeHandler2); - osmium::io::Reader reader_nodes{path, osmium::osm_entity_bits::node}; - NodeHandler2 nodeHandler2(*g, intmRels, nodeRels, filter, bboxNodes, nodes, - multNodes, orphanStations, attrKeys[0], intmRels.flat, opts); - osmium::apply(reader_nodes, nodeHandler2); + // we do four passes of the file here to be as memory creedy as possible: + // - the first pass collects all node IDs which are + // * inside the given bounding box + // * (TODO: maybe more filtering?) + // these nodes are stored on the HD via OsmIdSet (which implements a + // simple bloom filter / base 256 encoded id store + // - the second pass collects filtered relations + // - the third pass collects filtered ways which contain one of the nodes + // from pass 1 + // - the forth pass collects filtered nodes which were + // * collected as node ids in pass 1 + // * match the filter criteria + // * have been used in a way in pass 3 + } - // we do four passes of the file here to be as memory creedy as possible: - // - the first pass collects all node IDs which are - // * inside the given bounding box - // * (TODO: maybe more filtering?) - // these nodes are stored on the HD via OsmIdSet (which implements a - // simple bloom filter / base 256 encoded id store - // - the second pass collects filtered relations - // - the third pass collects filtered ways which contain one of the nodes - // from pass 1 - // - the forth pass collects filtered nodes which were - // * collected as node ids in pass 1 - // * match the filter criteria - // * have been used in a way in pass 3 - } + LOG(VDEBUG) << "OSM ID set lookups: " << osm::OsmIdSet::LOOKUPS + << ", file lookups: " << osm::OsmIdSet::FLOOKUPS; - LOG(VDEBUG) << "OSM ID set lookups: " << osm::OsmIdSet::LOOKUPS - << ", file lookups: " << osm::OsmIdSet::FLOOKUPS; + LOG(VDEBUG) << "Applying edge track numbers..."; + writeEdgeTracks(eTracks); + eTracks.clear(); - LOG(VDEBUG) << "Applying edge track numbers..."; - writeEdgeTracks(eTracks); - eTracks.clear(); + { + LOG(VDEBUG) << "Fixing gaps..."; + NodeGrid ng = buildNodeIdx(g, gridSize, bbox.getFullWebMercBox(), false); + fixGaps(g, &ng); + } - { - LOG(VDEBUG) << "Fixing gaps..."; - NodeGrid ng = buildNodeIdx(g, gridSize, bbox.getFullWebMercBox(), false); - fixGaps(g, &ng); - } + LOG(VDEBUG) << "Writing edge geoms..."; + writeGeoms(g); - LOG(VDEBUG) << "Writing edge geoms..."; - writeGeoms(g); + LOG(VDEBUG) << "Snapping stations..."; + snapStats(opts, g, bbox, gridSize, fs, res, orphanStations); - LOG(VDEBUG) << "Snapping stations..."; - snapStats(opts, g, bbox, gridSize, fs, res, orphanStations); + LOG(VDEBUG) << "Deleting orphan nodes..."; + deleteOrphNds(g); - LOG(VDEBUG) << "Deleting orphan nodes..."; - deleteOrphNds(g); + LOG(VDEBUG) << "Deleting orphan edges..."; + deleteOrphEdgs(g, opts); - LOG(VDEBUG) << "Deleting orphan edges..."; - deleteOrphEdgs(g, opts); + LOG(VDEBUG) << "Collapsing edges..."; + collapseEdges(g); - LOG(VDEBUG) << "Collapsing edges..."; - collapseEdges(g); + LOG(VDEBUG) << "Deleting orphan nodes..."; + deleteOrphNds(g); - LOG(VDEBUG) << "Deleting orphan nodes..."; - deleteOrphNds(g); + LOG(VDEBUG) << "Deleting orphan edges..."; + deleteOrphEdgs(g, opts); - LOG(VDEBUG) << "Deleting orphan edges..."; - deleteOrphEdgs(g, opts); + LOG(VDEBUG) << "Writing graph components..."; + // the restrictor is needed here to prevent connections in the graph + // which are not possible in reality + uint32_t comps = writeComps(g); - LOG(VDEBUG) << "Writing graph components..."; - // the restrictor is needed here to prevent connections in the graph - // which are not possible in reality - uint32_t comps = writeComps(g); + LOG(VDEBUG) << "Simplifying geometries..."; + simplifyGeoms(g); - LOG(VDEBUG) << "Simplifying geometries..."; - simplifyGeoms(g); + LOG(VDEBUG) << "Writing other-direction edges..."; + writeODirEdgs(g, res); - LOG(VDEBUG) << "Writing other-direction edges..."; - writeODirEdgs(g, res); + LOG(VDEBUG) << "Write dummy node self-edges..."; + writeSelfEdgs(g); - LOG(VDEBUG) << "Write dummy node self-edges..."; - writeSelfEdgs(g); + size_t numEdges = 0; - size_t numEdges = 0; + for (auto* n : *g->getNds()) { + numEdges += n->getAdjListOut().size(); + } - for (auto* n : *g->getNds()) { - numEdges += n->getAdjListOut().size(); - } - - LOG(DEBUG) << "Graph has " << g->getNds()->size() << " nodes, " << numEdges - << " edges and " << comps << " connected component(s)"; + LOG(DEBUG) << "Graph has " << g->getNds()->size() << " nodes, " << numEdges + << " edges and " << comps << " connected component(s)"; } // _____________________________________________________________________________ void OsmBuilder::overpassQryWrite(std::ostream* out, const std::vector& opts, const BBoxIdx& latLngBox) const { - OsmIdSet bboxNodes, noHupNodes; - MultAttrMap emptyF; + OsmIdSet bboxNodes, noHupNodes; + MultAttrMap emptyF; - RelLst rels; - OsmIdList ways; - RelMap nodeRels, wayRels; + RelLst rels; + OsmIdList ways; + RelMap nodeRels, wayRels; - // TODO(patrick): not needed here! - Restrictions rests; + // TODO(patrick): not needed here! + Restrictions rests; - NIdMap nodes; + NIdMap nodes; - // always empty - NIdMultMap multNodes; - util::xml::XmlWriter wr(out, true, 4); + // always empty + NIdMultMap multNodes; + util::xml::XmlWriter wr(out, true, 4); - *out << "\n"; - wr.openComment(); - wr.writeText(" - written by pfaedle -"); - wr.closeTag(); - wr.openTag("osm-script"); - - OsmFilter filter; - - for (const OsmReadOpts& o : opts) { - filter = filter.merge(OsmFilter(o.keepFilter, o.dropFilter)); - } - - wr.openTag("union"); - size_t c = 0; - for (auto box : latLngBox.getLeafs()) { - if (box.getLowerLeft().getX() > box.getUpperRight().getX()) continue; - c++; + *out << "\n"; wr.openComment(); - wr.writeText(std::string("Bounding box #") + std::to_string(c) + " (" + - std::to_string(box.getLowerLeft().getY()) + ", " + - std::to_string(box.getLowerLeft().getX()) + ", " + - std::to_string(box.getUpperRight().getY()) + ", " + - std::to_string(box.getUpperRight().getX()) + ")"); + wr.writeText(" - written by pfaedle -"); wr.closeTag(); - for (auto t : std::vector{"way", "node", "relation"}) { - for (auto r : filter.getKeepRules()) { - for (auto val : r.second) { - if (t == "way" && (val.second & OsmFilter::WAY)) continue; - if (t == "relation" && (val.second & OsmFilter::REL)) continue; - if (t == "node" && (val.second & OsmFilter::NODE)) continue; + wr.openTag("osm-script"); - wr.openTag("query", {{"type", t}}); - if (val.first == "*") - wr.openTag("has-kv", {{"k", r.first}}); - else - wr.openTag("has-kv", {{"k", r.first}, {"v", val.first}}); - wr.closeTag(); - wr.openTag("bbox-query", - {{"s", std::to_string(box.getLowerLeft().getY())}, - {"w", std::to_string(box.getLowerLeft().getX())}, - {"n", std::to_string(box.getUpperRight().getY())}, - {"e", std::to_string(box.getUpperRight().getX())}}); - wr.closeTag(); - wr.closeTag(); - } - } + OsmFilter filter; + + for (const OsmReadOpts& o : opts) { + filter = filter.merge(OsmFilter(o.keepFilter, o.dropFilter)); } - } - wr.closeTag(); + wr.openTag("union"); + size_t c = 0; + for (auto box : latLngBox.getLeafs()) { + if (box.getLowerLeft().getX() > box.getUpperRight().getX()) continue; + c++; + wr.openComment(); + wr.writeText(std::string("Bounding box #") + std::to_string(c) + " (" + + std::to_string(box.getLowerLeft().getY()) + ", " + + std::to_string(box.getLowerLeft().getX()) + ", " + + std::to_string(box.getUpperRight().getY()) + ", " + + std::to_string(box.getUpperRight().getX()) + ")"); + wr.closeTag(); + for (auto t : std::vector{"way", "node", "relation"}) { + for (auto r : filter.getKeepRules()) { + for (auto val : r.second) { + if (t == "way" && (val.second & OsmFilter::WAY)) continue; + if (t == "relation" && (val.second & OsmFilter::REL)) continue; + if (t == "node" && (val.second & OsmFilter::NODE)) continue; - wr.openTag("union"); - wr.openTag("item"); - wr.closeTag(); - wr.openTag("recurse", {{"type", "down"}}); - wr.closeTag(); - wr.closeTag(); - wr.openTag("print"); + wr.openTag("query", {{"type", t}}); + if (val.first == "*") + wr.openTag("has-kv", {{"k", r.first}}); + else + wr.openTag("has-kv", {{"k", r.first}, {"v", val.first}}); + wr.closeTag(); + wr.openTag("bbox-query", + {{"s", std::to_string(box.getLowerLeft().getY())}, + {"w", std::to_string(box.getLowerLeft().getX())}, + {"n", std::to_string(box.getUpperRight().getY())}, + {"e", std::to_string(box.getUpperRight().getX())}}); + wr.closeTag(); + wr.closeTag(); + } + } + } + } - wr.closeTags(); + wr.closeTag(); + + wr.openTag("union"); + wr.openTag("item"); + wr.closeTag(); + wr.openTag("recurse", {{"type", "down"}}); + wr.closeTag(); + wr.closeTag(); + wr.openTag("print"); + + wr.closeTags(); } // _____________________________________________________________________________ void OsmBuilder::filterWrite(const std::string& in, const std::string& out, const std::vector& opts, const BBoxIdx& latLngBox) { - OsmIdSet bboxNodes, noHupNodes; - MultAttrMap emptyF; + OsmIdSet bboxNodes, noHupNodes; + MultAttrMap emptyF; - RelLst rels; - OsmIdList ways; - RelMap nodeRels, wayRels; + RelLst rels; + OsmIdList ways; + RelMap nodeRels, wayRels; - // TODO(patrick): not needed here! - Restrictions rests; + // TODO(patrick): not needed here! + Restrictions rests; - NIdMap nodes; + NIdMap nodes; - // always empty - NIdMultMap multNodes; + // always empty + NIdMultMap multNodes; - pfxml::file xml(in); - std::ofstream outstr; - outstr.open(out); + pfxml::file xml(in); + std::ofstream outstr; + outstr.open(out); - util::xml::XmlWriter wr(&outstr, true, 4); + util::xml::XmlWriter wr(&outstr, true, 4); - outstr << "\n"; - wr.openTag("osm"); - wr.openTag( - "bounds", - {{"minlat", std::to_string(latLngBox.getFullBox().getLowerLeft().getY())}, - {"minlon", std::to_string(latLngBox.getFullBox().getLowerLeft().getX())}, - {"maxlat", - std::to_string(latLngBox.getFullBox().getUpperRight().getY())}, - {"maxlon", - std::to_string(latLngBox.getFullBox().getUpperRight().getX())}}); - wr.closeTag(); + outstr << "\n"; + wr.openTag("osm"); + wr.openTag( + "bounds", + {{"minlat", std::to_string(latLngBox.getFullBox().getLowerLeft().getY())}, + {"minlon", std::to_string(latLngBox.getFullBox().getLowerLeft().getX())}, + {"maxlat", + std::to_string(latLngBox.getFullBox().getUpperRight().getY())}, + {"maxlon", + std::to_string(latLngBox.getFullBox().getUpperRight().getX())}}); + wr.closeTag(); - OsmFilter filter; - AttrKeySet attrKeys[3] = {}; + OsmFilter filter; + AttrKeySet attrKeys[3] = {}; - for (const OsmReadOpts& o : opts) { - getKeptAttrKeys(o, attrKeys); - filter = filter.merge(OsmFilter(o.keepFilter, o.dropFilter)); - } + for (const OsmReadOpts& o : opts) { + getKeptAttrKeys(o, attrKeys); + filter = filter.merge(OsmFilter(o.keepFilter, o.dropFilter)); + } - skipUntil(&xml, "node"); - pfxml::parser_state nodeBeg = xml.state(); - pfxml::parser_state edgesBeg = - readBBoxNds(&xml, &bboxNodes, &noHupNodes, filter, latLngBox); + skipUntil(&xml, "node"); + pfxml::parser_state nodeBeg = xml.state(); + pfxml::parser_state edgesBeg = + readBBoxNds(&xml, &bboxNodes, &noHupNodes, filter, latLngBox); - skipUntil(&xml, "relation"); - readRels(&xml, &rels, &nodeRels, &wayRels, filter, attrKeys[2], &rests); + skipUntil(&xml, "relation"); + readRels(&xml, &rels, &nodeRels, &wayRels, filter, attrKeys[2], &rests); - xml.set_state(edgesBeg); - readEdges(&xml, wayRels, filter, bboxNodes, attrKeys[1], &ways, &nodes, + xml.set_state(edgesBeg); + readEdges(&xml, wayRels, filter, bboxNodes, attrKeys[1], &ways, &nodes, rels.flat); - xml.set_state(nodeBeg); + xml.set_state(nodeBeg); - readWriteNds(&xml, &wr, nodeRels, filter, bboxNodes, &nodes, attrKeys[0], - rels.flat); - readWriteWays(&xml, &wr, &ways, attrKeys[1]); + readWriteNds(&xml, &wr, nodeRels, filter, bboxNodes, &nodes, attrKeys[0], + rels.flat); + readWriteWays(&xml, &wr, &ways, attrKeys[1]); - std::sort(ways.begin(), ways.end()); - skipUntil(&xml, "relation"); - readWriteRels(&xml, &wr, &ways, &nodes, filter, attrKeys[2]); + std::sort(ways.begin(), ways.end()); + skipUntil(&xml, "relation"); + readWriteRels(&xml, &wr, &ways, &nodes, filter, attrKeys[2]); - wr.closeTags(); + wr.closeTags(); } // _____________________________________________________________________________ @@ -974,193 +1001,193 @@ void OsmBuilder::readWriteRels(pfxml::file* i, util::xml::XmlWriter* o, OsmIdList* ways, NIdMap* nodes, const OsmFilter& filter, const AttrKeySet& keepAttrs) { - OsmRel rel; - while ((rel = nextRel(i, filter, keepAttrs)).id) { - OsmIdList realNodes, realWays; - std::vector realNodeRoles, realWayRoles; + OsmRel rel; + while ((rel = nextRel(i, filter, keepAttrs)).id) { + OsmIdList realNodes, realWays; + std::vector realNodeRoles, realWayRoles; - for (size_t j = 0; j < rel.ways.size(); j++) { - osmid wid = rel.ways[j]; - const auto& i = std::lower_bound(ways->begin(), ways->end(), wid); - if (i != ways->end() && *i == wid) { - realWays.push_back(wid); - realWayRoles.push_back(rel.wayRoles[j].c_str()); - } + for (size_t j = 0; j < rel.ways.size(); j++) { + osmid wid = rel.ways[j]; + const auto& i = std::lower_bound(ways->begin(), ways->end(), wid); + if (i != ways->end() && *i == wid) { + realWays.push_back(wid); + realWayRoles.push_back(rel.wayRoles[j].c_str()); + } + } + + for (size_t j = 0; j < rel.nodes.size(); j++) { + osmid nid = rel.nodes[j]; + if (nodes->count(nid)) { + realNodes.push_back(nid); + realNodeRoles.push_back(rel.nodeRoles[j].c_str()); + } + } + + if (!realNodes.empty() || !realWays.empty()) { + o->openTag("relation", "id", std::to_string(rel.id)); + + for (size_t j = 0; j < realNodes.size(); j++) { + osmid nid = realNodes[j]; + std::map attrs; + attrs["type"] = "node"; + if (strlen(realNodeRoles[j])) attrs["role"] = realNodeRoles[j]; + attrs["ref"] = std::to_string(nid); + o->openTag("member", attrs); + o->closeTag(); + } + + for (size_t j = 0; j < realWays.size(); j++) { + osmid wid = realWays[j]; + std::map attrs; + attrs["type"] = "way"; + if (strlen(realWayRoles[j])) attrs["role"] = realWayRoles[j]; + attrs["ref"] = std::to_string(wid); + o->openTag("member", attrs); + o->closeTag(); + } + + for (const auto& kv : rel.attrs) { + std::map attrs = { + {"k", kv.first}, {"v", pfxml::file::decode(kv.second)}}; + o->openTag("tag", attrs); + o->closeTag(); + } + + o->closeTag(); + } } - - for (size_t j = 0; j < rel.nodes.size(); j++) { - osmid nid = rel.nodes[j]; - if (nodes->count(nid)) { - realNodes.push_back(nid); - realNodeRoles.push_back(rel.nodeRoles[j].c_str()); - } - } - - if (!realNodes.empty() || !realWays.empty()) { - o->openTag("relation", "id", std::to_string(rel.id)); - - for (size_t j = 0; j < realNodes.size(); j++) { - osmid nid = realNodes[j]; - std::map attrs; - attrs["type"] = "node"; - if (strlen(realNodeRoles[j])) attrs["role"] = realNodeRoles[j]; - attrs["ref"] = std::to_string(nid); - o->openTag("member", attrs); - o->closeTag(); - } - - for (size_t j = 0; j < realWays.size(); j++) { - osmid wid = realWays[j]; - std::map attrs; - attrs["type"] = "way"; - if (strlen(realWayRoles[j])) attrs["role"] = realWayRoles[j]; - attrs["ref"] = std::to_string(wid); - o->openTag("member", attrs); - o->closeTag(); - } - - for (const auto& kv : rel.attrs) { - std::map attrs = { - {"k", kv.first}, {"v", pfxml::file::decode(kv.second)}}; - o->openTag("tag", attrs); - o->closeTag(); - } - - o->closeTag(); - } - } } // _____________________________________________________________________________ void OsmBuilder::readWriteWays(pfxml::file* i, util::xml::XmlWriter* o, OsmIdList* ways, const AttrKeySet& keepAttrs) const { - OsmWay w; - NIdMultMap empty; - for (auto wid : *ways) { - w = nextWayWithId(i, wid, keepAttrs); - assert(w.id); - o->openTag("way", "id", std::to_string(wid)); - for (osmid nid : w.nodes) { - o->openTag("nd", "ref", std::to_string(nid)); - o->closeTag(); + OsmWay w; + NIdMultMap empty; + for (auto wid : *ways) { + w = nextWayWithId(i, wid, keepAttrs); + assert(w.id); + o->openTag("way", "id", std::to_string(wid)); + for (osmid nid : w.nodes) { + o->openTag("nd", "ref", std::to_string(nid)); + o->closeTag(); + } + for (const auto& kv : w.attrs) { + std::map attrs; + attrs["k"] = kv.first; + attrs["v"] = pfxml::file::decode(kv.second); + o->openTag("tag", attrs); + o->closeTag(); + } + o->closeTag(); } - for (const auto& kv : w.attrs) { - std::map attrs; - attrs["k"] = kv.first; - attrs["v"] = pfxml::file::decode(kv.second); - o->openTag("tag", attrs); - o->closeTag(); - } - o->closeTag(); - } } // _____________________________________________________________________________ NodePL OsmBuilder::plFromGtfs(const Stop* s, const OsmReadOpts& ops) { - NodePL ret( - util::geo::latLngToWebMerc(s->getLat(), s->getLng()), - StatInfo(ops.statNormzer(s->getName()), ops.trackNormzer(s->getPlatformCode()), false)); + NodePL ret( + util::geo::latLngToWebMerc(s->getLat(), s->getLng()), + StatInfo(ops.statNormzer(s->getName()), ops.trackNormzer(s->getPlatformCode()), false)); #ifdef PFAEDLE_STATION_IDS - // debug feature, store station id from GTFS - ret.getSI()->setId(s->getId()); + // debug feature, store station id from GTFS + ret.getSI()->setId(s->getId()); #endif - if (s->getParentStation()) { - ret.getSI()->addAltName(ops.statNormzer(s->getParentStation()->getName())); - } + if (s->getParentStation()) { + ret.getSI()->addAltName(ops.statNormzer(s->getParentStation()->getName())); + } - return ret; + return ret; } // _____________________________________________________________________________ pfxml::parser_state OsmBuilder::readBBoxNds(pfxml::file* xml, OsmIdSet* nodes, - OsmIdSet* nohupNodes, - const OsmFilter& filter, - const BBoxIdx& bbox) const { - bool inNodeBlock = false; - uint64_t curId = 0; + OsmIdSet* nohupNodes, + const OsmFilter& filter, + const BBoxIdx& bbox) const { + bool inNodeBlock = false; + uint64_t curId = 0; - do { - const pfxml::tag& cur = xml->get(); + do { + const pfxml::tag& cur = xml->get(); - if (inNodeBlock && xml->level() == 3 && curId && - strcmp(cur.name, "tag") == 0) { - if (filter.nohup(cur.attrs.find("k")->second, - cur.attrs.find("v")->second)) { - nohupNodes->add(curId); - } - } + if (inNodeBlock && xml->level() == 3 && curId && + strcmp(cur.name, "tag") == 0) { + if (filter.nohup(cur.attrs.find("k")->second, + cur.attrs.find("v")->second)) { + nohupNodes->add(curId); + } + } - if (xml->level() != 2) continue; - if (!inNodeBlock && strcmp(cur.name, "node") == 0) inNodeBlock = true; + if (xml->level() != 2) continue; + if (!inNodeBlock && strcmp(cur.name, "node") == 0) inNodeBlock = true; - if (inNodeBlock) { - // block ended - if (strcmp(cur.name, "node") != 0) - return xml->state(); - double y = util::atof(cur.attrs.find("lat")->second, 7); - double x = util::atof(cur.attrs.find("lon")->second, 7); + if (inNodeBlock) { + // block ended + if (strcmp(cur.name, "node") != 0) + return xml->state(); + double y = util::atof(cur.attrs.find("lat")->second, 7); + double x = util::atof(cur.attrs.find("lon")->second, 7); - if (bbox.contains(Point(x, y))) { - curId = util::atoul(cur.attrs.find("id")->second); - nodes->add(curId); - } - } - } while (xml->next()); + if (bbox.contains(Point(x, y))) { + curId = util::atoul(cur.attrs.find("id")->second); + nodes->add(curId); + } + } + } while (xml->next()); - return xml->state(); + return xml->state(); } // _____________________________________________________________________________ OsmWay OsmBuilder::nextWayWithId(pfxml::file* xml, osmid wid, const AttrKeySet& keepAttrs) const { - OsmWay w; + OsmWay w; - do { - const pfxml::tag& cur = xml->get(); - if (xml->level() == 2 || xml->level() == 0) { - if (w.id || strcmp(cur.name, "way")) return w; + do { + const pfxml::tag& cur = xml->get(); + if (xml->level() == 2 || xml->level() == 0) { + if (w.id || strcmp(cur.name, "way")) return w; - osmid id = util::atoul(cur.attrs.find("id")->second); - if (id == wid) w.id = id; - } + osmid id = util::atoul(cur.attrs.find("id")->second); + if (id == wid) w.id = id; + } - if (w.id && xml->level() == 3) { - if (strcmp(cur.name, "nd") == 0) { - w.nodes.push_back(util::atoul(cur.attrs.find("ref")->second)); - } else if (strcmp(cur.name, "tag") == 0) { - if (keepAttrs.count(cur.attrs.find("k")->second)) - w.attrs[cur.attrs.find("k")->second] = cur.attrs.find("v")->second; - } - } - } while (xml->next()); + if (w.id && xml->level() == 3) { + if (strcmp(cur.name, "nd") == 0) { + w.nodes.push_back(util::atoul(cur.attrs.find("ref")->second)); + } else if (strcmp(cur.name, "tag") == 0) { + if (keepAttrs.count(cur.attrs.find("k")->second)) + w.attrs[cur.attrs.find("k")->second] = cur.attrs.find("v")->second; + } + } + } while (xml->next()); - if (w.id) return w; + if (w.id) return w; - return OsmWay(); + return OsmWay(); } // _____________________________________________________________________________ void OsmBuilder::skipUntil(pfxml::file* xml, const std::string& s) const { - while (xml->next() && strcmp(xml->get().name, s.c_str()) != 0) { - } + while (xml->next() && strcmp(xml->get().name, s.c_str()) != 0) { + } } // _____________________________________________________________________________ bool OsmBuilder::relKeep(osmid id, const RelMap& rels, const FlatRels& fl) const { - auto it = rels.find(id); + auto it = rels.find(id); - if (it == rels.end()) return false; + if (it == rels.end()) return false; - for (osmid relId : it->second) { - // as soon as any of this entities relations is not flat, return true - if (!fl.count(relId)) return true; - } + for (osmid relId : it->second) { + // as soon as any of this entities relations is not flat, return true + if (!fl.count(relId)) return true; + } - return false; + return false; } // _____________________________________________________________________________ @@ -1168,55 +1195,55 @@ OsmWay OsmBuilder::nextWay(pfxml::file* xml, const RelMap& wayRels, const OsmFilter& filter, const OsmIdSet& bBoxNodes, const AttrKeySet& keepAttrs, const FlatRels& fl) const { - OsmWay w; + OsmWay w; - do { - const pfxml::tag& cur = xml->get(); - if (xml->level() == 2 || xml->level() == 0) { - if (keepWay(w, wayRels, filter, bBoxNodes, fl)) - return w; + do { + const pfxml::tag& cur = xml->get(); + if (xml->level() == 2 || xml->level() == 0) { + if (keepWay(w, wayRels, filter, bBoxNodes, fl)) + return w; - if (strcmp(cur.name, "way") != 0) - return OsmWay(); + if (strcmp(cur.name, "way") != 0) + return OsmWay(); - w.id = util::atoul(cur.attrs.find("id")->second); - w.nodes.clear(); - w.attrs.clear(); - } - - if (w.id && xml->level() == 3) { - if (strcmp(cur.name, "nd") == 0) { - osmid nid = util::atoul(cur.attrs.find("ref")->second); - w.nodes.push_back(nid); - } else if (strcmp(cur.name, "tag") == 0) { - if (keepAttrs.count(cur.attrs.find("k")->second)) { - w.attrs[cur.attrs.find("k")->second] = cur.attrs.find("v")->second; + w.id = util::atoul(cur.attrs.find("id")->second); + w.nodes.clear(); + w.attrs.clear(); } - } - } - } while (xml->next()); - if (keepWay(w, wayRels, filter, bBoxNodes, fl)) - return w; + if (w.id && xml->level() == 3) { + if (strcmp(cur.name, "nd") == 0) { + osmid nid = util::atoul(cur.attrs.find("ref")->second); + w.nodes.push_back(nid); + } else if (strcmp(cur.name, "tag") == 0) { + if (keepAttrs.count(cur.attrs.find("k")->second)) { + w.attrs[cur.attrs.find("k")->second] = cur.attrs.find("v")->second; + } + } + } + } while (xml->next()); - return OsmWay(); + if (keepWay(w, wayRels, filter, bBoxNodes, fl)) + return w; + + return OsmWay(); } // _____________________________________________________________________________ bool OsmBuilder::keepWay(const OsmWay& w, const RelMap& wayRels, const OsmFilter& filter, const OsmIdSet& bBoxNodes, const FlatRels& fl) const { - if (w.id && w.nodes.size() > 1 && - (relKeep(w.id, wayRels, fl) || filter.keep(w.attrs, OsmFilter::WAY)) && - !filter.drop(w.attrs, OsmFilter::WAY)) { - for (osmid nid : w.nodes) { - if (bBoxNodes.has(nid)) { - return true; - } + if (w.id && w.nodes.size() > 1 && + (relKeep(w.id, wayRels, fl) || filter.keep(w.attrs, OsmFilter::WAY)) && + !filter.drop(w.attrs, OsmFilter::WAY)) { + for (osmid nid : w.nodes) { + if (bBoxNodes.has(nid)) { + return true; + } + } } - } - return false; + return false; } // _____________________________________________________________________________ @@ -1224,13 +1251,13 @@ void OsmBuilder::readEdges(pfxml::file* xml, const RelMap& wayRels, const OsmFilter& filter, const OsmIdSet& bBoxNodes, const AttrKeySet& keepAttrs, OsmIdList* ret, NIdMap* nodes, const FlatRels& flat) { - OsmWay w; - while ((w = nextWay(xml, wayRels, filter, bBoxNodes, keepAttrs, flat)).id) { - ret->push_back(w.id); - for (auto n : w.nodes) { - (*nodes)[n] = nullptr; + OsmWay w; + while ((w = nextWay(xml, wayRels, filter, bBoxNodes, keepAttrs, flat)).id) { + ret->push_back(w.id); + for (auto n : w.nodes) { + (*nodes)[n] = nullptr; + } } - } } // _____________________________________________________________________________ @@ -1242,77 +1269,77 @@ void OsmBuilder::readEdges(pfxml::file* xml, Graph* g, const RelLst& rels, const Restrictions& rawRests, Restrictor* restor, const FlatRels& fl, EdgTracks* eTracks, const OsmReadOpts& opts) { - OsmWay w; - while ((w = nextWay(xml, wayRels, filter, bBoxNodes, keepAttrs, fl)).id) { - Node* last = nullptr; - std::vector lines; - if (wayRels.count(w.id)) { - lines = getLines(wayRels.find(w.id)->second, rels, opts); + OsmWay w; + while ((w = nextWay(xml, wayRels, filter, bBoxNodes, keepAttrs, fl)).id) { + Node* last = nullptr; + std::vector lines; + if (wayRels.count(w.id)) { + lines = getLines(wayRels.find(w.id)->second, rels, opts); + } + std::string track = + getAttrByFirstMatch(opts.edgePlatformRules, w.id, w.attrs, wayRels, + rels, opts.trackNormzer); + + osmid lastnid = 0; + for (osmid nid : w.nodes) { + Node* n = nullptr; + if (noHupNodes.has(nid)) { + n = g->addNd(); + (*multiNodes)[nid].insert(n); + } else if (!nodes->count(nid)) { + if (!bBoxNodes.has(nid)) continue; + n = g->addNd(); + (*nodes)[nid] = n; + } else { + n = (*nodes)[nid]; + } + if (last) { + auto e = g->addEdg(last, n, EdgePL()); + if (!e) continue; + + processRestr(nid, w.id, rawRests, e, n, restor); + processRestr(lastnid, w.id, rawRests, e, last, restor); + + e->pl().addLines(lines); + e->pl().setLvl(filter.level(w.attrs)); + if (!track.empty()) (*eTracks)[e] = track; + + if (filter.oneway(w.attrs)) e->pl().setOneWay(1); + if (filter.onewayrev(w.attrs)) e->pl().setOneWay(2); + } + lastnid = nid; + last = n; + } } - std::string track = - getAttrByFirstMatch(opts.edgePlatformRules, w.id, w.attrs, wayRels, - rels, opts.trackNormzer); - - osmid lastnid = 0; - for (osmid nid : w.nodes) { - Node* n = nullptr; - if (noHupNodes.has(nid)) { - n = g->addNd(); - (*multiNodes)[nid].insert(n); - } else if (!nodes->count(nid)) { - if (!bBoxNodes.has(nid)) continue; - n = g->addNd(); - (*nodes)[nid] = n; - } else { - n = (*nodes)[nid]; - } - if (last) { - auto e = g->addEdg(last, n, EdgePL()); - if (!e) continue; - - processRestr(nid, w.id, rawRests, e, n, restor); - processRestr(lastnid, w.id, rawRests, e, last, restor); - - e->pl().addLines(lines); - e->pl().setLvl(filter.level(w.attrs)); - if (!track.empty()) (*eTracks)[e] = track; - - if (filter.oneway(w.attrs)) e->pl().setOneWay(1); - if (filter.onewayrev(w.attrs)) e->pl().setOneWay(2); - } - lastnid = nid; - last = n; - } - } } // _____________________________________________________________________________ void OsmBuilder::processRestr(osmid nid, osmid wid, const Restrictions& rawRests, Edge* e, Node* n, Restrictor* restor) const { - if (rawRests.pos.count(nid)) { - for (const auto& kv : rawRests.pos.find(nid)->second) { - if (kv.eFrom == wid) { - e->pl().setRestricted(); - restor->add(e, kv.eTo, n, true); - } else if (kv.eTo == wid) { - e->pl().setRestricted(); - restor->relax(wid, n, e); - } + if (rawRests.pos.count(nid)) { + for (const auto& kv : rawRests.pos.find(nid)->second) { + if (kv.eFrom == wid) { + e->pl().setRestricted(); + restor->add(e, kv.eTo, n, true); + } else if (kv.eTo == wid) { + e->pl().setRestricted(); + restor->relax(wid, n, e); + } + } } - } - if (rawRests.neg.count(nid)) { - for (const auto& kv : rawRests.neg.find(nid)->second) { - if (kv.eFrom == wid) { - e->pl().setRestricted(); - restor->add(e, kv.eTo, n, false); - } else if (kv.eTo == wid) { - e->pl().setRestricted(); - restor->relax(wid, n, e); - } + if (rawRests.neg.count(nid)) { + for (const auto& kv : rawRests.neg.find(nid)->second) { + if (kv.eFrom == wid) { + e->pl().setRestricted(); + restor->add(e, kv.eTo, n, false); + } else if (kv.eTo == wid) { + e->pl().setRestricted(); + restor->relax(wid, n, e); + } + } } - } } // _____________________________________________________________________________ @@ -1321,31 +1348,31 @@ OsmNode OsmBuilder::nextNode(pfxml::file* xml, NIdMap* nodes, const OsmFilter& filter, const OsmIdSet& bBoxNodes, const AttrKeySet& keepAttrs, const FlatRels& fl) const { - OsmNode n; + OsmNode n; - do { - const pfxml::tag& cur = xml->get(); - if (xml->level() == 2 || xml->level() == 0) { - if (keepNode(n, *nodes, *multNodes, nodeRels, bBoxNodes, filter, fl)) + do { + const pfxml::tag& cur = xml->get(); + if (xml->level() == 2 || xml->level() == 0) { + if (keepNode(n, *nodes, *multNodes, nodeRels, bBoxNodes, filter, fl)) + return n; + // block ended + if (strcmp(cur.name, "node")) return OsmNode(); + + n.attrs.clear(); + n.lat = util::atof(cur.attrs.find("lat")->second, 7); + n.lng = util::atof(cur.attrs.find("lon")->second, 7); + n.id = util::atoul(cur.attrs.find("id")->second); + } + + if (xml->level() == 3 && n.id && strcmp(cur.name, "tag") == 0) { + if (keepAttrs.count(cur.attrs.find("k")->second)) + n.attrs[cur.attrs.find("k")->second] = cur.attrs.find("v")->second; + } + } while (xml->next()); + + if (keepNode(n, *nodes, *multNodes, nodeRels, bBoxNodes, filter, fl)) return n; - // block ended - if (strcmp(cur.name, "node")) return OsmNode(); - - n.attrs.clear(); - n.lat = util::atof(cur.attrs.find("lat")->second, 7); - n.lng = util::atof(cur.attrs.find("lon")->second, 7); - n.id = util::atoul(cur.attrs.find("id")->second); - } - - if (xml->level() == 3 && n.id && strcmp(cur.name, "tag") == 0) { - if (keepAttrs.count(cur.attrs.find("k")->second)) - n.attrs[cur.attrs.find("k")->second] = cur.attrs.find("v")->second; - } - } while (xml->next()); - - if (keepNode(n, *nodes, *multNodes, nodeRels, bBoxNodes, filter, fl)) - return n; - return OsmNode(); + return OsmNode(); } // _____________________________________________________________________________ @@ -1353,16 +1380,16 @@ bool OsmBuilder::keepNode(const OsmNode& n, const NIdMap& nodes, const NIdMultMap& multNodes, const RelMap& nodeRels, const OsmIdSet& bBoxNodes, const OsmFilter& filter, const FlatRels& fl) const { - if (n.id && - (nodes.count(n.id) || multNodes.count(n.id) || - relKeep(n.id, nodeRels, fl) || filter.keep(n.attrs, OsmFilter::NODE)) && - (nodes.count(n.id) || bBoxNodes.has(n.id)) && - (nodes.count(n.id) || multNodes.count(n.id) || - !filter.drop(n.attrs, OsmFilter::NODE))) { - return true; - } + if (n.id && + (nodes.count(n.id) || multNodes.count(n.id) || + relKeep(n.id, nodeRels, fl) || filter.keep(n.attrs, OsmFilter::NODE)) && + (nodes.count(n.id) || bBoxNodes.has(n.id)) && + (nodes.count(n.id) || multNodes.count(n.id) || + !filter.drop(n.attrs, OsmFilter::NODE))) { + return true; + } - return false; + return false; } // _____________________________________________________________________________ @@ -1371,20 +1398,20 @@ void OsmBuilder::readWriteNds(pfxml::file* i, util::xml::XmlWriter* o, const OsmIdSet& bBoxNds, NIdMap* nds, const AttrKeySet& keepAttrs, const FlatRels& f) const { - OsmNode nd; - NIdMultMap empt; - while ( - (nd = nextNode(i, nds, &empt, nRels, filter, bBoxNds, keepAttrs, f)).id) { - (*nds)[nd.id] = 0; - o->openTag("node", {{"id", std::to_string(nd.id)}, - {"lat", std::to_string(nd.lat)}, - {"lon", std::to_string(nd.lng)}}); - for (const auto& kv : nd.attrs) { - o->openTag("tag", {{"k", kv.first}, {"v", pfxml::file::decode(kv.second)}}); - o->closeTag(); + OsmNode nd; + NIdMultMap empt; + while ( + (nd = nextNode(i, nds, &empt, nRels, filter, bBoxNds, keepAttrs, f)).id) { + (*nds)[nd.id] = 0; + o->openTag("node", {{"id", std::to_string(nd.id)}, + {"lat", std::to_string(nd.lat)}, + {"lon", std::to_string(nd.lng)}}); + for (const auto& kv : nd.attrs) { + o->openTag("tag", {{"k", kv.first}, {"v", pfxml::file::decode(kv.second)}}); + o->closeTag(); + } + o->closeTag(); } - o->closeTag(); - } } // _____________________________________________________________________________ @@ -1394,127 +1421,127 @@ void OsmBuilder::readNodes(pfxml::file* xml, Graph* g, const RelLst& rels, NIdMultMap* multNodes, NodeSet* orphanStations, const AttrKeySet& keepAttrs, const FlatRels& fl, const OsmReadOpts& opts) const { - StAttrGroups attrGroups; + StAttrGroups attrGroups; - OsmNode nd; - while ((nd = nextNode(xml, nodes, multNodes, nodeRels, filter, bBoxNodes, - keepAttrs, fl)) - .id) { - Node* n = 0; - auto pos = util::geo::latLngToWebMerc(nd.lat, nd.lng); - if (nodes->count(nd.id)) { - n = (*nodes)[nd.id]; - n->pl().setGeom(pos); - if (filter.station(nd.attrs)) { - auto si = getStatInfo(n, nd.id, pos, nd.attrs, &attrGroups, nodeRels, - rels, opts); - if (!si.isNull()) n->pl().setSI(si); - } else if (filter.blocker(nd.attrs)) { - n->pl().setBlocker(); - } - } else if ((*multNodes).count(nd.id)) { - for (auto* n : (*multNodes)[nd.id]) { - n->pl().setGeom(pos); - if (filter.station(nd.attrs)) { - auto si = getStatInfo(n, nd.id, pos, nd.attrs, &attrGroups, nodeRels, - rels, opts); - if (!si.isNull()) n->pl().setSI(si); - } else if (filter.blocker(nd.attrs)) { - n->pl().setBlocker(); + OsmNode nd; + while ((nd = nextNode(xml, nodes, multNodes, nodeRels, filter, bBoxNodes, + keepAttrs, fl)) + .id) { + Node* n = 0; + auto pos = util::geo::latLngToWebMerc(nd.lat, nd.lng); + if (nodes->count(nd.id)) { + n = (*nodes)[nd.id]; + n->pl().setGeom(pos); + if (filter.station(nd.attrs)) { + auto si = getStatInfo(n, nd.id, pos, nd.attrs, &attrGroups, nodeRels, + rels, opts); + if (!si.isNull()) n->pl().setSI(si); + } else if (filter.blocker(nd.attrs)) { + n->pl().setBlocker(); + } + } else if ((*multNodes).count(nd.id)) { + for (auto* n : (*multNodes)[nd.id]) { + n->pl().setGeom(pos); + if (filter.station(nd.attrs)) { + auto si = getStatInfo(n, nd.id, pos, nd.attrs, &attrGroups, nodeRels, + rels, opts); + if (!si.isNull()) n->pl().setSI(si); + } else if (filter.blocker(nd.attrs)) { + n->pl().setBlocker(); + } + } + } else { + // these are nodes without any connected edges + if (filter.station(nd.attrs)) { + auto tmp = g->addNd(NodePL(pos)); + auto si = getStatInfo(tmp, nd.id, pos, nd.attrs, &attrGroups, nodeRels, + rels, opts); + if (!si.isNull()) tmp->pl().setSI(si); + if (tmp->pl().getSI()) { + tmp->pl().getSI()->setIsFromOsm(false); + orphanStations->insert(tmp); + } + } } - } - } else { - // these are nodes without any connected edges - if (filter.station(nd.attrs)) { - auto tmp = g->addNd(NodePL(pos)); - auto si = getStatInfo(tmp, nd.id, pos, nd.attrs, &attrGroups, nodeRels, - rels, opts); - if (!si.isNull()) tmp->pl().setSI(si); - if (tmp->pl().getSI()) { - tmp->pl().getSI()->setIsFromOsm(false); - orphanStations->insert(tmp); - } - } } - } } // _____________________________________________________________________________ OsmRel OsmBuilder::nextRel(pfxml::file* xml, const OsmFilter& filter, const AttrKeySet& keepAttrs) const { - OsmRel rel; + OsmRel rel; - do { - const pfxml::tag& cur = xml->get(); - if (xml->level() == 2 || xml->level() == 0) { - uint64_t keepFlags = 0; - uint64_t dropFlags = 0; - if (rel.id && !rel.attrs.empty() && - (keepFlags = filter.keep(rel.attrs, OsmFilter::REL)) && - !(dropFlags = filter.drop(rel.attrs, OsmFilter::REL))) { + do { + const pfxml::tag& cur = xml->get(); + if (xml->level() == 2 || xml->level() == 0) { + uint64_t keepFlags = 0; + uint64_t dropFlags = 0; + if (rel.id && !rel.attrs.empty() && + (keepFlags = filter.keep(rel.attrs, OsmFilter::REL)) && + !(dropFlags = filter.drop(rel.attrs, OsmFilter::REL))) { + rel.keepFlags = keepFlags; + rel.dropFlags = dropFlags; + return rel; + } + + // block ended + if (strcmp(cur.name, "relation") != 0) { + return OsmRel(); + } + + rel.attrs.clear(); + rel.nodes.clear(); + rel.ways.clear(); + rel.nodeRoles.clear(); + rel.wayRoles.clear(); + rel.keepFlags = 0; + rel.dropFlags = 0; + rel.id = util::atoul(cur.attrs.find("id")->second); + } + + if (xml->level() == 3 && rel.id) { + if (strcmp(cur.name, "member") == 0) { + if (strcmp(cur.attrs.find("type")->second, "node") == 0) { + osmid id = util::atoul(cur.attrs.find("ref")->second); + // TODO(patrick): no need to push IDs that have been filtered out by + // the bounding box!!!! + rel.nodes.push_back(id); + if (cur.attrs.count("role")) { + rel.nodeRoles.emplace_back(cur.attrs.find("role")->second); + } else { + rel.nodeRoles.emplace_back(""); + } + } + + if (strcmp(cur.attrs.find("type")->second, "way") == 0) { + osmid id = util::atoul(cur.attrs.find("ref")->second); + rel.ways.push_back(id); + if (cur.attrs.count("role")) { + rel.wayRoles.emplace_back(cur.attrs.find("role")->second); + } else { + rel.wayRoles.emplace_back(""); + } + } + + } else if (strcmp(cur.name, "tag") == 0) { + if (keepAttrs.count(cur.attrs.find("k")->second)) + rel.attrs[cur.attrs.find("k")->second] = cur.attrs.find("v")->second; + } + } + } while (xml->next()); + + // dont forget last relation + uint64_t keepFlags = 0; + uint64_t dropFlags = 0; + if (rel.id && !rel.attrs.empty() && + (keepFlags = filter.keep(rel.attrs, OsmFilter::REL)) && + !(dropFlags = filter.drop(rel.attrs, OsmFilter::REL))) { rel.keepFlags = keepFlags; rel.dropFlags = dropFlags; return rel; - } - - // block ended - if (strcmp(cur.name, "relation") != 0) { - return OsmRel(); - } - - rel.attrs.clear(); - rel.nodes.clear(); - rel.ways.clear(); - rel.nodeRoles.clear(); - rel.wayRoles.clear(); - rel.keepFlags = 0; - rel.dropFlags = 0; - rel.id = util::atoul(cur.attrs.find("id")->second); } - if (xml->level() == 3 && rel.id) { - if (strcmp(cur.name, "member") == 0) { - if (strcmp(cur.attrs.find("type")->second, "node") == 0) { - osmid id = util::atoul(cur.attrs.find("ref")->second); - // TODO(patrick): no need to push IDs that have been filtered out by - // the bounding box!!!! - rel.nodes.push_back(id); - if (cur.attrs.count("role")) { - rel.nodeRoles.emplace_back(cur.attrs.find("role")->second); - } else { - rel.nodeRoles.emplace_back(""); - } - } - - if (strcmp(cur.attrs.find("type")->second, "way") == 0) { - osmid id = util::atoul(cur.attrs.find("ref")->second); - rel.ways.push_back(id); - if (cur.attrs.count("role")) { - rel.wayRoles.emplace_back(cur.attrs.find("role")->second); - } else { - rel.wayRoles.emplace_back(""); - } - } - - } else if (strcmp(cur.name, "tag") == 0) { - if (keepAttrs.count(cur.attrs.find("k")->second)) - rel.attrs[cur.attrs.find("k")->second] = cur.attrs.find("v")->second; - } - } - } while (xml->next()); - - // dont forget last relation - uint64_t keepFlags = 0; - uint64_t dropFlags = 0; - if (rel.id && !rel.attrs.empty() && - (keepFlags = filter.keep(rel.attrs, OsmFilter::REL)) && - !(dropFlags = filter.drop(rel.attrs, OsmFilter::REL))) { - rel.keepFlags = keepFlags; - rel.dropFlags = dropFlags; - return rel; - } - - return OsmRel(); + return OsmRel(); } // _____________________________________________________________________________ @@ -1522,59 +1549,59 @@ void OsmBuilder::readRels(pfxml::file* xml, RelLst* rels, RelMap* nodeRels, RelMap* wayRels, const OsmFilter& filter, const AttrKeySet& keepAttrs, Restrictions* rests) const { - OsmRel rel; - while ((rel = nextRel(xml, filter, keepAttrs)).id) { - rels->rels.push_back(rel.attrs); - if (rel.keepFlags & osm::REL_NO_DOWN) { - rels->flat.insert(rels->rels.size() - 1); - } - for (osmid id : rel.nodes) (*nodeRels)[id].push_back(rels->rels.size() - 1); - for (osmid id : rel.ways) (*wayRels)[id].push_back(rels->rels.size() - 1); + OsmRel rel; + while ((rel = nextRel(xml, filter, keepAttrs)).id) { + rels->rels.push_back(rel.attrs); + if (rel.keepFlags & osm::REL_NO_DOWN) { + rels->flat.insert(rels->rels.size() - 1); + } + for (osmid id : rel.nodes) (*nodeRels)[id].push_back(rels->rels.size() - 1); + for (osmid id : rel.ways) (*wayRels)[id].push_back(rels->rels.size() - 1); - // TODO(patrick): this is not needed for the filtering - remove it here! - readRestr(rel, rests, filter); - } + // TODO(patrick): this is not needed for the filtering - remove it here! + readRestr(rel, rests, filter); + } } // _____________________________________________________________________________ void OsmBuilder::readRestr(const OsmRel& rel, Restrictions* rests, const OsmFilter& filter) const { - if (!rel.attrs.count("type")) return; - if (rel.attrs.find("type")->second != "restriction") return; + if (!rel.attrs.count("type")) return; + if (rel.attrs.find("type")->second != "restriction") return; - bool pos = filter.posRestr(rel.attrs); - bool neg = filter.negRestr(rel.attrs); + bool pos = filter.posRestr(rel.attrs); + bool neg = filter.negRestr(rel.attrs); - if (!pos && !neg) return; + if (!pos && !neg) return; - osmid from = 0; - osmid to = 0; - osmid via = 0; + osmid from = 0; + osmid to = 0; + osmid via = 0; - for (size_t i = 0; i < rel.ways.size(); i++) { - if (rel.wayRoles[i] == "from") { - if (from) return; // only one from member supported - from = rel.ways[i]; + for (size_t i = 0; i < rel.ways.size(); i++) { + if (rel.wayRoles[i] == "from") { + if (from) return; // only one from member supported + from = rel.ways[i]; + } + if (rel.wayRoles[i] == "to") { + if (to) return; // only one to member supported + to = rel.ways[i]; + } } - if (rel.wayRoles[i] == "to") { - if (to) return; // only one to member supported - to = rel.ways[i]; - } - } - for (size_t i = 0; i < rel.nodes.size(); i++) { - if (rel.nodeRoles[i] == "via") { - via = rel.nodes[i]; - break; + for (size_t i = 0; i < rel.nodes.size(); i++) { + if (rel.nodeRoles[i] == "via") { + via = rel.nodes[i]; + break; + } } - } - if (from && to && via) { - if (pos) - rests->pos[via].push_back(Restriction{from, to}); - else if (neg) - rests->neg[via].push_back(Restriction{from, to}); - } + if (from && to && via) { + if (pos) + rests->pos[via].push_back(Restriction{from, to}); + else if (neg) + rests->neg[via].push_back(Restriction{from, to}); + } } // _____________________________________________________________________________ @@ -1583,49 +1610,49 @@ std::string OsmBuilder::getAttrByFirstMatch(const DeepAttrLst& rule, osmid id, const RelMap& entRels, const RelLst& rels, const Normalizer& norm) const { - std::string ret; - for (const auto& s : rule) { - ret = norm(pfxml::file::decode(getAttr(s, id, attrs, entRels, rels))); - if (!ret.empty()) return ret; - } + std::string ret; + for (const auto& s : rule) { + ret = norm(pfxml::file::decode(getAttr(s, id, attrs, entRels, rels))); + if (!ret.empty()) return ret; + } - return ret; + return ret; } // _____________________________________________________________________________ std::vector OsmBuilder::getAttrMatchRanked( - const DeepAttrLst& rule, osmid id, const AttrMap& attrs, - const RelMap& entRels, const RelLst& rels, const Normalizer& norm) const { - std::vector ret; - for (const auto& s : rule) { - std::string tmp = - norm(pfxml::file::decode(getAttr(s, id, attrs, entRels, rels))); - if (!tmp.empty()) ret.push_back(tmp); - } + const DeepAttrLst& rule, osmid id, const AttrMap& attrs, + const RelMap& entRels, const RelLst& rels, const Normalizer& norm) const { + std::vector ret; + for (const auto& s : rule) { + std::string tmp = + norm(pfxml::file::decode(getAttr(s, id, attrs, entRels, rels))); + if (!tmp.empty()) ret.push_back(tmp); + } - return ret; + return ret; } // _____________________________________________________________________________ std::string OsmBuilder::getAttr(const DeepAttrRule& s, osmid id, const AttrMap& attrs, const RelMap& entRels, const RelLst& rels) const { - if (s.relRule.kv.first.empty()) { - if (attrs.find(s.attr) != attrs.end()) { - return attrs.find(s.attr)->second; - } - } else { - if (entRels.count(id)) { - for (const auto& relId : entRels.find(id)->second) { - if (OsmFilter::contained(rels.rels[relId], s.relRule.kv)) { - if (rels.rels[relId].count(s.attr)) { - return rels.rels[relId].find(s.attr)->second; - } + if (s.relRule.kv.first.empty()) { + if (attrs.find(s.attr) != attrs.end()) { + return attrs.find(s.attr)->second; + } + } else { + if (entRels.count(id)) { + for (const auto& relId : entRels.find(id)->second) { + if (OsmFilter::contained(rels.rels[relId], s.relRule.kv)) { + if (rels.rels[relId].count(s.attr)) { + return rels.rels[relId].find(s.attr)->second; + } + } + } } - } } - } - return ""; + return ""; } // _____________________________________________________________________________ @@ -1635,297 +1662,297 @@ Nullable OsmBuilder::getStatInfo(Node* node, osmid nid, const RelMap& nodeRels, const RelLst& rels, const OsmReadOpts& ops) const { - std::string platform; - std::vector names; + std::string platform; + std::vector names; - names = getAttrMatchRanked(ops.statAttrRules.nameRule, nid, m, nodeRels, rels, - ops.statNormzer); - platform = getAttrByFirstMatch(ops.statAttrRules.platformRule, nid, m, - nodeRels, rels, ops.trackNormzer); + names = getAttrMatchRanked(ops.statAttrRules.nameRule, nid, m, nodeRels, rels, + ops.statNormzer); + platform = getAttrByFirstMatch(ops.statAttrRules.platformRule, nid, m, + nodeRels, rels, ops.trackNormzer); - if (!names.size()) return Nullable(); + if (!names.size()) return Nullable(); - auto ret = StatInfo(names[0], platform, true); + auto ret = StatInfo(names[0], platform, true); #ifdef PFAEDLE_STATION_IDS - ret.setId(getAttrByFirstMatch(ops.statAttrRules.idRule, nid, m, nodeRels, - rels, ops.idNormzer)); + ret.setId(getAttrByFirstMatch(ops.statAttrRules.idRule, nid, m, nodeRels, + rels, ops.idNormzer)); #endif - for (size_t i = 1; i < names.size(); i++) ret.addAltName(names[i]); + for (size_t i = 1; i < names.size(); i++) ret.addAltName(names[i]); - bool groupFound = false; + bool groupFound = false; - for (const auto& rule : ops.statGroupNAttrRules) { - if (groupFound) break; - std::string ruleVal = getAttr(rule.attr, nid, m, nodeRels, rels); - if (!ruleVal.empty()) { - // check if a matching group exists - for (auto* group : (*groups)[rule.attr.attr][ruleVal]) { - if (groupFound) break; - for (const auto* member : group->getNodes()) { - if (webMercMeterDist(*member->pl().getGeom(), pos) <= rule.maxDist) { - // ok, group is matching - groupFound = true; - if (node) group->addNode(node); - ret.setGroup(group); - break; - } - } - } - } - } - - if (!groupFound) { for (const auto& rule : ops.statGroupNAttrRules) { - std::string ruleVal = getAttr(rule.attr, nid, m, nodeRels, rels); - if (!ruleVal.empty()) { - // add new group - StatGroup* g = new StatGroup(); - if (node) g->addNode(node); - ret.setGroup(g); - (*groups)[rule.attr.attr][ruleVal].push_back(g); - break; - } + if (groupFound) break; + std::string ruleVal = getAttr(rule.attr, nid, m, nodeRels, rels); + if (!ruleVal.empty()) { + // check if a matching group exists + for (auto* group : (*groups)[rule.attr.attr][ruleVal]) { + if (groupFound) break; + for (const auto* member : group->getNodes()) { + if (webMercMeterDist(*member->pl().getGeom(), pos) <= rule.maxDist) { + // ok, group is matching + groupFound = true; + if (node) group->addNode(node); + ret.setGroup(group); + break; + } + } + } + } } - } - return ret; + if (!groupFound) { + for (const auto& rule : ops.statGroupNAttrRules) { + std::string ruleVal = getAttr(rule.attr, nid, m, nodeRels, rels); + if (!ruleVal.empty()) { + // add new group + StatGroup* g = new StatGroup(); + if (node) g->addNode(node); + ret.setGroup(g); + (*groups)[rule.attr.attr][ruleVal].push_back(g); + break; + } + } + } + + return ret; } // _____________________________________________________________________________ double OsmBuilder::dist(const Node* a, const Node* b) { - return webMercMeterDist(*a->pl().getGeom(), *b->pl().getGeom()); + return webMercMeterDist(*a->pl().getGeom(), *b->pl().getGeom()); } // _____________________________________________________________________________ double OsmBuilder::webMercDist(const Node* a, const Node* b) { - return webMercMeterDist(*a->pl().getGeom(), *b->pl().getGeom()); + return webMercMeterDist(*a->pl().getGeom(), *b->pl().getGeom()); } // _____________________________________________________________________________ void OsmBuilder::writeGeoms(Graph* g) { - for (auto* n : *g->getNds()) { - for (auto* e : n->getAdjListOut()) { - e->pl().addPoint(*e->getFrom()->pl().getGeom()); - e->pl().setLength(dist(e->getFrom(), e->getTo())); - e->pl().addPoint(*e->getTo()->pl().getGeom()); + for (auto* n : *g->getNds()) { + for (auto* e : n->getAdjListOut()) { + e->pl().addPoint(*e->getFrom()->pl().getGeom()); + e->pl().setLength(dist(e->getFrom(), e->getTo())); + e->pl().addPoint(*e->getTo()->pl().getGeom()); + } } - } } // _____________________________________________________________________________ void OsmBuilder::fixGaps(Graph* g, NodeGrid* ng) { - double METER = 1; - for (auto* n : *g->getNds()) { - if (n->getInDeg() + n->getOutDeg() == 1) { - // get all nodes in distance - std::set ret; - double distor = util::geo::webMercDistFactor(*n->pl().getGeom()); - ng->get(util::geo::pad(util::geo::getBoundingBox(*n->pl().getGeom()), - METER / distor), - &ret); - for (auto* nb : ret) { - if (nb != n && (nb->getInDeg() + nb->getOutDeg()) == 1 && - webMercDist(nb, n) <= METER / distor) { - // special case: both node are non-stations, move - // the end point nb to n and delete nb - if (!nb->pl().getSI() && !n->pl().getSI()) { - Node* otherN; - if (nb->getOutDeg()) - otherN = (*nb->getAdjListOut().begin())->getOtherNd(nb); - else - otherN = (*nb->getAdjListIn().begin())->getOtherNd(nb); - LINE l; - l.push_back(*otherN->pl().getGeom()); - l.push_back(*n->pl().getGeom()); + double METER = 1; + for (auto* n : *g->getNds()) { + if (n->getInDeg() + n->getOutDeg() == 1) { + // get all nodes in distance + std::set ret; + double distor = util::geo::webMercDistFactor(*n->pl().getGeom()); + ng->get(util::geo::pad(util::geo::getBoundingBox(*n->pl().getGeom()), + METER / distor), + &ret); + for (auto* nb : ret) { + if (nb != n && (nb->getInDeg() + nb->getOutDeg()) == 1 && + webMercDist(nb, n) <= METER / distor) { + // special case: both node are non-stations, move + // the end point nb to n and delete nb + if (!nb->pl().getSI() && !n->pl().getSI()) { + Node* otherN; + if (nb->getOutDeg()) + otherN = (*nb->getAdjListOut().begin())->getOtherNd(nb); + else + otherN = (*nb->getAdjListIn().begin())->getOtherNd(nb); + LINE l; + l.push_back(*otherN->pl().getGeom()); + l.push_back(*n->pl().getGeom()); - Edge* e; - if (nb->getOutDeg()) - e = g->addEdg(otherN, n, (*nb->getAdjListOut().begin())->pl()); - else - e = g->addEdg(otherN, n, (*nb->getAdjListIn().begin())->pl()); - if (e) { - *e->pl().getGeom() = l; - g->delNd(nb); - ng->remove(nb); + Edge* e; + if (nb->getOutDeg()) + e = g->addEdg(otherN, n, (*nb->getAdjListOut().begin())->pl()); + else + e = g->addEdg(otherN, n, (*nb->getAdjListIn().begin())->pl()); + if (e) { + *e->pl().getGeom() = l; + g->delNd(nb); + ng->remove(nb); + } + } else { + // if one of the nodes is a station, just add an edge between them + if (nb->getOutDeg()) + g->addEdg(n, nb, (*nb->getAdjListOut().begin())->pl()); + else + g->addEdg(n, nb, (*nb->getAdjListIn().begin())->pl()); + } + } } - } else { - // if one of the nodes is a station, just add an edge between them - if (nb->getOutDeg()) - g->addEdg(n, nb, (*nb->getAdjListOut().begin())->pl()); - else - g->addEdg(n, nb, (*nb->getAdjListIn().begin())->pl()); - } } - } } - } } // _____________________________________________________________________________ EdgeGrid OsmBuilder::buildEdgeIdx(Graph* g, size_t size, const BOX& webMercBox) { - EdgeGrid ret(size, size, webMercBox, false); - for (auto* n : *g->getNds()) { - for (auto* e : n->getAdjListOut()) { - assert(e->pl().getGeom()); - ret.add(*e->pl().getGeom(), e); + EdgeGrid ret(size, size, webMercBox, false); + for (auto* n : *g->getNds()) { + for (auto* e : n->getAdjListOut()) { + assert(e->pl().getGeom()); + ret.add(*e->pl().getGeom(), e); + } } - } - return ret; + return ret; } // _____________________________________________________________________________ NodeGrid OsmBuilder::buildNodeIdx(Graph* g, size_t size, const BOX& webMercBox, bool which) { - NodeGrid ret(size, size, webMercBox, false); - for (auto* n : *g->getNds()) { - if (!which && n->getInDeg() + n->getOutDeg() == 1) - ret.add(*n->pl().getGeom(), n); - else if (which && n->pl().getSI()) - ret.add(*n->pl().getGeom(), n); - } - return ret; + NodeGrid ret(size, size, webMercBox, false); + for (auto* n : *g->getNds()) { + if (!which && n->getInDeg() + n->getOutDeg() == 1) + ret.add(*n->pl().getGeom(), n); + else if (which && n->pl().getSI()) + ret.add(*n->pl().getGeom(), n); + } + return ret; } // _____________________________________________________________________________ Node* OsmBuilder::depthSearch(const Edge* e, const StatInfo* si, const POINT& p, double maxD, int maxFullTurns, double minAngle, const SearchFunc& sfunc) { - // shortcuts - double dFrom = webMercMeterDist(*e->getFrom()->pl().getGeom(), p); - double dTo = webMercMeterDist(*e->getTo()->pl().getGeom(), p); - if (dFrom > maxD && dTo > maxD) return 0; + // shortcuts + double dFrom = webMercMeterDist(*e->getFrom()->pl().getGeom(), p); + double dTo = webMercMeterDist(*e->getTo()->pl().getGeom(), p); + if (dFrom > maxD && dTo > maxD) return 0; - if (dFrom <= maxD && sfunc(e->getFrom(), si)) return e->getFrom(); - if (dTo <= maxD && sfunc(e->getTo(), si)) return e->getTo(); + if (dFrom <= maxD && sfunc(e->getFrom(), si)) return e->getFrom(); + if (dTo <= maxD && sfunc(e->getTo(), si)) return e->getTo(); - NodeCandPQ pq; - NodeSet closed; - pq.push(NodeCand{dFrom, e->getFrom(), e, 0}); - if (e->getFrom() != e->getTo()) pq.push(NodeCand{dTo, e->getTo(), e, 0}); + NodeCandPQ pq; + NodeSet closed; + pq.push(NodeCand{dFrom, e->getFrom(), e, 0}); + if (e->getFrom() != e->getTo()) pq.push(NodeCand{dTo, e->getTo(), e, 0}); - while (!pq.empty()) { - auto cur = pq.top(); - pq.pop(); - if (closed.count(cur.node)) continue; - closed.insert(cur.node); + while (!pq.empty()) { + auto cur = pq.top(); + pq.pop(); + if (closed.count(cur.node)) continue; + closed.insert(cur.node); - for (size_t i = 0; i < cur.node->getInDeg() + cur.node->getOutDeg(); i++) { - trgraph::Node* cand; - trgraph::Edge* edg; + for (size_t i = 0; i < cur.node->getInDeg() + cur.node->getOutDeg(); i++) { + trgraph::Node* cand; + trgraph::Edge* edg; - if (i < cur.node->getInDeg()) { - edg = cur.node->getAdjListIn()[i]; - cand = edg->getFrom(); - } else { - edg = cur.node->getAdjListOut()[i - cur.node->getInDeg()]; - cand = edg->getTo(); - } + if (i < cur.node->getInDeg()) { + edg = cur.node->getAdjListIn()[i]; + cand = edg->getFrom(); + } else { + edg = cur.node->getAdjListOut()[i - cur.node->getInDeg()]; + cand = edg->getTo(); + } - if (cand == cur.node) continue; // dont follow self edges + if (cand == cur.node) continue; // dont follow self edges - int fullTurn = 0; + int fullTurn = 0; - if (cur.fromEdge && - cur.node->getInDeg() + cur.node->getOutDeg() > - 2) { // only intersection angles - const POINT& toP = *cand->pl().getGeom(); - const POINT& fromP = - *cur.fromEdge->getOtherNd(cur.node)->pl().getGeom(); - const POINT& nodeP = *cur.node->pl().getGeom(); + if (cur.fromEdge && + cur.node->getInDeg() + cur.node->getOutDeg() > + 2) { // only intersection angles + const POINT& toP = *cand->pl().getGeom(); + const POINT& fromP = + *cur.fromEdge->getOtherNd(cur.node)->pl().getGeom(); + const POINT& nodeP = *cur.node->pl().getGeom(); - if (util::geo::innerProd(nodeP, fromP, toP) < minAngle) fullTurn = 1; - } + if (util::geo::innerProd(nodeP, fromP, toP) < minAngle) fullTurn = 1; + } - if ((maxFullTurns < 0 || cur.fullTurns + fullTurn <= maxFullTurns) && - cur.dist + edg->pl().getLength() < maxD && !closed.count(cand)) { - if (sfunc(cand, si)) { - return cand; - } else { - pq.push(NodeCand{cur.dist + edg->pl().getLength(), cand, edg, - cur.fullTurns + fullTurn}); + if ((maxFullTurns < 0 || cur.fullTurns + fullTurn <= maxFullTurns) && + cur.dist + edg->pl().getLength() < maxD && !closed.count(cand)) { + if (sfunc(cand, si)) { + return cand; + } else { + pq.push(NodeCand{cur.dist + edg->pl().getLength(), cand, edg, + cur.fullTurns + fullTurn}); + } + } } - } } - } - return 0; + return 0; } // _____________________________________________________________________________ bool OsmBuilder::isBlocked(const Edge* e, const StatInfo* si, const POINT& p, double maxD, int maxFullTurns, double minAngle) { - return depthSearch(e, si, p, maxD, maxFullTurns, minAngle, BlockSearch()); + return depthSearch(e, si, p, maxD, maxFullTurns, minAngle, BlockSearch()); } // _____________________________________________________________________________ Node* OsmBuilder::eqStatReach(const Edge* e, const StatInfo* si, const POINT& p, double maxD, int maxFullTurns, double minAngle, bool orphanSnap) { - return depthSearch(e, si, p, maxD, maxFullTurns, minAngle, - EqSearch(orphanSnap)); + return depthSearch(e, si, p, maxD, maxFullTurns, minAngle, + EqSearch(orphanSnap)); } // _____________________________________________________________________________ void OsmBuilder::getEdgCands(const POINT& geom, EdgeCandPQ* ret, EdgeGrid* eg, double d) { - double distor = util::geo::webMercDistFactor(geom); - std::set neighs; - BOX box = util::geo::pad(util::geo::getBoundingBox(geom), d / distor); - eg->get(box, &neighs); + double distor = util::geo::webMercDistFactor(geom); + std::set neighs; + BOX box = util::geo::pad(util::geo::getBoundingBox(geom), d / distor); + eg->get(box, &neighs); - for (auto* e : neighs) { - double dist = util::geo::distToSegment(*e->getFrom()->pl().getGeom(), - *e->getTo()->pl().getGeom(), geom); + for (auto* e : neighs) { + double dist = util::geo::distToSegment(*e->getFrom()->pl().getGeom(), + *e->getTo()->pl().getGeom(), geom); - if (dist * distor <= d) { - ret->push(EdgeCand(-dist, e)); + if (dist * distor <= d) { + ret->push(EdgeCand(-dist, e)); + } } - } } // _____________________________________________________________________________ std::set OsmBuilder::getMatchingNds(const NodePL& s, NodeGrid* ng, double d) { - std::set ret; - double distor = util::geo::webMercDistFactor(*s.getGeom()); - std::set neighs; - BOX box = util::geo::pad(util::geo::getBoundingBox(*s.getGeom()), d / distor); - ng->get(box, &neighs); + std::set ret; + double distor = util::geo::webMercDistFactor(*s.getGeom()); + std::set neighs; + BOX box = util::geo::pad(util::geo::getBoundingBox(*s.getGeom()), d / distor); + ng->get(box, &neighs); - for (auto* n : neighs) { - if (n->pl().getSI() && n->pl().getSI()->simi(s.getSI()) > 0.5) { - double dist = webMercMeterDist(*n->pl().getGeom(), *s.getGeom()); - if (dist < d) ret.insert(n); + for (auto* n : neighs) { + if (n->pl().getSI() && n->pl().getSI()->simi(s.getSI()) > 0.5) { + double dist = webMercMeterDist(*n->pl().getGeom(), *s.getGeom()); + if (dist < d) ret.insert(n); + } } - } - return ret; + return ret; } // _____________________________________________________________________________ Node* OsmBuilder::getMatchingNd(const NodePL& s, NodeGrid* ng, double d) { - double distor = util::geo::webMercDistFactor(*s.getGeom()); - std::set neighs; - BOX box = util::geo::pad(util::geo::getBoundingBox(*s.getGeom()), d / distor); - ng->get(box, &neighs); + double distor = util::geo::webMercDistFactor(*s.getGeom()); + std::set neighs; + BOX box = util::geo::pad(util::geo::getBoundingBox(*s.getGeom()), d / distor); + ng->get(box, &neighs); - Node* ret = 0; - double bestD = std::numeric_limits::max(); + Node* ret = 0; + double bestD = std::numeric_limits::max(); - for (auto* n : neighs) { - if (n->pl().getSI() && n->pl().getSI()->simi(s.getSI()) > 0.5) { - double dist = webMercMeterDist(*n->pl().getGeom(), *s.getGeom()); - if (dist < d && dist < bestD) { - bestD = dist; - ret = n; - } + for (auto* n : neighs) { + if (n->pl().getSI() && n->pl().getSI()->simi(s.getSI()) > 0.5) { + double dist = webMercMeterDist(*n->pl().getGeom(), *s.getGeom()); + if (dist < d && dist < bestD) { + bestD = dist; + ret = n; + } + } } - } - return ret; + return ret; } // _____________________________________________________________________________ @@ -1933,547 +1960,547 @@ std::set OsmBuilder::snapStation(Graph* g, NodePL* s, EdgeGrid* eg, NodeGrid* sng, const OsmReadOpts& opts, Restrictor* restor, bool surrHeur, bool orphSnap, double d) { - assert(s->getSI()); - std::set ret; + assert(s->getSI()); + std::set ret; - EdgeCandPQ pq; + EdgeCandPQ pq; - getEdgCands(*s->getGeom(), &pq, eg, d); + getEdgCands(*s->getGeom(), &pq, eg, d); - if (pq.empty() && surrHeur) { - // no station found in the first round, try again with the nearest - // surrounding station with matching name - const Node* best = getMatchingNd(*s, sng, opts.maxSnapFallbackHeurDistance); - if (best) { - getEdgCands(*best->pl().getGeom(), &pq, eg, d); - } else { - // if still no luck, get edge cands in fallback snap distance - getEdgCands(*s->getGeom(), &pq, eg, opts.maxSnapFallbackHeurDistance); + if (pq.empty() && surrHeur) { + // no station found in the first round, try again with the nearest + // surrounding station with matching name + const Node* best = getMatchingNd(*s, sng, opts.maxSnapFallbackHeurDistance); + if (best) { + getEdgCands(*best->pl().getGeom(), &pq, eg, d); + } else { + // if still no luck, get edge cands in fallback snap distance + getEdgCands(*s->getGeom(), &pq, eg, opts.maxSnapFallbackHeurDistance); + } } - } - while (!pq.empty()) { - auto* e = pq.top().second; - pq.pop(); - auto geom = - util::geo::projectOn(*e->getFrom()->pl().getGeom(), *s->getGeom(), - *e->getTo()->pl().getGeom()); + while (!pq.empty()) { + auto* e = pq.top().second; + pq.pop(); + auto geom = + util::geo::projectOn(*e->getFrom()->pl().getGeom(), *s->getGeom(), + *e->getTo()->pl().getGeom()); - Node* eq = 0; - if (!(eq = eqStatReach(e, s->getSI(), geom, 2 * d, 0, - opts.maxAngleSnapReach, orphSnap))) { - if (e->pl().lvl() > opts.maxSnapLevel) continue; - if (isBlocked(e, s->getSI(), geom, opts.maxBlockDistance, 0, - opts.maxAngleSnapReach)) { - continue; - } + Node* eq = 0; + if (!(eq = eqStatReach(e, s->getSI(), geom, 2 * d, 0, + opts.maxAngleSnapReach, orphSnap))) { + if (e->pl().lvl() > opts.maxSnapLevel) continue; + if (isBlocked(e, s->getSI(), geom, opts.maxBlockDistance, 0, + opts.maxAngleSnapReach)) { + continue; + } - // if the projected position is near (< 2 meters) the end point of this - // way and the endpoint is not already a station, place the station there. - if (!e->getFrom()->pl().getSI() && - webMercMeterDist(geom, *e->getFrom()->pl().getGeom()) < 2) { - e->getFrom()->pl().setSI(*s->getSI()); - if (s->getSI()->getGroup()) - s->getSI()->getGroup()->addNode(e->getFrom()); - ret.insert(e->getFrom()); - } else if (!e->getTo()->pl().getSI() && - webMercMeterDist(geom, *e->getTo()->pl().getGeom()) < 2) { - e->getTo()->pl().setSI(*s->getSI()); - if (s->getSI()->getGroup()) s->getSI()->getGroup()->addNode(e->getTo()); - ret.insert(e->getTo()); - } else { - s->setGeom(geom); - Node* n = g->addNd(*s); - if (n->pl().getSI()->getGroup()) - n->pl().getSI()->getGroup()->addNode(n); - sng->add(geom, n); + // if the projected position is near (< 2 meters) the end point of this + // way and the endpoint is not already a station, place the station there. + if (!e->getFrom()->pl().getSI() && + webMercMeterDist(geom, *e->getFrom()->pl().getGeom()) < 2) { + e->getFrom()->pl().setSI(*s->getSI()); + if (s->getSI()->getGroup()) + s->getSI()->getGroup()->addNode(e->getFrom()); + ret.insert(e->getFrom()); + } else if (!e->getTo()->pl().getSI() && + webMercMeterDist(geom, *e->getTo()->pl().getGeom()) < 2) { + e->getTo()->pl().setSI(*s->getSI()); + if (s->getSI()->getGroup()) s->getSI()->getGroup()->addNode(e->getTo()); + ret.insert(e->getTo()); + } else { + s->setGeom(geom); + Node* n = g->addNd(*s); + if (n->pl().getSI()->getGroup()) + n->pl().getSI()->getGroup()->addNode(n); + sng->add(geom, n); - auto ne = g->addEdg(e->getFrom(), n, e->pl()); - ne->pl().setLength(webMercDist(n, e->getFrom())); - LINE l; - l.push_back(*e->getFrom()->pl().getGeom()); - l.push_back(*n->pl().getGeom()); - *ne->pl().getGeom() = l; - eg->add(l, ne); + auto ne = g->addEdg(e->getFrom(), n, e->pl()); + ne->pl().setLength(webMercDist(n, e->getFrom())); + LINE l; + l.push_back(*e->getFrom()->pl().getGeom()); + l.push_back(*n->pl().getGeom()); + *ne->pl().getGeom() = l; + eg->add(l, ne); - auto nf = g->addEdg(n, e->getTo(), e->pl()); - nf->pl().setLength(webMercDist(n, e->getTo())); - LINE ll; - ll.push_back(*n->pl().getGeom()); - ll.push_back(*e->getTo()->pl().getGeom()); - *nf->pl().getGeom() = ll; - eg->add(l, nf); + auto nf = g->addEdg(n, e->getTo(), e->pl()); + nf->pl().setLength(webMercDist(n, e->getTo())); + LINE ll; + ll.push_back(*n->pl().getGeom()); + ll.push_back(*e->getTo()->pl().getGeom()); + *nf->pl().getGeom() = ll; + eg->add(l, nf); - // replace edge in restrictor - restor->replaceEdge(e, ne, nf); + // replace edge in restrictor + restor->replaceEdge(e, ne, nf); - g->delEdg(e->getFrom(), e->getTo()); - eg->remove(e); - ret.insert(n); - } - } else { - // if the snapped station is very near to the original OSM station - // write additional info from this snap station to the equivalent stat - if (webMercMeterDist(*s->getGeom(), *eq->pl().getGeom()) < - opts.maxOsmStationDistance) { - if (eq->pl().getSI()->getTrack().empty()) - eq->pl().getSI()->setTrack(s->getSI()->getTrack()); - } - ret.insert(eq); + g->delEdg(e->getFrom(), e->getTo()); + eg->remove(e); + ret.insert(n); + } + } else { + // if the snapped station is very near to the original OSM station + // write additional info from this snap station to the equivalent stat + if (webMercMeterDist(*s->getGeom(), *eq->pl().getGeom()) < + opts.maxOsmStationDistance) { + if (eq->pl().getSI()->getTrack().empty()) + eq->pl().getSI()->setTrack(s->getSI()->getTrack()); + } + ret.insert(eq); + } } - } - return ret; + return ret; } // _____________________________________________________________________________ StatGroup* OsmBuilder::groupStats(const NodeSet& s) { - if (!s.size()) return 0; - // reference group - StatGroup* ret = new StatGroup(); - bool used = false; + if (!s.size()) return 0; + // reference group + StatGroup* ret = new StatGroup(); + bool used = false; - for (auto* n : s) { - if (!n->pl().getSI()) continue; - used = true; - if (n->pl().getSI()->getGroup()) { - // this node is already in a group - merge this group with this one - ret->merge(n->pl().getSI()->getGroup()); - } else { - ret->addNode(n); - n->pl().getSI()->setGroup(ret); + for (auto* n : s) { + if (!n->pl().getSI()) continue; + used = true; + if (n->pl().getSI()->getGroup()) { + // this node is already in a group - merge this group with this one + ret->merge(n->pl().getSI()->getGroup()); + } else { + ret->addNode(n); + n->pl().getSI()->setGroup(ret); + } } - } - if (!used) { - delete ret; - return 0; - } + if (!used) { + delete ret; + return 0; + } - return ret; + return ret; } // _____________________________________________________________________________ std::vector OsmBuilder::getLines( - const std::vector& edgeRels, const RelLst& rels, - const OsmReadOpts& ops) { - std::vector ret; - for (size_t relId : edgeRels) { - TransitEdgeLine* elp = 0; + const std::vector& edgeRels, const RelLst& rels, + const OsmReadOpts& ops) { + std::vector ret; + for (size_t relId : edgeRels) { + TransitEdgeLine* elp = 0; - if (_relLines.count(relId)) { - elp = _relLines[relId]; - } else { - TransitEdgeLine el; + if (_relLines.count(relId)) { + elp = _relLines[relId]; + } else { + TransitEdgeLine el; - bool found = false; - for (const auto& r : ops.relLinerules.sNameRule) { - for (const auto& relAttr : rels.rels[relId]) { - if (relAttr.first == r) { - el.shortName = ops.lineNormzer(pfxml::file::decode(relAttr.second)); - if (!el.shortName.empty()) found = true; - } + bool found = false; + for (const auto& r : ops.relLinerules.sNameRule) { + for (const auto& relAttr : rels.rels[relId]) { + if (relAttr.first == r) { + el.shortName = ops.lineNormzer(pfxml::file::decode(relAttr.second)); + if (!el.shortName.empty()) found = true; + } + } + if (found) break; + } + + found = false; + for (const auto& r : ops.relLinerules.fromNameRule) { + for (const auto& relAttr : rels.rels[relId]) { + if (relAttr.first == r) { + el.fromStr = ops.statNormzer(pfxml::file::decode(relAttr.second)); + if (!el.fromStr.empty()) found = true; + } + } + if (found) break; + } + + found = false; + for (const auto& r : ops.relLinerules.toNameRule) { + for (const auto& relAttr : rels.rels[relId]) { + if (relAttr.first == r) { + el.toStr = ops.statNormzer(pfxml::file::decode(relAttr.second)); + if (!el.toStr.empty()) found = true; + } + } + if (found) break; + } + + if (!el.shortName.size() && !el.fromStr.size() && !el.toStr.size()) + continue; + + if (_lines.count(el)) { + elp = _lines[el]; + _relLines[relId] = elp; + } else { + elp = new TransitEdgeLine(el); + _lines[el] = elp; + _relLines[relId] = elp; + } } - if (found) break; - } - - found = false; - for (const auto& r : ops.relLinerules.fromNameRule) { - for (const auto& relAttr : rels.rels[relId]) { - if (relAttr.first == r) { - el.fromStr = ops.statNormzer(pfxml::file::decode(relAttr.second)); - if (!el.fromStr.empty()) found = true; - } - } - if (found) break; - } - - found = false; - for (const auto& r : ops.relLinerules.toNameRule) { - for (const auto& relAttr : rels.rels[relId]) { - if (relAttr.first == r) { - el.toStr = ops.statNormzer(pfxml::file::decode(relAttr.second)); - if (!el.toStr.empty()) found = true; - } - } - if (found) break; - } - - if (!el.shortName.size() && !el.fromStr.size() && !el.toStr.size()) - continue; - - if (_lines.count(el)) { - elp = _lines[el]; - _relLines[relId] = elp; - } else { - elp = new TransitEdgeLine(el); - _lines[el] = elp; - _relLines[relId] = elp; - } + ret.push_back(elp); } - ret.push_back(elp); - } - return ret; + return ret; } // _____________________________________________________________________________ void OsmBuilder::getKeptAttrKeys(const OsmReadOpts& opts, AttrKeySet sets[3]) const { - for (const auto& i : opts.statGroupNAttrRules) { - if (i.attr.relRule.kv.first.empty()) { - sets[0].insert(i.attr.attr); - } else { - sets[2].insert(i.attr.relRule.kv.first); - sets[2].insert(i.attr.attr); + for (const auto& i : opts.statGroupNAttrRules) { + if (i.attr.relRule.kv.first.empty()) { + sets[0].insert(i.attr.attr); + } else { + sets[2].insert(i.attr.relRule.kv.first); + sets[2].insert(i.attr.attr); + } } - } - for (const auto& i : opts.keepFilter) { - for (size_t j = 0; j < 3; j++) sets[j].insert(i.first); - } - - for (const auto& i : opts.dropFilter) { - for (size_t j = 0; j < 3; j++) sets[j].insert(i.first); - } - - for (const auto& i : opts.noHupFilter) { - sets[0].insert(i.first); - } - - for (const auto& i : opts.oneWayFilter) { - sets[1].insert(i.first); - } - - for (const auto& i : opts.oneWayFilterRev) { - sets[1].insert(i.first); - } - - for (const auto& i : opts.twoWayFilter) { - sets[1].insert(i.first); - } - - for (const auto& i : opts.stationFilter) { - sets[0].insert(i.first); - sets[2].insert(i.first); - } - - for (const auto& i : opts.stationBlockerFilter) { - sets[0].insert(i.first); - } - - for (uint8_t j = 0; j < 7; j++) { - for (const auto& kv : *(opts.levelFilters + j)) { - sets[1].insert(kv.first); + for (const auto& i : opts.keepFilter) { + for (size_t j = 0; j < 3; j++) sets[j].insert(i.first); } - } - // restriction system - for (const auto& i : opts.restrPosRestr) { - sets[2].insert(i.first); - } - for (const auto& i : opts.restrNegRestr) { - sets[2].insert(i.first); - } - for (const auto& i : opts.noRestrFilter) { - sets[2].insert(i.first); - } - - sets[2].insert("from"); - sets[2].insert("via"); - sets[2].insert("to"); - - sets[2].insert(opts.relLinerules.toNameRule.begin(), - opts.relLinerules.toNameRule.end()); - sets[2].insert(opts.relLinerules.fromNameRule.begin(), - opts.relLinerules.fromNameRule.end()); - sets[2].insert(opts.relLinerules.sNameRule.begin(), - opts.relLinerules.sNameRule.end()); - - for (const auto& i : opts.statAttrRules.nameRule) { - if (i.relRule.kv.first.empty()) { - sets[0].insert(i.attr); - } else { - sets[2].insert(i.relRule.kv.first); - sets[2].insert(i.attr); + for (const auto& i : opts.dropFilter) { + for (size_t j = 0; j < 3; j++) sets[j].insert(i.first); } - } - for (const auto& i : opts.edgePlatformRules) { - if (i.relRule.kv.first.empty()) { - sets[1].insert(i.attr); - } else { - sets[2].insert(i.relRule.kv.first); - sets[2].insert(i.attr); + for (const auto& i : opts.noHupFilter) { + sets[0].insert(i.first); } - } - for (const auto& i : opts.statAttrRules.platformRule) { - if (i.relRule.kv.first.empty()) { - sets[0].insert(i.attr); - } else { - sets[2].insert(i.relRule.kv.first); - sets[2].insert(i.attr); + for (const auto& i : opts.oneWayFilter) { + sets[1].insert(i.first); } - } - for (const auto& i : opts.statAttrRules.idRule) { - if (i.relRule.kv.first.empty()) { - sets[0].insert(i.attr); - } else { - sets[2].insert(i.relRule.kv.first); - sets[2].insert(i.attr); + for (const auto& i : opts.oneWayFilterRev) { + sets[1].insert(i.first); + } + + for (const auto& i : opts.twoWayFilter) { + sets[1].insert(i.first); + } + + for (const auto& i : opts.stationFilter) { + sets[0].insert(i.first); + sets[2].insert(i.first); + } + + for (const auto& i : opts.stationBlockerFilter) { + sets[0].insert(i.first); + } + + for (uint8_t j = 0; j < 7; j++) { + for (const auto& kv : *(opts.levelFilters + j)) { + sets[1].insert(kv.first); + } + } + + // restriction system + for (const auto& i : opts.restrPosRestr) { + sets[2].insert(i.first); + } + for (const auto& i : opts.restrNegRestr) { + sets[2].insert(i.first); + } + for (const auto& i : opts.noRestrFilter) { + sets[2].insert(i.first); + } + + sets[2].insert("from"); + sets[2].insert("via"); + sets[2].insert("to"); + + sets[2].insert(opts.relLinerules.toNameRule.begin(), + opts.relLinerules.toNameRule.end()); + sets[2].insert(opts.relLinerules.fromNameRule.begin(), + opts.relLinerules.fromNameRule.end()); + sets[2].insert(opts.relLinerules.sNameRule.begin(), + opts.relLinerules.sNameRule.end()); + + for (const auto& i : opts.statAttrRules.nameRule) { + if (i.relRule.kv.first.empty()) { + sets[0].insert(i.attr); + } else { + sets[2].insert(i.relRule.kv.first); + sets[2].insert(i.attr); + } + } + + for (const auto& i : opts.edgePlatformRules) { + if (i.relRule.kv.first.empty()) { + sets[1].insert(i.attr); + } else { + sets[2].insert(i.relRule.kv.first); + sets[2].insert(i.attr); + } + } + + for (const auto& i : opts.statAttrRules.platformRule) { + if (i.relRule.kv.first.empty()) { + sets[0].insert(i.attr); + } else { + sets[2].insert(i.relRule.kv.first); + sets[2].insert(i.attr); + } + } + + for (const auto& i : opts.statAttrRules.idRule) { + if (i.relRule.kv.first.empty()) { + sets[0].insert(i.attr); + } else { + sets[2].insert(i.relRule.kv.first); + sets[2].insert(i.attr); + } } - } } // _____________________________________________________________________________ void OsmBuilder::deleteOrphEdgs(Graph* g, const OsmReadOpts& opts) { - size_t ROUNDS = 3; - for (size_t c = 0; c < ROUNDS; c++) { - for (auto i = g->getNds()->begin(); i != g->getNds()->end();) { - if ((*i)->getInDeg() + (*i)->getOutDeg() != 1 || (*i)->pl().getSI()) { - ++i; - continue; - } + size_t ROUNDS = 3; + for (size_t c = 0; c < ROUNDS; c++) { + for (auto i = g->getNds()->begin(); i != g->getNds()->end();) { + if ((*i)->getInDeg() + (*i)->getOutDeg() != 1 || (*i)->pl().getSI()) { + ++i; + continue; + } - // check if the removal of this edge would transform a steep angle - // full turn at an intersection into a node 2 eligible for contraction - // if so, dont delete - if (keepFullTurn(*i, opts.fullTurnAngle)) { - ++i; - continue; - } + // check if the removal of this edge would transform a steep angle + // full turn at an intersection into a node 2 eligible for contraction + // if so, dont delete + if (keepFullTurn(*i, opts.fullTurnAngle)) { + ++i; + continue; + } - i = g->delNd(*i); - continue; - i++; + i = g->delNd(*i); + continue; + i++; + } } - } } // _____________________________________________________________________________ void OsmBuilder::deleteOrphNds(Graph* g) { - for (auto i = g->getNds()->begin(); i != g->getNds()->end();) { - if ((*i)->getInDeg() + (*i)->getOutDeg() == 0 && - !((*i)->pl().getSI() && (*i)->pl().getSI()->getGroup())) { - i = g->delNd(i); - // TODO(patrick): maybe delete from node grid? - } else { - i++; + for (auto i = g->getNds()->begin(); i != g->getNds()->end();) { + if ((*i)->getInDeg() + (*i)->getOutDeg() == 0 && + !((*i)->pl().getSI() && (*i)->pl().getSI()->getGroup())) { + i = g->delNd(i); + // TODO(patrick): maybe delete from node grid? + } else { + i++; + } } - } } // _____________________________________________________________________________ bool OsmBuilder::edgesSim(const Edge* a, const Edge* b) { - if (static_cast(a->pl().oneWay()) ^ static_cast(b->pl().oneWay())) - return false; - if (a->pl().lvl() != b->pl().lvl()) return false; - if (a->pl().getLines().size() != b->pl().getLines().size()) return false; - if (a->pl().getLines() != b->pl().getLines()) return false; - if (a->pl().oneWay() && b->pl().oneWay()) { - if (a->getFrom() != b->getTo() && a->getTo() != b->getFrom()) return false; - } - if (a->pl().isRestricted() || b->pl().isRestricted()) return false; + if (static_cast(a->pl().oneWay()) ^ static_cast(b->pl().oneWay())) + return false; + if (a->pl().lvl() != b->pl().lvl()) return false; + if (a->pl().getLines().size() != b->pl().getLines().size()) return false; + if (a->pl().getLines() != b->pl().getLines()) return false; + if (a->pl().oneWay() && b->pl().oneWay()) { + if (a->getFrom() != b->getTo() && a->getTo() != b->getFrom()) return false; + } + if (a->pl().isRestricted() || b->pl().isRestricted()) return false; - return true; + return true; } // _____________________________________________________________________________ const EdgePL& OsmBuilder::mergeEdgePL(Edge* a, Edge* b) { - const Node* n = 0; - if (a->getFrom() == b->getFrom()) - n = a->getFrom(); - else if (a->getFrom() == b->getTo()) - n = a->getFrom(); - else - n = a->getTo(); + const Node* n = 0; + if (a->getFrom() == b->getFrom()) + n = a->getFrom(); + else if (a->getFrom() == b->getTo()) + n = a->getFrom(); + else + n = a->getTo(); - if (a->getTo() == n && b->getTo() == n) { - // --> n <-- - a->pl().getGeom()->insert(a->pl().getGeom()->end(), - b->pl().getGeom()->rbegin(), - b->pl().getGeom()->rend()); - } else if (a->getTo() == n && b->getFrom() == n) { - // --> n --> - a->pl().getGeom()->insert(a->pl().getGeom()->end(), - b->pl().getGeom()->begin(), - b->pl().getGeom()->end()); - } else if (a->getFrom() == n && b->getTo() == n) { - // <-- n <-- - std::reverse(a->pl().getGeom()->begin(), a->pl().getGeom()->end()); - a->pl().getGeom()->insert(a->pl().getGeom()->end(), - b->pl().getGeom()->rbegin(), - b->pl().getGeom()->rend()); - } else { - // <-- n --> - std::reverse(a->pl().getGeom()->begin(), a->pl().getGeom()->end()); - a->pl().getGeom()->insert(a->pl().getGeom()->end(), - b->pl().getGeom()->begin(), - b->pl().getGeom()->end()); - } + if (a->getTo() == n && b->getTo() == n) { + // --> n <-- + a->pl().getGeom()->insert(a->pl().getGeom()->end(), + b->pl().getGeom()->rbegin(), + b->pl().getGeom()->rend()); + } else if (a->getTo() == n && b->getFrom() == n) { + // --> n --> + a->pl().getGeom()->insert(a->pl().getGeom()->end(), + b->pl().getGeom()->begin(), + b->pl().getGeom()->end()); + } else if (a->getFrom() == n && b->getTo() == n) { + // <-- n <-- + std::reverse(a->pl().getGeom()->begin(), a->pl().getGeom()->end()); + a->pl().getGeom()->insert(a->pl().getGeom()->end(), + b->pl().getGeom()->rbegin(), + b->pl().getGeom()->rend()); + } else { + // <-- n --> + std::reverse(a->pl().getGeom()->begin(), a->pl().getGeom()->end()); + a->pl().getGeom()->insert(a->pl().getGeom()->end(), + b->pl().getGeom()->begin(), + b->pl().getGeom()->end()); + } - a->pl().setLength(a->pl().getLength() + b->pl().getLength()); + a->pl().setLength(a->pl().getLength() + b->pl().getLength()); - return a->pl(); + return a->pl(); } // _____________________________________________________________________________ void OsmBuilder::collapseEdges(Graph* g) { - for (auto* n : *g->getNds()) { - if (n->getOutDeg() + n->getInDeg() != 2 || n->pl().getSI()) continue; + for (auto* n : *g->getNds()) { + if (n->getOutDeg() + n->getInDeg() != 2 || n->pl().getSI()) continue; - Edge* ea; - Edge* eb; - if (n->getOutDeg() == 2) { - ea = *n->getAdjListOut().begin(); - eb = *n->getAdjListOut().rbegin(); - } else if (n->getInDeg() == 2) { - ea = *n->getAdjListIn().begin(); - eb = *n->getAdjListIn().rbegin(); - } else { - ea = *n->getAdjListOut().begin(); - eb = *n->getAdjListIn().begin(); + Edge* ea; + Edge* eb; + if (n->getOutDeg() == 2) { + ea = *n->getAdjListOut().begin(); + eb = *n->getAdjListOut().rbegin(); + } else if (n->getInDeg() == 2) { + ea = *n->getAdjListIn().begin(); + eb = *n->getAdjListIn().rbegin(); + } else { + ea = *n->getAdjListOut().begin(); + eb = *n->getAdjListIn().begin(); + } + + // important, we don't have a multigraph! if the same edge + // will already exist, leave this node + if (g->getEdg(ea->getOtherNd(n), eb->getOtherNd(n))) continue; + if (g->getEdg(eb->getOtherNd(n), ea->getOtherNd(n))) continue; + + if (edgesSim(ea, eb)) { + if (ea->pl().oneWay() && ea->getOtherNd(n) != ea->getFrom()) { + g->addEdg(eb->getOtherNd(n), ea->getOtherNd(n), mergeEdgePL(eb, ea)); + } else { + g->addEdg(ea->getOtherNd(n), eb->getOtherNd(n), mergeEdgePL(ea, eb)); + } + g->delEdg(ea->getFrom(), ea->getTo()); + g->delEdg(eb->getFrom(), eb->getTo()); + } } - - // important, we don't have a multigraph! if the same edge - // will already exist, leave this node - if (g->getEdg(ea->getOtherNd(n), eb->getOtherNd(n))) continue; - if (g->getEdg(eb->getOtherNd(n), ea->getOtherNd(n))) continue; - - if (edgesSim(ea, eb)) { - if (ea->pl().oneWay() && ea->getOtherNd(n) != ea->getFrom()) { - g->addEdg(eb->getOtherNd(n), ea->getOtherNd(n), mergeEdgePL(eb, ea)); - } else { - g->addEdg(ea->getOtherNd(n), eb->getOtherNd(n), mergeEdgePL(ea, eb)); - } - g->delEdg(ea->getFrom(), ea->getTo()); - g->delEdg(eb->getFrom(), eb->getTo()); - } - } } // _____________________________________________________________________________ void OsmBuilder::simplifyGeoms(Graph* g) { - for (auto* n : *g->getNds()) { - for (auto* e : n->getAdjListOut()) { - (*e->pl().getGeom()) = util::geo::simplify(*e->pl().getGeom(), 0.5); + for (auto* n : *g->getNds()) { + for (auto* e : n->getAdjListOut()) { + (*e->pl().getGeom()) = util::geo::simplify(*e->pl().getGeom(), 0.5); + } } - } } // _____________________________________________________________________________ uint32_t OsmBuilder::writeComps(Graph* g) { - Component* comp = new Component{7}; - uint32_t numC = 0; + Component* comp = new Component{7}; + uint32_t numC = 0; - for (auto* n : *g->getNds()) { - if (!n->pl().getComp()) { - std::stack> q; - q.push(std::pair(n, 0)); - while (!q.empty()) { - std::pair cur = q.top(); - q.pop(); + for (auto* n : *g->getNds()) { + if (!n->pl().getComp()) { + std::stack> q; + q.push(std::pair(n, 0)); + while (!q.empty()) { + std::pair cur = q.top(); + q.pop(); - cur.first->pl().setComp(comp); - for (auto* e : cur.first->getAdjListOut()) { - if (e->pl().lvl() < comp->minEdgeLvl) - comp->minEdgeLvl = e->pl().lvl(); - if (!e->getOtherNd(cur.first)->pl().getComp()) - q.push(std::pair(e->getOtherNd(cur.first), e)); + cur.first->pl().setComp(comp); + for (auto* e : cur.first->getAdjListOut()) { + if (e->pl().lvl() < comp->minEdgeLvl) + comp->minEdgeLvl = e->pl().lvl(); + if (!e->getOtherNd(cur.first)->pl().getComp()) + q.push(std::pair(e->getOtherNd(cur.first), e)); + } + for (auto* e : cur.first->getAdjListIn()) { + if (e->pl().lvl() < comp->minEdgeLvl) + comp->minEdgeLvl = e->pl().lvl(); + if (!e->getOtherNd(cur.first)->pl().getComp()) + q.push(std::pair(e->getOtherNd(cur.first), e)); + } + } + + numC++; + comp = new Component{7}; } - for (auto* e : cur.first->getAdjListIn()) { - if (e->pl().lvl() < comp->minEdgeLvl) - comp->minEdgeLvl = e->pl().lvl(); - if (!e->getOtherNd(cur.first)->pl().getComp()) - q.push(std::pair(e->getOtherNd(cur.first), e)); - } - } - - numC++; - comp = new Component{7}; } - } - // the last comp was not used - delete comp; + // the last comp was not used + delete comp; - return numC; + return numC; } // _____________________________________________________________________________ void OsmBuilder::writeEdgeTracks(const EdgTracks& tracks) { - for (const auto& tr : tracks) { - if (tr.first->getTo()->pl().getSI() && - tr.first->getTo()->pl().getSI()->getTrack().empty()) { - tr.first->getTo()->pl().getSI()->setTrack(tr.second); + for (const auto& tr : tracks) { + if (tr.first->getTo()->pl().getSI() && + tr.first->getTo()->pl().getSI()->getTrack().empty()) { + tr.first->getTo()->pl().getSI()->setTrack(tr.second); + } + if (tr.first->getFrom()->pl().getSI() && + tr.first->getFrom()->pl().getSI()->getTrack().empty()) { + tr.first->getFrom()->pl().getSI()->setTrack(tr.second); + } } - if (tr.first->getFrom()->pl().getSI() && - tr.first->getFrom()->pl().getSI()->getTrack().empty()) { - tr.first->getFrom()->pl().getSI()->setTrack(tr.second); - } - } } // _____________________________________________________________________________ void OsmBuilder::writeODirEdgs(Graph* g, Restrictor* restor) { - for (auto* n : *g->getNds()) { - for (auto* e : n->getAdjListOut()) { - if (g->getEdg(e->getTo(), e->getFrom())) continue; - auto newE = g->addEdg(e->getTo(), e->getFrom(), e->pl().revCopy()); - if (e->pl().isRestricted()) restor->duplicateEdge(e, newE); + for (auto* n : *g->getNds()) { + for (auto* e : n->getAdjListOut()) { + if (g->getEdg(e->getTo(), e->getFrom())) continue; + auto newE = g->addEdg(e->getTo(), e->getFrom(), e->pl().revCopy()); + if (e->pl().isRestricted()) restor->duplicateEdge(e, newE); + } } - } } // _____________________________________________________________________________ void OsmBuilder::writeSelfEdgs(Graph* g) { - for (auto* n : *g->getNds()) { - if (n->pl().getSI() && n->getAdjListOut().size() == 0) { - g->addEdg(n, n); + for (auto* n : *g->getNds()) { + if (n->pl().getSI() && n->getAdjListOut().size() == 0) { + g->addEdg(n, n); + } } - } } // _____________________________________________________________________________ bool OsmBuilder::keepFullTurn(const trgraph::Node* n, double ang) { - if (n->getInDeg() + n->getOutDeg() != 1) return false; + if (n->getInDeg() + n->getOutDeg() != 1) return false; - const trgraph::Edge* e = 0; - if (n->getOutDeg()) - e = n->getAdjListOut().front(); - else - e = n->getAdjListIn().front(); + const trgraph::Edge* e = 0; + if (n->getOutDeg()) + e = n->getAdjListOut().front(); + else + e = n->getAdjListIn().front(); - auto other = e->getOtherNd(n); + auto other = e->getOtherNd(n); - if (other->getInDeg() + other->getOutDeg() == 3) { - const trgraph::Edge* a = 0; - const trgraph::Edge* b = 0; - for (auto f : other->getAdjListIn()) { - if (f != e && !a) - a = f; - else if (f != e && !b) - b = f; + if (other->getInDeg() + other->getOutDeg() == 3) { + const trgraph::Edge* a = 0; + const trgraph::Edge* b = 0; + for (auto f : other->getAdjListIn()) { + if (f != e && !a) + a = f; + else if (f != e && !b) + b = f; + } + + for (auto f : other->getAdjListOut()) { + if (f != e && !a) + a = f; + else if (f != e && !b) + b = f; + } + + auto ap = a->pl().backHop(); + auto bp = b->pl().backHop(); + if (a->getTo() != other) ap = a->pl().frontHop(); + if (b->getTo() != other) bp = b->pl().frontHop(); + + return router::angSmaller(ap, *other->pl().getGeom(), bp, ang); } - for (auto f : other->getAdjListOut()) { - if (f != e && !a) - a = f; - else if (f != e && !b) - b = f; - } - - auto ap = a->pl().backHop(); - auto bp = b->pl().backHop(); - if (a->getTo() != other) ap = a->pl().frontHop(); - if (b->getTo() != other) bp = b->pl().frontHop(); - - return router::angSmaller(ap, *other->pl().getGeom(), bp, ang); - } - - return false; + return false; } // _____________________________________________________________________________ @@ -2481,117 +2508,117 @@ void OsmBuilder::snapStats(const OsmReadOpts& opts, Graph* g, const BBoxIdx& bbox, size_t gridSize, router::FeedStops* fs, Restrictor* res, const NodeSet& orphanStations) { - NodeGrid sng = buildNodeIdx(g, gridSize, bbox.getFullWebMercBox(), true); - EdgeGrid eg = buildEdgeIdx(g, gridSize, bbox.getFullWebMercBox()); + NodeGrid sng = buildNodeIdx(g, gridSize, bbox.getFullWebMercBox(), true); + EdgeGrid eg = buildEdgeIdx(g, gridSize, bbox.getFullWebMercBox()); - LOG(DEBUG) << "Grid size of " << sng.getXWidth() << "x" << sng.getYHeight(); + LOG(DEBUG) << "Grid size of " << sng.getXWidth() << "x" << sng.getYHeight(); - for (double d : opts.maxSnapDistances) { - for (auto s : orphanStations) { - POINT geom = *s->pl().getGeom(); - NodePL pl = s->pl(); - pl.getSI()->setIsFromOsm(false); - const auto& r = - snapStation(g, &pl, &eg, &sng, opts, res, false, false, d); - groupStats(r); - for (auto n : r) { - // if the snapped station is very near to the original OSM - // station, set is-from-osm to true - if (webMercMeterDist(geom, *n->pl().getGeom()) < - opts.maxOsmStationDistance) { - if (n->pl().getSI()) n->pl().getSI()->setIsFromOsm(true); + for (double d : opts.maxSnapDistances) { + for (auto s : orphanStations) { + POINT geom = *s->pl().getGeom(); + NodePL pl = s->pl(); + pl.getSI()->setIsFromOsm(false); + const auto& r = + snapStation(g, &pl, &eg, &sng, opts, res, false, false, d); + groupStats(r); + for (auto n : r) { + // if the snapped station is very near to the original OSM + // station, set is-from-osm to true + if (webMercMeterDist(geom, *n->pl().getGeom()) < + opts.maxOsmStationDistance) { + if (n->pl().getSI()) n->pl().getSI()->setIsFromOsm(true); + } + } } - } } - } - if (!fs) return; + if (!fs) return; - std::vector notSnapped; + std::vector notSnapped; - for (auto& s : *fs) { - bool snapped = false; - auto pl = plFromGtfs(s.first, opts); - for (size_t i = 0; i < opts.maxSnapDistances.size(); i++) { - double d = opts.maxSnapDistances[i]; + for (auto& s : *fs) { + bool snapped = false; + auto pl = plFromGtfs(s.first, opts); + for (size_t i = 0; i < opts.maxSnapDistances.size(); i++) { + double d = opts.maxSnapDistances[i]; - StatGroup* group = groupStats( - snapStation(g, &pl, &eg, &sng, opts, res, - i == opts.maxSnapDistances.size() - 1, false, d)); + StatGroup* group = groupStats( + snapStation(g, &pl, &eg, &sng, opts, res, + i == opts.maxSnapDistances.size() - 1, false, d)); - if (group) { - group->addStop(s.first); - (*fs)[s.first] = *group->getNodes().begin(); - snapped = true; - } - } - if (!snapped) { - LOG(VDEBUG) << "Could not snap station " - << "(" << pl.getSI()->getName() << ")" - << " (" << s.first->getLat() << "," << s.first->getLng() - << ") in normal run, trying again later in orphan mode."; - if (!bbox.contains(*pl.getGeom())) { - LOG(VDEBUG) << "Note: '" << pl.getSI()->getName() - << "' does not lie within the bounds for this graph and " - "may be a stray station"; - } - notSnapped.push_back(s.first); - } - } - - if (notSnapped.size()) - LOG(VDEBUG) << notSnapped.size() << " stations could not be snapped in " - "normal run, trying again in orphan " - "mode."; - - // try again, but aggressively snap to orphan OSM stations which have - // not been assigned to any GTFS stop yet - for (auto& s : notSnapped) { - bool snapped = false; - auto pl = plFromGtfs(s, opts); - for (size_t i = 0; i < opts.maxSnapDistances.size(); i++) { - double d = opts.maxSnapDistances[i]; - - StatGroup* group = groupStats( - snapStation(g, &pl, &eg, &sng, opts, res, - i == opts.maxSnapDistances.size() - 1, true, d)); - - if (group) { - group->addStop(s); - // add the added station name as an alt name to ensure future - // similarity - for (auto n : group->getNodes()) { - if (n->pl().getSI()) - n->pl().getSI()->addAltName(pl.getSI()->getName()); + if (group) { + group->addStop(s.first); + (*fs)[s.first] = *group->getNodes().begin(); + snapped = true; + } + } + if (!snapped) { + LOG(VDEBUG) << "Could not snap station " + << "(" << pl.getSI()->getName() << ")" + << " (" << s.first->getLat() << "," << s.first->getLng() + << ") in normal run, trying again later in orphan mode."; + if (!bbox.contains(*pl.getGeom())) { + LOG(VDEBUG) << "Note: '" << pl.getSI()->getName() + << "' does not lie within the bounds for this graph and " + "may be a stray station"; + } + notSnapped.push_back(s.first); } - (*fs)[s] = *group->getNodes().begin(); - snapped = true; - } } - if (!snapped) { - // finally give up - // add a group with only this stop in it - StatGroup* dummyGroup = new StatGroup(); - Node* dummyNode = g->addNd(pl); + if (notSnapped.size()) + LOG(VDEBUG) << notSnapped.size() << " stations could not be snapped in " + "normal run, trying again in orphan " + "mode."; - dummyNode->pl().getSI()->setGroup(dummyGroup); - dummyGroup->addNode(dummyNode); - dummyGroup->addStop(s); - (*fs)[s] = dummyNode; - if (!bbox.contains(*pl.getGeom())) { - LOG(VDEBUG) << "Could not snap station " - << "(" << pl.getSI()->getName() << ")" - << " (" << s->getLat() << "," << s->getLng() << ")"; - LOG(VDEBUG) << "Note: '" << pl.getSI()->getName() - << "' does not lie within the bounds for this graph and " - "may be a stray station"; - } else { - // only warn if it is contained in the BBOX for this graph - LOG(WARN) << "Could not snap station " - << "(" << pl.getSI()->getName() << ")" - << " (" << s->getLat() << "," << s->getLng() << ")"; - } + // try again, but aggressively snap to orphan OSM stations which have + // not been assigned to any GTFS stop yet + for (auto& s : notSnapped) { + bool snapped = false; + auto pl = plFromGtfs(s, opts); + for (size_t i = 0; i < opts.maxSnapDistances.size(); i++) { + double d = opts.maxSnapDistances[i]; + + StatGroup* group = groupStats( + snapStation(g, &pl, &eg, &sng, opts, res, + i == opts.maxSnapDistances.size() - 1, true, d)); + + if (group) { + group->addStop(s); + // add the added station name as an alt name to ensure future + // similarity + for (auto n : group->getNodes()) { + if (n->pl().getSI()) + n->pl().getSI()->addAltName(pl.getSI()->getName()); + } + (*fs)[s] = *group->getNodes().begin(); + snapped = true; + } + } + if (!snapped) { + // finally give up + + // add a group with only this stop in it + StatGroup* dummyGroup = new StatGroup(); + Node* dummyNode = g->addNd(pl); + + dummyNode->pl().getSI()->setGroup(dummyGroup); + dummyGroup->addNode(dummyNode); + dummyGroup->addStop(s); + (*fs)[s] = dummyNode; + if (!bbox.contains(*pl.getGeom())) { + LOG(VDEBUG) << "Could not snap station " + << "(" << pl.getSI()->getName() << ")" + << " (" << s->getLat() << "," << s->getLng() << ")"; + LOG(VDEBUG) << "Note: '" << pl.getSI()->getName() + << "' does not lie within the bounds for this graph and " + "may be a stray station"; + } else { + // only warn if it is contained in the BBOX for this graph + LOG(WARN) << "Could not snap station " + << "(" << pl.getSI()->getName() << ")" + << " (" << s->getLat() << "," << s->getLng() << ")"; + } + } } - } } diff --git a/src/pfaedle/osm/OsmFilter.h b/src/pfaedle/osm/OsmFilter.h index daf353a..579d73a 100644 --- a/src/pfaedle/osm/OsmFilter.h +++ b/src/pfaedle/osm/OsmFilter.h @@ -16,7 +16,7 @@ namespace osm { class OsmFilter { public: enum Type : uint64_t { NODE = 16, WAY = 8, REL = 4, ALL = 0 }; - OsmFilter() {} + OsmFilter() = default; OsmFilter(const MultAttrMap& keep, const MultAttrMap& drop); explicit OsmFilter(const OsmReadOpts& o); uint64_t keep(const AttrMap& attrs, Type t) const;