refactoring

This commit is contained in:
Patrick Brosi 2019-02-03 12:48:48 +01:00
parent 2fb157ef37
commit 4733b0c676
26 changed files with 774 additions and 406 deletions

@ -1 +1 @@
Subproject commit 63fcb1d54eb4889b376b76cafe140317326b5c56 Subproject commit afacc8bc778bd1e38ae1c4466d1eb10ce92ba96e

@ -1 +1 @@
Subproject commit 7bdfeffcbe5006ef74898e6dd760027a0dfa806e Subproject commit 212fdc7c8aff50b0f7a872ccb40850f8080eb402

View file

@ -25,6 +25,7 @@
#include "pfaedle/osm/OsmIdSet.h" #include "pfaedle/osm/OsmIdSet.h"
#include "pfaedle/router/ShapeBuilder.h" #include "pfaedle/router/ShapeBuilder.h"
#include "pfaedle/trgraph/Graph.h" #include "pfaedle/trgraph/Graph.h"
#include "pfaedle/trgraph/StatGroup.h"
#include "util/geo/output/GeoGraphJsonOutput.h" #include "util/geo/output/GeoGraphJsonOutput.h"
#include "util/geo/output/GeoJsonOutput.h" #include "util/geo/output/GeoJsonOutput.h"
#include "util/json/Writer.h" #include "util/json/Writer.h"
@ -54,9 +55,7 @@ enum class RetCode {
NO_MOT_CFG = 9 NO_MOT_CFG = 9
}; };
std::string getMotStr(const MOTs& mots);
std::string getFileNameMotStr(const MOTs& mots); std::string getFileNameMotStr(const MOTs& mots);
MOTs getContMots(const MotConfig& motCfg, const MOTs& mots);
std::vector<std::string> getCfgPaths(const Config& cfg); std::vector<std::string> getCfgPaths(const Config& cfg);
// _____________________________________________________________________________ // _____________________________________________________________________________
@ -74,7 +73,7 @@ int main(int argc, char** argv) {
cr.read(&cfg, argc, argv); cr.read(&cfg, argc, argv);
std::vector<pfaedle::gtfs::Feed> gtfs(cfg.feedPaths.size()); std::vector<pfaedle::gtfs::Feed> gtfs(cfg.feedPaths.size());
// feed containing the shapeas in memory for evaluation // feed containing the shapes in memory for evaluation
ad::cppgtfs::gtfs::Feed evalFeed; ad::cppgtfs::gtfs::Feed evalFeed;
std::vector<std::string> cfgPaths = getCfgPaths(cfg); std::vector<std::string> cfgPaths = getCfgPaths(cfg);
@ -202,19 +201,45 @@ int main(int argc, char** argv) {
for (const auto& motCfg : motCfgReader.getConfigs()) { for (const auto& motCfg : motCfgReader.getConfigs()) {
std::string filePost; std::string filePost;
auto usedMots = getContMots(motCfg, cmdCfgMots); auto usedMots = pfaedle::router::motISect(motCfg.mots, cmdCfgMots);
if (!usedMots.size()) continue; if (!usedMots.size()) continue;
if (singleTrip && !usedMots.count(singleTrip->getRoute()->getType())) if (singleTrip && !usedMots.count(singleTrip->getRoute()->getType()))
continue; continue;
if (motCfgReader.getConfigs().size() > 1) if (motCfgReader.getConfigs().size() > 1)
filePost = getFileNameMotStr(usedMots); filePost = getFileNameMotStr(usedMots);
std::string motStr = getMotStr(usedMots); std::string motStr = pfaedle::router::getMotStr(usedMots);
LOG(INFO) << "Calculating shapes for mots " << motStr; LOG(INFO) << "Calculating shapes for mots " << motStr;
try { try {
pfaedle::router::FeedStops fStops =
pfaedle::router::writeMotStops(&gtfs[0], usedMots, cfg.shapeTripId);
pfaedle::osm::Restrictor restr;
pfaedle::trgraph::Graph graph;
pfaedle::osm::OsmBuilder osmBuilder;
pfaedle::osm::BBoxIdx box(BOX_PADDING);
ShapeBuilder::getGtfsBox(&gtfs[0], cmdCfgMots, cfg.shapeTripId,
cfg.dropShapes, &box);
if (fStops.size())
osmBuilder.read(cfg.osmPath, motCfg.osmBuildOpts, &graph, box,
cfg.gridSize, &fStops, &restr);
// TODO(patrick): move this somewhere else
for (auto& feedStop : fStops) {
if (feedStop.second) {
feedStop.second->pl().getSI()->getGroup()->writePens(
motCfg.osmBuildOpts.trackNormzer,
motCfg.routingOpts.platformUnmatchedPen,
motCfg.routingOpts.stationDistPenFactor,
motCfg.routingOpts.nonOsmPen);
}
}
ShapeBuilder shapeBuilder(&gtfs[0], &evalFeed, cmdCfgMots, motCfg, &ecoll, ShapeBuilder shapeBuilder(&gtfs[0], &evalFeed, cmdCfgMots, motCfg, &ecoll,
cfg); &graph, &fStops, &restr, cfg);
if (cfg.writeGraph) { if (cfg.writeGraph) {
LOG(INFO) << "Outputting graph.json..."; LOG(INFO) << "Outputting graph.json...";
@ -276,19 +301,6 @@ int main(int argc, char** argv) {
return static_cast<int>(RetCode::SUCCESS); return static_cast<int>(RetCode::SUCCESS);
} }
// _____________________________________________________________________________
std::string getMotStr(const MOTs& mots) {
bool first = false;
std::string motStr;
for (const auto& mot : mots) {
if (first) motStr += ", ";
motStr += "<" + ad::cppgtfs::gtfs::flat::Route::getTypeString(mot) + ">";
first = true;
}
return motStr;
}
// _____________________________________________________________________________ // _____________________________________________________________________________
std::string getFileNameMotStr(const MOTs& mots) { std::string getFileNameMotStr(const MOTs& mots) {
std::string motStr; std::string motStr;
@ -299,18 +311,6 @@ std::string getFileNameMotStr(const MOTs& mots) {
return motStr; return motStr;
} }
// _____________________________________________________________________________
MOTs getContMots(const MotConfig& motCfg, const MOTs& mots) {
MOTs ret;
for (const auto& mot : mots) {
if (motCfg.mots.count(mot)) {
ret.insert(mot);
}
}
return ret;
}
// _____________________________________________________________________________ // _____________________________________________________________________________
std::vector<std::string> getCfgPaths(const Config& cfg) { std::vector<std::string> getCfgPaths(const Config& cfg) {
if (cfg.configPaths.size()) return cfg.configPaths; if (cfg.configPaths.size()) return cfg.configPaths;

View file

@ -5,21 +5,32 @@
#ifndef PFAEDLE_CONFIG_MOTCONFIG_H_ #ifndef PFAEDLE_CONFIG_MOTCONFIG_H_
#define PFAEDLE_CONFIG_MOTCONFIG_H_ #define PFAEDLE_CONFIG_MOTCONFIG_H_
#include <map>
#include <string>
#include "pfaedle/osm/OsmBuilder.h" #include "pfaedle/osm/OsmBuilder.h"
#include "pfaedle/router/Router.h" #include "pfaedle/router/Router.h"
namespace pfaedle { namespace pfaedle {
namespace config { namespace config {
struct MotConfig { struct MotConfig {
router::MOTs mots; router::MOTs mots;
osm::OsmReadOpts osmBuildOpts; osm::OsmReadOpts osmBuildOpts;
router::RoutingOpts routingOpts; router::RoutingOpts routingOpts;
std::map<std::string, std::string> unproced;
}; };
inline bool operator==(const MotConfig& a, const MotConfig& b) { inline bool operator==(const MotConfig& a, const MotConfig& b) {
return a.osmBuildOpts == b.osmBuildOpts && a.routingOpts == b.routingOpts; bool unprocedEq = a.unproced.size() == b.unproced.size();
for (const auto& kv : a.unproced) {
if (!b.unproced.count(kv.first) ||
b.unproced.find(kv.first)->second != kv.second) {
unprocedEq = false;
break;
}
}
return a.osmBuildOpts == b.osmBuildOpts && a.routingOpts == b.routingOpts &&
unprocedEq;
} }
} // namespace config } // namespace config

View file

@ -35,8 +35,11 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
for (const auto& sec : p.getSecs()) { for (const auto& sec : p.getSecs()) {
MotConfig curCfg; MotConfig curCfg;
std::string secStr = sec.first; std::string secStr = sec.first;
if (secStr.empty()) continue;
std::set<std::string> procedKeys;
if (p.hasKey(secStr, "osm_filter_keep")) { if (p.hasKey(secStr, "osm_filter_keep")) {
procedKeys.insert("osm_filter_keep");
for (const auto& kvs : p.getStrArr(sec.first, "osm_filter_keep", ' ')) { for (const auto& kvs : p.getStrArr(sec.first, "osm_filter_keep", ' ')) {
auto fRule = getFRule(kvs); auto fRule = getFRule(kvs);
curCfg.osmBuildOpts.keepFilter[fRule.kv.first].insert( curCfg.osmBuildOpts.keepFilter[fRule.kv.first].insert(
@ -47,6 +50,7 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
for (uint8_t i = 0; i < 8; i++) { for (uint8_t i = 0; i < 8; i++) {
std::string name = std::string("osm_filter_lvl") + std::to_string(i); std::string name = std::string("osm_filter_lvl") + std::to_string(i);
if (p.hasKey(secStr, name)) { if (p.hasKey(secStr, name)) {
procedKeys.insert(name);
for (const auto& kvs : p.getStrArr(sec.first, name, ' ')) { for (const auto& kvs : p.getStrArr(sec.first, name, ' ')) {
auto fRule = getFRule(kvs); auto fRule = getFRule(kvs);
curCfg.osmBuildOpts.levelFilters[i][fRule.kv.first].insert( curCfg.osmBuildOpts.levelFilters[i][fRule.kv.first].insert(
@ -56,6 +60,7 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
if (p.hasKey(secStr, "osm_filter_drop")) { if (p.hasKey(secStr, "osm_filter_drop")) {
procedKeys.insert("osm_filter_drop");
for (const auto& kvs : p.getStrArr(sec.first, "osm_filter_drop", ' ')) { for (const auto& kvs : p.getStrArr(sec.first, "osm_filter_drop", ' ')) {
auto fRule = getFRule(kvs); auto fRule = getFRule(kvs);
curCfg.osmBuildOpts.dropFilter[fRule.kv.first].insert( curCfg.osmBuildOpts.dropFilter[fRule.kv.first].insert(
@ -64,6 +69,7 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
if (p.hasKey(secStr, "osm_max_snap_level")) { if (p.hasKey(secStr, "osm_max_snap_level")) {
procedKeys.insert("osm_max_snap_level");
curCfg.osmBuildOpts.maxSnapLevel = curCfg.osmBuildOpts.maxSnapLevel =
p.getInt(sec.first, "osm_max_snap_level"); p.getInt(sec.first, "osm_max_snap_level");
} else { } else {
@ -71,6 +77,7 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
if (p.hasKey(secStr, "osm_filter_nohup")) { if (p.hasKey(secStr, "osm_filter_nohup")) {
procedKeys.insert("osm_filter_nohup");
for (const auto& kvs : p.getStrArr(sec.first, "osm_filter_nohup", ' ')) { for (const auto& kvs : p.getStrArr(sec.first, "osm_filter_nohup", ' ')) {
auto fRule = getFRule(kvs); auto fRule = getFRule(kvs);
curCfg.osmBuildOpts.noHupFilter[fRule.kv.first].insert( curCfg.osmBuildOpts.noHupFilter[fRule.kv.first].insert(
@ -79,6 +86,7 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
if (p.hasKey(secStr, "osm_filter_oneway")) { if (p.hasKey(secStr, "osm_filter_oneway")) {
procedKeys.insert("osm_filter_oneway");
for (const auto& kvs : p.getStrArr(sec.first, "osm_filter_oneway", ' ')) { for (const auto& kvs : p.getStrArr(sec.first, "osm_filter_oneway", ' ')) {
auto fRule = getFRule(kvs); auto fRule = getFRule(kvs);
curCfg.osmBuildOpts.oneWayFilter[fRule.kv.first].insert( curCfg.osmBuildOpts.oneWayFilter[fRule.kv.first].insert(
@ -87,6 +95,7 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
if (p.hasKey(secStr, "osm_filter_oneway_reverse")) { if (p.hasKey(secStr, "osm_filter_oneway_reverse")) {
procedKeys.insert("osm_filter_oneway_reverse");
for (const auto& kvs : for (const auto& kvs :
p.getStrArr(sec.first, "osm_filter_oneway_reverse", ' ')) { p.getStrArr(sec.first, "osm_filter_oneway_reverse", ' ')) {
auto fRule = getFRule(kvs); auto fRule = getFRule(kvs);
@ -96,6 +105,7 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
if (p.hasKey(secStr, "osm_filter_undirected")) { if (p.hasKey(secStr, "osm_filter_undirected")) {
procedKeys.insert("osm_filter_undirected");
for (const auto& kvs : for (const auto& kvs :
p.getStrArr(sec.first, "osm_filter_undirected", ' ')) { p.getStrArr(sec.first, "osm_filter_undirected", ' ')) {
auto fRule = getFRule(kvs); auto fRule = getFRule(kvs);
@ -105,6 +115,7 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
if (p.hasKey(secStr, "osm_filter_station")) { if (p.hasKey(secStr, "osm_filter_station")) {
procedKeys.insert("osm_filter_station");
for (const auto& kvs : for (const auto& kvs :
p.getStrArr(sec.first, "osm_filter_station", ' ')) { p.getStrArr(sec.first, "osm_filter_station", ' ')) {
auto fRule = getFRule(kvs); auto fRule = getFRule(kvs);
@ -114,6 +125,7 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
if (p.hasKey(secStr, "osm_filter_station_blocker")) { if (p.hasKey(secStr, "osm_filter_station_blocker")) {
procedKeys.insert("osm_filter_station_blocker");
for (const auto& kvs : for (const auto& kvs :
p.getStrArr(sec.first, "osm_filter_station_blocker", ' ')) { p.getStrArr(sec.first, "osm_filter_station_blocker", ' ')) {
auto fRule = getFRule(kvs); auto fRule = getFRule(kvs);
@ -123,6 +135,7 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
if (p.hasKey(secStr, "osm_node_positive_restriction")) { if (p.hasKey(secStr, "osm_node_positive_restriction")) {
procedKeys.insert("osm_node_positive_restriction");
for (const auto& kvs : for (const auto& kvs :
p.getStrArr(sec.first, "osm_node_positive_restriction", ' ')) { p.getStrArr(sec.first, "osm_node_positive_restriction", ' ')) {
auto fRule = getFRule(kvs); auto fRule = getFRule(kvs);
@ -132,6 +145,7 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
if (p.hasKey(secStr, "osm_node_negative_restriction")) { if (p.hasKey(secStr, "osm_node_negative_restriction")) {
procedKeys.insert("osm_node_negative_restriction");
for (const auto& kvs : for (const auto& kvs :
p.getStrArr(sec.first, "osm_node_negative_restriction", ' ')) { p.getStrArr(sec.first, "osm_node_negative_restriction", ' ')) {
auto fRule = getFRule(kvs); auto fRule = getFRule(kvs);
@ -141,6 +155,7 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
if (p.hasKey(secStr, "osm_filter_no_restriction")) { if (p.hasKey(secStr, "osm_filter_no_restriction")) {
procedKeys.insert("osm_filter_no_restriction");
for (const auto& kvs : for (const auto& kvs :
p.getStrArr(sec.first, "osm_filter_no_restriction", ' ')) { p.getStrArr(sec.first, "osm_filter_no_restriction", ' ')) {
auto fRule = getFRule(kvs); auto fRule = getFRule(kvs);
@ -150,6 +165,7 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
if (p.hasKey(secStr, "osm_station_name_attrs")) { if (p.hasKey(secStr, "osm_station_name_attrs")) {
procedKeys.insert("osm_station_name_attrs");
for (const std::string& r : for (const std::string& r :
p.getStrArr(sec.first, "osm_station_name_attrs", ' ')) { p.getStrArr(sec.first, "osm_station_name_attrs", ' ')) {
curCfg.osmBuildOpts.statAttrRules.nameRule.push_back( curCfg.osmBuildOpts.statAttrRules.nameRule.push_back(
@ -158,6 +174,7 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
if (p.hasKey(secStr, "osm_track_number_tags")) { if (p.hasKey(secStr, "osm_track_number_tags")) {
procedKeys.insert("osm_track_number_tags");
for (const std::string& r : for (const std::string& r :
p.getStrArr(sec.first, "osm_track_number_tags", ' ')) { p.getStrArr(sec.first, "osm_track_number_tags", ' ')) {
curCfg.osmBuildOpts.statAttrRules.platformRule.push_back( curCfg.osmBuildOpts.statAttrRules.platformRule.push_back(
@ -165,7 +182,16 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
} }
if (p.hasKey(secStr, "osm_station_id_attrs")) {
procedKeys.insert("osm_station_id_attrs");
for (const std::string& r :
p.getStrArr(sec.first, "osm_station_id_attrs", ' ')) {
curCfg.osmBuildOpts.statAttrRules.idRule.push_back(getDeepAttrRule(r));
}
}
if (p.hasKey(secStr, "osm_edge_track_number_tags")) { if (p.hasKey(secStr, "osm_edge_track_number_tags")) {
procedKeys.insert("osm_edge_track_number_tags");
for (const std::string& r : for (const std::string& r :
p.getStrArr(sec.first, "osm_edge_track_number_tags", ' ')) { p.getStrArr(sec.first, "osm_edge_track_number_tags", ' ')) {
curCfg.osmBuildOpts.edgePlatformRules.push_back(getDeepAttrRule(r)); curCfg.osmBuildOpts.edgePlatformRules.push_back(getDeepAttrRule(r));
@ -173,6 +199,7 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
if (p.hasKey(secStr, "osm_station_group_attrs")) { if (p.hasKey(secStr, "osm_station_group_attrs")) {
procedKeys.insert("osm_station_group_attrs");
auto arr = p.getStrArr(secStr, "osm_station_group_attrs", ' '); auto arr = p.getStrArr(secStr, "osm_station_group_attrs", ' ');
for (const auto& ruleStr : arr) { for (const auto& ruleStr : arr) {
@ -186,6 +213,7 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
if (p.hasKey(secStr, "osm_line_relation_tags")) { if (p.hasKey(secStr, "osm_line_relation_tags")) {
procedKeys.insert("osm_line_relation_tags");
auto arr = p.getStrArr(secStr, "osm_line_relation_tags", ' '); auto arr = p.getStrArr(secStr, "osm_line_relation_tags", ' ');
for (const auto& ruleStr : arr) { for (const auto& ruleStr : arr) {
@ -201,6 +229,7 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
if (p.hasKey(secStr, "osm_max_snap_distance")) { if (p.hasKey(secStr, "osm_max_snap_distance")) {
procedKeys.insert("osm_max_snap_distance");
curCfg.osmBuildOpts.maxSnapDistances = curCfg.osmBuildOpts.maxSnapDistances =
p.getDoubleArr(secStr, "osm_max_snap_distance", ','); p.getDoubleArr(secStr, "osm_max_snap_distance", ',');
} else { } else {
@ -208,6 +237,7 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
if (p.hasKey(secStr, "osm_max_snap_fallback_distance")) { if (p.hasKey(secStr, "osm_max_snap_fallback_distance")) {
procedKeys.insert("osm_max_snap_fallback_distance");
curCfg.osmBuildOpts.maxSnapFallbackHeurDistance = curCfg.osmBuildOpts.maxSnapFallbackHeurDistance =
p.getDouble(secStr, "osm_max_snap_fallback_distance"); p.getDouble(secStr, "osm_max_snap_fallback_distance");
} else { } else {
@ -218,6 +248,7 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
if (p.hasKey(secStr, "osm_max_osm_station_distance")) { if (p.hasKey(secStr, "osm_max_osm_station_distance")) {
procedKeys.insert("osm_max_osm_station_distance");
curCfg.osmBuildOpts.maxOsmStationDistance = curCfg.osmBuildOpts.maxOsmStationDistance =
p.getDouble(secStr, "osm_max_osm_station_distance"); p.getDouble(secStr, "osm_max_osm_station_distance");
} else { } else {
@ -225,6 +256,7 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
if (p.hasKey(secStr, "osm_max_node_block_distance")) { if (p.hasKey(secStr, "osm_max_node_block_distance")) {
procedKeys.insert("osm_max_node_block_distance");
curCfg.osmBuildOpts.maxBlockDistance = curCfg.osmBuildOpts.maxBlockDistance =
p.getDouble(secStr, "osm_max_node_block_distance"); p.getDouble(secStr, "osm_max_node_block_distance");
} else { } else {
@ -238,6 +270,7 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
std::string name = std::string name =
std::string("routing_lvl") + std::to_string(i) + "_fac"; std::string("routing_lvl") + std::to_string(i) + "_fac";
if (p.hasKey(secStr, name)) { if (p.hasKey(secStr, name)) {
procedKeys.insert(name);
double v = p.getDouble(sec.first, name); double v = p.getDouble(sec.first, name);
curCfg.routingOpts.levelPunish[i] = v; curCfg.routingOpts.levelPunish[i] = v;
} else { } else {
@ -246,10 +279,18 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
if (p.hasKey(secStr, "routing_full_turn_punish")) { if (p.hasKey(secStr, "routing_full_turn_punish")) {
procedKeys.insert("routing_full_turn_punish");
curCfg.routingOpts.fullTurnPunishFac = curCfg.routingOpts.fullTurnPunishFac =
p.getDouble(secStr, "routing_full_turn_punish"); p.getDouble(secStr, "routing_full_turn_punish");
} }
if (p.hasKey(secStr, "routing_no_self_hops")) {
procedKeys.insert("routing_no_self_hops");
curCfg.routingOpts.noSelfHops = p.getBool(secStr, "routing_no_self_hops");
}
if (p.hasKey(secStr, "routing_full_turn_angle")) { if (p.hasKey(secStr, "routing_full_turn_angle")) {
procedKeys.insert("routing_full_turn_angle");
double ang = p.getDouble(secStr, "routing_full_turn_angle"); double ang = p.getDouble(secStr, "routing_full_turn_angle");
curCfg.routingOpts.fullTurnAngle = ang; curCfg.routingOpts.fullTurnAngle = ang;
curCfg.osmBuildOpts.fullTurnAngle = ang; curCfg.osmBuildOpts.fullTurnAngle = ang;
@ -257,39 +298,55 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
curCfg.routingOpts.fullTurnAngle = 5; curCfg.routingOpts.fullTurnAngle = 5;
curCfg.osmBuildOpts.fullTurnAngle = 5; curCfg.osmBuildOpts.fullTurnAngle = 5;
} }
if (p.hasKey(secStr, "routing_snap_full_turn_angle")) { if (p.hasKey(secStr, "routing_snap_full_turn_angle")) {
procedKeys.insert("routing_snap_full_turn_angle");
double ang = p.getDouble(secStr, "routing_snap_full_turn_angle"); double ang = p.getDouble(secStr, "routing_snap_full_turn_angle");
curCfg.osmBuildOpts.maxAngleSnapReach = ang; curCfg.osmBuildOpts.maxAngleSnapReach = ang;
} else { } else {
curCfg.osmBuildOpts.maxAngleSnapReach = curCfg.routingOpts.fullTurnAngle; curCfg.osmBuildOpts.maxAngleSnapReach = curCfg.routingOpts.fullTurnAngle;
} }
if (p.hasKey(secStr, "routing_pass_thru_station_punish")) { if (p.hasKey(secStr, "routing_pass_thru_station_punish")) {
procedKeys.insert("routing_pass_thru_station_punish");
curCfg.routingOpts.passThruStationsPunish = curCfg.routingOpts.passThruStationsPunish =
p.getDouble(secStr, "routing_pass_thru_station_punish"); p.getDouble(secStr, "routing_pass_thru_station_punish");
} }
if (p.hasKey(secStr, "routing_one_way_meter_punish_fac")) { if (p.hasKey(secStr, "routing_one_way_meter_punish_fac")) {
procedKeys.insert("routing_one_way_meter_punish_fac");
curCfg.routingOpts.oneWayPunishFac = curCfg.routingOpts.oneWayPunishFac =
p.getDouble(secStr, "routing_one_way_meter_punish_fac"); p.getDouble(secStr, "routing_one_way_meter_punish_fac");
} }
if (p.hasKey(secStr, "routing_one_way_edge_punish")) { if (p.hasKey(secStr, "routing_one_way_edge_punish")) {
procedKeys.insert("routing_one_way_edge_punish");
curCfg.routingOpts.oneWayEdgePunish = curCfg.routingOpts.oneWayEdgePunish =
p.getDouble(secStr, "routing_one_way_edge_punish"); p.getDouble(secStr, "routing_one_way_edge_punish");
} }
if (p.hasKey(secStr, "routing_line_unmatched_punish_fac")) { if (p.hasKey(secStr, "routing_line_unmatched_punish_fac")) {
procedKeys.insert("routing_line_unmatched_punish_fac");
curCfg.routingOpts.lineUnmatchedPunishFact = curCfg.routingOpts.lineUnmatchedPunishFact =
p.getDouble(secStr, "routing_line_unmatched_punish_fac"); p.getDouble(secStr, "routing_line_unmatched_punish_fac");
} }
if (p.hasKey(secStr, "routing_platform_unmatched_punish")) { if (p.hasKey(secStr, "routing_platform_unmatched_punish")) {
procedKeys.insert("routing_platform_unmatched_punish");
curCfg.routingOpts.platformUnmatchedPen = curCfg.routingOpts.platformUnmatchedPen =
p.getDouble(secStr, "routing_platform_unmatched_punish"); p.getDouble(secStr, "routing_platform_unmatched_punish");
} }
if (p.hasKey(secStr, "routing_non_osm_station_punish")) { if (p.hasKey(secStr, "routing_non_osm_station_punish")) {
procedKeys.insert("routing_non_osm_station_punish");
curCfg.routingOpts.nonOsmPen = curCfg.routingOpts.nonOsmPen =
p.getDouble(secStr, "routing_non_osm_station_punish"); p.getDouble(secStr, "routing_non_osm_station_punish");
} else { } else {
curCfg.routingOpts.nonOsmPen = 0; curCfg.routingOpts.nonOsmPen = 0;
} }
if (p.hasKey(secStr, "routing_station_distance_punish_fac")) { if (p.hasKey(secStr, "routing_station_distance_punish_fac")) {
procedKeys.insert("routing_station_distance_punish_fac");
curCfg.routingOpts.stationDistPenFactor = curCfg.routingOpts.stationDistPenFactor =
p.getDouble(secStr, "routing_station_distance_punish_fac"); p.getDouble(secStr, "routing_station_distance_punish_fac");
} else { } else {
@ -297,6 +354,7 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
if (p.hasKey(secStr, "station_normalize_chain")) { if (p.hasKey(secStr, "station_normalize_chain")) {
procedKeys.insert("station_normalize_chain");
try { try {
auto arr = p.getStrArr(secStr, "station_normalize_chain", ';'); auto arr = p.getStrArr(secStr, "station_normalize_chain", ';');
curCfg.osmBuildOpts.statNormzer = curCfg.osmBuildOpts.statNormzer =
@ -311,6 +369,7 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
if (p.hasKey(secStr, "track_normalize_chain")) { if (p.hasKey(secStr, "track_normalize_chain")) {
procedKeys.insert("track_normalize_chain");
try { try {
auto arr = p.getStrArr(secStr, "track_normalize_chain", ';'); auto arr = p.getStrArr(secStr, "track_normalize_chain", ';');
curCfg.osmBuildOpts.trackNormzer = curCfg.osmBuildOpts.trackNormzer =
@ -325,19 +384,39 @@ void MotConfigReader::parse(const std::vector<std::string>& paths) {
} }
if (p.hasKey(secStr, "line_normalize_chain")) { if (p.hasKey(secStr, "line_normalize_chain")) {
procedKeys.insert("line_normalize_chain");
try { try {
auto arr = p.getStrArr(secStr, "line_normalize_chain", ';'); auto arr = p.getStrArr(secStr, "line_normalize_chain", ';');
curCfg.osmBuildOpts.lineNormzer = curCfg.osmBuildOpts.lineNormzer =
trgraph::Normalizer(getNormRules(arr)); trgraph::Normalizer(getNormRules(arr));
} catch (const std::exception& e) { } catch (const std::exception& e) {
throw ParseExc(p.getVal(secStr, "station_normalize_chain").line, throw ParseExc(p.getVal(secStr, "line_normalize_chain").line,
p.getVal(secStr, "station_normalize_chain").pos, p.getVal(secStr, "line_normalize_chain").pos,
"<valid regular expression>",
std::string("<regex error: ") + e.what() + ">",
p.getVal(secStr, "line_normalize_chain").file);
}
}
if (p.hasKey(secStr, "station_id_normalize_chain")) {
procedKeys.insert("station_id_normalize_chain");
try {
auto arr = p.getStrArr(secStr, "station_id_normalize_chain", ';');
curCfg.osmBuildOpts.idNormzer = trgraph::Normalizer(getNormRules(arr));
} catch (const std::exception& e) {
throw ParseExc(p.getVal(secStr, "station_id_normalize_chain").line,
p.getVal(secStr, "station_id_normalize_chain").pos,
"<valid regular expression>", "<valid regular expression>",
std::string("<regex error: ") + e.what() + ">", std::string("<regex error: ") + e.what() + ">",
p.getVal(secStr, "station_normalize_chain").file); p.getVal(secStr, "station_normalize_chain").file);
} }
} }
for (const auto& kv : p.getKeyVals(secStr)) {
if (!procedKeys.count(kv.first))
curCfg.unproced[kv.first] = kv.second.val;
}
bool found = false; bool found = false;
for (auto& cfg : _cfgs) { for (auto& cfg : _cfgs) {

View file

@ -6,6 +6,7 @@
#define PFAEDLE_GTFS_WRITER_H_ #define PFAEDLE_GTFS_WRITER_H_
#include <string> #include <string>
#include "ad/cppgtfs/Writer.h"
#include "Feed.h" #include "Feed.h"
namespace pfaedle { namespace pfaedle {

View file

@ -65,7 +65,6 @@ void OsmBuilder::read(const std::string& path, const OsmReadOpts& opts,
Graph* g, const BBoxIdx& bbox, size_t gridSize, Graph* g, const BBoxIdx& bbox, size_t gridSize,
router::FeedStops* fs, Restrictor* res) { router::FeedStops* fs, Restrictor* res) {
if (!bbox.size()) return; if (!bbox.size()) return;
if (!fs->size()) return;
LOG(INFO) << "Reading OSM file " << path << " ... "; LOG(INFO) << "Reading OSM file " << path << " ... ";
@ -141,119 +140,8 @@ void OsmBuilder::read(const std::string& path, const OsmReadOpts& opts,
LOG(VDEBUG) << "Writing edge geoms..."; LOG(VDEBUG) << "Writing edge geoms...";
writeGeoms(g); writeGeoms(g);
{ LOG(VDEBUG) << "Snapping stations...";
NodeGrid sng = buildNodeIdx(g, gridSize, bbox.getFullWebMercBox(), true); snapStats(opts, g, bbox, gridSize, fs, res, orphanStations);
EdgeGrid eg = buildEdgeIdx(g, gridSize, bbox.getFullWebMercBox());
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);
}
}
}
}
std::vector<const Stop*> 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];
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());
}
(*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() << ")";
}
}
}
}
LOG(VDEBUG) << "Deleting orphan nodes..."; LOG(VDEBUG) << "Deleting orphan nodes...";
deleteOrphNds(g); deleteOrphNds(g);
@ -534,12 +422,17 @@ void OsmBuilder::readWriteWays(xml::File* i, util::xml::XmlWriter* o,
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
NodePL OsmBuilder::plFromGtfs(const Stop* s, const OsmReadOpts& ops) const { NodePL OsmBuilder::plFromGtfs(const Stop* s, const OsmReadOpts& ops) {
NodePL ret( NodePL ret(
util::geo::latLngToWebMerc<PFAEDLE_PRECISION>(s->getLat(), s->getLng()), util::geo::latLngToWebMerc<PFAEDLE_PRECISION>(s->getLat(), s->getLng()),
StatInfo(ops.statNormzer(s->getName()), StatInfo(ops.statNormzer(s->getName()),
ops.trackNormzer(s->getPlatformCode()), false)); ops.trackNormzer(s->getPlatformCode()), false));
#ifdef PFAEDLE_STATION_IDS
// debug feature, store station id from GTFS
ret.getSI()->setId(s->getId());
#endif
if (s->getParentStation()) { if (s->getParentStation()) {
ret.getSI()->addAltName(ops.statNormzer(s->getParentStation()->getName())); ret.getSI()->addAltName(ops.statNormzer(s->getParentStation()->getName()));
} }
@ -1109,6 +1002,11 @@ Nullable<StatInfo> OsmBuilder::getStatInfo(Node* node, osmid nid,
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));
#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;
@ -1151,26 +1049,17 @@ Nullable<StatInfo> OsmBuilder::getStatInfo(Node* node, osmid nid,
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
double OsmBuilder::dist(const Node* a, const Node* b) const { 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::webMercDistFactor(const POINT& a) const { double OsmBuilder::webMercDist(const Node* a, const Node* b) {
// euclidean distance on web mercator is in meters on equator,
// and proportional to cos(lat) in both y directions
double lat = 2 * atan(exp(a.getY() / 6378137.0)) - 1.5707965;
return cos(lat);
}
// _____________________________________________________________________________
double OsmBuilder::webMercDist(const Node* a, const Node* b) const {
return webMercMeterDist(*a->pl().getGeom(), *b->pl().getGeom()); return webMercMeterDist(*a->pl().getGeom(), *b->pl().getGeom());
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
void OsmBuilder::writeGeoms(Graph* g) const { void OsmBuilder::writeGeoms(Graph* g) {
for (auto* n : *g->getNds()) { for (auto* n : *g->getNds()) {
for (auto* e : n->getAdjListOut()) { for (auto* e : n->getAdjListOut()) {
e->pl().addPoint(*e->getFrom()->pl().getGeom()); e->pl().addPoint(*e->getFrom()->pl().getGeom());
@ -1181,35 +1070,47 @@ void OsmBuilder::writeGeoms(Graph* g) const {
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
void OsmBuilder::fixGaps(Graph* g, NodeGrid* ng) const { void OsmBuilder::fixGaps(Graph* g, NodeGrid* ng) {
double METER = 1;
for (auto* n : *g->getNds()) { for (auto* n : *g->getNds()) {
if (n->getInDeg() + n->getOutDeg() == 1) { if (n->getInDeg() + n->getOutDeg() == 1) {
// get all nodes in a 1 meter distance // get all nodes in distance
std::set<Node*> ret; std::set<Node*> ret;
ng->get(util::geo::pad(util::geo::getBoundingBox(*n->pl().getGeom()), 1), double distor = util::geo::webMercDistFactor(*n->pl().getGeom());
ng->get(util::geo::pad(util::geo::getBoundingBox(*n->pl().getGeom()),
METER / distor),
&ret); &ret);
for (auto* nb : ret) { for (auto* nb : ret) {
if (nb != n && (nb->getInDeg() + nb->getOutDeg()) == 1 && if (nb != n && (nb->getInDeg() + nb->getOutDeg()) == 1 &&
webMercDist(nb, n) <= 1.0 && !nb->pl().getSI() && webMercDist(nb, n) <= METER / distor) {
!n->pl().getSI()) { // special case: both node are non-stations, move
Node* otherN; // the end point nb to n and delete nb
if (nb->getOutDeg()) if (!nb->pl().getSI() && !n->pl().getSI()) {
otherN = (*nb->getAdjListOut().begin())->getOtherNd(nb); Node* otherN;
else if (nb->getOutDeg())
otherN = (*nb->getAdjListIn().begin())->getOtherNd(nb); otherN = (*nb->getAdjListOut().begin())->getOtherNd(nb);
LINE l; else
l.push_back(*otherN->pl().getGeom()); otherN = (*nb->getAdjListIn().begin())->getOtherNd(nb);
l.push_back(*n->pl().getGeom()); LINE l;
l.push_back(*otherN->pl().getGeom());
l.push_back(*n->pl().getGeom());
Edge* e; Edge* e;
if (nb->getOutDeg()) if (nb->getOutDeg())
e = g->addEdg(otherN, n, (*nb->getAdjListOut().begin())->pl()); e = g->addEdg(otherN, n, (*nb->getAdjListOut().begin())->pl());
else else
e = g->addEdg(otherN, n, (*nb->getAdjListIn().begin())->pl()); e = g->addEdg(otherN, n, (*nb->getAdjListIn().begin())->pl());
if (e) { if (e) {
*e->pl().getGeom() = l; *e->pl().getGeom() = l;
g->delNd(nb); g->delNd(nb);
ng->remove(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());
} }
} }
} }
@ -1219,7 +1120,7 @@ void OsmBuilder::fixGaps(Graph* g, NodeGrid* ng) const {
// _____________________________________________________________________________ // _____________________________________________________________________________
EdgeGrid OsmBuilder::buildEdgeIdx(Graph* g, size_t size, EdgeGrid OsmBuilder::buildEdgeIdx(Graph* g, size_t size,
const BOX& webMercBox) const { const BOX& webMercBox) {
EdgeGrid ret(size, size, webMercBox, false); EdgeGrid ret(size, size, webMercBox, false);
for (auto* n : *g->getNds()) { for (auto* n : *g->getNds()) {
for (auto* e : n->getAdjListOut()) { for (auto* e : n->getAdjListOut()) {
@ -1232,7 +1133,7 @@ EdgeGrid OsmBuilder::buildEdgeIdx(Graph* g, size_t size,
// _____________________________________________________________________________ // _____________________________________________________________________________
NodeGrid OsmBuilder::buildNodeIdx(Graph* g, size_t size, const BOX& webMercBox, NodeGrid OsmBuilder::buildNodeIdx(Graph* g, size_t size, const BOX& webMercBox,
bool which) const { bool which) {
NodeGrid ret(size, size, webMercBox, false); NodeGrid ret(size, size, webMercBox, false);
for (auto* n : *g->getNds()) { for (auto* n : *g->getNds()) {
if (!which && n->getInDeg() + n->getOutDeg() == 1) if (!which && n->getInDeg() + n->getOutDeg() == 1)
@ -1246,7 +1147,7 @@ NodeGrid OsmBuilder::buildNodeIdx(Graph* g, size_t size, const BOX& webMercBox,
// _____________________________________________________________________________ // _____________________________________________________________________________
Node* OsmBuilder::depthSearch(const Edge* e, const StatInfo* si, const POINT& p, Node* OsmBuilder::depthSearch(const Edge* e, const StatInfo* si, const POINT& p,
double maxD, int maxFullTurns, double minAngle, double maxD, int maxFullTurns, double minAngle,
const SearchFunc& sfunc) const { const SearchFunc& sfunc) {
// shortcuts // shortcuts
double dFrom = webMercMeterDist(*e->getFrom()->pl().getGeom(), p); double dFrom = webMercMeterDist(*e->getFrom()->pl().getGeom(), p);
double dTo = webMercMeterDist(*e->getTo()->pl().getGeom(), p); double dTo = webMercMeterDist(*e->getTo()->pl().getGeom(), p);
@ -1310,23 +1211,22 @@ Node* OsmBuilder::depthSearch(const Edge* e, const StatInfo* si, const POINT& p,
// _____________________________________________________________________________ // _____________________________________________________________________________
bool OsmBuilder::isBlocked(const Edge* e, const StatInfo* si, const POINT& p, bool OsmBuilder::isBlocked(const Edge* e, const StatInfo* si, const POINT& p,
double maxD, int maxFullTurns, double maxD, int maxFullTurns, double minAngle) {
double minAngle) const {
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, Node* OsmBuilder::eqStatReach(const Edge* e, const StatInfo* si, const POINT& p,
double maxD, int maxFullTurns, double minAngle, double maxD, int maxFullTurns, double minAngle,
bool orphanSnap) const { bool orphanSnap) {
return depthSearch(e, si, p, maxD, maxFullTurns, minAngle, return depthSearch(e, si, p, maxD, maxFullTurns, minAngle,
EqSearch(orphanSnap)); EqSearch(orphanSnap));
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
void OsmBuilder::getEdgCands(const POINT& geom, EdgeCandPQ* ret, EdgeGrid* eg, void OsmBuilder::getEdgCands(const POINT& geom, EdgeCandPQ* ret, EdgeGrid* eg,
double d) const { double d) {
double distor = webMercDistFactor(geom); double distor = util::geo::webMercDistFactor(geom);
std::set<Edge*> neighs; std::set<Edge*> neighs;
BOX box = util::geo::pad(util::geo::getBoundingBox(geom), d / distor); BOX box = util::geo::pad(util::geo::getBoundingBox(geom), d / distor);
eg->get(box, &neighs); eg->get(box, &neighs);
@ -1343,9 +1243,9 @@ void OsmBuilder::getEdgCands(const POINT& geom, EdgeCandPQ* ret, EdgeGrid* eg,
// _____________________________________________________________________________ // _____________________________________________________________________________
std::set<Node*> OsmBuilder::getMatchingNds(const NodePL& s, NodeGrid* ng, std::set<Node*> OsmBuilder::getMatchingNds(const NodePL& s, NodeGrid* ng,
double d) const { double d) {
std::set<Node*> ret; std::set<Node*> ret;
double distor = webMercDistFactor(*s.getGeom()); double distor = util::geo::webMercDistFactor(*s.getGeom());
std::set<Node*> neighs; std::set<Node*> neighs;
BOX box = util::geo::pad(util::geo::getBoundingBox(*s.getGeom()), d / distor); BOX box = util::geo::pad(util::geo::getBoundingBox(*s.getGeom()), d / distor);
ng->get(box, &neighs); ng->get(box, &neighs);
@ -1361,8 +1261,8 @@ std::set<Node*> OsmBuilder::getMatchingNds(const NodePL& s, NodeGrid* ng,
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
Node* OsmBuilder::getMatchingNd(const NodePL& s, NodeGrid* ng, double d) const { Node* OsmBuilder::getMatchingNd(const NodePL& s, NodeGrid* ng, double d) {
double distor = webMercDistFactor(*s.getGeom()); double distor = util::geo::webMercDistFactor(*s.getGeom());
std::set<Node*> neighs; std::set<Node*> neighs;
BOX box = util::geo::pad(util::geo::getBoundingBox(*s.getGeom()), d / distor); BOX box = util::geo::pad(util::geo::getBoundingBox(*s.getGeom()), d / distor);
ng->get(box, &neighs); ng->get(box, &neighs);
@ -1387,7 +1287,7 @@ Node* OsmBuilder::getMatchingNd(const NodePL& s, NodeGrid* ng, double d) const {
std::set<Node*> OsmBuilder::snapStation(Graph* g, NodePL* s, EdgeGrid* eg, std::set<Node*> OsmBuilder::snapStation(Graph* g, NodePL* s, EdgeGrid* eg,
NodeGrid* sng, const OsmReadOpts& opts, NodeGrid* sng, const OsmReadOpts& opts,
Restrictor* restor, bool surrHeur, Restrictor* restor, bool surrHeur,
bool orphSnap, double d) const { bool orphSnap, double d) {
assert(s->getSI()); assert(s->getSI());
std::set<Node*> ret; std::set<Node*> ret;
@ -1467,6 +1367,13 @@ std::set<Node*> OsmBuilder::snapStation(Graph* g, NodePL* s, EdgeGrid* eg,
ret.insert(n); ret.insert(n);
} }
} else { } 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); ret.insert(eq);
} }
} }
@ -1475,7 +1382,7 @@ std::set<Node*> OsmBuilder::snapStation(Graph* g, NodePL* s, EdgeGrid* eg,
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
StatGroup* OsmBuilder::groupStats(const NodeSet& s) const { StatGroup* OsmBuilder::groupStats(const NodeSet& s) {
if (!s.size()) return 0; if (!s.size()) return 0;
// reference group // reference group
StatGroup* ret = new StatGroup(); StatGroup* ret = new StatGroup();
@ -1664,10 +1571,19 @@ void OsmBuilder::getKeptAttrKeys(const OsmReadOpts& opts,
sets[2].insert(i.attr); 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) const { void OsmBuilder::deleteOrphEdgs(Graph* g, const OsmReadOpts& opts) {
size_t ROUNDS = 3; size_t ROUNDS = 3;
for (size_t c = 0; c < ROUNDS; c++) { for (size_t c = 0; c < ROUNDS; c++) {
for (auto i = g->getNds()->begin(); i != g->getNds()->end();) { for (auto i = g->getNds()->begin(); i != g->getNds()->end();) {
@ -1692,11 +1608,10 @@ void OsmBuilder::deleteOrphEdgs(Graph* g, const OsmReadOpts& opts) const {
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
void OsmBuilder::deleteOrphNds(Graph* g) const { void OsmBuilder::deleteOrphNds(Graph* g) {
for (auto i = g->getNds()->begin(); i != g->getNds()->end();) { for (auto i = g->getNds()->begin(); i != g->getNds()->end();) {
if ((*i)->getInDeg() + (*i)->getOutDeg() == 0 && if ((*i)->getInDeg() + (*i)->getOutDeg() == 0 &&
!((*i)->pl().getSI() && (*i)->pl().getSI()->getGroup() && !((*i)->pl().getSI() && (*i)->pl().getSI()->getGroup())) {
(*i)->pl().getSI()->getGroup()->getStops().size())) {
i = g->delNd(i); i = g->delNd(i);
// TODO(patrick): maybe delete from node grid? // TODO(patrick): maybe delete from node grid?
} else { } else {
@ -1706,7 +1621,7 @@ void OsmBuilder::deleteOrphNds(Graph* g) const {
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
bool OsmBuilder::edgesSim(const Edge* a, const Edge* b) const { bool OsmBuilder::edgesSim(const Edge* a, const Edge* b) {
if (static_cast<bool>(a->pl().oneWay()) ^ static_cast<bool>(b->pl().oneWay())) if (static_cast<bool>(a->pl().oneWay()) ^ static_cast<bool>(b->pl().oneWay()))
return false; return false;
if (a->pl().lvl() != b->pl().lvl()) return false; if (a->pl().lvl() != b->pl().lvl()) return false;
@ -1721,7 +1636,7 @@ bool OsmBuilder::edgesSim(const Edge* a, const Edge* b) const {
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
const EdgePL& OsmBuilder::mergeEdgePL(Edge* a, Edge* b) const { const EdgePL& OsmBuilder::mergeEdgePL(Edge* a, Edge* b) {
const Node* n = 0; const Node* n = 0;
if (a->getFrom() == b->getFrom()) if (a->getFrom() == b->getFrom())
n = a->getFrom(); n = a->getFrom();
@ -1760,7 +1675,7 @@ const EdgePL& OsmBuilder::mergeEdgePL(Edge* a, Edge* b) const {
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
void OsmBuilder::collapseEdges(Graph* g) const { void OsmBuilder::collapseEdges(Graph* g) {
for (auto* n : *g->getNds()) { for (auto* n : *g->getNds()) {
if (n->getOutDeg() + n->getInDeg() != 2 || n->pl().getSI()) continue; if (n->getOutDeg() + n->getInDeg() != 2 || n->pl().getSI()) continue;
@ -1795,7 +1710,7 @@ void OsmBuilder::collapseEdges(Graph* g) const {
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
void OsmBuilder::simplifyGeoms(Graph* g) const { void OsmBuilder::simplifyGeoms(Graph* g) {
for (auto* n : *g->getNds()) { for (auto* n : *g->getNds()) {
for (auto* e : n->getAdjListOut()) { for (auto* e : n->getAdjListOut()) {
(*e->pl().getGeom()) = util::geo::simplify(*e->pl().getGeom(), 0.5); (*e->pl().getGeom()) = util::geo::simplify(*e->pl().getGeom(), 0.5);
@ -1804,7 +1719,7 @@ void OsmBuilder::simplifyGeoms(Graph* g) const {
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
uint32_t OsmBuilder::writeComps(Graph* g) const { uint32_t OsmBuilder::writeComps(Graph* g) {
Component* comp = new Component{7}; Component* comp = new Component{7};
uint32_t numC = 0; uint32_t numC = 0;
@ -1843,7 +1758,7 @@ uint32_t OsmBuilder::writeComps(Graph* g) const {
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
void OsmBuilder::writeEdgeTracks(const EdgTracks& tracks) const { void OsmBuilder::writeEdgeTracks(const EdgTracks& tracks) {
for (const auto& tr : tracks) { for (const auto& tr : tracks) {
if (tr.first->getTo()->pl().getSI() && if (tr.first->getTo()->pl().getSI() &&
tr.first->getTo()->pl().getSI()->getTrack().empty()) { tr.first->getTo()->pl().getSI()->getTrack().empty()) {
@ -1857,7 +1772,7 @@ void OsmBuilder::writeEdgeTracks(const EdgTracks& tracks) const {
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
void OsmBuilder::writeODirEdgs(Graph* g, Restrictor* restor) const { void OsmBuilder::writeODirEdgs(Graph* g, Restrictor* restor) {
for (auto* n : *g->getNds()) { for (auto* n : *g->getNds()) {
for (auto* e : n->getAdjListOut()) { for (auto* e : n->getAdjListOut()) {
if (g->getEdg(e->getTo(), e->getFrom())) continue; if (g->getEdg(e->getTo(), e->getFrom())) continue;
@ -1868,7 +1783,7 @@ void OsmBuilder::writeODirEdgs(Graph* g, Restrictor* restor) const {
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
void OsmBuilder::writeSelfEdgs(Graph* g) const { void OsmBuilder::writeSelfEdgs(Graph* g) {
for (auto* n : *g->getNds()) { for (auto* n : *g->getNds()) {
if (n->pl().getSI() && n->getAdjListOut().size() == 0) { if (n->pl().getSI() && n->getAdjListOut().size() == 0) {
g->addEdg(n, n); g->addEdg(n, n);
@ -1877,7 +1792,7 @@ void OsmBuilder::writeSelfEdgs(Graph* g) const {
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
bool OsmBuilder::keepFullTurn(const trgraph::Node* n, double ang) const { 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; const trgraph::Edge* e = 0;
@ -1915,3 +1830,123 @@ bool OsmBuilder::keepFullTurn(const trgraph::Node* n, double ang) const {
return false; return false;
} }
// _____________________________________________________________________________
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());
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);
}
}
}
}
if (!fs) return;
std::vector<const Stop*> 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];
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());
}
(*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() << ")";
}
}
}
}

View file

@ -4,7 +4,6 @@
#ifndef PFAEDLE_OSM_OSMBUILDER_H_ #ifndef PFAEDLE_OSM_OSMBUILDER_H_
#define PFAEDLE_OSM_OSMBUILDER_H_ #define PFAEDLE_OSM_OSMBUILDER_H_
#include <map> #include <map>
#include <queue> #include <queue>
#include <set> #include <set>
@ -168,65 +167,70 @@ class OsmBuilder {
OsmRel nextRel(xml::File* xml, const OsmFilter& filter, OsmRel nextRel(xml::File* xml, const OsmFilter& filter,
const AttrKeySet& keepAttrs) const; const AttrKeySet& keepAttrs) const;
protected:
Nullable<StatInfo> getStatInfo(Node* node, osmid nid, const POINT& pos, Nullable<StatInfo> getStatInfo(Node* node, osmid nid, const POINT& pos,
const AttrMap& m, StAttrGroups* groups, const AttrMap& m, StAttrGroups* groups,
const RelMap& nodeRels, const RelLst& rels, const RelMap& nodeRels, const RelLst& rels,
const OsmReadOpts& ops) const; const OsmReadOpts& ops) const;
void writeGeoms(Graph* g) const; static void snapStats(const OsmReadOpts& opts, Graph* g, const BBoxIdx& bbox,
void deleteOrphNds(Graph* g) const; size_t gridSize, router::FeedStops* fs, Restrictor* res,
void deleteOrphEdgs(Graph* g, const OsmReadOpts& opts) const; const NodeSet& orphanStations);
double dist(const Node* a, const Node* b) const; static void writeGeoms(Graph* g);
double webMercDist(const Node* a, const Node* b) const; static void deleteOrphNds(Graph* g);
double webMercDistFactor(const POINT& a) const; static void deleteOrphEdgs(Graph* g, const OsmReadOpts& opts);
static double dist(const Node* a, const Node* b);
static double webMercDist(const Node* a, const Node* b);
NodeGrid buildNodeIdx(Graph* g, size_t size, const BOX& webMercBox, static NodeGrid buildNodeIdx(Graph* g, size_t size, const BOX& webMercBox,
bool which) const; bool which);
EdgeGrid buildEdgeIdx(Graph* g, size_t size, const BOX& webMercBox) const; static EdgeGrid buildEdgeIdx(Graph* g, size_t size, const BOX& webMercBox);
void fixGaps(Graph* g, NodeGrid* ng) const; static void fixGaps(Graph* g, NodeGrid* ng);
void collapseEdges(Graph* g) const; static void collapseEdges(Graph* g);
void writeODirEdgs(Graph* g, Restrictor* restor) const; static void writeODirEdgs(Graph* g, Restrictor* restor);
void writeSelfEdgs(Graph* g) const; static void writeSelfEdgs(Graph* g);
void writeEdgeTracks(const EdgTracks& tracks) const; static void writeEdgeTracks(const EdgTracks& tracks);
void simplifyGeoms(Graph* g) const; static void simplifyGeoms(Graph* g);
uint32_t writeComps(Graph* g) const; static uint32_t writeComps(Graph* g);
bool edgesSim(const Edge* a, const Edge* b) const; static bool edgesSim(const Edge* a, const Edge* b);
const EdgePL& mergeEdgePL(Edge* a, Edge* b) const; static const EdgePL& mergeEdgePL(Edge* a, Edge* b);
void getEdgCands(const POINT& s, EdgeCandPQ* ret, EdgeGrid* eg, static void getEdgCands(const POINT& s, EdgeCandPQ* ret, EdgeGrid* eg,
double d) const; double d);
std::set<Node*> getMatchingNds(const NodePL& s, NodeGrid* ng, double d) const; static std::set<Node*> getMatchingNds(const NodePL& s, NodeGrid* ng,
double d);
Node* getMatchingNd(const NodePL& s, NodeGrid* ng, double d) const; static Node* getMatchingNd(const NodePL& s, NodeGrid* ng, double d);
NodeSet snapStation(Graph* g, NodePL* s, EdgeGrid* eg, NodeGrid* sng, static NodeSet snapStation(Graph* g, NodePL* s, EdgeGrid* eg, NodeGrid* sng,
const OsmReadOpts& opts, Restrictor* restor, bool surHeur, const OsmReadOpts& opts, Restrictor* restor,
bool orphSnap, double maxD) const; bool surHeur, bool orphSnap, double maxD);
// Checks if from the edge e, a station similar to si can be reach with less // Checks if from the edge e, a station similar to si can be reach with less
// than maxD distance and less or equal to "maxFullTurns" full turns. If // than maxD distance and less or equal to "maxFullTurns" full turns. If
// such a station exists, it is returned. If not, 0 is returned. // such a station exists, it is returned. If not, 0 is returned.
Node* eqStatReach(const Edge* e, const StatInfo* si, const POINT& p, static Node* eqStatReach(const Edge* e, const StatInfo* si, const POINT& p,
double maxD, int maxFullTurns, double maxAng, double maxD, int maxFullTurns, double maxAng,
bool orph) const; bool orph);
Node* depthSearch(const Edge* e, const StatInfo* si, const POINT& p, static Node* depthSearch(const Edge* e, const StatInfo* si, const POINT& p,
double maxD, int maxFullTurns, double minAngle, double maxD, int maxFullTurns, double minAngle,
const SearchFunc& sfunc) const; const SearchFunc& sfunc);
bool isBlocked(const Edge* e, const StatInfo* si, const POINT& p, double maxD, static bool isBlocked(const Edge* e, const StatInfo* si, const POINT& p,
int maxFullTurns, double minAngle) const; double maxD, int maxFullTurns, double minAngle);
static bool keepFullTurn(const trgraph::Node* n, double ang);
StatGroup* groupStats(const NodeSet& s) const; static StatGroup* groupStats(const NodeSet& s);
static NodePL plFromGtfs(const Stop* s, const OsmReadOpts& ops);
std::vector<TransitEdgeLine*> getLines(const std::vector<size_t>& edgeRels, std::vector<TransitEdgeLine*> getLines(const std::vector<size_t>& edgeRels,
const RelLst& rels, const RelLst& rels,
const OsmReadOpts& ops); const OsmReadOpts& ops);
NodePL plFromGtfs(const Stop* s, const OsmReadOpts& ops) const;
void getKeptAttrKeys(const OsmReadOpts& opts, AttrKeySet sets[3]) const; void getKeptAttrKeys(const OsmReadOpts& opts, AttrKeySet sets[3]) const;
void skipUntil(xml::File* xml, const std::string& s) const; void skipUntil(xml::File* xml, const std::string& s) const;
@ -238,6 +242,7 @@ class OsmBuilder {
const AttrMap& attrs, const RelMap& entRels, const AttrMap& attrs, const RelMap& entRels,
const RelLst& rels, const RelLst& rels,
const Normalizer& norm) const; const Normalizer& norm) const;
std::vector<std::string> getAttrMatchRanked(const DeepAttrLst& rule, osmid id, std::vector<std::string> getAttrMatchRanked(const DeepAttrLst& rule, osmid id,
const AttrMap& attrs, const AttrMap& attrs,
const RelMap& entRels, const RelMap& entRels,
@ -249,8 +254,6 @@ class OsmBuilder {
bool relKeep(osmid id, const RelMap& rels, const FlatRels& fl) const; bool relKeep(osmid id, const RelMap& rels, const FlatRels& fl) const;
bool keepFullTurn(const trgraph::Node* n, double ang) const;
std::map<TransitEdgeLine, TransitEdgeLine*> _lines; std::map<TransitEdgeLine, TransitEdgeLine*> _lines;
std::map<size_t, TransitEdgeLine*> _relLines; std::map<size_t, TransitEdgeLine*> _relLines;
}; };

View file

@ -87,6 +87,7 @@ inline bool operator==(const RelLineRules& a, const RelLineRules& b) {
struct StationAttrRules { struct StationAttrRules {
DeepAttrLst nameRule; DeepAttrLst nameRule;
DeepAttrLst platformRule; DeepAttrLst platformRule;
DeepAttrLst idRule;
}; };
inline bool operator==(const StationAttrRules& a, const StationAttrRules& b) { inline bool operator==(const StationAttrRules& a, const StationAttrRules& b) {
@ -125,6 +126,7 @@ struct OsmReadOpts {
trgraph::Normalizer statNormzer; trgraph::Normalizer statNormzer;
trgraph::Normalizer lineNormzer; trgraph::Normalizer lineNormzer;
trgraph::Normalizer trackNormzer; trgraph::Normalizer trackNormzer;
trgraph::Normalizer idNormzer;
RelLineRules relLinerules; RelLineRules relLinerules;
StationAttrRules statAttrRules; StationAttrRules statAttrRules;

View file

@ -12,6 +12,8 @@
#include "ad/cppgtfs/gtfs/Feed.h" #include "ad/cppgtfs/gtfs/Feed.h"
#include "ad/cppgtfs/gtfs/Route.h" #include "ad/cppgtfs/gtfs/Route.h"
#include "pfaedle/trgraph/Graph.h" #include "pfaedle/trgraph/Graph.h"
#include "pfaedle/gtfs/Feed.h"
#include "util/Nullable.h"
using ad::cppgtfs::gtfs::Route; using ad::cppgtfs::gtfs::Route;
using ad::cppgtfs::gtfs::Stop; using ad::cppgtfs::gtfs::Stop;
@ -24,6 +26,11 @@ struct NodeCand {
double pen; double pen;
}; };
struct EdgeCand {
trgraph::Edge* e;
double pen;
};
struct RoutingOpts { struct RoutingOpts {
RoutingOpts() RoutingOpts()
: fullTurnPunishFac(2000), : fullTurnPunishFac(2000),
@ -33,7 +40,9 @@ struct RoutingOpts {
oneWayEdgePunish(0), oneWayEdgePunish(0),
lineUnmatchedPunishFact(0.5), lineUnmatchedPunishFact(0.5),
platformUnmatchedPen(0), platformUnmatchedPen(0),
stationDistPenFactor(0) {} stationDistPenFactor(0),
popReachEdge(true),
noSelfHops(true) {}
double fullTurnPunishFac; double fullTurnPunishFac;
double fullTurnAngle; double fullTurnAngle;
double passThruStationsPunish; double passThruStationsPunish;
@ -44,6 +53,8 @@ struct RoutingOpts {
double stationDistPenFactor; double stationDistPenFactor;
double nonOsmPen; double nonOsmPen;
double levelPunish[8]; double levelPunish[8];
bool popReachEdge;
bool noSelfHops;
}; };
inline bool operator==(const RoutingOpts& a, const RoutingOpts& b) { inline bool operator==(const RoutingOpts& a, const RoutingOpts& b) {
@ -63,7 +74,8 @@ inline bool operator==(const RoutingOpts& a, const RoutingOpts& b) {
fabs(a.levelPunish[4] - b.levelPunish[4]) < 0.01 && fabs(a.levelPunish[4] - b.levelPunish[4]) < 0.01 &&
fabs(a.levelPunish[5] - b.levelPunish[5]) < 0.01 && fabs(a.levelPunish[5] - b.levelPunish[5]) < 0.01 &&
fabs(a.levelPunish[6] - b.levelPunish[6]) < 0.01 && fabs(a.levelPunish[6] - b.levelPunish[6]) < 0.01 &&
fabs(a.levelPunish[7] - b.levelPunish[7]) < 0.01; fabs(a.levelPunish[7] - b.levelPunish[7]) < 0.01 &&
a.popReachEdge == b.popReachEdge && a.noSelfHops == b.noSelfHops;
} }
struct EdgeCost { struct EdgeCost {
@ -124,6 +136,9 @@ typedef std::unordered_map<const Stop*, trgraph::Node*> FeedStops;
typedef std::vector<NodeCand> NodeCandGroup; typedef std::vector<NodeCand> NodeCandGroup;
typedef std::vector<NodeCandGroup> NodeCandRoute; typedef std::vector<NodeCandGroup> NodeCandRoute;
typedef std::vector<EdgeCand> EdgeCandGroup;
typedef std::vector<EdgeCandGroup> EdgeCandRoute;
typedef std::vector<trgraph::Edge*> EdgeList; typedef std::vector<trgraph::Edge*> EdgeList;
typedef std::vector<trgraph::Node*> NodeList; typedef std::vector<trgraph::Node*> NodeList;
@ -136,6 +151,38 @@ struct EdgeListHop {
typedef std::vector<EdgeListHop> EdgeListHops; typedef std::vector<EdgeListHop> EdgeListHops;
typedef std::set<Route::TYPE> MOTs; typedef std::set<Route::TYPE> MOTs;
inline MOTs motISect(const MOTs& a, const MOTs& b) {
MOTs ret;
for (auto mot : a)
if (b.count(mot)) ret.insert(mot);
return ret;
}
inline pfaedle::router::FeedStops writeMotStops(const pfaedle::gtfs::Feed* feed,
const MOTs mots,
const std::string& tid) {
pfaedle::router::FeedStops ret;
for (auto t : feed->getTrips()) {
if (!tid.empty() && t.getId() != tid) continue;
if (mots.count(t.getRoute()->getType())) {
for (auto st : t.getStopTimes()) ret[st.getStop()] = 0;
}
}
return ret;
}
inline std::string getMotStr(const MOTs& mots) {
bool first = false;
std::string motStr;
for (const auto& mot : mots) {
if (first) motStr += ", ";
motStr += "<" + ad::cppgtfs::gtfs::flat::Route::getTypeString(mot) + ">";
first = true;
}
return motStr;
}
} // namespace router } // namespace router
} // namespace pfaedle } // namespace pfaedle

View file

@ -107,11 +107,14 @@ EdgeCost CostFunc::operator()(const trgraph::Edge* from, const trgraph::Node* n,
// _____________________________________________________________________________ // _____________________________________________________________________________
double CostFunc::transitLineCmp(const trgraph::EdgePL& e) const { double CostFunc::transitLineCmp(const trgraph::EdgePL& e) const {
if (_rAttrs.shortName.empty() && _rAttrs.toString.empty() &&
_rAttrs.fromString.empty())
return 0;
double best = 1; double best = 1;
for (const auto* l : e.getLines()) { for (const auto* l : e.getLines()) {
double cur = _rAttrs.simi(l); double cur = _rAttrs.simi(l);
if (cur < 0.0001) return cur; if (cur < 0.0001) return 0;
if (cur < best) best = cur; if (cur < best) best = cur;
} }
@ -206,10 +209,11 @@ Router::~Router() {
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
bool Router::compConned(const NodeCandGroup& a, const NodeCandGroup& b) const { bool Router::compConned(const EdgeCandGroup& a, const EdgeCandGroup& b) const {
for (auto n1 : a) { for (auto n1 : a) {
for (auto n2 : b) { for (auto n2 : b) {
if (n1.nd->pl().getComp() == n2.nd->pl().getComp()) return true; if (n1.e->getFrom()->pl().getComp() == n2.e->getFrom()->pl().getComp())
return true;
} }
} }
@ -217,7 +221,7 @@ bool Router::compConned(const NodeCandGroup& a, const NodeCandGroup& b) const {
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
HopBand Router::getHopBand(const NodeCandGroup& a, const NodeCandGroup& b, HopBand Router::getHopBand(const EdgeCandGroup& a, const EdgeCandGroup& b,
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts, const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
const osm::Restrictor& rest) const { const osm::Restrictor& rest) const {
assert(a.size()); assert(a.size());
@ -226,8 +230,8 @@ HopBand Router::getHopBand(const NodeCandGroup& a, const NodeCandGroup& b,
double pend = 0; double pend = 0;
for (size_t i = 0; i < a.size(); i++) { for (size_t i = 0; i < a.size(); i++) {
for (size_t j = 0; j < b.size(); j++) { for (size_t j = 0; j < b.size(); j++) {
double d = double d = webMercMeterDist(*a[i].e->getFrom()->pl().getGeom(),
webMercMeterDist(*a[i].nd->pl().getGeom(), *b[j].nd->pl().getGeom()); *b[j].e->getFrom()->pl().getGeom());
if (d > pend) pend = d; if (d > pend) pend = d;
} }
} }
@ -236,23 +240,18 @@ HopBand Router::getHopBand(const NodeCandGroup& a, const NodeCandGroup& b,
const trgraph::StatGroup* tgGrpTo = 0; const trgraph::StatGroup* tgGrpTo = 0;
if (b.begin()->nd->pl().getSI()) if (b.begin()->e->getFrom()->pl().getSI())
tgGrpTo = b.begin()->nd->pl().getSI()->getGroup(); tgGrpTo = b.begin()->e->getFrom()->pl().getSI()->getGroup();
CostFunc costF(rAttrs, rOpts, rest, tgGrpTo, pend * 50); CostFunc costF(rAttrs, rOpts, rest, tgGrpTo, pend * 50);
std::set<trgraph::Edge *> from, to; std::set<trgraph::Edge *> from, to;
// TODO(patrick): test if the two sets share a common connected component for (auto e : a) from.insert(e.e);
for (auto e : b) to.insert(e.e);
for (auto n : a)
from.insert(n.nd->getAdjListOut().begin(), n.nd->getAdjListOut().end());
for (auto n : b)
to.insert(n.nd->getAdjListOut().begin(), n.nd->getAdjListOut().end());
LOG(VDEBUG) << "Doing pilot run between " << from.size() << "->" << to.size() LOG(VDEBUG) << "Doing pilot run between " << from.size() << "->" << to.size()
<< " candidates"; << " edge candidates";
EdgeList el; EdgeList el;
EdgeCost ret = costF.inf(); EdgeCost ret = costF.inf();
@ -282,7 +281,8 @@ HopBand Router::getHopBand(const NodeCandGroup& a, const NodeCandGroup& b,
} }
// TODO(patrick): derive the punish level here automatically // TODO(patrick): derive the punish level here automatically
double maxD = std::max(ret.getValue(), pend * rOpts.levelPunish[2]) * 3; double maxD = std::max(ret.getValue(), pend * rOpts.levelPunish[2]) * 3 +
rOpts.fullTurnPunishFac + rOpts.platformUnmatchedPen;
double minD = ret.getValue(); double minD = ret.getValue();
LOG(VDEBUG) << "Pilot run: min distance between two groups is " LOG(VDEBUG) << "Pilot run: min distance between two groups is "
@ -379,7 +379,15 @@ EdgeListHops Router::routeGreedy2(const NodeCandRoute& route,
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
EdgeListHops Router::route(const NodeCandRoute& route, EdgeListHops Router::route(const EdgeCandRoute& route,
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
const osm::Restrictor& rest) const {
router::Graph cg;
return Router::route(route, rAttrs, rOpts, rest, &cg);
}
// _____________________________________________________________________________
EdgeListHops Router::route(const EdgeCandRoute& route,
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts, const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
const osm::Restrictor& rest, const osm::Restrictor& rest,
router::Graph* cgraph) const { router::Graph* cgraph) const {
@ -393,15 +401,14 @@ EdgeListHops Router::route(const NodeCandRoute& route,
CombNodeMap nextNodes; CombNodeMap nextNodes;
for (size_t i = 0; i < route[0].size(); i++) { for (size_t i = 0; i < route[0].size(); i++) {
for (const auto* e : route[0][i].nd->getAdjListOut()) { auto e = route[0][i].e;
// we can be sure that each edge is exactly assigned to only one // we can be sure that each edge is exactly assigned to only one
// node because the transitgraph is directed // node because the transitgraph is directed
nodes[e] = cgraph->addNd(route[0][i].nd); nodes[e] = cgraph->addNd(route[0][i].e->getFrom());
cgraph->addEdg(source, nodes[e]) cgraph->addEdg(source, nodes[e])
->pl() ->pl()
.setCost(EdgeCost(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, .setCost(EdgeCost(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
route[0][i].pen, 0)); route[0][i].pen, 0));
}
} }
size_t iters = EDijkstra::ITERS; size_t iters = EDijkstra::ITERS;
@ -412,14 +419,11 @@ EdgeListHops Router::route(const NodeCandRoute& route,
HopBand hopBand = getHopBand(route[i], route[i + 1], rAttrs, rOpts, rest); HopBand hopBand = getHopBand(route[i], route[i + 1], rAttrs, rOpts, rest);
const trgraph::StatGroup* tgGrp = 0; const trgraph::StatGroup* tgGrp = 0;
if (route[i + 1].begin()->nd->pl().getSI()) if (route[i + 1].begin()->e->getFrom()->pl().getSI())
tgGrp = route[i + 1].begin()->nd->pl().getSI()->getGroup(); tgGrp = route[i + 1].begin()->e->getFrom()->pl().getSI()->getGroup();
std::set<trgraph::Edge*> froms; std::set<trgraph::Edge*> froms;
for (const auto& fr : route[i]) { for (const auto& fr : route[i]) froms.insert(fr.e);
froms.insert(fr.nd->getAdjListOut().begin(),
fr.nd->getAdjListOut().end());
}
for (auto eFr : froms) { for (auto eFr : froms) {
router::Node* cNodeFr = nodes.find(eFr)->second; router::Node* cNodeFr = nodes.find(eFr)->second;
@ -433,24 +437,22 @@ EdgeListHops Router::route(const NodeCandRoute& route,
assert(route[i + 1].size()); assert(route[i + 1].size());
for (const auto& to : route[i + 1]) { for (const auto& to : route[i + 1]) {
assert(to.nd->getAdjListOut().size()); auto eTo = to.e;
for (auto eTo : to.nd->getAdjListOut()) { tos.insert(eTo);
tos.insert(eTo); if (!nextNodes.count(eTo))
if (!nextNodes.count(eTo)) nextNodes[eTo] = cgraph->addNd(to.nd); nextNodes[eTo] = cgraph->addNd(to.e->getFrom());
if (i == route.size() - 2) cgraph->addEdg(nextNodes[eTo], sink); if (i == route.size() - 2) cgraph->addEdg(nextNodes[eTo], sink);
auto* ce = cgraph->addEdg(cNodeFr, nextNodes[eTo]); edges[eTo] = cgraph->addEdg(cNodeFr, nextNodes[eTo]);
edges[eTo] = ce; pens[eTo] = to.pen;
pens[eTo] = to.pen;
edgeLists[eTo] = ce->pl().getEdges(); edgeLists[eTo] = edges[eTo]->pl().getEdges();
ce->pl().setStartNode(eFr->getFrom()); edges[eTo]->pl().setStartNode(eFr->getFrom());
// for debugging // for debugging
ce->pl().setStartEdge(eFr); edges[eTo]->pl().setStartEdge(eFr);
ce->pl().setEndNode(to.nd); edges[eTo]->pl().setEndNode(to.e->getFrom());
// for debugging // for debugging
ce->pl().setEndEdge(eTo); edges[eTo]->pl().setEndEdge(eTo);
}
} }
size_t iters = EDijkstra::ITERS; size_t iters = EDijkstra::ITERS;
@ -475,7 +477,7 @@ EdgeListHops Router::route(const NodeCandRoute& route,
EdgeCost(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pens[kv.first], 0) + EdgeCost(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pens[kv.first], 0) +
costs[kv.first]); costs[kv.first]);
if (kv.second->pl().getEdges()->size()) { if (rOpts.popReachEdge && kv.second->pl().getEdges()->size()) {
if (kv.second->pl().getEdges() && if (kv.second->pl().getEdges() &&
kv.second->pl().getEdges()->size()) { kv.second->pl().getEdges()->size()) {
// the reach edge is included, but we dont want it in the geometry // the reach edge is included, but we dont want it in the geometry
@ -516,6 +518,30 @@ EdgeListHops Router::route(const NodeCandRoute& route,
return ret; return ret;
} }
// _____________________________________________________________________________
EdgeListHops Router::route(const NodeCandRoute& route,
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
const osm::Restrictor& rest) const {
router::Graph cg;
return Router::route(route, rAttrs, rOpts, rest, &cg);
}
// _____________________________________________________________________________
EdgeListHops Router::route(const NodeCandRoute& route,
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
const osm::Restrictor& rest,
router::Graph* cgraph) const {
EdgeCandRoute r;
for (auto& nCands : route) {
r.emplace_back();
for (auto n : nCands)
for (auto* e : n.nd->getAdjListOut())
r.back().push_back(EdgeCand{e, n.pen});
}
return Router::route(r, rAttrs, rOpts, rest, cgraph);
}
// _____________________________________________________________________________ // _____________________________________________________________________________
void Router::hops(trgraph::Edge* from, const std::set<trgraph::Edge*>& froms, void Router::hops(trgraph::Edge* from, const std::set<trgraph::Edge*>& froms,
const std::set<trgraph::Edge*> tos, const std::set<trgraph::Edge*> tos,
@ -533,7 +559,7 @@ void Router::hops(trgraph::Edge* from, const std::set<trgraph::Edge*>& froms,
for (auto e : cached) { for (auto e : cached) {
// shortcut: if the nodes lie in two different connected components, // shortcut: if the nodes lie in two different connected components,
// the distance between them is trivially infinite // the distance between them is trivially infinite
if (e == from || e->getFrom() == from->getFrom() || if ((rOpts.noSelfHops && (e == from || e->getFrom() == from->getFrom())) ||
from->getFrom()->pl().getComp() != e->getTo()->pl().getComp() || from->getFrom()->pl().getComp() != e->getTo()->pl().getComp() ||
e->pl().oneWay() == 2 || from->pl().oneWay() == 2) { e->pl().oneWay() == 2 || from->pl().oneWay() == 2) {
(*rCosts)[e] = cost.inf(); (*rCosts)[e] = cost.inf();

View file

@ -5,23 +5,23 @@
#ifndef PFAEDLE_ROUTER_ROUTER_H_ #ifndef PFAEDLE_ROUTER_ROUTER_H_
#define PFAEDLE_ROUTER_ROUTER_H_ #define PFAEDLE_ROUTER_ROUTER_H_
#include <mutex> #include <limits>
#include <map> #include <map>
#include <mutex>
#include <set>
#include <string>
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <set> #include "pfaedle/Def.h"
#include <limits>
#include <string>
#include "pfaedle/osm/Restrictor.h" #include "pfaedle/osm/Restrictor.h"
#include "pfaedle/router/Graph.h" #include "pfaedle/router/Graph.h"
#include "pfaedle/router/Misc.h" #include "pfaedle/router/Misc.h"
#include "pfaedle/router/RoutingAttrs.h" #include "pfaedle/router/RoutingAttrs.h"
#include "pfaedle/trgraph/Graph.h" #include "pfaedle/trgraph/Graph.h"
#include "util/geo/Geo.h"
#include "util/graph/Dijkstra.h" #include "util/graph/Dijkstra.h"
#include "util/graph/EDijkstra.h" #include "util/graph/EDijkstra.h"
#include "util/geo/Geo.h"
#include "pfaedle/Def.h"
using util::graph::EDijkstra; using util::graph::EDijkstra;
using util::graph::Dijkstra; using util::graph::Dijkstra;
@ -53,14 +53,12 @@ struct CostFunc
: _rAttrs(rAttrs), : _rAttrs(rAttrs),
_rOpts(rOpts), _rOpts(rOpts),
_res(res), _res(res),
_max(max),
_tgGrp(tgGrp), _tgGrp(tgGrp),
_inf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _max, 0) {} _inf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, max, 0) {}
const RoutingAttrs& _rAttrs; const RoutingAttrs& _rAttrs;
const RoutingOpts& _rOpts; const RoutingOpts& _rOpts;
const osm::Restrictor& _res; const osm::Restrictor& _res;
double _max;
const trgraph::StatGroup* _tgGrp; const trgraph::StatGroup* _tgGrp;
EdgeCost _inf; EdgeCost _inf;
@ -142,6 +140,17 @@ class Router {
// Find the most likely path through the graph for a node candidate route. // Find the most likely path through the graph for a node candidate route.
EdgeListHops route(const NodeCandRoute& route, const RoutingAttrs& rAttrs, EdgeListHops route(const NodeCandRoute& route, const RoutingAttrs& rAttrs,
const RoutingOpts& rOpts,
const osm::Restrictor& rest) const;
EdgeListHops route(const NodeCandRoute& route, const RoutingAttrs& rAttrs,
const RoutingOpts& rOpts, const osm::Restrictor& rest,
router::Graph* cgraph) const;
// Find the most likely path through the graph for an edge candidate route.
EdgeListHops route(const EdgeCandRoute& route, const RoutingAttrs& rAttrs,
const RoutingOpts& rOpts,
const osm::Restrictor& rest) const;
EdgeListHops route(const EdgeCandRoute& route, const RoutingAttrs& rAttrs,
const RoutingOpts& rOpts, const osm::Restrictor& rest, const RoutingOpts& rOpts, const osm::Restrictor& rest,
router::Graph* cgraph) const; router::Graph* cgraph) const;
@ -164,7 +173,7 @@ class Router {
private: private:
mutable std::vector<Cache*> _cache; mutable std::vector<Cache*> _cache;
bool _caching; bool _caching;
HopBand getHopBand(const NodeCandGroup& a, const NodeCandGroup& b, HopBand getHopBand(const EdgeCandGroup& a, const EdgeCandGroup& b,
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts, const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
const osm::Restrictor& rest) const; const osm::Restrictor& rest) const;
@ -187,7 +196,7 @@ class Router {
void nestedCache(const EdgeList* el, const std::set<trgraph::Edge*>& froms, void nestedCache(const EdgeList* el, const std::set<trgraph::Edge*>& froms,
const CostFunc& cost, const RoutingAttrs& rAttrs) const; const CostFunc& cost, const RoutingAttrs& rAttrs) const;
bool compConned(const NodeCandGroup& a, const NodeCandGroup& b) const; bool compConned(const EdgeCandGroup& a, const EdgeCandGroup& b) const;
}; };
} // namespace router } // namespace router
} // namespace pfaedle } // namespace pfaedle

View file

@ -22,19 +22,22 @@ struct RoutingAttrs {
mutable std::map<const TransitEdgeLine*, double> _simiCache; mutable std::map<const TransitEdgeLine*, double> _simiCache;
// carfull: lower return value = higher similarity
double simi(const TransitEdgeLine* line) const { double simi(const TransitEdgeLine* line) const {
auto i = _simiCache.find(line); auto i = _simiCache.find(line);
if (i != _simiCache.end()) return i->second; if (i != _simiCache.end()) return i->second;
double cur = 1; double cur = 1;
if (router::lineSimi(line->shortName, shortName) > 0.5) cur -= 0.33; if (shortName.empty() || router::lineSimi(line->shortName, shortName) > 0.5)
cur -= 0.333333333;
if (line->toStr.empty() || router::statSimi(line->toStr, toString) > 0.5) if (toString.empty() || line->toStr.empty() ||
cur -= 0.33; router::statSimi(line->toStr, toString) > 0.5)
cur -= 0.333333333;
if (line->fromStr.empty() || if (fromString.empty() || line->fromStr.empty() ||
router::statSimi(line->fromStr, fromString) > 0.5) router::statSimi(line->fromStr, fromString) > 0.5)
cur -= 0.33; cur -= 0.333333333;
_simiCache[line] = cur; _simiCache[line] = cur;

View file

@ -54,43 +54,27 @@ using ad::cppgtfs::gtfs::ShapePoint;
// _____________________________________________________________________________ // _____________________________________________________________________________
ShapeBuilder::ShapeBuilder(Feed* feed, ad::cppgtfs::gtfs::Feed* evalFeed, ShapeBuilder::ShapeBuilder(Feed* feed, ad::cppgtfs::gtfs::Feed* evalFeed,
MOTs mots, const config::MotConfig& motCfg, MOTs mots, const config::MotConfig& motCfg,
eval::Collector* ecoll, const config::Config& cfg) eval::Collector* ecoll, pfaedle::trgraph::Graph* g,
router::FeedStops* fStops, osm::Restrictor* restr,
const config::Config& cfg)
: _feed(feed), : _feed(feed),
_evalFeed(evalFeed), _evalFeed(evalFeed),
_mots(mots), _mots(mots),
_motCfg(motCfg), _motCfg(motCfg),
_ecoll(ecoll), _ecoll(ecoll),
_cfg(cfg), _cfg(cfg),
_g(g),
_crouter(omp_get_num_procs(), cfg.useCaching), _crouter(omp_get_num_procs(), cfg.useCaching),
_curShpCnt(0) { _stops(fStops),
_curShpCnt(0),
_restr(restr) {
_numThreads = _crouter.getCacheNumber(); _numThreads = _crouter.getCacheNumber();
writeMotStops();
buildGraph();
} }
// _____________________________________________________________________________
void ShapeBuilder::writeMotStops() {
for (auto t : _feed->getTrips()) {
if (!_cfg.shapeTripId.empty() && t.getId() != _cfg.shapeTripId) continue;
if (_mots.count(t.getRoute()->getType()) &&
_motCfg.mots.count(t.getRoute()->getType())) {
for (auto st : t.getStopTimes()) {
_stops[st.getStop()] = 0;
}
}
}
}
// _____________________________________________________________________________
FeedStops* ShapeBuilder::getFeedStops() { return &_stops; }
// _____________________________________________________________________________ // _____________________________________________________________________________
const NodeCandGroup& ShapeBuilder::getNodeCands(const Stop* s) const { const NodeCandGroup& ShapeBuilder::getNodeCands(const Stop* s) const {
if (_stops.find(s) == _stops.end() || _stops.at(s) == 0) { if (_stops->find(s) == _stops->end() || _stops->at(s) == 0) return _emptyNCG;
return _emptyNCG; return _stops->at(s)->pl().getSI()->getGroup()->getNodeCands(s);
}
return _stops.at(s)->pl().getSI()->getGroup()->getNodeCands(s);
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
@ -138,7 +122,7 @@ EdgeListHops ShapeBuilder::route(const router::NodeCandRoute& ncr,
if (_cfg.solveMethod == "global") { if (_cfg.solveMethod == "global") {
const router::EdgeListHops& ret = const router::EdgeListHops& ret =
_crouter.route(ncr, rAttrs, _motCfg.routingOpts, _restr, &g); _crouter.route(ncr, rAttrs, _motCfg.routingOpts, *_restr, &g);
// write combination graph // write combination graph
if (!_cfg.shapeTripId.empty() && _cfg.writeCombGraph) { if (!_cfg.shapeTripId.empty() && _cfg.writeCombGraph) {
@ -150,9 +134,9 @@ EdgeListHops ShapeBuilder::route(const router::NodeCandRoute& ncr,
return ret; return ret;
} else if (_cfg.solveMethod == "greedy") { } else if (_cfg.solveMethod == "greedy") {
return _crouter.routeGreedy(ncr, rAttrs, _motCfg.routingOpts, _restr); return _crouter.routeGreedy(ncr, rAttrs, _motCfg.routingOpts, *_restr);
} else if (_cfg.solveMethod == "greedy2") { } else if (_cfg.solveMethod == "greedy2") {
return _crouter.routeGreedy2(ncr, rAttrs, _motCfg.routingOpts, _restr); return _crouter.routeGreedy2(ncr, rAttrs, _motCfg.routingOpts, *_restr);
} else { } else {
LOG(ERROR) << "Unknown solution method " << _cfg.solveMethod; LOG(ERROR) << "Unknown solution method " << _cfg.solveMethod;
exit(1); exit(1);
@ -228,15 +212,6 @@ void ShapeBuilder::shape(pfaedle::netgraph::Graph* ng) {
LOG(INFO) << "@ " << j << " / " << clusters.size() << " (" LOG(INFO) << "@ " << j << " / " << clusters.size() << " ("
<< (static_cast<int>((j * 1.0) / clusters.size() * 100)) << (static_cast<int>((j * 1.0) / clusters.size() * 100))
<< "%, " << (EDijkstra::ITERS - oiters) << " iters, " << "%, " << (EDijkstra::ITERS - oiters) << " iters, "
/**
TODO: this is actually misleading. We are counting the
Dijkstra iterations, but measuring them against
the total running time (including all overhead + HMM solve)
<< tput "
<< (static_cast<double>(EDijkstra::ITERS - oiters)) /
TOOK(t1, TIME())
<< " iters/ms, "
**/
<< "matching " << (10.0 / (TOOK(t1, TIME()) / 1000)) << "matching " << (10.0 / (TOOK(t1, TIME()) / 1000))
<< " trips/sec)"; << " trips/sec)";
@ -259,13 +234,13 @@ void ShapeBuilder::shape(pfaedle::netgraph::Graph* ng) {
const ad::cppgtfs::gtfs::Shape& shp = const ad::cppgtfs::gtfs::Shape& shp =
getGtfsShape(cshp, clusters[i][0], &distances); getGtfsShape(cshp, clusters[i][0], &distances);
LOG(DEBUG) << "Took " << EDijkstra::ITERS - iters << " iterations."; LOG(VDEBUG) << "Took " << EDijkstra::ITERS - iters << " iterations.";
iters = EDijkstra::ITERS; iters = EDijkstra::ITERS;
totNumTrips += clusters[i].size(); totNumTrips += clusters[i].size();
for (auto t : clusters[i]) { for (auto t : clusters[i]) {
if (_cfg.evaluate) { if (_cfg.evaluate && _evalFeed && _ecoll) {
_ecoll->add(t, _evalFeed->getShapes().get(t->getShape()), shp, _ecoll->add(t, _evalFeed->getShapes().get(t->getShape()), shp,
distances); distances);
} }
@ -472,27 +447,6 @@ void ShapeBuilder::getGtfsBox(const Feed* feed, const MOTs& mots,
} }
} }
// _____________________________________________________________________________
void ShapeBuilder::buildGraph() {
osm::OsmBuilder osmBuilder;
osm::BBoxIdx box(BOX_PADDING);
getGtfsBox(_feed, _mots, _cfg.shapeTripId, _cfg.dropShapes, &box);
osmBuilder.read(_cfg.osmPath, _motCfg.osmBuildOpts, &_g, box, _cfg.gridSize,
getFeedStops(), &_restr);
for (auto& feedStop : *getFeedStops()) {
if (feedStop.second) {
feedStop.second->pl().getSI()->getGroup()->writePens(
_motCfg.osmBuildOpts.trackNormzer,
_motCfg.routingOpts.platformUnmatchedPen,
_motCfg.routingOpts.stationDistPenFactor,
_motCfg.routingOpts.nonOsmPen);
}
}
}
// _____________________________________________________________________________ // _____________________________________________________________________________
NodeCandRoute ShapeBuilder::getNCR(Trip* trip) const { NodeCandRoute ShapeBuilder::getNCR(Trip* trip) const {
router::NodeCandRoute ncr(trip->getStopTimes().size()); router::NodeCandRoute ncr(trip->getStopTimes().size());
@ -613,14 +567,14 @@ bool ShapeBuilder::routingEqual(Trip* a, Trip* b) {
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
const pfaedle::trgraph::Graph* ShapeBuilder::getGraph() const { return &_g; } const pfaedle::trgraph::Graph* ShapeBuilder::getGraph() const { return _g; }
// _____________________________________________________________________________ // _____________________________________________________________________________
void ShapeBuilder::writeTransitGraph(const Shape& shp, TrGraphEdgs* edgs, void ShapeBuilder::writeTransitGraph(const Shape& shp, TrGraphEdgs* edgs,
const Cluster& cluster) const { const Cluster& cluster) const {
for (auto hop : shp.hops) { for (auto hop : shp.hops) {
for (const auto* e : hop.edges) { for (const auto* e : hop.edges) {
if (e->pl().isRev()) e = _g.getEdg(e->getTo(), e->getFrom()); if (e->pl().isRev()) e = _g->getEdg(e->getTo(), e->getFrom());
(*edgs)[e].insert(cluster.begin(), cluster.end()); (*edgs)[e].insert(cluster.begin(), cluster.end());
} }
} }

View file

@ -51,7 +51,8 @@ class ShapeBuilder {
public: public:
ShapeBuilder(Feed* feed, ad::cppgtfs::gtfs::Feed* evalFeed, MOTs mots, ShapeBuilder(Feed* feed, ad::cppgtfs::gtfs::Feed* evalFeed, MOTs mots,
const config::MotConfig& motCfg, eval::Collector* ecoll, const config::MotConfig& motCfg, eval::Collector* ecoll,
const config::Config& cfg); trgraph::Graph* g, router::FeedStops* stops,
osm::Restrictor* restr, const config::Config& cfg);
void shape(pfaedle::netgraph::Graph* ng); void shape(pfaedle::netgraph::Graph* ng);
@ -79,10 +80,10 @@ class ShapeBuilder {
config::MotConfig _motCfg; config::MotConfig _motCfg;
eval::Collector* _ecoll; eval::Collector* _ecoll;
config::Config _cfg; config::Config _cfg;
trgraph::Graph _g; trgraph::Graph* _g;
router::Router _crouter; router::Router _crouter;
router::FeedStops _stops; router::FeedStops* _stops;
NodeCandGroup _emptyNCG; NodeCandGroup _emptyNCG;
@ -92,10 +93,9 @@ class ShapeBuilder {
TripRAttrs _rAttrs; TripRAttrs _rAttrs;
osm::Restrictor _restr; osm::Restrictor* _restr;
void writeMotStops(); void buildGraph(router::FeedStops* fStops);
void buildGraph();
Clusters clusterTrips(Feed* f, MOTs mots); Clusters clusterTrips(Feed* f, MOTs mots);
void writeTransitGraph(const Shape& shp, TrGraphEdgs* edgs, void writeTransitGraph(const Shape& shp, TrGraphEdgs* edgs,

View file

@ -129,6 +129,12 @@ util::json::Dict NodePL::getAttrs() const {
obj["station_group"] = obj["station_group"] =
std::to_string(reinterpret_cast<size_t>(_si->getGroup())); std::to_string(reinterpret_cast<size_t>(_si->getGroup()));
#ifdef PFAEDLE_STATION_IDS
// only print this in debug mode
obj["station_id"] = _si->getId();
#endif
std::stringstream gtfsIds; std::stringstream gtfsIds;
if (_si->getGroup()) { if (_si->getGroup()) {
for (auto* s : _si->getGroup()->getStops()) { for (auto* s : _si->getGroup()->getStops()) {

View file

@ -22,6 +22,9 @@ StatInfo::StatInfo(const StatInfo& si)
_fromOsm(si._fromOsm), _fromOsm(si._fromOsm),
_group(0) { _group(0) {
setGroup(si._group); setGroup(si._group);
#ifdef PFAEDLE_STATION_IDS
_id = si._id;
#endif
} }
// _____________________________________________________________________________ // _____________________________________________________________________________

View file

@ -55,6 +55,11 @@ class StatInfo {
// Set this stop as coming from osm // Set this stop as coming from osm
void setIsFromOsm(bool is); void setIsFromOsm(bool is);
#ifdef PFAEDLE_STATION_IDS
const std::string& getId() const { return _id; }
void setId(const std::string& id) { _id = id; }
#endif
private: private:
std::string _name; std::string _name;
std::vector<std::string> _altNames; std::vector<std::string> _altNames;
@ -62,6 +67,12 @@ class StatInfo {
bool _fromOsm; bool _fromOsm;
StatGroup* _group; StatGroup* _group;
#ifdef PFAEDLE_STATION_IDS
// debug feature to store station ids from both OSM
// and GTFS
std::string _id;
#endif
static std::unordered_map<const StatGroup*, size_t> _groups; static std::unordered_map<const StatGroup*, size_t> _groups;
static void unRefGroup(StatGroup* g); static void unRefGroup(StatGroup* g);
}; };

View file

@ -7,6 +7,7 @@
#include <cmath> #include <cmath>
#include <chrono> #include <chrono>
#include <sstream>
#define UNUSED(expr) do { (void)(expr); } while (0) #define UNUSED(expr) do { (void)(expr); } while (0)
#define TIME() std::chrono::high_resolution_clock::now() #define TIME() std::chrono::high_resolution_clock::now()
@ -39,10 +40,18 @@ inline uint64_t atoul(const char* p) {
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
inline float atof(const char* p, uint8_t mn) { inline bool isFloatingPoint(const std::string& str) {
std::stringstream ss(str);
double f;
ss >> std::noskipws >> f;
return ss.eof() && ! ss.fail();
}
// _____________________________________________________________________________
inline double atof(const char* p, uint8_t mn) {
// this atof implementation works only on "normal" float strings like // this atof implementation works only on "normal" float strings like
// 56.445 or -345.00, but should be faster than std::atof // 56.445 or -345.00, but should be faster than std::atof
float ret = 0.0; double ret = 0.0;
bool neg = false; bool neg = false;
if (*p == '-') { if (*p == '-') {
neg = true; neg = true;
@ -56,14 +65,14 @@ inline float atof(const char* p, uint8_t mn) {
if (*p == '.') { if (*p == '.') {
p++; p++;
float f = 0; double f = 0;
uint8_t n = 0; uint8_t n = 0;
for (; n < mn && *p >= '0' && *p <= '9'; n++, p++) { for (; n < mn && *p >= '0' && *p <= '9'; n++, p++) {
f = f * 10.0 + (*p - '0'); f = f * 10.0 + (*p - '0');
} }
if (n < 11) if (n < 10)
ret += f / pow10[n]; ret += f / pow10[n];
else else
ret += f / std::pow(10, n); ret += f / std::pow(10, n);

View file

@ -175,6 +175,18 @@ inline size_t prefixEditDist(const std::string& prefix, const std::string& s) {
return prefixEditDist(prefix, s, s.size()); return prefixEditDist(prefix, s, s.size());
} }
// _____________________________________________________________________________
inline std::string toUpper(std::string str) {
std::transform(str.begin(), str.end(),str.begin(), toupper);
return str;
}
// _____________________________________________________________________________
inline std::string toLower(std::string str) {
std::transform(str.begin(), str.end(),str.begin(), tolower);
return str;
}
// _____________________________________________________________________________ // _____________________________________________________________________________
template <class Iter> template <class Iter>
inline std::string implode(Iter begin, const Iter& end, const char* del) { inline std::string implode(Iter begin, const Iter& end, const char* del) {
@ -190,6 +202,25 @@ inline std::string implode(Iter begin, const Iter& end, const char* del) {
return ss.str(); return ss.str();
} }
// _____________________________________________________________________________
inline std::string normalizeWhiteSpace(const std::string& input) {
std::string ret;
bool ws = false;
for (size_t i = 0; i < input.size(); i++) {
if (std::isspace(input[i])) {
if (!ws) {
ret += " ";
ws = true;
}
continue;
} else {
ws = false;
ret += input[i];
}
}
return ret;
}
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename T> template <typename T>
inline std::string implode(const std::vector<T>& vec, const char* del) { inline std::string implode(const std::vector<T>& vec, const char* del) {

View file

@ -13,6 +13,7 @@
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include "util/Misc.h" #include "util/Misc.h"
#include "util/String.h"
#include "util/geo/Box.h" #include "util/geo/Box.h"
#include "util/geo/Line.h" #include "util/geo/Line.h"
#include "util/geo/Point.h" #include "util/geo/Point.h"
@ -734,6 +735,45 @@ inline double dist(const Point<T>& p1, const Point<T>& p2) {
return dist(p1.getX(), p1.getY(), p2.getX(), p2.getY()); return dist(p1.getX(), p1.getY(), p2.getX(), p2.getY());
} }
// _____________________________________________________________________________
template <typename T>
inline Point<T> pointFromWKT(std::string wkt) {
wkt = util::normalizeWhiteSpace(util::trim(wkt));
if (wkt.rfind("POINT") == 0 || wkt.rfind("MPOINT") == 0) {
size_t b = wkt.find("(") + 1;
size_t e = wkt.find(")", b);
if (b > e) throw std::runtime_error("Could not parse WKT");
auto xy = util::split(util::trim(wkt.substr(b, e - b)), ' ');
if (xy.size() < 2) throw std::runtime_error("Could not parse WKT");
double x = atof(xy[0].c_str());
double y = atof(xy[1].c_str());
return Point<T>(x, y);
}
throw std::runtime_error("Could not parse WKT");
}
// _____________________________________________________________________________
template <typename T>
inline Line<T> lineFromWKT(std::string wkt) {
wkt = util::normalizeWhiteSpace(util::trim(wkt));
if (wkt.rfind("LINESTRING") == 0 || wkt.rfind("MLINESTRING") == 0) {
Line<T> ret;
size_t b = wkt.find("(") + 1;
size_t e = wkt.find(")", b);
if (b > e) throw std::runtime_error("Could not parse WKT");
auto pairs = util::split(wkt.substr(b, e - b), ',');
for (const auto& p : pairs) {
auto xy = util::split(util::trim(p), ' ');
if (xy.size() < 2) throw std::runtime_error("Could not parse WKT");
double x = atof(xy[0].c_str());
double y = atof(xy[1].c_str());
ret.push_back({x, y});
}
return ret;
}
throw std::runtime_error("Could not parse WKT");
}
// _____________________________________________________________________________ // _____________________________________________________________________________
template <typename T> template <typename T>
inline std::string getWKT(const Point<T>& p) { inline std::string getWKT(const Point<T>& p) {
@ -1479,6 +1519,24 @@ inline double webMercMeterDist(const G1& a, const G2& b) {
return util::geo::dist(a, b) * cos((latA + latB) / 2.0); return util::geo::dist(a, b) * cos((latA + latB) / 2.0);
} }
// _____________________________________________________________________________
template <typename T>
inline double webMercLen(const Line<T>& g) {
double ret = 0;
for (size_t i = 1; i < g.size(); i++) ret += webMercMeterDist(g[i - 1], g[i]);
return ret;
}
// _____________________________________________________________________________
template <typename G>
inline double webMercDistFactor(const G& a) {
// euclidean distance on web mercator is in meters on equator,
// and proportional to cos(lat) in both y directions
double lat = 2 * atan(exp(a.getY() / 6378137.0)) - 1.5707965;
return cos(lat);
}
} }
} }

View file

@ -11,9 +11,6 @@
#include "util/geo/output/GeoJsonOutput.h" #include "util/geo/output/GeoJsonOutput.h"
#include "util/graph/Graph.h" #include "util/graph/Graph.h"
using util::toString;
using util::graph::Graph;
namespace util { namespace util {
namespace geo { namespace geo {
namespace output { namespace output {
@ -22,7 +19,7 @@ class GeoGraphJsonOutput {
public: public:
inline GeoGraphJsonOutput(){}; inline GeoGraphJsonOutput(){};
template <typename N, typename E> template <typename N, typename E>
void print(const Graph<N, E>& outG, std::ostream& str); void print(const util::graph::Graph<N, E>& outG, std::ostream& str);
private: private:
template <typename T> template <typename T>

View file

@ -22,10 +22,10 @@ void GeoGraphJsonOutput::print(const util::graph::Graph<N, E>& outG,
for (util::graph::Node<N, E>* n : outG.getNds()) { for (util::graph::Node<N, E>* n : outG.getNds()) {
if (!n->pl().getGeom()) continue; if (!n->pl().getGeom()) continue;
json::Dict props{{"id", toString(n)}, json::Dict props{{"id", util::toString(n)},
{"deg", toString(n->getDeg())}, {"deg", util::toString(n->getDeg())},
{"deg_out", toString(n->getOutDeg())}, {"deg_out", util::toString(n->getOutDeg())},
{"deg_in", toString(n->getInDeg())}}; {"deg_in", util::toString(n->getInDeg())}};
auto addProps = n->pl().getAttrs(); auto addProps = n->pl().getAttrs();
props.insert(addProps.begin(), addProps.end()); props.insert(addProps.begin(), addProps.end());
@ -38,9 +38,9 @@ void GeoGraphJsonOutput::print(const util::graph::Graph<N, E>& outG,
for (graph::Edge<N, E>* e : n->getAdjListOut()) { for (graph::Edge<N, E>* e : n->getAdjListOut()) {
// to avoid double output for undirected graphs // to avoid double output for undirected graphs
if (e->getFrom() != n) continue; if (e->getFrom() != n) continue;
json::Dict props{{"from", toString(e->getFrom())}, json::Dict props{{"from", util::toString(e->getFrom())},
{"to", toString(e->getTo())}, {"to", util::toString(e->getTo())},
{"id", toString(e)}}; {"id", util::toString(e)}};
auto addProps = e->pl().getAttrs(); auto addProps = e->pl().getAttrs();
props.insert(addProps.begin(), addProps.end()); props.insert(addProps.begin(), addProps.end());

View file

@ -17,9 +17,18 @@ GeoJsonOutput::GeoJsonOutput(std::ostream& str) : _wr(&str, 10, true) {
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
GeoJsonOutput::~GeoJsonOutput() { GeoJsonOutput::GeoJsonOutput(std::ostream& str, json::Val attrs)
flush(); : _wr(&str, 10, true) {
_wr.obj();
_wr.keyVal("type", "FeatureCollection");
_wr.key("properties");
_wr.val(attrs);
_wr.key("features");
_wr.arr();
} }
// _____________________________________________________________________________
GeoJsonOutput::~GeoJsonOutput() { flush(); }
// _____________________________________________________________________________ // _____________________________________________________________________________
void GeoJsonOutput::flush() { _wr.closeAll(); } void GeoJsonOutput::flush() { _wr.closeAll(); }

View file

@ -19,6 +19,7 @@ namespace output {
class GeoJsonOutput { class GeoJsonOutput {
public: public:
GeoJsonOutput(std::ostream& str); GeoJsonOutput(std::ostream& str);
GeoJsonOutput(std::ostream& str, json::Val attrs);
~GeoJsonOutput(); ~GeoJsonOutput();
template <typename T> template <typename T>
void print(const Point<T>& p, json::Val attrs); void print(const Point<T>& p, json::Val attrs);

View file

@ -1001,9 +1001,82 @@ CASE("nullable") {
} }
}}, }},
// ___________________________________________________________________________
{
CASE("geomwkt") {
auto p = pointFromWKT<double>("POINT(10 50)");
EXPECT(p.getX() == approx(10));
EXPECT(p.getY() == approx(50));
p = pointFromWKT<double>("POINT( 10 50)");
EXPECT(p.getX() == approx(10));
EXPECT(p.getY() == approx(50));
p = pointFromWKT<double>("POINT (10 50 30)");
EXPECT(p.getX() == approx(10));
EXPECT(p.getY() == approx(50));
p = pointFromWKT<double>("POINT (10 50 30)");
EXPECT(p.getX() == approx(10));
EXPECT(p.getY() == approx(50));
p = pointFromWKT<double>("POINT(10 50 30)");
EXPECT(p.getX() == approx(10));
EXPECT(p.getY() == approx(50));
p = pointFromWKT<double>("POINT (10 50) ");
EXPECT(p.getX() == approx(10));
EXPECT(p.getY() == approx(50));
p = pointFromWKT<double>("MPOINT(10 50 30)");
EXPECT(p.getX() == approx(10));
EXPECT(p.getY() == approx(50));
p = pointFromWKT<double>("MPOINT(10 50)");
EXPECT(p.getX() == approx(10));
EXPECT(p.getY() == approx(50));
p = pointFromWKT<double>("POINT(10.05 50.05)");
EXPECT(p.getX() == approx(10.05));
EXPECT(p.getY() == approx(50.05));
auto wktl = lineFromWKT<double>("LINESTRING(0 0, 1 1,2 3, 0 1)");
EXPECT(wktl.size() == (size_t)4);
EXPECT(wktl[0].getX() == approx(0));
EXPECT(wktl[0].getY() == approx(0));
EXPECT(wktl[1].getX() == approx(1));
EXPECT(wktl[1].getY() == approx(1));
EXPECT(wktl[2].getX() == approx(2));
EXPECT(wktl[2].getY() == approx(3));
EXPECT(wktl[3].getX() == approx(0));
EXPECT(wktl[3].getY() == approx(1));
wktl = lineFromWKT<double>("MLINESTRING(0 0, 1 1,2 3, 0 1)");
EXPECT(wktl.size() == (size_t)4);
EXPECT(wktl[0].getX() == approx(0));
EXPECT(wktl[0].getY() == approx(0));
EXPECT(wktl[1].getX() == approx(1));
EXPECT(wktl[1].getY() == approx(1));
EXPECT(wktl[2].getX() == approx(2));
EXPECT(wktl[2].getY() == approx(3));
EXPECT(wktl[3].getX() == approx(0));
EXPECT(wktl[3].getY() == approx(1));
wktl = lineFromWKT<double>("MLINESTRING (0 0, 1 1,2 3, 0 1 )");
EXPECT(wktl.size() == (size_t)4);
EXPECT(wktl[0].getX() == approx(0));
EXPECT(wktl[0].getY() == approx(0));
EXPECT(wktl[1].getX() == approx(1));
EXPECT(wktl[1].getY() == approx(1));
EXPECT(wktl[2].getX() == approx(2));
EXPECT(wktl[2].getY() == approx(3));
EXPECT(wktl[3].getX() == approx(0));
EXPECT(wktl[3].getY() == approx(1));
}},
// ___________________________________________________________________________ // ___________________________________________________________________________
{ {
CASE("geometry") { CASE("geometry") {
geo::Point<double> a(1, 2); geo::Point<double> a(1, 2);
geo::Point<double> b(2, 3); geo::Point<double> b(2, 3);
geo::Point<double> c(4, 5); geo::Point<double> c(4, 5);