refactoring
This commit is contained in:
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
|
|
@ -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(>fs[0], usedMots, cfg.shapeTripId);
|
||||||
|
|
||||||
|
pfaedle::osm::Restrictor restr;
|
||||||
|
pfaedle::trgraph::Graph graph;
|
||||||
|
pfaedle::osm::OsmBuilder osmBuilder;
|
||||||
|
|
||||||
|
pfaedle::osm::BBoxIdx box(BOX_PADDING);
|
||||||
|
ShapeBuilder::getGtfsBox(>fs[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(>fs[0], &evalFeed, cmdCfgMots, motCfg, &ecoll,
|
ShapeBuilder shapeBuilder(>fs[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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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() << ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
// _____________________________________________________________________________
|
// _____________________________________________________________________________
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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(); }
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue