clean up and refactor half-baked development commits and squash them into a new version.
Changes: * support for multiple GTFS feeds as input in filtering, read default global and local configuration files * be a bit more memory conservative * make caching optional * dont delete orphan edge if it would transform a degree 3 node with a possible full turn into a degree 2 node eligible for contraction * dedicated filters for funicular and gondola * make max snap level option more intuitive * allow filter rules for level 0 * additional fallback for station snapping * dont try to route for MOT unequal to trip in -T mode, force-snap to orphaned OSM station if not snap was possible * write bounds to filtered osm * remove unused surrounding heuristic * use bus lanes info * be a bit more tolerant for bus oneway streets * create missing directories * error if no cfg is present, clean up evaluation Makefile
This commit is contained in:
parent
2cc2d2dc23
commit
63f0b61ea1
60 changed files with 4532 additions and 1576 deletions
|
|
@ -25,4 +25,6 @@
|
|||
#define BOX util::geo::Box<PFAEDLE_PRECISION>
|
||||
#define POLYLINE util::geo::PolyLine<PFAEDLE_PRECISION>
|
||||
|
||||
#define BOX_PADDING 2500
|
||||
|
||||
#endif // PFAEDLE_DEF_H_
|
||||
|
|
|
|||
|
|
@ -2,19 +2,25 @@
|
|||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#include <limits.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "ad/cppgtfs/Parser.h"
|
||||
#include "ad/cppgtfs/Writer.h"
|
||||
#include "ad/cppgtfs/gtfs/Feed.h"
|
||||
#include "pfaedle/config/ConfigReader.h"
|
||||
#include "pfaedle/config/MotConfig.h"
|
||||
#include "pfaedle/config/MotConfigReader.h"
|
||||
#include "pfaedle/eval/Collector.h"
|
||||
#include "pfaedle/gtfs/Feed.h"
|
||||
#include "pfaedle/gtfs/Writer.h"
|
||||
#include "pfaedle/netgraph/Graph.h"
|
||||
#include "pfaedle/osm/OsmIdSet.h"
|
||||
#include "pfaedle/router/ShapeBuilder.h"
|
||||
|
|
@ -30,13 +36,28 @@ using pfaedle::osm::OsmBuilder;
|
|||
using pfaedle::config::MotConfig;
|
||||
using pfaedle::config::Config;
|
||||
using pfaedle::router::ShapeBuilder;
|
||||
using configparser::ParseFileExc;
|
||||
using pfaedle::config::MotConfigReader;
|
||||
using pfaedle::config::ConfigReader;
|
||||
using pfaedle::eval::Collector;
|
||||
|
||||
enum class RetCode {
|
||||
SUCCESS = 0,
|
||||
NO_INPUT_FEED = 1,
|
||||
MULT_FEEDS_NOT_ALWD = 2,
|
||||
TRIP_NOT_FOUND = 3,
|
||||
GTFS_PARSE_ERR = 4,
|
||||
NO_OSM_INPUT = 5,
|
||||
MOT_CFG_PARSE_ERR = 6,
|
||||
OSM_PARSE_ERR = 7,
|
||||
GTFS_WRITE_ERR = 8,
|
||||
NO_MOT_CFG = 9
|
||||
};
|
||||
|
||||
std::string getMotStr(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);
|
||||
|
||||
// _____________________________________________________________________________
|
||||
int main(int argc, char** argv) {
|
||||
|
|
@ -52,44 +73,90 @@ int main(int argc, char** argv) {
|
|||
ConfigReader cr;
|
||||
cr.read(&cfg, argc, argv);
|
||||
|
||||
ad::cppgtfs::gtfs::Feed gtfs;
|
||||
std::vector<pfaedle::gtfs::Feed> gtfs(cfg.feedPaths.size());
|
||||
// feed containing the shapeas in memory for evaluation
|
||||
ad::cppgtfs::gtfs::Feed evalFeed;
|
||||
|
||||
motCfgReader.parse(cfg.configPaths);
|
||||
std::vector<std::string> cfgPaths = getCfgPaths(cfg);
|
||||
|
||||
if (cfg.osmPath.empty()) {
|
||||
try {
|
||||
motCfgReader.parse(cfgPaths);
|
||||
} catch (configparser::ParseExc ex) {
|
||||
LOG(ERROR) << "Could not parse MOT configurations, reason was:";
|
||||
std::cerr << ex.what() << std::endl;
|
||||
exit(static_cast<int>(RetCode::MOT_CFG_PARSE_ERR));
|
||||
}
|
||||
|
||||
if (cfg.osmPath.empty() && !cfg.writeOverpass) {
|
||||
std::cerr << "No OSM input file specified (-x), see --help." << std::endl;
|
||||
exit(5);
|
||||
exit(static_cast<int>(RetCode::NO_OSM_INPUT));
|
||||
}
|
||||
|
||||
if (motCfgReader.getConfigs().size() == 0) {
|
||||
LOG(ERROR) << "No MOT configurations specified and no implicit "
|
||||
"configurations found, see --help.";
|
||||
exit(static_cast<int>(RetCode::NO_MOT_CFG));
|
||||
}
|
||||
|
||||
if (cfg.feedPaths.size() == 1) {
|
||||
LOG(INFO) << "Reading " << cfg.feedPaths[0] << " ...";
|
||||
ad::cppgtfs::Parser p;
|
||||
p.parse(>fs, cfg.feedPaths[0]);
|
||||
LOG(INFO) << "Done.";
|
||||
if (cfg.inPlace) cfg.outputPath = cfg.feedPaths[0];
|
||||
if (!cfg.writeOverpass)
|
||||
LOG(INFO) << "Reading " << cfg.feedPaths[0] << " ...";
|
||||
try {
|
||||
ad::cppgtfs::Parser p;
|
||||
p.parse(>fs[0], cfg.feedPaths[0]);
|
||||
if (cfg.evaluate) {
|
||||
// read the shapes and store them in memory
|
||||
p.parseShapes(&evalFeed, cfg.feedPaths[0]);
|
||||
}
|
||||
} catch (ad::cppgtfs::ParserException ex) {
|
||||
LOG(ERROR) << "Could not parse input GTFS feed, reason was:";
|
||||
std::cerr << ex.what() << std::endl;
|
||||
exit(static_cast<int>(RetCode::GTFS_PARSE_ERR));
|
||||
}
|
||||
if (!cfg.writeOverpass) LOG(INFO) << "Done.";
|
||||
} else if (cfg.writeOsm.size() || cfg.writeOverpass) {
|
||||
for (size_t i = 0; i < cfg.feedPaths.size(); i++) {
|
||||
if (!cfg.writeOverpass)
|
||||
LOG(INFO) << "Reading " << cfg.feedPaths[i] << " ...";
|
||||
ad::cppgtfs::Parser p;
|
||||
try {
|
||||
p.parse(>fs[i], cfg.feedPaths[i]);
|
||||
} catch (ad::cppgtfs::ParserException ex) {
|
||||
LOG(ERROR) << "Could not parse input GTFS feed, reason was:";
|
||||
std::cerr << ex.what() << std::endl;
|
||||
exit(static_cast<int>(RetCode::GTFS_PARSE_ERR));
|
||||
}
|
||||
if (!cfg.writeOverpass) LOG(INFO) << "Done.";
|
||||
}
|
||||
} else if (cfg.feedPaths.size() > 1) {
|
||||
std::cerr << "Maximally one input feed allowed." << std::endl;
|
||||
exit(2);
|
||||
std::cerr << "Multiple feeds only allowed in filter mode." << std::endl;
|
||||
exit(static_cast<int>(RetCode::MULT_FEEDS_NOT_ALWD));
|
||||
}
|
||||
|
||||
LOG(DEBUG) << "Read " << motCfgReader.getConfigs().size()
|
||||
<< " unique MOT configs.";
|
||||
MOTs cmdCfgMots = cfg.mots;
|
||||
ad::cppgtfs::gtfs::Trip* singleTrip = 0;
|
||||
pfaedle::gtfs::Trip* singleTrip = 0;
|
||||
|
||||
if (cfg.shapeTripId.size()) {
|
||||
singleTrip = gtfs.getTrips().get(cfg.shapeTripId);
|
||||
if (!cfg.feedPaths.size()) {
|
||||
std::cout << "No input feed specified, see --help" << std::endl;
|
||||
exit(static_cast<int>(RetCode::NO_INPUT_FEED));
|
||||
}
|
||||
singleTrip = gtfs[0].getTrips().get(cfg.shapeTripId);
|
||||
if (!singleTrip) {
|
||||
LOG(ERROR) << "Trip #" << cfg.shapeTripId << " not found.";
|
||||
exit(3);
|
||||
exit(static_cast<int>(RetCode::TRIP_NOT_FOUND));
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.writeOsm.size()) {
|
||||
LOG(INFO) << "Writing filtered XML to " << cfg.writeOsm << " ...";
|
||||
BBoxIdx box(2500);
|
||||
if (cfg.feedPaths.size()) {
|
||||
box = ShapeBuilder::getPaddedGtfsBox(>fs, 2500, cmdCfgMots,
|
||||
cfg.shapeTripId, true);
|
||||
BBoxIdx box(BOX_PADDING);
|
||||
for (size_t i = 0; i < cfg.feedPaths.size(); i++) {
|
||||
ShapeBuilder::getGtfsBox(>fs[i], cmdCfgMots, cfg.shapeTripId, true,
|
||||
&box);
|
||||
}
|
||||
OsmBuilder osmBuilder;
|
||||
std::vector<pfaedle::osm::OsmReadOpts> opts;
|
||||
|
|
@ -99,15 +166,33 @@ int main(int argc, char** argv) {
|
|||
opts.push_back(o.osmBuildOpts);
|
||||
}
|
||||
}
|
||||
osmBuilder.filterWrite(cfg.osmPath, cfg.writeOsm, opts, box);
|
||||
exit(0);
|
||||
try {
|
||||
osmBuilder.filterWrite(cfg.osmPath, cfg.writeOsm, opts, box);
|
||||
} catch (xml::XmlFileException ex) {
|
||||
LOG(ERROR) << "Could not parse OSM data, reason was:";
|
||||
std::cerr << ex.what() << std::endl;
|
||||
exit(static_cast<int>(RetCode::OSM_PARSE_ERR));
|
||||
}
|
||||
exit(static_cast<int>(RetCode::SUCCESS));
|
||||
} else if (cfg.writeOverpass) {
|
||||
BBoxIdx box(BOX_PADDING);
|
||||
for (size_t i = 0; i < cfg.feedPaths.size(); i++) {
|
||||
ShapeBuilder::getGtfsBox(>fs[i], cmdCfgMots, cfg.shapeTripId, true,
|
||||
&box);
|
||||
}
|
||||
OsmBuilder osmBuilder;
|
||||
std::vector<pfaedle::osm::OsmReadOpts> opts;
|
||||
for (const auto& o : motCfgReader.getConfigs()) {
|
||||
if (std::find_first_of(o.mots.begin(), o.mots.end(), cmdCfgMots.begin(),
|
||||
cmdCfgMots.end()) != o.mots.end()) {
|
||||
opts.push_back(o.osmBuildOpts);
|
||||
}
|
||||
}
|
||||
osmBuilder.overpassQryWrite(&std::cout, opts, box);
|
||||
exit(static_cast<int>(RetCode::SUCCESS));
|
||||
} else if (!cfg.feedPaths.size()) {
|
||||
std::cout << "No input feed specified, see --help" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (motCfgReader.getConfigs().size() == 0) {
|
||||
LOG(WARN) << "No MOT configurations specified, see --help.";
|
||||
exit(static_cast<int>(RetCode::NO_INPUT_FEED));
|
||||
}
|
||||
|
||||
std::vector<double> dfBins;
|
||||
|
|
@ -119,62 +204,76 @@ int main(int argc, char** argv) {
|
|||
std::string filePost;
|
||||
auto usedMots = getContMots(motCfg, cmdCfgMots);
|
||||
if (!usedMots.size()) continue;
|
||||
if (singleTrip && !usedMots.count(singleTrip->getRoute()->getType()))
|
||||
continue;
|
||||
if (motCfgReader.getConfigs().size() > 1)
|
||||
filePost = getFileNameMotStr(usedMots);
|
||||
|
||||
std::string motStr = getMotStr(usedMots);
|
||||
LOG(INFO) << "Calculating shapes for mots " << motStr;
|
||||
|
||||
ShapeBuilder shapeBuilder(>fs, cmdCfgMots, motCfg, &ecoll, cfg);
|
||||
try {
|
||||
ShapeBuilder shapeBuilder(>fs[0], &evalFeed, cmdCfgMots, motCfg, &ecoll,
|
||||
cfg);
|
||||
|
||||
if (cfg.writeGraph) {
|
||||
LOG(INFO) << "Outputting graph.json...";
|
||||
util::geo::output::GeoGraphJsonOutput out;
|
||||
std::ofstream fstr(cfg.dbgOutputPath + "/graph.json");
|
||||
out.print(*shapeBuilder.getGraph(), fstr);
|
||||
fstr.close();
|
||||
}
|
||||
|
||||
if (singleTrip) {
|
||||
LOG(INFO) << "Outputting path.json...";
|
||||
std::ofstream pstr(cfg.dbgOutputPath + "/path.json");
|
||||
util::geo::output::GeoJsonOutput o(pstr);
|
||||
|
||||
auto l = shapeBuilder.shapeL(singleTrip);
|
||||
|
||||
if (singleTrip->getShape()) {
|
||||
auto orig = Collector::getWebMercLine(singleTrip->getShape(), -1, -1);
|
||||
o.print(orig, util::json::Dict{{"ver", "old"}});
|
||||
if (cfg.writeGraph) {
|
||||
LOG(INFO) << "Outputting graph.json...";
|
||||
util::geo::output::GeoGraphJsonOutput out;
|
||||
mkdir(cfg.dbgOutputPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
std::ofstream fstr(cfg.dbgOutputPath + "/graph.json");
|
||||
out.print(*shapeBuilder.getGraph(), fstr);
|
||||
fstr.close();
|
||||
}
|
||||
|
||||
o.print(l, util::json::Dict{{"ver", "new"}});
|
||||
o.flush();
|
||||
pstr.close();
|
||||
if (singleTrip) {
|
||||
LOG(INFO) << "Outputting path.json...";
|
||||
mkdir(cfg.dbgOutputPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
std::ofstream pstr(cfg.dbgOutputPath + "/path.json");
|
||||
util::geo::output::GeoJsonOutput o(pstr);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
auto l = shapeBuilder.shapeL(singleTrip);
|
||||
|
||||
pfaedle::netgraph::Graph ng;
|
||||
shapeBuilder.shape(&ng);
|
||||
o.print(l, util::json::Dict{{"ver", "new"}});
|
||||
o.flush();
|
||||
pstr.close();
|
||||
|
||||
if (cfg.buildTransitGraph) {
|
||||
util::geo::output::GeoGraphJsonOutput out;
|
||||
LOG(INFO) << "Outputting trgraph" + filePost + ".json...";
|
||||
std::ofstream fstr(cfg.dbgOutputPath + "/trgraph" + filePost + ".json");
|
||||
out.print(ng, fstr);
|
||||
fstr.close();
|
||||
exit(static_cast<int>(RetCode::SUCCESS));
|
||||
}
|
||||
|
||||
pfaedle::netgraph::Graph ng;
|
||||
shapeBuilder.shape(&ng);
|
||||
|
||||
if (cfg.buildTransitGraph) {
|
||||
util::geo::output::GeoGraphJsonOutput out;
|
||||
LOG(INFO) << "Outputting trgraph" + filePost + ".json...";
|
||||
mkdir(cfg.dbgOutputPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
std::ofstream fstr(cfg.dbgOutputPath + "/trgraph" + filePost + ".json");
|
||||
out.print(ng, fstr);
|
||||
fstr.close();
|
||||
}
|
||||
} catch (xml::XmlFileException ex) {
|
||||
LOG(ERROR) << "Could not parse OSM data, reason was:";
|
||||
std::cerr << ex.what() << std::endl;
|
||||
exit(static_cast<int>(RetCode::OSM_PARSE_ERR));
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.evaluate) ecoll.printStats(&std::cout);
|
||||
|
||||
if (cfg.feedPaths.size()) {
|
||||
LOG(INFO) << "Writing output GTFS to " << cfg.outputPath << " ...";
|
||||
ad::cppgtfs::Writer w;
|
||||
w.write(>fs, cfg.outputPath);
|
||||
try {
|
||||
mkdir(cfg.outputPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
LOG(INFO) << "Writing output GTFS to " << cfg.outputPath << " ...";
|
||||
pfaedle::gtfs::Writer w;
|
||||
w.write(>fs[0], cfg.outputPath);
|
||||
} catch (ad::cppgtfs::WriterException ex) {
|
||||
LOG(ERROR) << "Could not write final GTFS feed, reason was:";
|
||||
std::cerr << ex.what() << std::endl;
|
||||
exit(static_cast<int>(RetCode::GTFS_WRITE_ERR));
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
return static_cast<int>(RetCode::SUCCESS);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
|
|
@ -183,7 +282,7 @@ std::string getMotStr(const MOTs& mots) {
|
|||
std::string motStr;
|
||||
for (const auto& mot : mots) {
|
||||
if (first) motStr += ", ";
|
||||
motStr += "<" + Route::getTypeString(mot) + ">";
|
||||
motStr += "<" + ad::cppgtfs::gtfs::flat::Route::getTypeString(mot) + ">";
|
||||
first = true;
|
||||
}
|
||||
|
||||
|
|
@ -194,7 +293,7 @@ std::string getMotStr(const MOTs& mots) {
|
|||
std::string getFileNameMotStr(const MOTs& mots) {
|
||||
std::string motStr;
|
||||
for (const auto& mot : mots) {
|
||||
motStr += "-" + Route::getTypeString(mot);
|
||||
motStr += "-" + ad::cppgtfs::gtfs::flat::Route::getTypeString(mot);
|
||||
}
|
||||
|
||||
return motStr;
|
||||
|
|
@ -211,3 +310,73 @@ MOTs getContMots(const MotConfig& motCfg, const MOTs& mots) {
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
std::vector<std::string> getCfgPaths(const Config& cfg) {
|
||||
if (cfg.configPaths.size()) return cfg.configPaths;
|
||||
std::vector<std::string> ret;
|
||||
|
||||
// parse implicit paths
|
||||
const char* homedir = 0;
|
||||
char* buf = 0;
|
||||
|
||||
if ((homedir = getenv("HOME")) == 0) {
|
||||
homedir = "";
|
||||
struct passwd pwd;
|
||||
struct passwd* result;
|
||||
size_t bufsize;
|
||||
bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
|
||||
if (bufsize == static_cast<size_t>(-1)) bufsize = 0x4000;
|
||||
buf = static_cast<char*>(malloc(bufsize));
|
||||
if (buf != 0) {
|
||||
getpwuid_r(getuid(), &pwd, buf, bufsize, &result);
|
||||
if (result != NULL) homedir = result->pw_dir;
|
||||
}
|
||||
}
|
||||
|
||||
// install prefix global configuration path, if available
|
||||
{
|
||||
auto path = std::string(INSTALL_PREFIX) +
|
||||
std::string(XDG_CONFIG_DIRS_DEFAULT) + "/" + "pfaedle" + "/" +
|
||||
CFG_FILE_NAME;
|
||||
std::ifstream is(path);
|
||||
|
||||
LOG(DEBUG) << "Testing for config file at " << path;
|
||||
if (is.good()) {
|
||||
ret.push_back(path);
|
||||
LOG(DEBUG) << "Found implicit config file " << path;
|
||||
}
|
||||
}
|
||||
|
||||
// local user configuration path, if available
|
||||
{
|
||||
auto path = std::string(homedir) + XDG_CONFIG_HOME_SUFFIX + "/" +
|
||||
"pfaedle" + "/" + CFG_FILE_NAME;
|
||||
std::ifstream is(path);
|
||||
|
||||
LOG(DEBUG) << "Testing for config file at " << path;
|
||||
if (is.good()) {
|
||||
ret.push_back(path);
|
||||
LOG(DEBUG) << "Found implicit config file " << path;
|
||||
}
|
||||
}
|
||||
|
||||
if (buf) free(buf);
|
||||
|
||||
// CWD
|
||||
{
|
||||
char cwd[PATH_MAX];
|
||||
if (getcwd(cwd, sizeof(cwd))) {
|
||||
auto path = std::string(cwd) + "/" + CFG_FILE_NAME;
|
||||
std::ifstream is(path);
|
||||
|
||||
LOG(DEBUG) << "Testing for config file at " << path;
|
||||
if (is.good()) {
|
||||
ret.push_back(path);
|
||||
LOG(DEBUG) << "Found implicit config file " << path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,4 +7,7 @@
|
|||
// version number from cmake version module
|
||||
#define VERSION_FULL "@VERSION_GIT_FULL@"
|
||||
|
||||
// version number from cmake version module
|
||||
#define INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@"
|
||||
|
||||
#endif // SRC_PFAEDLE_CONFIG_H_N
|
||||
|
|
|
|||
|
|
@ -26,67 +26,96 @@ static const char* AUTHORS = "Patrick Brosi <brosi@informatik.uni-freiburg.de>";
|
|||
|
||||
// _____________________________________________________________________________
|
||||
void ConfigReader::help(const char* bin) {
|
||||
std::cout
|
||||
<< std::setfill(' ') << std::left << "pfaedle GTFS map matcher\n"
|
||||
<< VERSION_FULL << " (built " << __DATE__ << " " << __TIME__
|
||||
<< " with geometry precision <" << PFAEDLE_PRECISION_STR << ">)\n\n"
|
||||
<< "(C) " << YEAR << " " << COPY << "\n"
|
||||
<< "Authors: " << AUTHORS << "\n\n"
|
||||
<< "Usage: " << bin << " -x <OSM FILE> -c <CFG FILE> <GTFS FEED>\n\n"
|
||||
<< "Allowed options:\n\n"
|
||||
<< "General:\n"
|
||||
<< std::setw(35) << " -v [ --version ]"
|
||||
<< "print version\n"
|
||||
<< std::setw(35) << " -h [ --help ]"
|
||||
<< "show this help message\n"
|
||||
<< std::setw(35) << " -D [ --drop-shapes ]"
|
||||
<< "drop shapes already present in the feed and recalculate them\n"
|
||||
<< "\nInput:\n"
|
||||
<< std::setw(35) << " -c [ --config ] arg"
|
||||
<< "pfaedle config file\n"
|
||||
<< std::setw(35) << " -i [ --input ] arg"
|
||||
<< "gtfs feed(s), may also be given as positional parameter (see usage)\n"
|
||||
<< std::setw(35) << " -x [ --osm-file ] arg"
|
||||
<< "OSM xml input file\n"
|
||||
<< std::setw(35) << " -m [ --mots ] arg (=all)"
|
||||
<< "MOTs to calculate shapes for, comma separated, either as string "
|
||||
"{all,\n"
|
||||
<< std::setw(35) << " "
|
||||
<< "tram | streetcar, subway | metro, rail | train, bus, ferry | boat | "
|
||||
"\n"
|
||||
<< std::setw(35) << " "
|
||||
<< "ship, cableclar, gondola, funicular} or as GTFS mot codes\n"
|
||||
<< "\nOutput:\n"
|
||||
<< std::setw(35) << " -o [ --output ] arg (=gtfs-out)"
|
||||
<< "GTFS output path\n"
|
||||
<< std::setw(35) << " -X [ --osm-out ] arg"
|
||||
<< "if specified, a filtered OSM file will be written to <arg>\n"
|
||||
<< "\nDebug Output:\n"
|
||||
<< std::setw(35) << " -d [ --dbg-path ] arg (=geo)"
|
||||
<< "output path for debug files\n"
|
||||
<< std::setw(35) << " --write-trgraph"
|
||||
<< "write transit graph as GeoJSON to <dbg-path>/trgraph.json\n"
|
||||
<< std::setw(35) << " --write-graph"
|
||||
<< "write routing graph as GeoJSON to <dbg-path>/graph.json\n"
|
||||
<< std::setw(35) << " --write-cgraph"
|
||||
<< "if -T is set, write combination graph as GeoJSON to "
|
||||
"<dbg-path>/combgraph.json\n"
|
||||
<< std::setw(35) << " --method arg (=global)"
|
||||
<< "matching method to use, either 'global' (based on HMM), 'greedy' or "
|
||||
"'greedy2'\n"
|
||||
<< std::setw(35) << " --eval"
|
||||
<< "evaluate existing shapes against matched shapes and print results\n"
|
||||
<< std::setw(35) << " --eval-path arg (=.)"
|
||||
<< "path for eval file output\n"
|
||||
<< std::setw(35) << " --eval-df-bins arg (= )"
|
||||
<< "bins to use for d_f histogram, comma separated (e.g. 10,20,30,40)\n"
|
||||
<< "\nMisc:\n"
|
||||
<< std::setw(35) << " -T [ --trip-id ] arg"
|
||||
<< "Do routing only for trip <arg>, write result to\n"
|
||||
<< std::setw(35) << " "
|
||||
<< "<dbg-path>/path.json\n"
|
||||
<< std::setw(35) << " --grid-size arg (=2000)"
|
||||
<< "Grid cell size\n";
|
||||
std::cout << std::setfill(' ') << std::left << "pfaedle GTFS map matcher "
|
||||
<< VERSION_FULL << "\n(built " << __DATE__ << " " << __TIME__
|
||||
<< " with geometry precision <" << PFAEDLE_PRECISION_STR << ">)\n\n"
|
||||
<< "(C) " << YEAR << " " << COPY << "\n"
|
||||
<< "Authors: " << AUTHORS << "\n\n"
|
||||
<< "Usage: " << bin
|
||||
<< " -x <OSM FILE> <GTFS FEED>\n\n"
|
||||
<< "Allowed options:\n\n"
|
||||
<< "General:\n"
|
||||
<< std::setw(35) << " -v [ --version ]"
|
||||
<< "print version\n"
|
||||
<< std::setw(35) << " -h [ --help ]"
|
||||
<< "show this help message\n"
|
||||
<< std::setw(35) << " -D [ --drop-shapes ]"
|
||||
<< "drop shapes already present in the feed and\n"
|
||||
<< std::setw(35) << " "
|
||||
<< " recalculate them\n"
|
||||
<< "\nInput:\n"
|
||||
<< std::setw(35) << " -c [ --config ] arg"
|
||||
<< "pfaedle config file\n"
|
||||
<< std::setw(35) << " -i [ --input ] arg"
|
||||
<< "gtfs feed(s), may also be given as positional\n"
|
||||
<< std::setw(35) << " "
|
||||
<< " parameter (see usage)\n"
|
||||
<< std::setw(35) << " -x [ --osm-file ] arg"
|
||||
<< "OSM xml input file\n"
|
||||
<< std::setw(35) << " -m [ --mots ] arg (=all)"
|
||||
<< "MOTs to calculate shapes for, comma sep.,\n"
|
||||
<< std::setw(35) << " "
|
||||
<< " either as string "
|
||||
"{all, tram | streetcar,\n"
|
||||
<< std::setw(35) << " "
|
||||
<< " subway | metro, rail | train, bus,\n"
|
||||
<< std::setw(35) << " "
|
||||
<< " ferry | boat | ship, cablecar, gondola,\n"
|
||||
<< std::setw(35) << " "
|
||||
<< " funicular, coach} or as GTFS mot codes\n"
|
||||
<< "\nOutput:\n"
|
||||
<< std::setw(35) << " -o [ --output ] arg (=gtfs-out)"
|
||||
<< "GTFS output path\n"
|
||||
<< std::setw(35) << " -X [ --osm-out ] arg"
|
||||
<< "if specified, a filtered OSM file will be\n"
|
||||
<< std::setw(35) << " "
|
||||
<< " written to <arg>\n"
|
||||
<< std::setw(35) << " --inplace"
|
||||
<< "overwrite input GTFS feed with output feed\n"
|
||||
<< "\nDebug Output:\n"
|
||||
<< std::setw(35) << " -d [ --dbg-path ] arg (=geo)"
|
||||
<< "output path for debug files\n"
|
||||
<< std::setw(35) << " --write-trgraph"
|
||||
<< "write transit graph as GeoJSON to\n"
|
||||
<< std::setw(35) << " "
|
||||
<< " <dbg-path>/trgraph.json\n"
|
||||
<< std::setw(35) << " --write-graph"
|
||||
<< "write routing graph as GeoJSON to\n"
|
||||
<< std::setw(35) << " "
|
||||
<< " <dbg-path>/graph.json\n"
|
||||
<< std::setw(35) << " --write-cgraph"
|
||||
<< "if -T is set, write combination graph as\n"
|
||||
<< std::setw(35) << " "
|
||||
<< " GeoJSON to "
|
||||
"<dbg-path>/combgraph.json\n"
|
||||
<< std::setw(35) << " --method arg (=global)"
|
||||
<< "matching method to use, either 'global'\n"
|
||||
<< std::setw(35) << " "
|
||||
<< " (based on HMM), 'greedy' or "
|
||||
"'greedy2'\n"
|
||||
<< std::setw(35) << " --eval"
|
||||
<< "evaluate existing shapes against matched\n"
|
||||
<< std::setw(35) << " "
|
||||
<< " shapes and print results\n"
|
||||
<< std::setw(35) << " --eval-path arg (=.)"
|
||||
<< "path for eval file output\n"
|
||||
<< std::setw(35) << " --eval-df-bins arg (= )"
|
||||
<< "bins to use for d_f histogram, comma sep.\n"
|
||||
<< std::setw(35) << " "
|
||||
<< " (e.g. 10,20,30,40)\n"
|
||||
<< "\nMisc:\n"
|
||||
<< std::setw(35) << " -T [ --trip-id ] arg"
|
||||
<< "Do routing only for trip <arg>, write result \n"
|
||||
<< std::setw(35) << " "
|
||||
<< " to <dbg-path>/path.json\n"
|
||||
<< std::setw(35) << " --overpass"
|
||||
<< "Output overpass query for matching OSM data\n"
|
||||
<< std::setw(35) << " --grid-size arg (=2000)"
|
||||
<< "Grid cell size\n"
|
||||
<< std::setw(35) << " --use-route-cache"
|
||||
<< "(experimental) cache intermediate routing\n"
|
||||
<< std::setw(35) << " "
|
||||
<< " results\n";
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
|
|
@ -101,6 +130,7 @@ void ConfigReader::read(Config* cfg, int argc, char** argv) {
|
|||
{"drop-shapes", required_argument, 0, 'D'},
|
||||
{"mots", required_argument, NULL, 'm'},
|
||||
{"grid-size", required_argument, 0, 'g'},
|
||||
{"overpass", no_argument, 0, 'a'},
|
||||
{"osm-out", required_argument, 0, 'X'},
|
||||
{"trip-id", required_argument, 0, 'T'},
|
||||
{"write-graph", no_argument, 0, 1},
|
||||
|
|
@ -113,6 +143,8 @@ void ConfigReader::read(Config* cfg, int argc, char** argv) {
|
|||
{"dbg-path", required_argument, 0, 'd'},
|
||||
{"version", no_argument, 0, 'v'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"inplace", no_argument, 0, 9},
|
||||
{"use-route-cache", no_argument, 0, 8},
|
||||
{0, 0, 0, 0}};
|
||||
|
||||
char c;
|
||||
|
|
@ -140,6 +172,9 @@ void ConfigReader::read(Config* cfg, int argc, char** argv) {
|
|||
case 7:
|
||||
cfg->evalDfBins = optarg;
|
||||
break;
|
||||
case 8:
|
||||
cfg->useCaching = true;
|
||||
break;
|
||||
case 'o':
|
||||
cfg->outputPath = optarg;
|
||||
break;
|
||||
|
|
@ -170,6 +205,12 @@ void ConfigReader::read(Config* cfg, int argc, char** argv) {
|
|||
case 'd':
|
||||
cfg->dbgOutputPath = optarg;
|
||||
break;
|
||||
case 'a':
|
||||
cfg->writeOverpass = true;
|
||||
break;
|
||||
case 9:
|
||||
cfg->inPlace = true;
|
||||
break;
|
||||
case 'v':
|
||||
std::cout << "pfaedle " << VERSION_FULL << " (built " << __DATE__ << " "
|
||||
<< __TIME__ << " with geometry precision <"
|
||||
|
|
@ -204,7 +245,8 @@ void ConfigReader::read(Config* cfg, int argc, char** argv) {
|
|||
|
||||
auto v = util::split(motStr, ',');
|
||||
for (const auto& motStr : v) {
|
||||
const auto& mots = Route::getTypesFromString(util::trim(motStr));
|
||||
const auto& mots =
|
||||
ad::cppgtfs::gtfs::flat::Route::getTypesFromString(util::trim(motStr));
|
||||
cfg->mots.insert(mots.begin(), mots.end());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include "pfaedle/config/MotConfigReader.h"
|
||||
#include "util/Misc.h"
|
||||
#include "util/String.h"
|
||||
#include "util/log/Log.h"
|
||||
|
||||
using pfaedle::config::MotConfigReader;
|
||||
using pfaedle::config::MotConfig;
|
||||
|
|
@ -23,341 +24,336 @@ MotConfigReader::MotConfigReader() {}
|
|||
|
||||
// _____________________________________________________________________________
|
||||
void MotConfigReader::parse(const std::vector<std::string>& paths) {
|
||||
ConfigFileParser p;
|
||||
|
||||
// parse explicitely given paths
|
||||
for (const auto& s : paths) {
|
||||
ConfigFileParser p;
|
||||
LOG(DEBUG) << "Reading config file " << s;
|
||||
p.parse(s);
|
||||
}
|
||||
|
||||
for (const auto& sec : p.getSecs()) {
|
||||
MotConfig curCfg;
|
||||
std::string secStr = sec.first;
|
||||
for (const auto& sec : p.getSecs()) {
|
||||
MotConfig curCfg;
|
||||
std::string secStr = sec.first;
|
||||
|
||||
if (p.hasKey(secStr, "osm_filter_keep")) {
|
||||
for (const auto& kvs : p.getStrArr(sec.first, "osm_filter_keep", ' ')) {
|
||||
if (p.hasKey(secStr, "osm_filter_keep")) {
|
||||
for (const auto& kvs : p.getStrArr(sec.first, "osm_filter_keep", ' ')) {
|
||||
auto fRule = getFRule(kvs);
|
||||
curCfg.osmBuildOpts.keepFilter[fRule.kv.first].insert(
|
||||
osm::AttrFlagPair(fRule.kv.second, getFlags(fRule.flags)));
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
std::string name = std::string("osm_filter_lvl") + std::to_string(i);
|
||||
if (p.hasKey(secStr, name)) {
|
||||
for (const auto& kvs : p.getStrArr(sec.first, name, ' ')) {
|
||||
auto fRule = getFRule(kvs);
|
||||
curCfg.osmBuildOpts.keepFilter[fRule.kv.first].insert(
|
||||
curCfg.osmBuildOpts.levelFilters[i][fRule.kv.first].insert(
|
||||
osm::AttrFlagPair(fRule.kv.second, getFlags(fRule.flags)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < 7; i++) {
|
||||
std::string name =
|
||||
std::string("osm_filter_lvl") + std::to_string(i + 1);
|
||||
if (p.hasKey(secStr, name)) {
|
||||
for (const auto& kvs : p.getStrArr(sec.first, name, ' ')) {
|
||||
auto fRule = getFRule(kvs);
|
||||
curCfg.osmBuildOpts.levelFilters[i][fRule.kv.first].insert(
|
||||
osm::AttrFlagPair(fRule.kv.second, getFlags(fRule.flags)));
|
||||
}
|
||||
}
|
||||
if (p.hasKey(secStr, "osm_filter_drop")) {
|
||||
for (const auto& kvs : p.getStrArr(sec.first, "osm_filter_drop", ' ')) {
|
||||
auto fRule = getFRule(kvs);
|
||||
curCfg.osmBuildOpts.dropFilter[fRule.kv.first].insert(
|
||||
osm::AttrFlagPair(fRule.kv.second, getFlags(fRule.flags)));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_filter_drop")) {
|
||||
for (const auto& kvs : p.getStrArr(sec.first, "osm_filter_drop", ' ')) {
|
||||
auto fRule = getFRule(kvs);
|
||||
curCfg.osmBuildOpts.dropFilter[fRule.kv.first].insert(
|
||||
osm::AttrFlagPair(fRule.kv.second, getFlags(fRule.flags)));
|
||||
}
|
||||
if (p.hasKey(secStr, "osm_max_snap_level")) {
|
||||
curCfg.osmBuildOpts.maxSnapLevel =
|
||||
p.getInt(sec.first, "osm_max_snap_level");
|
||||
} else {
|
||||
curCfg.osmBuildOpts.maxSnapLevel = 7;
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_filter_nohup")) {
|
||||
for (const auto& kvs : p.getStrArr(sec.first, "osm_filter_nohup", ' ')) {
|
||||
auto fRule = getFRule(kvs);
|
||||
curCfg.osmBuildOpts.noHupFilter[fRule.kv.first].insert(
|
||||
osm::AttrFlagPair(fRule.kv.second, getFlags(fRule.flags)));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_max_snap_level")) {
|
||||
curCfg.osmBuildOpts.maxSnapLevel =
|
||||
p.getInt(sec.first, "osm_max_snap_level");
|
||||
if (p.hasKey(secStr, "osm_filter_oneway")) {
|
||||
for (const auto& kvs : p.getStrArr(sec.first, "osm_filter_oneway", ' ')) {
|
||||
auto fRule = getFRule(kvs);
|
||||
curCfg.osmBuildOpts.oneWayFilter[fRule.kv.first].insert(
|
||||
osm::AttrFlagPair(fRule.kv.second, getFlags(fRule.flags)));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_filter_oneway_reverse")) {
|
||||
for (const auto& kvs :
|
||||
p.getStrArr(sec.first, "osm_filter_oneway_reverse", ' ')) {
|
||||
auto fRule = getFRule(kvs);
|
||||
curCfg.osmBuildOpts.oneWayFilterRev[fRule.kv.first].insert(
|
||||
osm::AttrFlagPair(fRule.kv.second, getFlags(fRule.flags)));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_filter_undirected")) {
|
||||
for (const auto& kvs :
|
||||
p.getStrArr(sec.first, "osm_filter_undirected", ' ')) {
|
||||
auto fRule = getFRule(kvs);
|
||||
curCfg.osmBuildOpts.twoWayFilter[fRule.kv.first].insert(
|
||||
osm::AttrFlagPair(fRule.kv.second, getFlags(fRule.flags)));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_filter_station")) {
|
||||
for (const auto& kvs :
|
||||
p.getStrArr(sec.first, "osm_filter_station", ' ')) {
|
||||
auto fRule = getFRule(kvs);
|
||||
curCfg.osmBuildOpts.stationFilter[fRule.kv.first].insert(
|
||||
osm::AttrFlagPair(fRule.kv.second, getFlags(fRule.flags)));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_filter_station_blocker")) {
|
||||
for (const auto& kvs :
|
||||
p.getStrArr(sec.first, "osm_filter_station_blocker", ' ')) {
|
||||
auto fRule = getFRule(kvs);
|
||||
curCfg.osmBuildOpts.stationBlockerFilter[fRule.kv.first].insert(
|
||||
osm::AttrFlagPair(fRule.kv.second, getFlags(fRule.flags)));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_node_positive_restriction")) {
|
||||
for (const auto& kvs :
|
||||
p.getStrArr(sec.first, "osm_node_positive_restriction", ' ')) {
|
||||
auto fRule = getFRule(kvs);
|
||||
curCfg.osmBuildOpts.restrPosRestr[fRule.kv.first].insert(
|
||||
osm::AttrFlagPair(fRule.kv.second, getFlags(fRule.flags)));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_node_negative_restriction")) {
|
||||
for (const auto& kvs :
|
||||
p.getStrArr(sec.first, "osm_node_negative_restriction", ' ')) {
|
||||
auto fRule = getFRule(kvs);
|
||||
curCfg.osmBuildOpts.restrNegRestr[fRule.kv.first].insert(
|
||||
osm::AttrFlagPair(fRule.kv.second, getFlags(fRule.flags)));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_filter_no_restriction")) {
|
||||
for (const auto& kvs :
|
||||
p.getStrArr(sec.first, "osm_filter_no_restriction", ' ')) {
|
||||
auto fRule = getFRule(kvs);
|
||||
curCfg.osmBuildOpts.noRestrFilter[fRule.kv.first].insert(
|
||||
osm::AttrFlagPair(fRule.kv.second, getFlags(fRule.flags)));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_station_name_attrs")) {
|
||||
for (const std::string& r :
|
||||
p.getStrArr(sec.first, "osm_station_name_attrs", ' ')) {
|
||||
curCfg.osmBuildOpts.statAttrRules.nameRule.push_back(
|
||||
getDeepAttrRule(r));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_track_number_tags")) {
|
||||
for (const std::string& r :
|
||||
p.getStrArr(sec.first, "osm_track_number_tags", ' ')) {
|
||||
curCfg.osmBuildOpts.statAttrRules.platformRule.push_back(
|
||||
getDeepAttrRule(r));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_edge_track_number_tags")) {
|
||||
for (const std::string& r :
|
||||
p.getStrArr(sec.first, "osm_edge_track_number_tags", ' ')) {
|
||||
curCfg.osmBuildOpts.edgePlatformRules.push_back(getDeepAttrRule(r));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_station_group_attrs")) {
|
||||
auto arr = p.getStrArr(secStr, "osm_station_group_attrs", ' ');
|
||||
|
||||
for (const auto& ruleStr : arr) {
|
||||
auto deep = getDeepAttrRule(ruleStr);
|
||||
// TODO(patrick): getKv is misused here as a a=b parser
|
||||
auto attrD = getKv(deep.attr);
|
||||
deep.attr = attrD.first;
|
||||
double dist = atof(attrD.second.c_str());
|
||||
curCfg.osmBuildOpts.statGroupNAttrRules.push_back({deep, dist});
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_line_relation_tags")) {
|
||||
auto arr = p.getStrArr(secStr, "osm_line_relation_tags", ' ');
|
||||
|
||||
for (const auto& ruleStr : arr) {
|
||||
auto rule = getKv(ruleStr);
|
||||
auto tags = util::split(rule.second, ',');
|
||||
if (rule.first == "from_name")
|
||||
curCfg.osmBuildOpts.relLinerules.fromNameRule = tags;
|
||||
else if (rule.first == "to_name")
|
||||
curCfg.osmBuildOpts.relLinerules.toNameRule = tags;
|
||||
else if (rule.first == "line_name")
|
||||
curCfg.osmBuildOpts.relLinerules.sNameRule = tags;
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_max_snap_distance")) {
|
||||
curCfg.osmBuildOpts.maxSnapDistances =
|
||||
p.getDoubleArr(secStr, "osm_max_snap_distance", ',');
|
||||
} else {
|
||||
curCfg.osmBuildOpts.maxSnapDistances.push_back(50);
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_max_snap_fallback_distance")) {
|
||||
curCfg.osmBuildOpts.maxSnapFallbackHeurDistance =
|
||||
p.getDouble(secStr, "osm_max_snap_fallback_distance");
|
||||
} else {
|
||||
curCfg.osmBuildOpts.maxSnapFallbackHeurDistance =
|
||||
*std::max_element(curCfg.osmBuildOpts.maxSnapDistances.begin(),
|
||||
curCfg.osmBuildOpts.maxSnapDistances.end()) *
|
||||
2;
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_max_osm_station_distance")) {
|
||||
curCfg.osmBuildOpts.maxOsmStationDistance =
|
||||
p.getDouble(secStr, "osm_max_osm_station_distance");
|
||||
} else {
|
||||
curCfg.osmBuildOpts.maxOsmStationDistance = 5;
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_max_node_block_distance")) {
|
||||
curCfg.osmBuildOpts.maxBlockDistance =
|
||||
p.getDouble(secStr, "osm_max_node_block_distance");
|
||||
} else {
|
||||
curCfg.osmBuildOpts.maxBlockDistance =
|
||||
*std::max_element(curCfg.osmBuildOpts.maxSnapDistances.begin(),
|
||||
curCfg.osmBuildOpts.maxSnapDistances.end()) /
|
||||
8;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
std::string name =
|
||||
std::string("routing_lvl") + std::to_string(i) + "_fac";
|
||||
if (p.hasKey(secStr, name)) {
|
||||
double v = p.getDouble(sec.first, name);
|
||||
curCfg.routingOpts.levelPunish[i] = v;
|
||||
} else {
|
||||
curCfg.osmBuildOpts.maxSnapLevel = 7;
|
||||
curCfg.routingOpts.levelPunish[i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_filter_nohup")) {
|
||||
for (const auto& kvs :
|
||||
p.getStrArr(sec.first, "osm_filter_nohup", ' ')) {
|
||||
auto fRule = getFRule(kvs);
|
||||
curCfg.osmBuildOpts.noHupFilter[fRule.kv.first].insert(
|
||||
osm::AttrFlagPair(fRule.kv.second, getFlags(fRule.flags)));
|
||||
if (p.hasKey(secStr, "routing_full_turn_punish")) {
|
||||
curCfg.routingOpts.fullTurnPunishFac =
|
||||
p.getDouble(secStr, "routing_full_turn_punish");
|
||||
}
|
||||
if (p.hasKey(secStr, "routing_full_turn_angle")) {
|
||||
double ang = p.getDouble(secStr, "routing_full_turn_angle");
|
||||
curCfg.routingOpts.fullTurnAngle = ang;
|
||||
curCfg.osmBuildOpts.fullTurnAngle = ang;
|
||||
} else {
|
||||
curCfg.routingOpts.fullTurnAngle = 5;
|
||||
curCfg.osmBuildOpts.fullTurnAngle = 5;
|
||||
}
|
||||
if (p.hasKey(secStr, "routing_snap_full_turn_angle")) {
|
||||
double ang = p.getDouble(secStr, "routing_snap_full_turn_angle");
|
||||
curCfg.osmBuildOpts.maxAngleSnapReach = ang;
|
||||
} else {
|
||||
curCfg.osmBuildOpts.maxAngleSnapReach = curCfg.routingOpts.fullTurnAngle;
|
||||
}
|
||||
if (p.hasKey(secStr, "routing_pass_thru_station_punish")) {
|
||||
curCfg.routingOpts.passThruStationsPunish =
|
||||
p.getDouble(secStr, "routing_pass_thru_station_punish");
|
||||
}
|
||||
if (p.hasKey(secStr, "routing_one_way_meter_punish_fac")) {
|
||||
curCfg.routingOpts.oneWayPunishFac =
|
||||
p.getDouble(secStr, "routing_one_way_meter_punish_fac");
|
||||
}
|
||||
if (p.hasKey(secStr, "routing_one_way_edge_punish")) {
|
||||
curCfg.routingOpts.oneWayEdgePunish =
|
||||
p.getDouble(secStr, "routing_one_way_edge_punish");
|
||||
}
|
||||
if (p.hasKey(secStr, "routing_line_unmatched_punish_fac")) {
|
||||
curCfg.routingOpts.lineUnmatchedPunishFact =
|
||||
p.getDouble(secStr, "routing_line_unmatched_punish_fac");
|
||||
}
|
||||
if (p.hasKey(secStr, "routing_platform_unmatched_punish")) {
|
||||
curCfg.routingOpts.platformUnmatchedPen =
|
||||
p.getDouble(secStr, "routing_platform_unmatched_punish");
|
||||
}
|
||||
if (p.hasKey(secStr, "routing_non_osm_station_punish")) {
|
||||
curCfg.routingOpts.nonOsmPen =
|
||||
p.getDouble(secStr, "routing_non_osm_station_punish");
|
||||
} else {
|
||||
curCfg.routingOpts.nonOsmPen = 0;
|
||||
}
|
||||
if (p.hasKey(secStr, "routing_station_distance_punish_fac")) {
|
||||
curCfg.routingOpts.stationDistPenFactor =
|
||||
p.getDouble(secStr, "routing_station_distance_punish_fac");
|
||||
} else {
|
||||
curCfg.routingOpts.stationDistPenFactor = 1;
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "station_normalize_chain")) {
|
||||
try {
|
||||
auto arr = p.getStrArr(secStr, "station_normalize_chain", ';');
|
||||
curCfg.osmBuildOpts.statNormzer =
|
||||
trgraph::Normalizer(getNormRules(arr));
|
||||
} catch (const std::exception& e) {
|
||||
throw ParseExc(p.getVal(secStr, "station_normalize_chain").line,
|
||||
p.getVal(secStr, "station_normalize_chain").pos,
|
||||
"<valid regular expression>",
|
||||
std::string("<regex error: ") + e.what() + ">",
|
||||
p.getVal(secStr, "station_normalize_chain").file);
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "track_normalize_chain")) {
|
||||
try {
|
||||
auto arr = p.getStrArr(secStr, "track_normalize_chain", ';');
|
||||
curCfg.osmBuildOpts.trackNormzer =
|
||||
trgraph::Normalizer(getNormRules(arr));
|
||||
} catch (const std::exception& e) {
|
||||
throw ParseExc(p.getVal(secStr, "track_normalize_chain").line,
|
||||
p.getVal(secStr, "track_normalize_chain").pos,
|
||||
"<valid regular expression>",
|
||||
std::string("<regex error: ") + e.what() + ">",
|
||||
p.getVal(secStr, "track_normalize_chain").file);
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "line_normalize_chain")) {
|
||||
try {
|
||||
auto arr = p.getStrArr(secStr, "line_normalize_chain", ';');
|
||||
curCfg.osmBuildOpts.lineNormzer =
|
||||
trgraph::Normalizer(getNormRules(arr));
|
||||
} catch (const std::exception& e) {
|
||||
throw ParseExc(p.getVal(secStr, "station_normalize_chain").line,
|
||||
p.getVal(secStr, "station_normalize_chain").pos,
|
||||
"<valid regular expression>",
|
||||
std::string("<regex error: ") + e.what() + ">",
|
||||
p.getVal(secStr, "station_normalize_chain").file);
|
||||
}
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
|
||||
for (auto& cfg : _cfgs) {
|
||||
if (cfg == curCfg) {
|
||||
for (auto mot :
|
||||
ad::cppgtfs::gtfs::flat::Route::getTypesFromString(secStr)) {
|
||||
cfg.mots.insert(mot);
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_filter_oneway")) {
|
||||
for (const auto& kvs :
|
||||
p.getStrArr(sec.first, "osm_filter_oneway", ' ')) {
|
||||
auto fRule = getFRule(kvs);
|
||||
curCfg.osmBuildOpts.oneWayFilter[fRule.kv.first].insert(
|
||||
osm::AttrFlagPair(fRule.kv.second, getFlags(fRule.flags)));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_filter_oneway_reverse")) {
|
||||
for (const auto& kvs :
|
||||
p.getStrArr(sec.first, "osm_filter_oneway_reverse", ' ')) {
|
||||
auto fRule = getFRule(kvs);
|
||||
curCfg.osmBuildOpts.oneWayFilterRev[fRule.kv.first].insert(
|
||||
osm::AttrFlagPair(fRule.kv.second, getFlags(fRule.flags)));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_filter_undirected")) {
|
||||
for (const auto& kvs :
|
||||
p.getStrArr(sec.first, "osm_filter_undirected", ' ')) {
|
||||
auto fRule = getFRule(kvs);
|
||||
curCfg.osmBuildOpts.twoWayFilter[fRule.kv.first].insert(
|
||||
osm::AttrFlagPair(fRule.kv.second, getFlags(fRule.flags)));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_filter_station")) {
|
||||
for (const auto& kvs :
|
||||
p.getStrArr(sec.first, "osm_filter_station", ' ')) {
|
||||
auto fRule = getFRule(kvs);
|
||||
curCfg.osmBuildOpts.stationFilter[fRule.kv.first].insert(
|
||||
osm::AttrFlagPair(fRule.kv.second, getFlags(fRule.flags)));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_filter_station_blocker")) {
|
||||
for (const auto& kvs :
|
||||
p.getStrArr(sec.first, "osm_filter_station_blocker", ' ')) {
|
||||
auto fRule = getFRule(kvs);
|
||||
curCfg.osmBuildOpts.stationBlockerFilter[fRule.kv.first].insert(
|
||||
osm::AttrFlagPair(fRule.kv.second, getFlags(fRule.flags)));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_node_positive_restriction")) {
|
||||
for (const auto& kvs :
|
||||
p.getStrArr(sec.first, "osm_node_positive_restriction", ' ')) {
|
||||
auto fRule = getFRule(kvs);
|
||||
curCfg.osmBuildOpts.restrPosRestr[fRule.kv.first].insert(
|
||||
osm::AttrFlagPair(fRule.kv.second, getFlags(fRule.flags)));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_node_negative_restriction")) {
|
||||
for (const auto& kvs :
|
||||
p.getStrArr(sec.first, "osm_node_negative_restriction", ' ')) {
|
||||
auto fRule = getFRule(kvs);
|
||||
curCfg.osmBuildOpts.restrNegRestr[fRule.kv.first].insert(
|
||||
osm::AttrFlagPair(fRule.kv.second, getFlags(fRule.flags)));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_filter_no_restriction")) {
|
||||
for (const auto& kvs :
|
||||
p.getStrArr(sec.first, "osm_filter_no_restriction", ' ')) {
|
||||
auto fRule = getFRule(kvs);
|
||||
curCfg.osmBuildOpts.noRestrFilter[fRule.kv.first].insert(
|
||||
osm::AttrFlagPair(fRule.kv.second, getFlags(fRule.flags)));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_station_name_attrs")) {
|
||||
for (const std::string& r :
|
||||
p.getStrArr(sec.first, "osm_station_name_attrs", ' ')) {
|
||||
curCfg.osmBuildOpts.statAttrRules.nameRule.push_back(
|
||||
getDeepAttrRule(r));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_track_number_tags")) {
|
||||
for (const std::string& r :
|
||||
p.getStrArr(sec.first, "osm_track_number_tags", ' ')) {
|
||||
curCfg.osmBuildOpts.statAttrRules.platformRule.push_back(
|
||||
getDeepAttrRule(r));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_edge_track_number_tags")) {
|
||||
for (const std::string& r :
|
||||
p.getStrArr(sec.first, "osm_edge_track_number_tags", ' ')) {
|
||||
curCfg.osmBuildOpts.edgePlatformRules.push_back(getDeepAttrRule(r));
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_station_group_attrs")) {
|
||||
auto arr = p.getStrArr(secStr, "osm_station_group_attrs", ' ');
|
||||
|
||||
for (const auto& ruleStr : arr) {
|
||||
auto deep = getDeepAttrRule(ruleStr);
|
||||
// TODO(patrick): getKv is misused here as a a=b parser
|
||||
auto attrD = getKv(deep.attr);
|
||||
deep.attr = attrD.first;
|
||||
double dist = atof(attrD.second.c_str());
|
||||
curCfg.osmBuildOpts.statGroupNAttrRules.push_back({deep, dist});
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_line_relation_tags")) {
|
||||
auto arr = p.getStrArr(secStr, "osm_line_relation_tags", ' ');
|
||||
|
||||
for (const auto& ruleStr : arr) {
|
||||
auto rule = getKv(ruleStr);
|
||||
auto tags = util::split(rule.second, ',');
|
||||
if (rule.first == "from_name")
|
||||
curCfg.osmBuildOpts.relLinerules.fromNameRule = tags;
|
||||
else if (rule.first == "to_name")
|
||||
curCfg.osmBuildOpts.relLinerules.toNameRule = tags;
|
||||
else if (rule.first == "line_name")
|
||||
curCfg.osmBuildOpts.relLinerules.sNameRule = tags;
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_max_snap_distance")) {
|
||||
curCfg.osmBuildOpts.maxSnapDistances =
|
||||
p.getDoubleArr(secStr, "osm_max_snap_distance", ',');
|
||||
} else {
|
||||
curCfg.osmBuildOpts.maxSnapDistances.push_back(50);
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_max_snap_fallback_distance")) {
|
||||
curCfg.osmBuildOpts.maxSnapFallbackHeurDistance =
|
||||
p.getDouble(secStr, "osm_max_snap_fallback_distance");
|
||||
} else {
|
||||
curCfg.osmBuildOpts.maxSnapFallbackHeurDistance =
|
||||
*std::max_element(curCfg.osmBuildOpts.maxSnapDistances.begin(),
|
||||
curCfg.osmBuildOpts.maxSnapDistances.end()) *
|
||||
2;
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_max_group_search_distance")) {
|
||||
curCfg.osmBuildOpts.maxGroupSearchDistance =
|
||||
p.getDouble(secStr, "osm_max_group_search_distance");
|
||||
} else {
|
||||
curCfg.osmBuildOpts.maxGroupSearchDistance =
|
||||
*std::max_element(curCfg.osmBuildOpts.maxSnapDistances.begin(),
|
||||
curCfg.osmBuildOpts.maxSnapDistances.end()) *
|
||||
4;
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_max_osm_station_distance")) {
|
||||
curCfg.osmBuildOpts.maxOsmStationDistance =
|
||||
p.getDouble(secStr, "osm_max_osm_station_distance");
|
||||
} else {
|
||||
curCfg.osmBuildOpts.maxOsmStationDistance = 5;
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "osm_max_node_block_distance")) {
|
||||
curCfg.osmBuildOpts.maxBlockDistance =
|
||||
p.getDouble(secStr, "osm_max_node_block_distance");
|
||||
} else {
|
||||
curCfg.osmBuildOpts.maxBlockDistance =
|
||||
*std::max_element(curCfg.osmBuildOpts.maxSnapDistances.begin(),
|
||||
curCfg.osmBuildOpts.maxSnapDistances.end()) /
|
||||
8;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
std::string name =
|
||||
std::string("routing_lvl") + std::to_string(i) + "_fac";
|
||||
if (p.hasKey(secStr, name)) {
|
||||
double v = p.getDouble(sec.first, name);
|
||||
curCfg.routingOpts.levelPunish[i] = v;
|
||||
} else {
|
||||
curCfg.routingOpts.levelPunish[i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "routing_full_turn_punish")) {
|
||||
curCfg.routingOpts.fullTurnPunishFac =
|
||||
p.getDouble(secStr, "routing_full_turn_punish");
|
||||
}
|
||||
if (p.hasKey(secStr, "routing_full_turn_angle")) {
|
||||
double ang = p.getDouble(secStr, "routing_full_turn_angle");
|
||||
curCfg.routingOpts.fullTurnAngle = ang;
|
||||
} else {
|
||||
curCfg.routingOpts.fullTurnAngle = 5;
|
||||
}
|
||||
if (p.hasKey(secStr, "routing_snap_full_turn_angle")) {
|
||||
double ang = p.getDouble(secStr, "routing_snap_full_turn_angle");
|
||||
curCfg.osmBuildOpts.maxAngleSnapReach = ang;
|
||||
} else {
|
||||
curCfg.osmBuildOpts.maxAngleSnapReach =
|
||||
curCfg.routingOpts.fullTurnAngle;
|
||||
}
|
||||
if (p.hasKey(secStr, "routing_pass_thru_station_punish")) {
|
||||
curCfg.routingOpts.passThruStationsPunish =
|
||||
p.getDouble(secStr, "routing_pass_thru_station_punish");
|
||||
}
|
||||
if (p.hasKey(secStr, "routing_one_way_meter_punish_fac")) {
|
||||
curCfg.routingOpts.oneWayPunishFac =
|
||||
p.getDouble(secStr, "routing_one_way_meter_punish_fac");
|
||||
}
|
||||
if (p.hasKey(secStr, "routing_one_way_edge_punish")) {
|
||||
curCfg.routingOpts.oneWayEdgePunish =
|
||||
p.getDouble(secStr, "routing_one_way_edge_punish");
|
||||
}
|
||||
if (p.hasKey(secStr, "routing_line_unmatched_punish_fac")) {
|
||||
curCfg.routingOpts.lineUnmatchedPunishFact =
|
||||
p.getDouble(secStr, "routing_line_unmatched_punish_fac");
|
||||
}
|
||||
if (p.hasKey(secStr, "routing_platform_unmatched_punish")) {
|
||||
curCfg.routingOpts.platformUnmatchedPen =
|
||||
p.getDouble(secStr, "routing_platform_unmatched_punish");
|
||||
}
|
||||
if (p.hasKey(secStr, "routing_non_osm_station_punish")) {
|
||||
curCfg.routingOpts.nonOsmPen =
|
||||
p.getDouble(secStr, "routing_non_osm_station_punish");
|
||||
} else {
|
||||
curCfg.routingOpts.nonOsmPen = 0;
|
||||
}
|
||||
if (p.hasKey(secStr, "routing_station_distance_punish_fac")) {
|
||||
curCfg.routingOpts.stationDistPenFactor =
|
||||
p.getDouble(secStr, "routing_station_distance_punish_fac");
|
||||
} else {
|
||||
curCfg.routingOpts.stationDistPenFactor = 1;
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "station_normalize_chain")) {
|
||||
try {
|
||||
auto arr = p.getStrArr(secStr, "station_normalize_chain", ';');
|
||||
curCfg.osmBuildOpts.statNormzer =
|
||||
trgraph::Normalizer(getNormRules(arr));
|
||||
} catch (const std::exception& e) {
|
||||
throw ParseExc(p.getVal(secStr, "station_normalize_chain").line,
|
||||
p.getVal(secStr, "station_normalize_chain").pos,
|
||||
"<valid regular expression>",
|
||||
std::string("<regex error: ") + e.what() + ">", s);
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "track_normalize_chain")) {
|
||||
try {
|
||||
auto arr = p.getStrArr(secStr, "track_normalize_chain", ';');
|
||||
curCfg.osmBuildOpts.trackNormzer =
|
||||
trgraph::Normalizer(getNormRules(arr));
|
||||
} catch (const std::exception& e) {
|
||||
throw ParseExc(p.getVal(secStr, "track_normalize_chain").line,
|
||||
p.getVal(secStr, "station_normalize_chain").pos,
|
||||
"<valid regular expression>",
|
||||
std::string("<regex error: ") + e.what() + ">", s);
|
||||
}
|
||||
}
|
||||
|
||||
if (p.hasKey(secStr, "line_normalize_chain")) {
|
||||
try {
|
||||
auto arr = p.getStrArr(secStr, "line_normalize_chain", ';');
|
||||
curCfg.osmBuildOpts.lineNormzer =
|
||||
trgraph::Normalizer(getNormRules(arr));
|
||||
} catch (const std::exception& e) {
|
||||
throw ParseExc(p.getVal(secStr, "station_normalize_chain").line,
|
||||
p.getVal(secStr, "station_normalize_chain").pos,
|
||||
"<valid regular expression>",
|
||||
std::string("<regex error: ") + e.what() + ">", s);
|
||||
}
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
|
||||
for (auto& cfg : _cfgs) {
|
||||
if (cfg == curCfg) {
|
||||
for (auto mot : Route::getTypesFromString(secStr)) {
|
||||
cfg.mots.insert(mot);
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
curCfg.mots = Route::getTypesFromString(secStr);
|
||||
_cfgs.push_back(curCfg);
|
||||
}
|
||||
if (!found) {
|
||||
curCfg.mots = ad::cppgtfs::gtfs::flat::Route::getTypesFromString(secStr);
|
||||
_cfgs.push_back(curCfg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,30 @@
|
|||
#ifndef PFAEDLE_CONFIG_MOTCONFIGREADER_H_
|
||||
#define PFAEDLE_CONFIG_MOTCONFIGREADER_H_
|
||||
|
||||
#include "pfaedle/_config.h"
|
||||
|
||||
#ifndef HOME_VAR
|
||||
#define HOME_VAR "HOME"
|
||||
#endif
|
||||
#ifndef XDG_DATA_HOME_SUFFIX
|
||||
#define XDG_DATA_HOME_SUFFIX "/.local/share"
|
||||
#endif
|
||||
#ifndef XDG_CONFIG_HOME_SUFFIX
|
||||
#define XDG_CONFIG_HOME_SUFFIX "/.config"
|
||||
#endif
|
||||
#ifndef XDG_CACHE_HOME_SUFFIX
|
||||
#define XDG_CACHE_HOME_SUFFIX "/.cache"
|
||||
#endif
|
||||
#ifndef XDG_DATA_DIRS_DEFAULT
|
||||
#define XDG_DATA_DIRS_DEFAULT "/usr/local/share"
|
||||
#endif
|
||||
#ifndef XDG_CONFIG_DIRS_DEFAULT
|
||||
#define XDG_CONFIG_DIRS_DEFAULT "/etc"
|
||||
#endif
|
||||
#ifndef CFG_FILE_NAME
|
||||
#define CFG_FILE_NAME "pfaedle.cfg"
|
||||
#endif
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@ struct Config {
|
|||
writeCombGraph(false),
|
||||
evaluate(false),
|
||||
buildTransitGraph(false),
|
||||
useCaching(false),
|
||||
writeOverpass(false),
|
||||
inPlace(false),
|
||||
gridSize(2000) {}
|
||||
std::string dbgOutputPath;
|
||||
std::string solveMethod;
|
||||
|
|
@ -46,6 +49,9 @@ struct Config {
|
|||
bool writeCombGraph;
|
||||
bool evaluate;
|
||||
bool buildTransitGraph;
|
||||
bool useCaching;
|
||||
bool writeOverpass;
|
||||
bool inPlace;
|
||||
double gridSize;
|
||||
|
||||
std::string toString() {
|
||||
|
|
@ -60,6 +66,8 @@ struct Config {
|
|||
<< "write-graph: " << writeGraph << "\n"
|
||||
<< "write-cgraph: " << writeCombGraph << "\n"
|
||||
<< "grid-size: " << gridSize << "\n"
|
||||
<< "use-cache: " << useCaching << "\n"
|
||||
<< "write-overpass: " << writeOverpass << "\n"
|
||||
<< "feed-paths: ";
|
||||
|
||||
for (const auto& p : feedPaths) {
|
||||
|
|
|
|||
|
|
@ -18,14 +18,14 @@
|
|||
|
||||
using util::geo::PolyLine;
|
||||
|
||||
using ad::cppgtfs::gtfs::Trip;
|
||||
using pfaedle::gtfs::Trip;
|
||||
using ad::cppgtfs::gtfs::Shape;
|
||||
using pfaedle::eval::Collector;
|
||||
using pfaedle::eval::Result;
|
||||
using util::geo::output::GeoJsonOutput;
|
||||
|
||||
// _____________________________________________________________________________
|
||||
double Collector::add(const Trip* t, const Shape* oldS, const Shape* newS,
|
||||
double Collector::add(const Trip* t, const Shape* oldS, const Shape& newS,
|
||||
const std::vector<double>& newTripDists) {
|
||||
if (!oldS) {
|
||||
_noOrigShp++;
|
||||
|
|
@ -51,7 +51,7 @@ double Collector::add(const Trip* t, const Shape* oldS, const Shape* newS,
|
|||
(--t->getStopTimes().end())->getShapeDistanceTravelled(), &oldDists);
|
||||
|
||||
std::vector<double> newDists;
|
||||
LINE newL = getWebMercLine(newS, -1, -1, &newDists);
|
||||
LINE newL = getWebMercLine(&newS, -1, -1, &newDists);
|
||||
|
||||
std::ofstream fstr(_evalOutPath + "/trip-" + t->getId() + ".json");
|
||||
GeoJsonOutput gjout(fstr);
|
||||
|
|
@ -123,19 +123,19 @@ double Collector::add(const Trip* t, const Shape* oldS, const Shape* newS,
|
|||
6378137.0)) -
|
||||
1.5707965);
|
||||
|
||||
if (_dCache.count(oldS) && _dCache.find(oldS)->second.count(newS)) {
|
||||
fd = _dCache[oldS][newS];
|
||||
if (_dCache.count(oldS) && _dCache.find(oldS)->second.count(newS.getId())) {
|
||||
fd = _dCache[oldS][newS.getId()];
|
||||
} else {
|
||||
fd = util::geo::accFrechetDistC(oldLCut, newLCut, 5 / fac) * fac;
|
||||
_dCache[oldS][newS] = fd;
|
||||
_dCache[oldS][newS.getId()] = fd;
|
||||
}
|
||||
|
||||
if (_dACache.count(oldS) && _dACache.find(oldS)->second.count(newS)) {
|
||||
unmatchedSegments = _dACache[oldS][newS].first;
|
||||
unmatchedSegmentsLength = _dACache[oldS][newS].second;
|
||||
if (_dACache.count(oldS) && _dACache.find(oldS)->second.count(newS.getId())) {
|
||||
unmatchedSegments = _dACache[oldS][newS.getId()].first;
|
||||
unmatchedSegmentsLength = _dACache[oldS][newS.getId()].second;
|
||||
} else {
|
||||
auto dA = getDa(oldSegs, newSegs);
|
||||
_dACache[oldS][newS] = dA;
|
||||
_dACache[oldS][newS.getId()] = dA;
|
||||
unmatchedSegments = dA.first;
|
||||
unmatchedSegmentsLength = dA.second;
|
||||
}
|
||||
|
|
@ -199,6 +199,8 @@ std::vector<LINE> Collector::segmentize(
|
|||
// get first half of geometry, and search for start point there!
|
||||
size_t before = std::upper_bound(dists.begin(), dists.end(), cuts[1].second) -
|
||||
dists.begin();
|
||||
if (before + 1 > shape.size()) before = shape.size() - 1;
|
||||
assert(shape.begin() + before + 1 <= shape.end());
|
||||
POLYLINE l(LINE(shape.begin(), shape.begin() + before + 1));
|
||||
auto lastLp = l.projectOn(cuts.front().first);
|
||||
|
||||
|
|
|
|||
|
|
@ -12,11 +12,12 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
#include "ad/cppgtfs/gtfs/Feed.h"
|
||||
#include "pfaedle/gtfs/Feed.h"
|
||||
#include "pfaedle/Def.h"
|
||||
#include "pfaedle/eval/Result.h"
|
||||
#include "util/geo/Geo.h"
|
||||
|
||||
using ad::cppgtfs::gtfs::Trip;
|
||||
using pfaedle::gtfs::Trip;
|
||||
using ad::cppgtfs::gtfs::Shape;
|
||||
|
||||
namespace pfaedle {
|
||||
|
|
@ -37,7 +38,7 @@ class Collector {
|
|||
|
||||
// Add a shape found by our tool newS for a trip t with newly calculated
|
||||
// station dist values with the old shape oldS
|
||||
double add(const Trip* t, const Shape* oldS, const Shape* newS,
|
||||
double add(const Trip* t, const Shape* oldS, const Shape& newS,
|
||||
const std::vector<double>& newDists);
|
||||
|
||||
// Return the set of all Result objects
|
||||
|
|
@ -65,8 +66,8 @@ class Collector {
|
|||
std::set<Result> _results;
|
||||
std::set<Result> _resultsAN;
|
||||
std::set<Result> _resultsAL;
|
||||
std::map<const Shape*, std::map<const Shape*, double> > _dCache;
|
||||
std::map<const Shape*, std::map<const Shape*, std::pair<size_t, double> > >
|
||||
std::map<const Shape*, std::map<std::string, double> > _dCache;
|
||||
std::map<const Shape*, std::map<std::string, std::pair<size_t, double> > >
|
||||
_dACache;
|
||||
size_t _noOrigShp;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,9 +5,10 @@
|
|||
#ifndef PFAEDLE_EVAL_RESULT_H_
|
||||
#define PFAEDLE_EVAL_RESULT_H_
|
||||
|
||||
#include "pfaedle/gtfs/Feed.h"
|
||||
#include "ad/cppgtfs/gtfs/Feed.h"
|
||||
|
||||
using ad::cppgtfs::gtfs::Trip;
|
||||
using pfaedle::gtfs::Trip;
|
||||
using ad::cppgtfs::gtfs::Shape;
|
||||
|
||||
namespace pfaedle {
|
||||
|
|
|
|||
37
src/pfaedle/gtfs/Feed.h
Normal file
37
src/pfaedle/gtfs/Feed.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright 2016, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_GTFS_FEED_H_
|
||||
#define PFAEDLE_GTFS_FEED_H_
|
||||
|
||||
#include <string>
|
||||
#include "Route.h"
|
||||
#include "Service.h"
|
||||
#include "ShapeContainer.h"
|
||||
#include "StopTime.h"
|
||||
#include "ad/cppgtfs/gtfs/ContContainer.h"
|
||||
#include "ad/cppgtfs/gtfs/Feed.h"
|
||||
#include "ad/cppgtfs/gtfs/NullContainer.h"
|
||||
#include "ad/cppgtfs/gtfs/Stop.h"
|
||||
#include "ad/cppgtfs/gtfs/StopTime.h"
|
||||
#include "ad/cppgtfs/gtfs/Trip.h"
|
||||
|
||||
namespace pfaedle {
|
||||
namespace gtfs {
|
||||
|
||||
typedef ad::cppgtfs::gtfs::FeedB<
|
||||
ad::cppgtfs::gtfs::Agency, Route, ad::cppgtfs::gtfs::Stop, Service,
|
||||
StopTime, Shape, ad::cppgtfs::gtfs::Fare, ad::cppgtfs::gtfs::Container,
|
||||
ad::cppgtfs::gtfs::ContContainer, ad::cppgtfs::gtfs::NullContainer,
|
||||
ad::cppgtfs::gtfs::ContContainer, ad::cppgtfs::gtfs::ContContainer,
|
||||
ShapeContainer, ad::cppgtfs::gtfs::NullContainer>
|
||||
Feed;
|
||||
typedef ad::cppgtfs::gtfs::TripB<StopTime<ad::cppgtfs::gtfs::Stop>, Service,
|
||||
Route, Shape>
|
||||
Trip;
|
||||
|
||||
} // namespace gtfs
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_GTFS_FEED_H_
|
||||
61
src/pfaedle/gtfs/Route.h
Normal file
61
src/pfaedle/gtfs/Route.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
// Copyright 2016, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_GTFS_ROUTE_H_
|
||||
#define PFAEDLE_GTFS_ROUTE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include "ad/cppgtfs/gtfs/Agency.h"
|
||||
#include "ad/cppgtfs/gtfs/Route.h"
|
||||
#include "util/Misc.h"
|
||||
|
||||
using std::exception;
|
||||
using std::string;
|
||||
|
||||
namespace pfaedle {
|
||||
namespace gtfs {
|
||||
|
||||
class Route {
|
||||
public:
|
||||
typedef Route* Ref;
|
||||
static std::string getId(Ref r) { return r->getId(); }
|
||||
|
||||
Route() {}
|
||||
|
||||
Route(const string& id, ad::cppgtfs::gtfs::Agency* agency,
|
||||
const string& short_name, const string& long_name, const string& desc,
|
||||
ad::cppgtfs::gtfs::flat::Route::TYPE type, const string& url,
|
||||
uint32_t color, uint32_t text_color)
|
||||
: _id(id), _short_name(short_name), _long_name(long_name), _type(type) {
|
||||
UNUSED(agency);
|
||||
UNUSED(desc);
|
||||
UNUSED(url);
|
||||
UNUSED(color);
|
||||
UNUSED(text_color);
|
||||
}
|
||||
|
||||
const std::string& getId() const { return _id; }
|
||||
|
||||
const std::string& getShortName() const { return _short_name; }
|
||||
|
||||
const std::string& getLongName() const { return _long_name; }
|
||||
|
||||
ad::cppgtfs::gtfs::flat::Route::TYPE getType() const { return _type; }
|
||||
|
||||
private:
|
||||
string _id;
|
||||
string _short_name;
|
||||
string _long_name;
|
||||
ad::cppgtfs::gtfs::flat::Route::TYPE _type;
|
||||
};
|
||||
|
||||
} // namespace gtfs
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_GTFS_ROUTE_H_
|
||||
43
src/pfaedle/gtfs/Service.h
Normal file
43
src/pfaedle/gtfs/Service.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2016, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_GTFS_SERVICE_H_
|
||||
#define PFAEDLE_GTFS_SERVICE_H_
|
||||
|
||||
#include <string>
|
||||
#include "ad/cppgtfs/gtfs/Service.h"
|
||||
#include "util/Misc.h"
|
||||
|
||||
namespace pfaedle {
|
||||
namespace gtfs {
|
||||
|
||||
class Service {
|
||||
public:
|
||||
typedef std::string Ref;
|
||||
static std::string getId(Ref r) { return r; }
|
||||
|
||||
explicit Service(const string& id) : _id(id) {}
|
||||
Service(const string& id, uint8_t serviceDays,
|
||||
ad::cppgtfs::gtfs::ServiceDate start,
|
||||
ad::cppgtfs::gtfs::ServiceDate end)
|
||||
: _id(id) {
|
||||
UNUSED(serviceDays);
|
||||
UNUSED(start);
|
||||
UNUSED(end);
|
||||
}
|
||||
|
||||
const std::string& getId() const { return _id; }
|
||||
void addException(const ad::cppgtfs::gtfs::ServiceDate& d,
|
||||
ad::cppgtfs::gtfs::Service::EXCEPTION_TYPE t) {
|
||||
UNUSED(d);
|
||||
UNUSED(t);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string _id;
|
||||
};
|
||||
} // namespace gtfs
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_GTFS_SERVICE_H_
|
||||
69
src/pfaedle/gtfs/ShapeContainer.h
Normal file
69
src/pfaedle/gtfs/ShapeContainer.h
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_GTFS_SHAPECONTAINER_H_
|
||||
#define PFAEDLE_GTFS_SHAPECONTAINER_H_
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include "ad/cppgtfs/gtfs/Shape.h"
|
||||
#include "ad/cppgtfs/gtfs/flat/Shape.h"
|
||||
#include "util/Misc.h"
|
||||
|
||||
namespace pfaedle {
|
||||
namespace gtfs {
|
||||
|
||||
struct Shape {
|
||||
explicit Shape(const std::string& id) : id(id) {}
|
||||
typedef std::string Ref;
|
||||
static std::string getId(Ref r) { return r; }
|
||||
|
||||
template <typename T>
|
||||
bool addPoint(T p) {
|
||||
UNUSED(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::string& getId() const { return id; }
|
||||
|
||||
std::string id;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ShapeContainer {
|
||||
public:
|
||||
ShapeContainer();
|
||||
~ShapeContainer();
|
||||
T* add(const T& obj);
|
||||
bool remove(const std::string& id);
|
||||
const T* get(const std::string& id) const;
|
||||
T* get(const std::string& id);
|
||||
const std::string getRef(const std::string& id) const;
|
||||
std::string getRef(const std::string& id);
|
||||
size_t size() const;
|
||||
void finalize() {}
|
||||
bool has(const std::string& id) const;
|
||||
|
||||
std::string add(const ad::cppgtfs::gtfs::Shape& s);
|
||||
void open();
|
||||
bool nextStoragePt(ad::cppgtfs::gtfs::flat::ShapePoint* ret);
|
||||
|
||||
private:
|
||||
std::set<std::string> _ids;
|
||||
std::fstream _storage;
|
||||
size_t _ptr;
|
||||
size_t _max;
|
||||
std::string _curId;
|
||||
std::stringstream _writeBuffer;
|
||||
};
|
||||
|
||||
#include "ShapeContainer.tpp"
|
||||
|
||||
} // namespace gtfs
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_GTFS_SHAPECONTAINER_H_
|
||||
154
src/pfaedle/gtfs/ShapeContainer.tpp
Normal file
154
src/pfaedle/gtfs/ShapeContainer.tpp
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
|
||||
// ____________________________________________________________________________
|
||||
template <typename T>
|
||||
ShapeContainer<T>::ShapeContainer() {
|
||||
std::string f = ".pfaedle-tmp";
|
||||
|
||||
while (access(f.c_str(), F_OK) != -1) {
|
||||
std::stringstream ss;
|
||||
ss << ".pfaedle-tmp-";
|
||||
ss << std::rand();
|
||||
f = ss.str().c_str();
|
||||
}
|
||||
|
||||
_storage.open(f, std::fstream::in | std::fstream::out | std::fstream::trunc);
|
||||
|
||||
// immediately unlink
|
||||
unlink(f.c_str());
|
||||
|
||||
if (!_storage.good()) {
|
||||
std::cerr << "Could not open temporary file " << f << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
template <typename T>
|
||||
ShapeContainer<T>::~ShapeContainer() {
|
||||
_storage.close();
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
template <typename T>
|
||||
T* ShapeContainer<T>::add(const T& ent) {
|
||||
_ids.insert(ent.getId());
|
||||
return reinterpret_cast<T*>(1);
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
template <typename T>
|
||||
bool ShapeContainer<T>::remove(const std::string& id) {
|
||||
_ids.erase(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
template <typename T>
|
||||
T* ShapeContainer<T>::get(const std::string& id) {
|
||||
if (!has(id)) return 0;
|
||||
return reinterpret_cast<T*>(1);
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
template <typename T>
|
||||
const T* ShapeContainer<T>::get(const std::string& id) const {
|
||||
if (!has(id)) return 0;
|
||||
return reinterpret_cast<T*>(1);
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
template <typename T>
|
||||
bool ShapeContainer<T>::has(const std::string& id) const {
|
||||
return _ids.count(id);
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
template <typename T>
|
||||
size_t ShapeContainer<T>::size() const {
|
||||
return _ids.size();
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
template <typename T>
|
||||
std::string ShapeContainer<T>::add(const ad::cppgtfs::gtfs::Shape& s) {
|
||||
if (has(s.getId())) return s.getId();
|
||||
_ids.insert(s.getId());
|
||||
|
||||
_writeBuffer << s.getId() << '\t' << s.getPoints().size();
|
||||
_writeBuffer << std::setprecision(11);
|
||||
for (auto p : s.getPoints()) {
|
||||
_writeBuffer << " " << p.lat << " " << p.lng << " " << p.travelDist;
|
||||
}
|
||||
// entries are newline separated
|
||||
_writeBuffer << '\n';
|
||||
|
||||
if (_writeBuffer.tellp() > 1000 * 5000) {
|
||||
_storage << _writeBuffer.rdbuf();
|
||||
_writeBuffer.clear();
|
||||
}
|
||||
|
||||
return s.getId();
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
template <typename T>
|
||||
void ShapeContainer<T>::open() {
|
||||
_storage << _writeBuffer.rdbuf();
|
||||
_writeBuffer.clear();
|
||||
|
||||
_ptr = 0;
|
||||
_max = 0;
|
||||
_storage.clear();
|
||||
_storage.seekg(0, std::ios::beg);
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
template <typename T>
|
||||
bool ShapeContainer<T>::nextStoragePt(
|
||||
ad::cppgtfs::gtfs::flat::ShapePoint* ret) {
|
||||
while (_storage.good() && !_storage.fail()) {
|
||||
if (!_ptr) {
|
||||
_storage >> _curId;
|
||||
_storage >> _max;
|
||||
}
|
||||
|
||||
if (!_storage.good() || _storage.fail()) return false;
|
||||
|
||||
_storage >> ret->lat;
|
||||
_storage >> ret->lng;
|
||||
_storage >> ret->travelDist;
|
||||
ret->seq = _ptr + 1;
|
||||
ret->id = _curId;
|
||||
|
||||
if (_ptr + 1 == _max)
|
||||
_ptr = 0;
|
||||
else
|
||||
_ptr++;
|
||||
|
||||
if (!_storage.good() || _storage.fail()) return false;
|
||||
|
||||
if (has(ret->id)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
template <typename T>
|
||||
const std::string ShapeContainer<T>::getRef(const std::string& id) const {
|
||||
if (!has(id)) return "";
|
||||
return id;
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
template <typename T>
|
||||
std::string ShapeContainer<T>::getRef(const std::string& id) {
|
||||
if (!has(id)) return "";
|
||||
return id;
|
||||
}
|
||||
71
src/pfaedle/gtfs/StopTime.h
Normal file
71
src/pfaedle/gtfs/StopTime.h
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
// Copyright 2016, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_GTFS_STOPTIME_H_
|
||||
#define PFAEDLE_GTFS_STOPTIME_H_
|
||||
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "ad/cppgtfs/gtfs/Stop.h"
|
||||
#include "ad/cppgtfs/gtfs/StopTime.h"
|
||||
#include "util/Misc.h"
|
||||
|
||||
using std::exception;
|
||||
using std::string;
|
||||
|
||||
namespace pfaedle {
|
||||
namespace gtfs {
|
||||
|
||||
template <typename StopT>
|
||||
class StopTime {
|
||||
public:
|
||||
StopTime(const ad::cppgtfs::gtfs::Time& at, const ad::cppgtfs::gtfs::Time& dt,
|
||||
typename StopT::Ref s, uint32_t seq, const std::string& hs,
|
||||
ad::cppgtfs::gtfs::flat::StopTime::PU_DO_TYPE put,
|
||||
ad::cppgtfs::gtfs::flat::StopTime::PU_DO_TYPE dot, float distTrav,
|
||||
bool isTp)
|
||||
: _s(s), _sequence(seq), _dist(distTrav) {
|
||||
UNUSED(at);
|
||||
UNUSED(dt);
|
||||
UNUSED(hs);
|
||||
UNUSED(put);
|
||||
UNUSED(dot);
|
||||
UNUSED(distTrav);
|
||||
UNUSED(isTp);
|
||||
}
|
||||
|
||||
const typename StopT::Ref getStop() const { return _s; }
|
||||
typename StopT::Ref getStop() { return _s; }
|
||||
void setShapeDistanceTravelled(double d) { _dist = d; }
|
||||
|
||||
ad::cppgtfs::gtfs::Time getArrivalTime() const {
|
||||
return ad::cppgtfs::gtfs::Time(0, 0, 0);
|
||||
}
|
||||
ad::cppgtfs::gtfs::Time getDepartureTime() const {
|
||||
return ad::cppgtfs::gtfs::Time(0, 0, 0);
|
||||
}
|
||||
|
||||
float getShapeDistanceTravelled() const { return _dist; }
|
||||
|
||||
uint16_t getSeq() const { return _sequence; }
|
||||
|
||||
private:
|
||||
typename StopT::Ref _s;
|
||||
uint32_t _sequence;
|
||||
float _dist;
|
||||
};
|
||||
|
||||
template <typename StopTimeT>
|
||||
struct StopTimeCompare {
|
||||
bool operator()(const StopTimeT& lh, const StopTimeT& rh) const {
|
||||
return lh.getSeq() < rh.getSeq();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gtfs
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_GTFS_STOPTIME_H_
|
||||
495
src/pfaedle/gtfs/Writer.cpp
Normal file
495
src/pfaedle/gtfs/Writer.cpp
Normal file
|
|
@ -0,0 +1,495 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include "ad/cppgtfs/Parser.h"
|
||||
#include "ad/cppgtfs/Writer.h"
|
||||
#include "ad/cppgtfs/gtfs/flat/Agency.h"
|
||||
#include "ad/util/CsvWriter.h"
|
||||
#include "pfaedle/gtfs/Writer.h"
|
||||
|
||||
using ad::util::CsvWriter;
|
||||
using ad::cppgtfs::Parser;
|
||||
using pfaedle::gtfs::Writer;
|
||||
|
||||
// ____________________________________________________________________________
|
||||
bool Writer::write(gtfs::Feed* sourceFeed, const std::string& path) const {
|
||||
std::ofstream fs;
|
||||
std::ifstream is;
|
||||
std::string gtfsPath(path);
|
||||
std::string curFile;
|
||||
std::string curFileTg;
|
||||
|
||||
curFile = gtfsPath + "/.agency.txt";
|
||||
curFileTg = gtfsPath + "/agency.txt";
|
||||
fs.open(curFile.c_str());
|
||||
if (!fs.good()) cannotWrite(curFile, curFileTg);
|
||||
writeAgency(sourceFeed, &fs);
|
||||
fs.close();
|
||||
std::rename(curFile.c_str(), curFileTg.c_str());
|
||||
|
||||
curFile = gtfsPath + "/.stops.txt";
|
||||
curFileTg = gtfsPath + "/stops.txt";
|
||||
fs.open(curFile.c_str());
|
||||
if (!fs.good()) cannotWrite(curFile, curFileTg);
|
||||
writeStops(sourceFeed, &fs);
|
||||
fs.close();
|
||||
std::rename(curFile.c_str(), curFileTg.c_str());
|
||||
|
||||
curFile = gtfsPath + "/.routes.txt";
|
||||
curFileTg = gtfsPath + "/routes.txt";
|
||||
fs.open(curFile.c_str());
|
||||
if (!fs.good()) cannotWrite(curFile, curFileTg);
|
||||
writeRoutes(sourceFeed, &fs);
|
||||
fs.close();
|
||||
std::rename(curFile.c_str(), curFileTg.c_str());
|
||||
|
||||
is.open((sourceFeed->getPath() + "/calendar.txt").c_str());
|
||||
if (is.good()) {
|
||||
is.close();
|
||||
curFile = gtfsPath + "/.calendar.txt";
|
||||
curFileTg = gtfsPath + "/calendar.txt";
|
||||
fs.open(curFile.c_str());
|
||||
if (!fs.good()) cannotWrite(curFile, curFileTg);
|
||||
writeCalendar(sourceFeed, &fs);
|
||||
fs.close();
|
||||
std::rename(curFile.c_str(), curFileTg.c_str());
|
||||
}
|
||||
|
||||
is.open((sourceFeed->getPath() + "/calendar_dates.txt").c_str());
|
||||
if (is.good()) {
|
||||
is.close();
|
||||
curFile = gtfsPath + "/.calendar_dates.txt";
|
||||
curFileTg = gtfsPath + "/calendar_dates.txt";
|
||||
fs.open(curFile.c_str());
|
||||
if (!fs.good()) cannotWrite(curFile, curFileTg);
|
||||
writeCalendarDates(sourceFeed, &fs);
|
||||
fs.close();
|
||||
std::rename(curFile.c_str(), curFileTg.c_str());
|
||||
}
|
||||
|
||||
is.open((sourceFeed->getPath() + "/transfers.txt").c_str());
|
||||
if (is.good()) {
|
||||
is.close();
|
||||
curFile = gtfsPath + "/.transfers.txt";
|
||||
curFileTg = gtfsPath + "/transfers.txt";
|
||||
fs.open(curFile.c_str());
|
||||
if (!fs.good()) cannotWrite(curFile, curFileTg);
|
||||
writeTransfers(sourceFeed, &fs);
|
||||
fs.close();
|
||||
std::rename(curFile.c_str(), curFileTg.c_str());
|
||||
}
|
||||
|
||||
is.open((sourceFeed->getPath() + "/fare_attributes.txt").c_str());
|
||||
if (is.good()) {
|
||||
is.close();
|
||||
curFile = gtfsPath + "/.fare_attributes.txt";
|
||||
curFileTg = gtfsPath + "/fare_attributes.txt";
|
||||
fs.open(curFile.c_str());
|
||||
if (!fs.good()) cannotWrite(curFile, curFileTg);
|
||||
writeFares(sourceFeed, &fs);
|
||||
fs.close();
|
||||
std::rename(curFile.c_str(), curFileTg.c_str());
|
||||
}
|
||||
|
||||
is.open((sourceFeed->getPath() + "/fare_rules.txt").c_str());
|
||||
if (is.good()) {
|
||||
is.close();
|
||||
curFile = gtfsPath + "/.fare_rules.txt";
|
||||
curFileTg = gtfsPath + "/fare_rules.txt";
|
||||
fs.open(curFile.c_str());
|
||||
if (!fs.good()) cannotWrite(curFile, curFileTg);
|
||||
writeFareRules(sourceFeed, &fs);
|
||||
fs.close();
|
||||
std::rename(curFile.c_str(), curFileTg.c_str());
|
||||
}
|
||||
|
||||
is.close();
|
||||
curFile = gtfsPath + "/.shapes.txt";
|
||||
curFileTg = gtfsPath + "/shapes.txt";
|
||||
fs.open(curFile.c_str());
|
||||
if (!fs.good()) cannotWrite(curFile, curFileTg);
|
||||
writeShapes(sourceFeed, &fs);
|
||||
fs.close();
|
||||
std::rename(curFile.c_str(), curFileTg.c_str());
|
||||
|
||||
is.close();
|
||||
curFile = gtfsPath + "/.trips.txt";
|
||||
curFileTg = gtfsPath + "/trips.txt";
|
||||
fs.open(curFile.c_str());
|
||||
if (!fs.good()) cannotWrite(curFile, curFileTg);
|
||||
bool hasFreqs = writeTrips(sourceFeed, &fs);
|
||||
fs.close();
|
||||
std::rename(curFile.c_str(), curFileTg.c_str());
|
||||
|
||||
is.open((sourceFeed->getPath() + "/frequencies.txt").c_str());
|
||||
if (hasFreqs && is.good()) {
|
||||
is.close();
|
||||
curFile = gtfsPath + "/.frequencies.txt";
|
||||
curFileTg = gtfsPath + "/frequencies.txt";
|
||||
fs.open(curFile.c_str());
|
||||
if (!fs.good()) cannotWrite(curFile, curFileTg);
|
||||
writeFrequencies(sourceFeed, &fs);
|
||||
fs.close();
|
||||
std::rename(curFile.c_str(), curFileTg.c_str());
|
||||
}
|
||||
|
||||
is.close();
|
||||
curFile = gtfsPath + "/.stop_times.txt";
|
||||
curFileTg = gtfsPath + "/stop_times.txt";
|
||||
fs.open(curFile.c_str());
|
||||
if (!fs.good()) cannotWrite(curFile, curFileTg);
|
||||
writeStopTimes(sourceFeed, &fs);
|
||||
fs.close();
|
||||
std::rename(curFile.c_str(), curFileTg.c_str());
|
||||
|
||||
if (!sourceFeed->getPublisherUrl().empty() &&
|
||||
!sourceFeed->getPublisherName().empty()) {
|
||||
curFile = gtfsPath + "/.feed_info.txt";
|
||||
curFileTg = gtfsPath + "/feed_info.txt";
|
||||
fs.open(curFile.c_str());
|
||||
if (!fs.good()) cannotWrite(curFile, curFileTg);
|
||||
writeFeedInfo(sourceFeed, &fs);
|
||||
fs.close();
|
||||
std::rename(curFile.c_str(), curFileTg.c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
bool Writer::writeFeedInfo(gtfs::Feed* f, std::ostream* os) const {
|
||||
auto csvw = ad::cppgtfs::Writer::getFeedInfoCsvw(os);
|
||||
csvw.flushLine();
|
||||
csvw.writeString(f->getPublisherName());
|
||||
csvw.writeString(f->getPublisherUrl());
|
||||
csvw.writeString(f->getLang());
|
||||
if (!f->getStartDate().empty())
|
||||
csvw.writeInt(f->getStartDate().getYYYYMMDD());
|
||||
else
|
||||
csvw.skip();
|
||||
if (!f->getEndDate().empty())
|
||||
csvw.writeInt(f->getEndDate().getYYYYMMDD());
|
||||
else
|
||||
csvw.skip();
|
||||
csvw.writeString(f->getVersion());
|
||||
csvw.flushLine();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
bool Writer::writeAgency(gtfs::Feed* sourceFeed, std::ostream* os) const {
|
||||
std::ifstream fs;
|
||||
fs.open((sourceFeed->getPath() + "/agency.txt").c_str());
|
||||
|
||||
CsvParser csvp(&fs);
|
||||
Parser p;
|
||||
ad::cppgtfs::Writer w;
|
||||
|
||||
CsvWriter csvw = ad::cppgtfs::Writer::getAgencyCsvw(os);
|
||||
csvw.flushLine();
|
||||
|
||||
ad::cppgtfs::gtfs::flat::Agency fa;
|
||||
auto flds = Parser::getAgencyFlds(&csvp);
|
||||
|
||||
while (p.nextAgency(&csvp, &fa, flds)) {
|
||||
w.writeAgency(fa, &csvw);
|
||||
}
|
||||
fs.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
bool Writer::writeStops(gtfs::Feed* sourceFeed, std::ostream* os) const {
|
||||
std::ifstream fs;
|
||||
fs.open((sourceFeed->getPath() + "/stops.txt").c_str());
|
||||
|
||||
CsvParser csvp(&fs);
|
||||
Parser p;
|
||||
ad::cppgtfs::Writer w;
|
||||
|
||||
CsvWriter csvw = ad::cppgtfs::Writer::getStopsCsvw(os);
|
||||
csvw.flushLine();
|
||||
|
||||
ad::cppgtfs::gtfs::flat::Stop s;
|
||||
auto flds = Parser::getStopFlds(&csvp);
|
||||
|
||||
while (p.nextStop(&csvp, &s, flds)) {
|
||||
w.writeStop(s, &csvw);
|
||||
}
|
||||
fs.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
bool Writer::writeRoutes(gtfs::Feed* sourceFeed, std::ostream* os) const {
|
||||
std::ifstream fs;
|
||||
fs.open((sourceFeed->getPath() + "/routes.txt").c_str());
|
||||
|
||||
CsvParser csvp(&fs);
|
||||
Parser p;
|
||||
ad::cppgtfs::Writer w;
|
||||
|
||||
CsvWriter csvw = ad::cppgtfs::Writer::getRoutesCsvw(os);
|
||||
csvw.flushLine();
|
||||
|
||||
ad::cppgtfs::gtfs::flat::Route s;
|
||||
auto flds = Parser::getRouteFlds(&csvp);
|
||||
|
||||
while (p.nextRoute(&csvp, &s, flds)) {
|
||||
w.writeRoute(s, &csvw);
|
||||
}
|
||||
fs.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
bool Writer::writeCalendar(gtfs::Feed* sourceFeed, std::ostream* os) const {
|
||||
std::ifstream fs;
|
||||
fs.open((sourceFeed->getPath() + "/calendar.txt").c_str());
|
||||
|
||||
CsvParser csvp(&fs);
|
||||
Parser p;
|
||||
ad::cppgtfs::Writer w;
|
||||
|
||||
CsvWriter csvw = ad::cppgtfs::Writer::getCalendarCsvw(os);
|
||||
csvw.flushLine();
|
||||
|
||||
ad::cppgtfs::gtfs::flat::Calendar c;
|
||||
auto flds = Parser::getCalendarFlds(&csvp);
|
||||
|
||||
while (p.nextCalendar(&csvp, &c, flds)) {
|
||||
w.writeCalendar(c, &csvw);
|
||||
}
|
||||
fs.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
bool Writer::writeCalendarDates(gtfs::Feed* sourceFeed,
|
||||
std::ostream* os) const {
|
||||
std::ifstream fs;
|
||||
fs.open((sourceFeed->getPath() + "/calendar_dates.txt").c_str());
|
||||
|
||||
CsvParser csvp(&fs);
|
||||
Parser p;
|
||||
ad::cppgtfs::Writer w;
|
||||
|
||||
CsvWriter csvw = ad::cppgtfs::Writer::getCalendarDatesCsvw(os);
|
||||
csvw.flushLine();
|
||||
|
||||
ad::cppgtfs::gtfs::flat::CalendarDate c;
|
||||
auto flds = Parser::getCalendarDateFlds(&csvp);
|
||||
|
||||
while (p.nextCalendarDate(&csvp, &c, flds)) {
|
||||
w.writeCalendarDate(c, &csvw);
|
||||
}
|
||||
fs.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
bool Writer::writeFrequencies(gtfs::Feed* sourceFeed, std::ostream* os) const {
|
||||
std::ifstream fs;
|
||||
fs.open((sourceFeed->getPath() + "/frequencies.txt").c_str());
|
||||
|
||||
CsvParser csvp(&fs);
|
||||
Parser p;
|
||||
ad::cppgtfs::Writer w;
|
||||
|
||||
CsvWriter csvw = ad::cppgtfs::Writer::getFrequencyCsvw(os);
|
||||
csvw.flushLine();
|
||||
|
||||
ad::cppgtfs::gtfs::flat::Frequency f;
|
||||
auto flds = Parser::getFrequencyFlds(&csvp);
|
||||
|
||||
while (p.nextFrequency(&csvp, &f, flds)) {
|
||||
w.writeFrequency(f, &csvw);
|
||||
}
|
||||
fs.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
bool Writer::writeTransfers(gtfs::Feed* sourceFeed, std::ostream* os) const {
|
||||
std::ifstream fs;
|
||||
fs.open((sourceFeed->getPath() + "/transfers.txt").c_str());
|
||||
|
||||
CsvParser csvp(&fs);
|
||||
Parser p;
|
||||
ad::cppgtfs::Writer w;
|
||||
|
||||
CsvWriter csvw = ad::cppgtfs::Writer::getTransfersCsvw(os);
|
||||
csvw.flushLine();
|
||||
|
||||
ad::cppgtfs::gtfs::flat::Transfer t;
|
||||
auto flds = Parser::getTransfersFlds(&csvp);
|
||||
|
||||
while (p.nextTransfer(&csvp, &t, flds)) {
|
||||
w.writeTransfer(t, &csvw);
|
||||
}
|
||||
fs.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
bool Writer::writeFares(gtfs::Feed* sourceFeed, std::ostream* os) const {
|
||||
std::ifstream fs;
|
||||
fs.open((sourceFeed->getPath() + "/fare_attributes.txt").c_str());
|
||||
|
||||
CsvParser csvp(&fs);
|
||||
Parser p;
|
||||
ad::cppgtfs::Writer w;
|
||||
|
||||
CsvWriter csvw = ad::cppgtfs::Writer::getFaresCsvw(os);
|
||||
csvw.flushLine();
|
||||
|
||||
ad::cppgtfs::gtfs::flat::Fare f;
|
||||
auto flds = Parser::getFareFlds(&csvp);
|
||||
|
||||
while (p.nextFare(&csvp, &f, flds)) {
|
||||
w.writeFare(f, &csvw);
|
||||
}
|
||||
fs.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
bool Writer::writeFareRules(gtfs::Feed* sourceFeed, std::ostream* os) const {
|
||||
std::ifstream fs;
|
||||
fs.open((sourceFeed->getPath() + "/fare_rules.txt").c_str());
|
||||
|
||||
CsvParser csvp(&fs);
|
||||
Parser p;
|
||||
ad::cppgtfs::Writer w;
|
||||
|
||||
CsvWriter csvw = ad::cppgtfs::Writer::getFareRulesCsvw(os);
|
||||
csvw.flushLine();
|
||||
|
||||
ad::cppgtfs::gtfs::flat::FareRule f;
|
||||
auto flds = Parser::getFareRuleFlds(&csvp);
|
||||
|
||||
while (p.nextFareRule(&csvp, &f, flds)) {
|
||||
w.writeFareRule(f, &csvw);
|
||||
}
|
||||
fs.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
bool Writer::writeShapes(gtfs::Feed* sourceFeed, std::ostream* os) const {
|
||||
std::ifstream fs;
|
||||
fs.open((sourceFeed->getPath() + "/shapes.txt").c_str());
|
||||
|
||||
CsvWriter csvw = ad::cppgtfs::Writer::getShapesCsvw(os);
|
||||
csvw.flushLine();
|
||||
ad::cppgtfs::gtfs::flat::ShapePoint sp;
|
||||
ad::cppgtfs::Writer w;
|
||||
|
||||
if (fs.good()) {
|
||||
CsvParser csvp(&fs);
|
||||
Parser p;
|
||||
|
||||
auto flds = Parser::getShapeFlds(&csvp);
|
||||
|
||||
std::string curShapeId;
|
||||
std::string curSkipShapeId;
|
||||
|
||||
while (p.nextShapePoint(&csvp, &sp, flds)) {
|
||||
if (sp.id == curSkipShapeId) continue;
|
||||
if (sp.id != curShapeId) {
|
||||
if (sourceFeed->getShapes().has(sp.id)) {
|
||||
curShapeId = sp.id;
|
||||
} else {
|
||||
curSkipShapeId = sp.id;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
w.writeShapePoint(sp, &csvw);
|
||||
}
|
||||
}
|
||||
|
||||
sourceFeed->getShapes().open();
|
||||
while (sourceFeed->getShapes().nextStoragePt(&sp)) {
|
||||
w.writeShapePoint(sp, &csvw);
|
||||
}
|
||||
|
||||
fs.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
bool Writer::writeTrips(gtfs::Feed* sourceFeed, std::ostream* os) const {
|
||||
ad::cppgtfs::Writer w;
|
||||
bool hasFreqs = false;
|
||||
|
||||
CsvWriter csvw = ad::cppgtfs::Writer::getTripsCsvw(os);
|
||||
csvw.flushLine();
|
||||
|
||||
for (auto t : sourceFeed->getTrips()) {
|
||||
if (t.getFrequencies().size()) hasFreqs = true;
|
||||
w.writeTrip(t.getFlat(), &csvw);
|
||||
}
|
||||
|
||||
return hasFreqs;
|
||||
}
|
||||
|
||||
// ____________________________________________________________________________
|
||||
bool Writer::writeStopTimes(gtfs::Feed* sourceFeed, std::ostream* os) const {
|
||||
std::ifstream fs;
|
||||
fs.open((sourceFeed->getPath() + "/stop_times.txt").c_str());
|
||||
|
||||
CsvParser csvp(&fs);
|
||||
Parser p;
|
||||
ad::cppgtfs::Writer w;
|
||||
|
||||
CsvWriter csvw = ad::cppgtfs::Writer::getStopTimesCsvw(os);
|
||||
csvw.flushLine();
|
||||
|
||||
ad::cppgtfs::gtfs::flat::StopTime st;
|
||||
auto flds = Parser::getStopTimeFlds(&csvp);
|
||||
|
||||
std::string curTripId;
|
||||
Trip* cur = 0;
|
||||
|
||||
while (p.nextStopTime(&csvp, &st, flds)) {
|
||||
// we may have changed to distance field
|
||||
if (curTripId != st.trip) {
|
||||
cur = sourceFeed->getTrips().get(st.trip);
|
||||
curTripId = st.trip;
|
||||
}
|
||||
for (const auto& stN : cur->getStopTimes()) {
|
||||
if (stN.getSeq() == st.sequence)
|
||||
st.shapeDistTravelled = stN.getShapeDistanceTravelled();
|
||||
}
|
||||
|
||||
w.writeStopTime(st, &csvw);
|
||||
}
|
||||
fs.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ___________________________________________________________________________
|
||||
void Writer::cannotWrite(const std::string& file, const std::string& file2) {
|
||||
std::stringstream ss;
|
||||
ss << "(temporary file for " << file2 << ") Could not write to file";
|
||||
throw ad::cppgtfs::WriterException(ss.str(), file);
|
||||
}
|
||||
41
src/pfaedle/gtfs/Writer.h
Normal file
41
src/pfaedle/gtfs/Writer.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2016, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_GTFS_WRITER_H_
|
||||
#define PFAEDLE_GTFS_WRITER_H_
|
||||
|
||||
#include <string>
|
||||
#include "Feed.h"
|
||||
|
||||
namespace pfaedle {
|
||||
namespace gtfs {
|
||||
|
||||
class Writer {
|
||||
public:
|
||||
Writer() {}
|
||||
|
||||
bool write(Feed* sourceFeed, const std::string& path) const;
|
||||
|
||||
private:
|
||||
bool writeFeedInfo(Feed* f, std::ostream* os) const;
|
||||
bool writeAgency(Feed* f, std::ostream* os) const;
|
||||
bool writeStops(Feed* f, std::ostream* os) const;
|
||||
bool writeRoutes(Feed* f, std::ostream* os) const;
|
||||
bool writeCalendar(Feed* f, std::ostream* os) const;
|
||||
bool writeCalendarDates(Feed* f, std::ostream* os) const;
|
||||
bool writeFrequencies(Feed* f, std::ostream* os) const;
|
||||
bool writeTransfers(Feed* f, std::ostream* os) const;
|
||||
bool writeFares(Feed* f, std::ostream* os) const;
|
||||
bool writeFareRules(Feed* f, std::ostream* os) const;
|
||||
bool writeShapes(Feed* f, std::ostream* os) const;
|
||||
bool writeTrips(Feed* f, std::ostream* os) const;
|
||||
bool writeStopTimes(Feed* f, std::ostream* os) const;
|
||||
|
||||
static void cannotWrite(const std::string& file, const std::string& file2);
|
||||
};
|
||||
|
||||
} // namespace gtfs
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_GTFS_WRITER_H_
|
||||
|
|
@ -9,11 +9,12 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
#include "ad/cppgtfs/gtfs/Feed.h"
|
||||
#include "pfaedle/gtfs/Feed.h"
|
||||
#include "util/String.h"
|
||||
#include "util/geo/GeoGraph.h"
|
||||
|
||||
using util::geograph::GeoEdgePL;
|
||||
using ad::cppgtfs::gtfs::Trip;
|
||||
using pfaedle::gtfs::Trip;
|
||||
|
||||
namespace pfaedle {
|
||||
namespace netgraph {
|
||||
|
|
@ -22,7 +23,7 @@ namespace netgraph {
|
|||
* A payload class for edges on a network graph - that is a graph
|
||||
* that exactly represents a physical public transit network
|
||||
*/
|
||||
class EdgePL : public GeoEdgePL<PFAEDLE_PRECISION> {
|
||||
class EdgePL {
|
||||
public:
|
||||
EdgePL() {}
|
||||
EdgePL(const LINE& l, const std::set<const Trip*>& trips)
|
||||
|
|
@ -36,10 +37,10 @@ class EdgePL : public GeoEdgePL<PFAEDLE_PRECISION> {
|
|||
util::json::Dict getAttrs() const {
|
||||
util::json::Dict obj;
|
||||
obj["num_trips"] = static_cast<int>(_trips.size());
|
||||
obj["route_short_names"] = util::json::Array(
|
||||
_routeShortNames.begin(), _routeShortNames.end());
|
||||
obj["trip_short_names"] = util::json::Array(_tripShortNames.begin(),
|
||||
_tripShortNames.end());
|
||||
obj["route_short_names"] =
|
||||
util::json::Array(_routeShortNames.begin(), _routeShortNames.end());
|
||||
obj["trip_short_names"] =
|
||||
util::json::Array(_tripShortNames.begin(), _tripShortNames.end());
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
using util::geograph::GeoNodePL;
|
||||
|
||||
|
||||
namespace pfaedle {
|
||||
namespace netgraph {
|
||||
|
||||
|
|
@ -20,15 +19,13 @@ namespace netgraph {
|
|||
* A payload class for edges on a network graph - that is a graph
|
||||
* that exactly represents a physical public transit network
|
||||
*/
|
||||
class NodePL : public GeoNodePL<PFAEDLE_PRECISION> {
|
||||
class NodePL {
|
||||
public:
|
||||
NodePL() {}
|
||||
NodePL(const POINT& geom) { _geom = geom; } // NOLINT
|
||||
|
||||
const POINT* getGeom() const { return &_geom; }
|
||||
util::json::Dict getAttrs() const {
|
||||
return util::json::Dict();
|
||||
}
|
||||
util::json::Dict getAttrs() const { return util::json::Dict(); }
|
||||
|
||||
private:
|
||||
POINT _geom;
|
||||
|
|
|
|||
|
|
@ -37,6 +37,31 @@ BOX BBoxIdx::getFullWebMercBox() const {
|
|||
_root.box.getUpperRight().getY(), _root.box.getUpperRight().getX()));
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
BOX BBoxIdx::getFullBox() const { return _root.box; }
|
||||
|
||||
// _____________________________________________________________________________
|
||||
std::vector<util::geo::Box<double>> BBoxIdx::getLeafs() const {
|
||||
std::vector<util::geo::Box<double>> ret;
|
||||
getLeafsRec(_root, &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void BBoxIdx::getLeafsRec(const BBoxIdxNd& nd,
|
||||
std::vector<util::geo::Box<double>>* ret) const {
|
||||
if (!nd.childs.size()) {
|
||||
ret->push_back(nd.box);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& child : nd.childs) {
|
||||
getLeafsRec(child, ret);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
bool BBoxIdx::treeHas(const Point<double>& p, const BBoxIdxNd& nd) const {
|
||||
if (!nd.childs.size()) return util::geo::contains(p, nd.box);
|
||||
|
|
|
|||
|
|
@ -38,9 +38,15 @@ class BBoxIdx {
|
|||
// Return the full total bounding box of this index
|
||||
BOX getFullWebMercBox() const;
|
||||
|
||||
// Return the full total bounding box of this index
|
||||
BOX getFullBox() const;
|
||||
|
||||
// Return the size of this index
|
||||
size_t size() const;
|
||||
|
||||
// return the leaf bounding boxes of this idx
|
||||
std::vector<Box<double>> getLeafs() const;
|
||||
|
||||
private:
|
||||
double _padding;
|
||||
size_t _size;
|
||||
|
|
@ -50,6 +56,9 @@ class BBoxIdx {
|
|||
void addToTree(const Box<double>& box, BBoxIdxNd* nd, size_t lvl);
|
||||
bool treeHas(const Point<double>& p, const BBoxIdxNd& nd) const;
|
||||
|
||||
void getLeafsRec(const BBoxIdxNd& nd,
|
||||
std::vector<util::geo::Box<double>>* ret) const;
|
||||
|
||||
static const size_t MAX_LVL = 5;
|
||||
static constexpr double MIN_COM_AREA = 0.0;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -43,8 +43,20 @@ using pfaedle::osm::OsmRel;
|
|||
using pfaedle::osm::OsmNode;
|
||||
using pfaedle::osm::EdgeGrid;
|
||||
using pfaedle::osm::NodeGrid;
|
||||
using pfaedle::osm::EqSearch;
|
||||
using pfaedle::osm::BlockSearch;
|
||||
using ad::cppgtfs::gtfs::Stop;
|
||||
|
||||
// _____________________________________________________________________________
|
||||
bool EqSearch::operator()(const Node* cand, const StatInfo* si) const {
|
||||
if (orphanSnap && cand->pl().getSI() &&
|
||||
(!cand->pl().getSI()->getGroup() ||
|
||||
cand->pl().getSI()->getGroup()->getStops().size() == 0)) {
|
||||
return true;
|
||||
}
|
||||
return cand->pl().getSI() && cand->pl().getSI()->simi(si) > minSimi;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
OsmBuilder::OsmBuilder() {}
|
||||
|
||||
|
|
@ -140,7 +152,8 @@ void OsmBuilder::read(const std::string& path, const OsmReadOpts& opts,
|
|||
POINT geom = *s->pl().getGeom();
|
||||
NodePL pl = s->pl();
|
||||
pl.getSI()->setIsFromOsm(false);
|
||||
const auto& r = snapStation(g, &pl, &eg, &sng, opts, res, false, d);
|
||||
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
|
||||
|
|
@ -153,32 +166,70 @@ void OsmBuilder::read(const std::string& path, const OsmReadOpts& opts,
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<const Stop*> notSnapped;
|
||||
|
||||
for (size_t i = 0; i < opts.maxSnapDistances.size(); i++) {
|
||||
double d = opts.maxSnapDistances[i];
|
||||
for (auto& s : *fs) {
|
||||
auto pl = plFromGtfs(s.first, opts);
|
||||
|
||||
StatGroup* group =
|
||||
groupStats(snapStation(g, &pl, &eg, &sng, opts, res,
|
||||
i == opts.maxSnapDistances.size() - 1, d));
|
||||
StatGroup* group = groupStats(
|
||||
snapStation(g, &pl, &eg, &sng, opts, res,
|
||||
i == opts.maxSnapDistances.size() - 1, false, d));
|
||||
|
||||
if (group) {
|
||||
group->addStop(s.first);
|
||||
(*fs)[s.first] = *group->getNodes().begin();
|
||||
} else if (i == opts.maxSnapDistances.size() - 1) {
|
||||
LOG(VDEBUG) << "Could not snap station "
|
||||
<< "(" << pl.getSI()->getName() << ")"
|
||||
<< " (" << s.first->getLat() << "," << s.first->getLng()
|
||||
<< ") in normal run, trying again later in orphan mode.";
|
||||
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 (size_t i = 0; i < opts.maxSnapDistances.size(); i++) {
|
||||
double d = opts.maxSnapDistances[i];
|
||||
for (auto& s : notSnapped) {
|
||||
auto pl = plFromGtfs(s, opts);
|
||||
|
||||
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();
|
||||
} else if (i ==
|
||||
opts.maxSnapDistances.size() - 1) { // only fail on last
|
||||
// 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.first);
|
||||
(*fs)[s.first] = dummyNode;
|
||||
dummyGroup->addStop(s);
|
||||
(*fs)[s] = dummyNode;
|
||||
LOG(WARN) << "Could not snap station "
|
||||
<< "(" << pl.getSI()->getName() << ")"
|
||||
<< " (" << s.first->getLat() << "," << s.first->getLng()
|
||||
<< ")";
|
||||
<< " (" << s->getLat() << "," << s->getLng() << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -188,7 +239,7 @@ void OsmBuilder::read(const std::string& path, const OsmReadOpts& opts,
|
|||
deleteOrphNds(g);
|
||||
|
||||
LOG(VDEBUG) << "Deleting orphan edges...";
|
||||
deleteOrphEdgs(g);
|
||||
deleteOrphEdgs(g, opts);
|
||||
|
||||
LOG(VDEBUG) << "Collapsing edges...";
|
||||
collapseEdges(g);
|
||||
|
|
@ -197,7 +248,7 @@ void OsmBuilder::read(const std::string& path, const OsmReadOpts& opts,
|
|||
deleteOrphNds(g);
|
||||
|
||||
LOG(VDEBUG) << "Deleting orphan edges...";
|
||||
deleteOrphEdgs(g);
|
||||
deleteOrphEdgs(g, opts);
|
||||
|
||||
LOG(VDEBUG) << "Writing graph components...";
|
||||
// the restrictor is needed here to prevent connections in the graph
|
||||
|
|
@ -223,6 +274,89 @@ void OsmBuilder::read(const std::string& path, const OsmReadOpts& opts,
|
|||
<< " edges and " << comps << " connected component(s)";
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void OsmBuilder::overpassQryWrite(std::ostream* out,
|
||||
const std::vector<OsmReadOpts>& opts,
|
||||
const BBoxIdx& latLngBox) const {
|
||||
OsmIdSet bboxNodes, noHupNodes;
|
||||
MultAttrMap emptyF;
|
||||
|
||||
RelLst rels;
|
||||
OsmIdList ways;
|
||||
RelMap nodeRels, wayRels;
|
||||
|
||||
// TODO(patrick): not needed here!
|
||||
Restrictions rests;
|
||||
|
||||
NIdMap nodes;
|
||||
|
||||
// always empty
|
||||
NIdMultMap multNodes;
|
||||
util::xml::XmlWriter wr(out, true, 4);
|
||||
|
||||
*out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||
wr.openComment();
|
||||
wr.writeText(" - written by pfaedle -");
|
||||
wr.closeTag();
|
||||
wr.openTag("osm-script",
|
||||
{{"timeout", "99999"}, {"element-limit", "1073741824"}});
|
||||
|
||||
OsmFilter filter;
|
||||
|
||||
for (const OsmReadOpts& o : opts) {
|
||||
filter = filter.merge(OsmFilter(o.keepFilter, o.dropFilter));
|
||||
}
|
||||
|
||||
wr.openTag("union");
|
||||
size_t c = 0;
|
||||
for (auto box : latLngBox.getLeafs()) {
|
||||
if (box.getLowerLeft().getX() > box.getUpperRight().getX()) continue;
|
||||
c++;
|
||||
wr.openComment();
|
||||
wr.writeText(std::string("Bounding box #") + std::to_string(c) + " (" +
|
||||
std::to_string(box.getLowerLeft().getY()) + ", " +
|
||||
std::to_string(box.getLowerLeft().getX()) + ", " +
|
||||
std::to_string(box.getUpperRight().getY()) + ", " +
|
||||
std::to_string(box.getUpperRight().getX()) + ")");
|
||||
wr.closeTag();
|
||||
for (auto t : std::vector<std::string>{"way", "node", "relation"}) {
|
||||
for (auto r : filter.getKeepRules()) {
|
||||
for (auto val : r.second) {
|
||||
if (t == "way" && (val.second & OsmFilter::WAY)) continue;
|
||||
if (t == "relation" && (val.second & OsmFilter::REL)) continue;
|
||||
if (t == "node" && (val.second & OsmFilter::NODE)) continue;
|
||||
|
||||
wr.openTag("query", {{"type", t}});
|
||||
if (val.first == "*")
|
||||
wr.openTag("has-kv", {{"k", r.first}});
|
||||
else
|
||||
wr.openTag("has-kv", {{"k", r.first}, {"v", val.first}});
|
||||
wr.closeTag();
|
||||
wr.openTag("bbox-query",
|
||||
{{"s", std::to_string(box.getLowerLeft().getY())},
|
||||
{"w", std::to_string(box.getLowerLeft().getX())},
|
||||
{"n", std::to_string(box.getUpperRight().getY())},
|
||||
{"e", std::to_string(box.getUpperRight().getX())}});
|
||||
wr.closeTag();
|
||||
wr.closeTag();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wr.closeTag();
|
||||
|
||||
wr.openTag("union");
|
||||
wr.openTag("item");
|
||||
wr.closeTag();
|
||||
wr.openTag("recurse", {{"type", "down"}});
|
||||
wr.closeTag();
|
||||
wr.closeTag();
|
||||
wr.openTag("print");
|
||||
|
||||
wr.closeTags();
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void OsmBuilder::filterWrite(const std::string& in, const std::string& out,
|
||||
const std::vector<OsmReadOpts>& opts,
|
||||
|
|
@ -250,8 +384,15 @@ void OsmBuilder::filterWrite(const std::string& in, const std::string& out,
|
|||
|
||||
outstr << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||
wr.openTag("osm");
|
||||
|
||||
// TODO(patrick): write bounding box tag
|
||||
wr.openTag(
|
||||
"bounds",
|
||||
{{"minlat", std::to_string(latLngBox.getFullBox().getLowerLeft().getY())},
|
||||
{"minlon", std::to_string(latLngBox.getFullBox().getLowerLeft().getX())},
|
||||
{"maxlat",
|
||||
std::to_string(latLngBox.getFullBox().getUpperRight().getY())},
|
||||
{"maxlon",
|
||||
std::to_string(latLngBox.getFullBox().getUpperRight().getX())}});
|
||||
wr.closeTag();
|
||||
|
||||
OsmFilter filter;
|
||||
AttrKeySet attrKeys[3] = {};
|
||||
|
|
@ -1071,8 +1212,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 {
|
||||
NodeGrid ret(size, size, webMercBox, false);
|
||||
for (auto* n : *g->getNds()) {
|
||||
|
|
@ -1158,9 +1298,10 @@ bool OsmBuilder::isBlocked(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) const {
|
||||
return depthSearch(e, si, p, maxD, maxFullTurns, minAngle, EqSearch());
|
||||
double maxD, int maxFullTurns, double minAngle,
|
||||
bool orphanSnap) const {
|
||||
return depthSearch(e, si, p, maxD, maxFullTurns, minAngle,
|
||||
EqSearch(orphanSnap));
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
|
|
@ -1187,8 +1328,7 @@ std::set<Node*> OsmBuilder::getMatchingNds(const NodePL& s, NodeGrid* ng,
|
|||
std::set<Node*> ret;
|
||||
double distor = webMercDistFactor(*s.getGeom());
|
||||
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);
|
||||
|
||||
for (auto* n : neighs) {
|
||||
|
|
@ -1205,8 +1345,7 @@ std::set<Node*> OsmBuilder::getMatchingNds(const NodePL& s, NodeGrid* ng,
|
|||
Node* OsmBuilder::getMatchingNd(const NodePL& s, NodeGrid* ng, double d) const {
|
||||
double distor = webMercDistFactor(*s.getGeom());
|
||||
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);
|
||||
|
||||
Node* ret = 0;
|
||||
|
|
@ -1229,7 +1368,7 @@ Node* OsmBuilder::getMatchingNd(const NodePL& s, NodeGrid* ng, double d) const {
|
|||
std::set<Node*> OsmBuilder::snapStation(Graph* g, NodePL* s, EdgeGrid* eg,
|
||||
NodeGrid* sng, const OsmReadOpts& opts,
|
||||
Restrictor* restor, bool surrHeur,
|
||||
double d) const {
|
||||
bool orphSnap, double d) const {
|
||||
assert(s->getSI());
|
||||
std::set<Node*> ret;
|
||||
|
||||
|
|
@ -1239,10 +1378,14 @@ std::set<Node*> OsmBuilder::snapStation(Graph* g, NodePL* s, EdgeGrid* eg,
|
|||
|
||||
if (pq.empty() && surrHeur) {
|
||||
// no station found in the first round, try again with the nearest
|
||||
// surrounding
|
||||
// station with matching name
|
||||
// surrounding station with matching name
|
||||
const Node* best = getMatchingNd(*s, sng, opts.maxSnapFallbackHeurDistance);
|
||||
if (best) getEdgCands(*best->pl().getGeom(), &pq, eg, d);
|
||||
if (best) {
|
||||
getEdgCands(*best->pl().getGeom(), &pq, eg, d);
|
||||
} else {
|
||||
// if still no luck, get edge cands in fallback snap distance
|
||||
getEdgCands(*s->getGeom(), &pq, eg, opts.maxSnapFallbackHeurDistance);
|
||||
}
|
||||
}
|
||||
|
||||
while (!pq.empty()) {
|
||||
|
|
@ -1254,7 +1397,7 @@ std::set<Node*> OsmBuilder::snapStation(Graph* g, NodePL* s, EdgeGrid* eg,
|
|||
|
||||
Node* eq = 0;
|
||||
if (!(eq = eqStatReach(e, s->getSI(), geom, 2 * d, 0,
|
||||
opts.maxAngleSnapReach))) {
|
||||
opts.maxAngleSnapReach, orphSnap))) {
|
||||
if (e->pl().lvl() > opts.maxSnapLevel) continue;
|
||||
if (isBlocked(e, s->getSI(), geom, opts.maxBlockDistance, 0,
|
||||
opts.maxAngleSnapReach)) {
|
||||
|
|
@ -1309,11 +1452,6 @@ std::set<Node*> OsmBuilder::snapStation(Graph* g, NodePL* s, EdgeGrid* eg,
|
|||
}
|
||||
}
|
||||
|
||||
// get surrounding nodes
|
||||
// TODO(patrick): own distance configuration for this!
|
||||
const auto& sur = getMatchingNds(*s, sng, opts.maxGroupSearchDistance);
|
||||
ret.insert(sur.begin(), sur.end());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -1336,7 +1474,10 @@ StatGroup* OsmBuilder::groupStats(const NodeSet& s) const {
|
|||
}
|
||||
}
|
||||
|
||||
if (!used) delete ret;
|
||||
if (!used) {
|
||||
delete ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1507,7 +1648,7 @@ void OsmBuilder::getKeptAttrKeys(const OsmReadOpts& opts,
|
|||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void OsmBuilder::deleteOrphEdgs(Graph* g) const {
|
||||
void OsmBuilder::deleteOrphEdgs(Graph* g, const OsmReadOpts& opts) const {
|
||||
size_t ROUNDS = 3;
|
||||
for (size_t c = 0; c < ROUNDS; c++) {
|
||||
for (auto i = g->getNds()->begin(); i != g->getNds()->end();) {
|
||||
|
|
@ -1515,6 +1656,15 @@ void OsmBuilder::deleteOrphEdgs(Graph* g) const {
|
|||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if the removal of this edge would transform a steep angle
|
||||
// full turn at an intersection into a node 2 eligible for contraction
|
||||
// if so, dont delete
|
||||
if (keepFullTurn(*i, opts.fullTurnAngle)) {
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
i = g->delNd(*i);
|
||||
continue;
|
||||
i++;
|
||||
|
|
@ -1706,3 +1856,43 @@ void OsmBuilder::writeSelfEdgs(Graph* g) const {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
bool OsmBuilder::keepFullTurn(const trgraph::Node* n, double ang) const {
|
||||
if (n->getInDeg() + n->getOutDeg() != 1) return false;
|
||||
|
||||
const trgraph::Edge* e = 0;
|
||||
if (n->getOutDeg())
|
||||
e = n->getAdjListOut().front();
|
||||
else
|
||||
e = n->getAdjListIn().front();
|
||||
|
||||
auto other = e->getOtherNd(n);
|
||||
|
||||
if (other->getInDeg() + other->getOutDeg() == 3) {
|
||||
const trgraph::Edge* a = 0;
|
||||
const trgraph::Edge* b = 0;
|
||||
for (auto f : other->getAdjListIn()) {
|
||||
if (f != e && !a)
|
||||
a = f;
|
||||
else if (f != e && !b)
|
||||
b = f;
|
||||
}
|
||||
|
||||
for (auto f : other->getAdjListOut()) {
|
||||
if (f != e && !a)
|
||||
a = f;
|
||||
else if (f != e && !b)
|
||||
b = f;
|
||||
}
|
||||
|
||||
auto ap = a->pl().backHop();
|
||||
auto bp = b->pl().backHop();
|
||||
if (a->getTo() != other) ap = a->pl().frontHop();
|
||||
if (b->getTo() != other) bp = b->pl().frontHop();
|
||||
|
||||
return router::angSmaller(ap, *other->pl().getGeom(), bp, ang);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,10 +59,10 @@ struct SearchFunc {
|
|||
};
|
||||
|
||||
struct EqSearch : public SearchFunc {
|
||||
explicit EqSearch(bool orphanSnap) : orphanSnap(orphanSnap) {}
|
||||
double minSimi = 0.9;
|
||||
bool operator()(const Node* cand, const StatInfo* si) const {
|
||||
return cand->pl().getSI() && cand->pl().getSI()->simi(si) > minSimi;
|
||||
}
|
||||
bool orphanSnap;
|
||||
bool operator()(const Node* cand, const StatInfo* si) const;
|
||||
};
|
||||
|
||||
struct BlockSearch : public SearchFunc {
|
||||
|
|
@ -91,6 +91,11 @@ class OsmBuilder {
|
|||
const BBoxIdx& box, size_t gridSize, router::FeedStops* fs,
|
||||
Restrictor* res);
|
||||
|
||||
// Based on the list of options, output an overpass XML query for getting
|
||||
// the data needed for routing
|
||||
void overpassQryWrite(std::ostream* out, const std::vector<OsmReadOpts>& opts,
|
||||
const BBoxIdx& latLngBox) const;
|
||||
|
||||
// Based on the list of options, read an OSM file from in and output an
|
||||
// OSM file to out which contains exactly the entities that are needed
|
||||
// from the file at in
|
||||
|
|
@ -170,7 +175,7 @@ class OsmBuilder {
|
|||
|
||||
void writeGeoms(Graph* g) const;
|
||||
void deleteOrphNds(Graph* g) const;
|
||||
void deleteOrphEdgs(Graph* g) const;
|
||||
void deleteOrphEdgs(Graph* g, const OsmReadOpts& opts) const;
|
||||
double dist(const Node* a, const Node* b) const;
|
||||
double webMercDist(const Node* a, const Node* b) const;
|
||||
double webMercDistFactor(const POINT& a) const;
|
||||
|
|
@ -198,13 +203,14 @@ class OsmBuilder {
|
|||
|
||||
NodeSet snapStation(Graph* g, NodePL* s, EdgeGrid* eg, NodeGrid* sng,
|
||||
const OsmReadOpts& opts, Restrictor* restor, bool surHeur,
|
||||
double maxD) const;
|
||||
bool orphSnap, double maxD) const;
|
||||
|
||||
// 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
|
||||
// such a station exists, it is returned. If not, 0 is returned.
|
||||
Node* eqStatReach(const Edge* e, const StatInfo* si, const POINT& p,
|
||||
double maxD, int maxFullTurns, double maxAng) const;
|
||||
double maxD, int maxFullTurns, double maxAng,
|
||||
bool orph) const;
|
||||
|
||||
Node* depthSearch(const Edge* e, const StatInfo* si, const POINT& p,
|
||||
double maxD, int maxFullTurns, double minAngle,
|
||||
|
|
@ -243,6 +249,8 @@ class OsmBuilder {
|
|||
|
||||
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<size_t, TransitEdgeLine*> _relLines;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -102,12 +102,12 @@ uint64_t OsmFilter::contained(const AttrMap& attrs, const Attr& attr) {
|
|||
// _____________________________________________________________________________
|
||||
uint8_t OsmFilter::level(const AttrMap& attrs) const {
|
||||
// the best matching level is always returned
|
||||
for (int16_t i = 0; i < 7; i++) {
|
||||
for (int16_t i = 0; i < 8; i++) {
|
||||
for (const auto& kv : attrs) {
|
||||
const auto& lkv = (_levels + i)->find(kv.first);
|
||||
if (lkv != (_levels + i)->end()) {
|
||||
for (const auto& val : lkv->second) {
|
||||
if (valMatches(kv.second, val.first)) return i + 1;
|
||||
if (valMatches(kv.second, val.first)) return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -169,7 +169,7 @@ std::vector<std::string> OsmFilter::getAttrKeys() const {
|
|||
for (const auto& kv : _noRestr) {
|
||||
ret.push_back(kv.first);
|
||||
}
|
||||
for (uint8_t i = 0; i < 7; i++) {
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
for (const auto& kv : *(_levels + i)) {
|
||||
ret.push_back(kv.first);
|
||||
}
|
||||
|
|
@ -191,27 +191,6 @@ OsmFilter OsmFilter::merge(const OsmFilter& other) const {
|
|||
keep[kv.first].insert(kv.second.begin(), kv.second.end());
|
||||
}
|
||||
|
||||
// TODO(patrick): multi-level combination for filters. otherwise
|
||||
// filter drop filters meant as a refinement for keep filters
|
||||
// interfere with other keeps
|
||||
|
||||
// const auto* d = &_drop;
|
||||
|
||||
// for (size_t i = 0; i < 2; i++) {
|
||||
// for (const auto& kv : *d) {
|
||||
// if (keep.find(kv.first) != keep.end()) {
|
||||
// for (const auto& val : kv.second) {
|
||||
// if (keep[kv.first].find(val.first) == keep[kv.first].end()) {
|
||||
// drop[kv.first].insert(val);
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// drop[kv.first].insert(kv.second.begin(), kv.second.end());
|
||||
// }
|
||||
// }
|
||||
// d = &other._drop;
|
||||
// }
|
||||
|
||||
return OsmFilter(keep, drop);
|
||||
}
|
||||
|
||||
|
|
@ -258,3 +237,13 @@ uint64_t OsmFilter::posRestr(const AttrMap& attrs) const {
|
|||
if (contained(attrs, _noRestr, ALL)) return false;
|
||||
return (contained(attrs, _posRestr, ALL));
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const pfaedle::osm::MultAttrMap& OsmFilter::getKeepRules() const {
|
||||
return _keep;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const pfaedle::osm::MultAttrMap& OsmFilter::getDropRules() const {
|
||||
return _drop;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@ class OsmFilter {
|
|||
|
||||
OsmFilter merge(const OsmFilter& other) const;
|
||||
|
||||
const MultAttrMap& getKeepRules() const;
|
||||
const MultAttrMap& getDropRules() const;
|
||||
|
||||
std::string toString() const;
|
||||
|
||||
static bool valMatches(const std::string& a, const std::string& b, bool m);
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ struct OsmReadOpts {
|
|||
|
||||
MultAttrMap noHupFilter;
|
||||
MultAttrMap keepFilter;
|
||||
MultAttrMap levelFilters[7];
|
||||
MultAttrMap levelFilters[8];
|
||||
MultAttrMap dropFilter;
|
||||
MultAttrMap oneWayFilter;
|
||||
MultAttrMap oneWayFilterRev;
|
||||
|
|
@ -136,7 +136,6 @@ struct OsmReadOpts {
|
|||
double maxAngleSnapReach;
|
||||
std::vector<double> maxSnapDistances;
|
||||
double maxSnapFallbackHeurDistance;
|
||||
double maxGroupSearchDistance;
|
||||
double maxBlockDistance;
|
||||
|
||||
double maxOsmStationDistance;
|
||||
|
|
@ -144,6 +143,8 @@ struct OsmReadOpts {
|
|||
// TODO(patrick): this is not implemented yet
|
||||
double levelSnapPunishFac[7] = {0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
double fullTurnAngle;
|
||||
|
||||
// restriction system
|
||||
MultAttrMap restrPosRestr;
|
||||
MultAttrMap restrNegRestr;
|
||||
|
|
@ -179,7 +180,6 @@ inline bool operator==(const OsmReadOpts& a, const OsmReadOpts& b) {
|
|||
fabs(a.maxOsmStationDistance - b.maxOsmStationDistance) < 0.1 &&
|
||||
fabs(a.maxSnapFallbackHeurDistance - b.maxSnapFallbackHeurDistance) <
|
||||
0.1 &&
|
||||
fabs(a.maxGroupSearchDistance - b.maxGroupSearchDistance) < 0.1 &&
|
||||
fabs(a.maxBlockDistance - b.maxBlockDistance) < 0.1 &&
|
||||
fabs(a.levelSnapPunishFac[0] - b.levelSnapPunishFac[0]) < 0.1 &&
|
||||
fabs(a.levelSnapPunishFac[1] - b.levelSnapPunishFac[1]) < 0.1 &&
|
||||
|
|
@ -188,6 +188,7 @@ inline bool operator==(const OsmReadOpts& a, const OsmReadOpts& b) {
|
|||
fabs(a.levelSnapPunishFac[4] - b.levelSnapPunishFac[4]) < 0.1 &&
|
||||
fabs(a.levelSnapPunishFac[5] - b.levelSnapPunishFac[5]) < 0.1 &&
|
||||
fabs(a.levelSnapPunishFac[6] - b.levelSnapPunishFac[6]) < 0.1 &&
|
||||
fabs(a.fullTurnAngle - b.fullTurnAngle) < 0.1 &&
|
||||
a.restrPosRestr == b.restrPosRestr &&
|
||||
a.restrNegRestr == b.restrNegRestr &&
|
||||
a.noRestrFilter == b.noRestrFilter;
|
||||
|
|
|
|||
|
|
@ -60,11 +60,28 @@ inline double lineSimi(const std::string& a, const std::string& b) {
|
|||
|
||||
if (a.empty() || b.empty()) return 0;
|
||||
|
||||
// if one of the lines is completely contained in the other, return 1
|
||||
if (a.find(b) != std::string::npos) {
|
||||
return 1;
|
||||
} else if (b.find(a) != std::string::npos) {
|
||||
return 1;
|
||||
if (a.size() > b.size() + 1) {
|
||||
// check if a begins with b
|
||||
if (a.compare(0, b.size() + 1, b + " ") == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// check if a ends with b
|
||||
if (a.compare(a.size() - (b.size() + 1), b.size() + 1, " " + b) == 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (b.size() > a.size() + 1) {
|
||||
// check if b begins with a
|
||||
if (b.compare(0, a.size() + 1, a + " ") == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// check if b ends with a
|
||||
if (b.compare(b.size() - (a.size() + 1), a.size() + 1, " " + a) == 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -82,21 +82,6 @@ util::json::Dict EdgePL::getAttrs() const {
|
|||
obj["cost"] = std::to_string(_cost.getValue());
|
||||
obj["from_edge"] = util::toString(_startE);
|
||||
obj["to_edge"] = util::toString(_endE);
|
||||
obj["cost_m_lvl1"] = std::to_string(_cost.meterDistLvl1);
|
||||
obj["cost_m_lvl0"] = std::to_string(_cost.meterDist);
|
||||
obj["cost_m_lvl1"] = std::to_string(_cost.meterDistLvl1);
|
||||
obj["cost_m_lvl2"] = std::to_string(_cost.meterDistLvl2);
|
||||
obj["cost_m_lvl3"] = std::to_string(_cost.meterDistLvl3);
|
||||
obj["cost_m_lvl4"] = std::to_string(_cost.meterDistLvl4);
|
||||
obj["cost_m_lvl5"] = std::to_string(_cost.meterDistLvl5);
|
||||
obj["cost_m_lvl6"] = std::to_string(_cost.meterDistLvl6);
|
||||
obj["cost_m_lvl7"] = std::to_string(_cost.meterDistLvl7);
|
||||
obj["cost_fullturn"] = std::to_string(_cost.fullTurns);
|
||||
obj["cost_st_passthru"] = std::to_string(_cost.passThruStations);
|
||||
obj["cost_m_oneway"] = std::to_string(_cost.oneWayMeters);
|
||||
obj["cost_m_lineunmatch"] = std::to_string(_cost.lineUnmatchedMeters);
|
||||
obj["cost_reach_node_pen"] = std::to_string(_cost.reachPen);
|
||||
obj["cost_oneway_event"] = std::to_string(_cost.oneWayEdges);
|
||||
obj["dummy"] = _edges.size() ? "no" : "yes";
|
||||
|
||||
return obj;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ using util::geograph::GeoEdgePL;
|
|||
namespace pfaedle {
|
||||
namespace router {
|
||||
|
||||
class EdgePL : public GeoEdgePL<PFAEDLE_PRECISION> {
|
||||
class EdgePL {
|
||||
public:
|
||||
EdgePL() : _cost(), _start(0), _end(0), _startE(0), _endE(0) {}
|
||||
const LINE* getGeom() const;
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include "ad/cppgtfs/gtfs/Feed.h"
|
||||
#include "ad/cppgtfs/gtfs/Route.h"
|
||||
#include "pfaedle/trgraph/Graph.h"
|
||||
|
|
@ -67,90 +67,35 @@ inline bool operator==(const RoutingOpts& a, const RoutingOpts& b) {
|
|||
}
|
||||
|
||||
struct EdgeCost {
|
||||
EdgeCost()
|
||||
: meterDist(0),
|
||||
meterDistLvl1(0),
|
||||
meterDistLvl2(0),
|
||||
meterDistLvl3(0),
|
||||
meterDistLvl4(0),
|
||||
meterDistLvl5(0),
|
||||
meterDistLvl6(0),
|
||||
meterDistLvl7(0),
|
||||
fullTurns(0),
|
||||
passThruStations(0),
|
||||
oneWayMeters(0),
|
||||
oneWayEdges(0),
|
||||
lineUnmatchedMeters(0),
|
||||
reachPen(0),
|
||||
o(0) {}
|
||||
EdgeCost() : _cost(0) {}
|
||||
explicit EdgeCost(double cost) : _cost(cost) {}
|
||||
EdgeCost(double mDist, double mDistLvl1, double mDistLvl2, double mDistLvl3,
|
||||
double mDistLvl4, double mDistLvl5, double mDistLvl6,
|
||||
double mDistLvl7, uint32_t fullTurns, int32_t passThru,
|
||||
double oneWayMeters, size_t oneWayEdges, double lineUnmatchedMeters,
|
||||
double reachPen, const RoutingOpts* o)
|
||||
: meterDist(mDist),
|
||||
meterDistLvl1(mDistLvl1),
|
||||
meterDistLvl2(mDistLvl2),
|
||||
meterDistLvl3(mDistLvl3),
|
||||
meterDistLvl4(mDistLvl4),
|
||||
meterDistLvl5(mDistLvl5),
|
||||
meterDistLvl6(mDistLvl6),
|
||||
meterDistLvl7(mDistLvl7),
|
||||
fullTurns(fullTurns),
|
||||
passThruStations(passThru),
|
||||
oneWayMeters(oneWayMeters),
|
||||
oneWayEdges(oneWayEdges),
|
||||
lineUnmatchedMeters(lineUnmatchedMeters),
|
||||
reachPen(reachPen),
|
||||
o(o) {}
|
||||
double meterDist;
|
||||
double meterDistLvl1;
|
||||
double meterDistLvl2;
|
||||
double meterDistLvl3;
|
||||
double meterDistLvl4;
|
||||
double meterDistLvl5;
|
||||
double meterDistLvl6;
|
||||
double meterDistLvl7;
|
||||
uint32_t fullTurns;
|
||||
int32_t passThruStations;
|
||||
double oneWayMeters;
|
||||
size_t oneWayEdges;
|
||||
double lineUnmatchedMeters;
|
||||
double reachPen;
|
||||
const RoutingOpts* o;
|
||||
|
||||
double getValue() const {
|
||||
if (!o) return meterDist + reachPen;
|
||||
return meterDist * o->levelPunish[0] + meterDistLvl1 * o->levelPunish[1] +
|
||||
meterDistLvl2 * o->levelPunish[2] +
|
||||
meterDistLvl3 * o->levelPunish[3] +
|
||||
meterDistLvl4 * o->levelPunish[4] +
|
||||
meterDistLvl5 * o->levelPunish[5] +
|
||||
meterDistLvl6 * o->levelPunish[6] +
|
||||
meterDistLvl7 * o->levelPunish[7] +
|
||||
oneWayMeters * o->oneWayPunishFac +
|
||||
oneWayEdges * o->oneWayEdgePunish +
|
||||
lineUnmatchedMeters * o->lineUnmatchedPunishFact +
|
||||
fullTurns * o->fullTurnPunishFac +
|
||||
passThruStations * o->passThruStationsPunish + reachPen;
|
||||
double reachPen, const RoutingOpts* o) {
|
||||
if (!o) {
|
||||
_cost = mDist + reachPen;
|
||||
} else {
|
||||
_cost = mDist * o->levelPunish[0] + mDistLvl1 * o->levelPunish[1] +
|
||||
mDistLvl2 * o->levelPunish[2] + mDistLvl3 * o->levelPunish[3] +
|
||||
mDistLvl4 * o->levelPunish[4] + mDistLvl5 * o->levelPunish[5] +
|
||||
mDistLvl6 * o->levelPunish[6] + mDistLvl7 * o->levelPunish[7] +
|
||||
oneWayMeters * o->oneWayPunishFac +
|
||||
oneWayEdges * o->oneWayEdgePunish +
|
||||
lineUnmatchedMeters * o->lineUnmatchedPunishFact +
|
||||
fullTurns * o->fullTurnPunishFac +
|
||||
passThru * o->passThruStationsPunish + reachPen;
|
||||
}
|
||||
}
|
||||
|
||||
double getTotalMeters() const {
|
||||
return meterDist + meterDistLvl1 + meterDistLvl2 + meterDistLvl3 +
|
||||
meterDistLvl4 + meterDistLvl5 + meterDistLvl6 + meterDistLvl7;
|
||||
}
|
||||
float _cost;
|
||||
|
||||
double getValue() const { return _cost; }
|
||||
};
|
||||
|
||||
inline EdgeCost operator+(const EdgeCost& a, const EdgeCost& b) {
|
||||
return EdgeCost(
|
||||
a.meterDist + b.meterDist, a.meterDistLvl1 + b.meterDistLvl1,
|
||||
a.meterDistLvl2 + b.meterDistLvl2, a.meterDistLvl3 + b.meterDistLvl3,
|
||||
a.meterDistLvl4 + b.meterDistLvl4, a.meterDistLvl5 + b.meterDistLvl5,
|
||||
a.meterDistLvl6 + b.meterDistLvl6, a.meterDistLvl7 + b.meterDistLvl7,
|
||||
a.fullTurns + b.fullTurns, a.passThruStations + b.passThruStations,
|
||||
a.oneWayMeters + b.oneWayMeters, a.oneWayEdges + b.oneWayEdges,
|
||||
a.lineUnmatchedMeters + b.lineUnmatchedMeters, a.reachPen + b.reachPen,
|
||||
a.o ? a.o : b.o);
|
||||
return EdgeCost(a.getValue() + b.getValue());
|
||||
}
|
||||
|
||||
inline bool operator<=(const EdgeCost& a, const EdgeCost& b) {
|
||||
|
|
@ -165,9 +110,9 @@ inline bool operator>(const EdgeCost& a, const EdgeCost& b) {
|
|||
return a.getValue() > b.getValue();
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
template <typename F>
|
||||
inline bool angSmaller(const Point<F>& f, const Point<F>& m, const Point<F>& t,
|
||||
double ang) {
|
||||
double ang) {
|
||||
if (util::geo::innerProd(m, f, t) < ang) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ using util::geograph::GeoNodePL;
|
|||
namespace pfaedle {
|
||||
namespace router {
|
||||
|
||||
class NodePL : public GeoNodePL<PFAEDLE_PRECISION> {
|
||||
class NodePL {
|
||||
public:
|
||||
NodePL() : _n(0) {}
|
||||
NodePL(const pfaedle::trgraph::Node* n) : _n(n) {} // NOLINT
|
||||
|
|
|
|||
|
|
@ -191,7 +191,8 @@ double CombCostFunc::operator()(const router::Edge* from, const router::Node* n,
|
|||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
Router::Router(size_t numThreads) : _cache(numThreads) {
|
||||
Router::Router(size_t numThreads, bool caching)
|
||||
: _cache(numThreads), _caching(caching) {
|
||||
for (size_t i = 0; i < numThreads; i++) {
|
||||
_cache[i] = new Cache();
|
||||
}
|
||||
|
|
@ -219,6 +220,9 @@ bool Router::compConned(const NodeCandGroup& a, const NodeCandGroup& b) const {
|
|||
HopBand Router::getHopBand(const NodeCandGroup& a, const NodeCandGroup& b,
|
||||
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest) const {
|
||||
assert(a.size());
|
||||
assert(b.size());
|
||||
|
||||
double pend = 0;
|
||||
for (size_t i = 0; i < a.size(); i++) {
|
||||
for (size_t j = 0; j < b.size(); j++) {
|
||||
|
|
@ -231,6 +235,7 @@ HopBand Router::getHopBand(const NodeCandGroup& a, const NodeCandGroup& b,
|
|||
LOG(VDEBUG) << "Pending max hop distance is " << pend << " meters";
|
||||
|
||||
const trgraph::StatGroup* tgGrpTo = 0;
|
||||
|
||||
if (b.begin()->nd->pl().getSI())
|
||||
tgGrpTo = b.begin()->nd->pl().getSI()->getGroup();
|
||||
|
||||
|
|
@ -556,6 +561,7 @@ void Router::nestedCache(const EdgeList* el,
|
|||
const std::set<trgraph::Edge*>& froms,
|
||||
const CostFunc& cost,
|
||||
const RoutingAttrs& rAttrs) const {
|
||||
if (!_caching) return;
|
||||
if (el->size() == 0) return;
|
||||
// iterate over result edges backwards
|
||||
EdgeList curEdges;
|
||||
|
|
@ -586,7 +592,7 @@ std::set<pfaedle::trgraph::Edge*> Router::getCachedHops(
|
|||
const RoutingAttrs& rAttrs) const {
|
||||
std::set<trgraph::Edge*> ret;
|
||||
for (auto to : tos) {
|
||||
if ((*_cache[omp_get_thread_num()])[rAttrs][from].count(to)) {
|
||||
if (_caching && (*_cache[omp_get_thread_num()])[rAttrs][from].count(to)) {
|
||||
const auto& cv = (*_cache[omp_get_thread_num()])[rAttrs][from][to];
|
||||
(*rCosts)[to] = cv.first;
|
||||
*edgesRet.at(to) = cv.second;
|
||||
|
|
@ -601,6 +607,7 @@ std::set<pfaedle::trgraph::Edge*> Router::getCachedHops(
|
|||
// _____________________________________________________________________________
|
||||
void Router::cache(trgraph::Edge* from, trgraph::Edge* to, const EdgeCost& c,
|
||||
EdgeList* edges, const RoutingAttrs& rAttrs) const {
|
||||
if (!_caching) return;
|
||||
if (from == to) return;
|
||||
(*_cache[omp_get_thread_num()])[rAttrs][from][to] =
|
||||
std::pair<EdgeCost, EdgeList>(c, *edges);
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ struct CombCostFunc
|
|||
class Router {
|
||||
public:
|
||||
// Init this router with caches for numThreads threads
|
||||
explicit Router(size_t numThreads);
|
||||
explicit Router(size_t numThreads, bool caching);
|
||||
~Router();
|
||||
|
||||
// Find the most likely path through the graph for a node candidate route.
|
||||
|
|
@ -163,6 +163,7 @@ class Router {
|
|||
|
||||
private:
|
||||
mutable std::vector<Cache*> _cache;
|
||||
bool _caching;
|
||||
HopBand getHopBand(const NodeCandGroup& a, const NodeCandGroup& b,
|
||||
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest) const;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#define omp_get_num_procs() 1
|
||||
#endif
|
||||
|
||||
#include <exception>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
|
|
@ -16,6 +17,8 @@
|
|||
#include "ad/cppgtfs/gtfs/Feed.h"
|
||||
#include "pfaedle/Def.h"
|
||||
#include "pfaedle/eval/Collector.h"
|
||||
#include "pfaedle/gtfs/Feed.h"
|
||||
#include "pfaedle/gtfs/StopTime.h"
|
||||
#include "pfaedle/osm/OsmBuilder.h"
|
||||
#include "pfaedle/router/ShapeBuilder.h"
|
||||
#include "pfaedle/trgraph/StatGroup.h"
|
||||
|
|
@ -43,38 +46,36 @@ using pfaedle::router::EdgeListHops;
|
|||
using pfaedle::router::Clusters;
|
||||
using pfaedle::osm::BBoxIdx;
|
||||
using ad::cppgtfs::gtfs::Stop;
|
||||
using ad::cppgtfs::gtfs::Trip;
|
||||
using ad::cppgtfs::gtfs::Feed;
|
||||
using ad::cppgtfs::gtfs::StopTime;
|
||||
using pfaedle::gtfs::Trip;
|
||||
using pfaedle::gtfs::Feed;
|
||||
using pfaedle::gtfs::StopTime;
|
||||
using ad::cppgtfs::gtfs::ShapePoint;
|
||||
|
||||
// _____________________________________________________________________________
|
||||
ShapeBuilder::ShapeBuilder(Feed* feed, MOTs mots,
|
||||
const config::MotConfig& motCfg,
|
||||
ShapeBuilder::ShapeBuilder(Feed* feed, ad::cppgtfs::gtfs::Feed* evalFeed,
|
||||
MOTs mots, const config::MotConfig& motCfg,
|
||||
eval::Collector* ecoll, const config::Config& cfg)
|
||||
: _feed(feed),
|
||||
_evalFeed(evalFeed),
|
||||
_mots(mots),
|
||||
_motCfg(motCfg),
|
||||
_ecoll(ecoll),
|
||||
_cfg(cfg),
|
||||
_crouter(omp_get_num_procs()),
|
||||
_crouter(omp_get_num_procs(), cfg.useCaching),
|
||||
_curShpCnt(0) {
|
||||
_numThreads = _crouter.getCacheNumber();
|
||||
writeMotStops();
|
||||
|
||||
// TODO(patrick): maybe do this on demand to avoid graph filtering / reading
|
||||
// for input where no routing is necessary (already shape'd)
|
||||
buildGraph();
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void ShapeBuilder::writeMotStops() {
|
||||
for (auto t : _feed->getTrips()) {
|
||||
if (!_cfg.shapeTripId.empty() && t.second->getId() != _cfg.shapeTripId)
|
||||
continue;
|
||||
if (_mots.count(t.second->getRoute()->getType()) &&
|
||||
_motCfg.mots.count(t.second->getRoute()->getType())) {
|
||||
for (auto st : t.second->getStopTimes()) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -95,28 +96,34 @@ const NodeCandGroup& ShapeBuilder::getNodeCands(const Stop* s) const {
|
|||
// _____________________________________________________________________________
|
||||
LINE ShapeBuilder::shapeL(const router::NodeCandRoute& ncr,
|
||||
const router::RoutingAttrs& rAttrs) {
|
||||
const router::EdgeListHops& res = route(ncr, rAttrs);
|
||||
try {
|
||||
const router::EdgeListHops& res = route(ncr, rAttrs);
|
||||
|
||||
LINE l;
|
||||
for (const auto& hop : res) {
|
||||
const trgraph::Node* last = hop.start;
|
||||
if (hop.edges.size() == 0) {
|
||||
l.push_back(*hop.start->pl().getGeom());
|
||||
l.push_back(*hop.end->pl().getGeom());
|
||||
}
|
||||
for (auto i = hop.edges.rbegin(); i != hop.edges.rend(); i++) {
|
||||
const auto* e = *i;
|
||||
if ((e->getFrom() == last) ^ e->pl().isRev()) {
|
||||
l.insert(l.end(), e->pl().getGeom()->begin(), e->pl().getGeom()->end());
|
||||
} else {
|
||||
l.insert(l.end(), e->pl().getGeom()->rbegin(),
|
||||
e->pl().getGeom()->rend());
|
||||
LINE l;
|
||||
for (const auto& hop : res) {
|
||||
const trgraph::Node* last = hop.start;
|
||||
if (hop.edges.size() == 0) {
|
||||
l.push_back(*hop.start->pl().getGeom());
|
||||
l.push_back(*hop.end->pl().getGeom());
|
||||
}
|
||||
for (auto i = hop.edges.rbegin(); i != hop.edges.rend(); i++) {
|
||||
const auto* e = *i;
|
||||
if ((e->getFrom() == last) ^ e->pl().isRev()) {
|
||||
l.insert(l.end(), e->pl().getGeom()->begin(),
|
||||
e->pl().getGeom()->end());
|
||||
} else {
|
||||
l.insert(l.end(), e->pl().getGeom()->rbegin(),
|
||||
e->pl().getGeom()->rend());
|
||||
}
|
||||
last = e->getOtherNd(last);
|
||||
}
|
||||
last = e->getOtherNd(last);
|
||||
}
|
||||
}
|
||||
|
||||
return l;
|
||||
return l;
|
||||
} catch (const std::runtime_error& e) {
|
||||
LOG(ERROR) << e.what();
|
||||
return LINE();
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
|
|
@ -193,9 +200,9 @@ void ShapeBuilder::shape(pfaedle::netgraph::Graph* ng) {
|
|||
Clusters clusters = clusterTrips(_feed, _mots);
|
||||
LOG(DEBUG) << "Clustered trips into " << clusters.size() << " clusters.";
|
||||
|
||||
std::map<ad::cppgtfs::gtfs::Shape*, size_t> shpUsage;
|
||||
std::map<std::string, size_t> shpUsage;
|
||||
for (auto t : _feed->getTrips()) {
|
||||
if (t.second->getShape()) shpUsage[t.second->getShape()]++;
|
||||
if (!t.getShape().empty()) shpUsage[t.getShape()]++;
|
||||
}
|
||||
|
||||
// to avoid unfair load balance on threads
|
||||
|
|
@ -223,7 +230,7 @@ void ShapeBuilder::shape(pfaedle::netgraph::Graph* ng) {
|
|||
<< "%, " << (EDijkstra::ITERS - oiters) << " iters, "
|
||||
/**
|
||||
TODO: this is actually misleading. We are counting the
|
||||
Dijkstra iterations, but the measuring them against
|
||||
Dijkstra iterations, but measuring them against
|
||||
the total running time (including all overhead + HMM solve)
|
||||
<< tput "
|
||||
<< (static_cast<double>(EDijkstra::ITERS - oiters)) /
|
||||
|
|
@ -249,7 +256,7 @@ void ShapeBuilder::shape(pfaedle::netgraph::Graph* ng) {
|
|||
}
|
||||
|
||||
std::vector<double> distances;
|
||||
ad::cppgtfs::gtfs::Shape* shp =
|
||||
const ad::cppgtfs::gtfs::Shape& shp =
|
||||
getGtfsShape(cshp, clusters[i][0], &distances);
|
||||
|
||||
LOG(DEBUG) << "Took " << EDijkstra::ITERS - iters << " iterations.";
|
||||
|
|
@ -259,14 +266,14 @@ void ShapeBuilder::shape(pfaedle::netgraph::Graph* ng) {
|
|||
|
||||
for (auto t : clusters[i]) {
|
||||
if (_cfg.evaluate) {
|
||||
_ecoll->add(t, t->getShape(), shp, distances);
|
||||
_ecoll->add(t, _evalFeed->getShapes().get(t->getShape()), shp,
|
||||
distances);
|
||||
}
|
||||
|
||||
if (t->getShape() && shpUsage[t->getShape()] > 0) {
|
||||
if (!t->getShape().empty() && shpUsage[t->getShape()] > 0) {
|
||||
shpUsage[t->getShape()]--;
|
||||
if (shpUsage[t->getShape()] == 0) {
|
||||
_feed->getShapes().remove(t->getShape()->getId());
|
||||
delete t->getShape();
|
||||
_feed->getShapes().remove(t->getShape());
|
||||
}
|
||||
}
|
||||
setShape(t, shp, distances);
|
||||
|
|
@ -295,27 +302,25 @@ void ShapeBuilder::shape(pfaedle::netgraph::Graph* ng) {
|
|||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void ShapeBuilder::setShape(Trip* t, ad::cppgtfs::gtfs::Shape* s,
|
||||
void ShapeBuilder::setShape(Trip* t, const ad::cppgtfs::gtfs::Shape& s,
|
||||
const std::vector<double>& distances) {
|
||||
assert(distances.size() == t->getStopTimes().size());
|
||||
// set distances
|
||||
size_t i = 0;
|
||||
for (const StopTime& st : t->getStopTimes()) {
|
||||
const_cast<StopTime&>(st).setShapeDistanceTravelled(distances[i]);
|
||||
for (const auto& st : t->getStopTimes()) {
|
||||
const_cast<StopTime<Stop>&>(st).setShapeDistanceTravelled(distances[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
t->setShape(s);
|
||||
|
||||
std::lock_guard<std::mutex> guard(_shpMutex);
|
||||
_feed->getShapes().add(s);
|
||||
// TODO(patrick):
|
||||
t->setShape(_feed->getShapes().add(s));
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
ad::cppgtfs::gtfs::Shape* ShapeBuilder::getGtfsShape(
|
||||
ad::cppgtfs::gtfs::Shape ShapeBuilder::getGtfsShape(
|
||||
const Shape& shp, Trip* t, std::vector<double>* hopDists) {
|
||||
ad::cppgtfs::gtfs::Shape* ret =
|
||||
new ad::cppgtfs::gtfs::Shape(getFreeShapeId(t));
|
||||
ad::cppgtfs::gtfs::Shape ret(getFreeShapeId(t));
|
||||
|
||||
assert(shp.hops.size() == t->getStopTimes().size() - 1);
|
||||
|
||||
|
|
@ -338,7 +343,7 @@ ad::cppgtfs::gtfs::Shape* ShapeBuilder::getGtfsShape(
|
|||
last = *hop.start->pl().getGeom();
|
||||
|
||||
if (dist - lastDist > 0.01) {
|
||||
ret->addPoint(ShapePoint(ll.getY(), ll.getX(), dist, seq));
|
||||
ret.addPoint(ShapePoint(ll.getY(), ll.getX(), dist, seq));
|
||||
seq++;
|
||||
lastDist = dist;
|
||||
}
|
||||
|
|
@ -349,11 +354,12 @@ ad::cppgtfs::gtfs::Shape* ShapeBuilder::getGtfsShape(
|
|||
if (dist - lastDist > 0.01) {
|
||||
ll = webMercToLatLng<PFAEDLE_PRECISION>(
|
||||
hop.end->pl().getGeom()->getX(), hop.end->pl().getGeom()->getY());
|
||||
ret->addPoint(ShapePoint(ll.getY(), ll.getX(), dist, seq));
|
||||
ret.addPoint(ShapePoint(ll.getY(), ll.getX(), dist, seq));
|
||||
seq++;
|
||||
lastDist = dist;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto i = hop.edges.rbegin(); i != hop.edges.rend(); i++) {
|
||||
const auto* e = *i;
|
||||
if ((e->getFrom() == l) ^ e->pl().isRev()) {
|
||||
|
|
@ -367,7 +373,7 @@ ad::cppgtfs::gtfs::Shape* ShapeBuilder::getGtfsShape(
|
|||
if (dist - lastDist > 0.01) {
|
||||
POINT ll =
|
||||
webMercToLatLng<PFAEDLE_PRECISION>(cur.getX(), cur.getY());
|
||||
ret->addPoint(ShapePoint(ll.getY(), ll.getX(), dist, seq));
|
||||
ret.addPoint(ShapePoint(ll.getY(), ll.getX(), dist, seq));
|
||||
seq++;
|
||||
lastDist = dist;
|
||||
}
|
||||
|
|
@ -383,7 +389,7 @@ ad::cppgtfs::gtfs::Shape* ShapeBuilder::getGtfsShape(
|
|||
if (dist - lastDist > 0.01) {
|
||||
POINT ll =
|
||||
webMercToLatLng<PFAEDLE_PRECISION>(cur.getX(), cur.getY());
|
||||
ret->addPoint(ShapePoint(ll.getY(), ll.getX(), dist, seq));
|
||||
ret.addPoint(ShapePoint(ll.getY(), ll.getX(), dist, seq));
|
||||
seq++;
|
||||
lastDist = dist;
|
||||
}
|
||||
|
|
@ -447,33 +453,30 @@ const RoutingAttrs& ShapeBuilder::getRAttrs(const Trip* trip) const {
|
|||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
BBoxIdx ShapeBuilder::getPaddedGtfsBox(const Feed* feed, double pad,
|
||||
const MOTs& mots, const std::string& tid,
|
||||
bool dropShapes) {
|
||||
osm::BBoxIdx box(pad);
|
||||
void ShapeBuilder::getGtfsBox(const Feed* feed, const MOTs& mots,
|
||||
const std::string& tid, bool dropShapes,
|
||||
osm::BBoxIdx* box) {
|
||||
for (const auto& t : feed->getTrips()) {
|
||||
if (!tid.empty() && t.second->getId() != tid) continue;
|
||||
if (tid.empty() && t.second->getShape() && !dropShapes) continue;
|
||||
if (t.second->getStopTimes().size() < 2) continue;
|
||||
if (mots.count(t.second->getRoute()->getType())) {
|
||||
if (!tid.empty() && t.getId() != tid) continue;
|
||||
if (tid.empty() && !t.getShape().empty() && !dropShapes) continue;
|
||||
if (t.getStopTimes().size() < 2) continue;
|
||||
if (mots.count(t.getRoute()->getType())) {
|
||||
DBox cur;
|
||||
for (const auto& st : t.second->getStopTimes()) {
|
||||
for (const auto& st : t.getStopTimes()) {
|
||||
cur = extendBox(DPoint(st.getStop()->getLng(), st.getStop()->getLat()),
|
||||
cur);
|
||||
}
|
||||
box.add(cur);
|
||||
box->add(cur);
|
||||
}
|
||||
}
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void ShapeBuilder::buildGraph() {
|
||||
osm::OsmBuilder osmBuilder;
|
||||
|
||||
osm::BBoxIdx box =
|
||||
getPaddedGtfsBox(_feed, 2500, _mots, _cfg.shapeTripId, _cfg.dropShapes);
|
||||
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);
|
||||
|
|
@ -497,6 +500,11 @@ NodeCandRoute ShapeBuilder::getNCR(Trip* trip) const {
|
|||
|
||||
for (const auto& st : trip->getStopTimes()) {
|
||||
ncr[i] = getNodeCands(st.getStop());
|
||||
if (ncr[i].size() == 0) {
|
||||
throw std::runtime_error("No node candidate found for station '" +
|
||||
st.getStop()->getName() + "' on trip '" +
|
||||
trip->getId() + "'");
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return ncr;
|
||||
|
|
@ -535,29 +543,29 @@ Clusters ShapeBuilder::clusterTrips(Feed* f, MOTs mots) {
|
|||
size_t j = 0;
|
||||
|
||||
Clusters ret;
|
||||
for (const auto& trip : f->getTrips()) {
|
||||
if (trip.second->getShape() && !_cfg.dropShapes) continue;
|
||||
if (trip.second->getStopTimes().size() < 2) continue;
|
||||
if (!mots.count(trip.second->getRoute()->getType()) ||
|
||||
!_motCfg.mots.count(trip.second->getRoute()->getType()))
|
||||
for (auto& trip : f->getTrips()) {
|
||||
if (!trip.getShape().empty() && !_cfg.dropShapes) continue;
|
||||
if (trip.getStopTimes().size() < 2) continue;
|
||||
if (!mots.count(trip.getRoute()->getType()) ||
|
||||
!_motCfg.mots.count(trip.getRoute()->getType()))
|
||||
continue;
|
||||
bool found = false;
|
||||
auto spair = StopPair(trip.second->getStopTimes().begin()->getStop(),
|
||||
trip.second->getStopTimes().rbegin()->getStop());
|
||||
auto spair = StopPair(trip.getStopTimes().begin()->getStop(),
|
||||
trip.getStopTimes().rbegin()->getStop());
|
||||
const auto& c = clusterIdx[spair];
|
||||
|
||||
for (size_t i = 0; i < c.size(); i++) {
|
||||
j++;
|
||||
if (routingEqual(ret[c[i]][0], trip.second)) {
|
||||
ret[c[i]].push_back(trip.second);
|
||||
if (routingEqual(ret[c[i]][0], &trip)) {
|
||||
ret[c[i]].push_back(&trip);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
ret.push_back({trip.second});
|
||||
ret.push_back(Cluster{&trip});
|
||||
// explicit call to write render attrs to cache
|
||||
getRAttrs(trip.second);
|
||||
getRAttrs(&trip);
|
||||
clusterIdx[spair].push_back(ret.size() - 1);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include "pfaedle/config/MotConfig.h"
|
||||
#include "pfaedle/config/PfaedleConfig.h"
|
||||
#include "pfaedle/eval/Collector.h"
|
||||
#include "pfaedle/gtfs/Feed.h"
|
||||
#include "pfaedle/netgraph/Graph.h"
|
||||
#include "pfaedle/osm/Restrictor.h"
|
||||
#include "pfaedle/router/Misc.h"
|
||||
|
|
@ -27,8 +28,8 @@ namespace pfaedle {
|
|||
namespace router {
|
||||
|
||||
using ad::cppgtfs::gtfs::Stop;
|
||||
using ad::cppgtfs::gtfs::Trip;
|
||||
using ad::cppgtfs::gtfs::Feed;
|
||||
using pfaedle::gtfs::Trip;
|
||||
using pfaedle::gtfs::Feed;
|
||||
|
||||
struct Shape {
|
||||
router::EdgeListHops hops;
|
||||
|
|
@ -48,8 +49,9 @@ typedef std::unordered_map<const trgraph::Edge*, std::set<const Trip*>>
|
|||
*/
|
||||
class ShapeBuilder {
|
||||
public:
|
||||
ShapeBuilder(Feed* feed, MOTs mots, const config::MotConfig& motCfg,
|
||||
eval::Collector* ecoll, const config::Config& cfg);
|
||||
ShapeBuilder(Feed* feed, ad::cppgtfs::gtfs::Feed* evalFeed, MOTs mots,
|
||||
const config::MotConfig& motCfg, eval::Collector* ecoll,
|
||||
const config::Config& cfg);
|
||||
|
||||
void shape(pfaedle::netgraph::Graph* ng);
|
||||
|
||||
|
|
@ -66,12 +68,13 @@ class ShapeBuilder {
|
|||
|
||||
const trgraph::Graph* getGraph() const;
|
||||
|
||||
static osm::BBoxIdx getPaddedGtfsBox(const Feed* feed, double pad,
|
||||
const MOTs& mots, const std::string& tid,
|
||||
bool dropShapes);
|
||||
static void getGtfsBox(const Feed* feed, const MOTs& mots,
|
||||
const std::string& tid, bool dropShapes,
|
||||
osm::BBoxIdx* box);
|
||||
|
||||
private:
|
||||
Feed* _feed;
|
||||
ad::cppgtfs::gtfs::Feed* _evalFeed;
|
||||
MOTs _mots;
|
||||
config::MotConfig _motCfg;
|
||||
eval::Collector* _ecoll;
|
||||
|
|
@ -101,10 +104,10 @@ class ShapeBuilder {
|
|||
|
||||
std::string getFreeShapeId(Trip* t);
|
||||
|
||||
ad::cppgtfs::gtfs::Shape* getGtfsShape(const Shape& shp, Trip* t,
|
||||
ad::cppgtfs::gtfs::Shape getGtfsShape(const Shape& shp, Trip* t,
|
||||
std::vector<double>* hopDists);
|
||||
|
||||
void setShape(Trip* t, ad::cppgtfs::gtfs::Shape* s,
|
||||
void setShape(Trip* t, const ad::cppgtfs::gtfs::Shape& s,
|
||||
const std::vector<double>& dists);
|
||||
|
||||
router::NodeCandRoute getNCR(Trip* trip) const;
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ EdgePL::EdgePL(const EdgePL& pl, bool geoflat)
|
|||
}
|
||||
_flines[_l]++;
|
||||
|
||||
for (auto l : _lines) addLine(l);
|
||||
for (auto l : pl._lines) addLine(l);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
|
|
@ -82,7 +82,9 @@ double EdgePL::getLength() const { return _length; }
|
|||
|
||||
// _____________________________________________________________________________
|
||||
void EdgePL::addLine(const TransitEdgeLine* l) {
|
||||
if (_lines.insert(l).second) {
|
||||
if (std::find(_lines.begin(), _lines.end(), l) == _lines.end()) {
|
||||
_lines.reserve(_lines.size() + 1);
|
||||
_lines.push_back(l);
|
||||
if (_tlines.count(l))
|
||||
_tlines[l]++;
|
||||
else
|
||||
|
|
@ -96,7 +98,7 @@ void EdgePL::addLines(const std::vector<TransitEdgeLine*>& l) {
|
|||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const std::set<const TransitEdgeLine*>& EdgePL::getLines() const {
|
||||
const std::vector<const TransitEdgeLine*>& EdgePL::getLines() const {
|
||||
return _lines;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ inline bool operator<(const TransitEdgeLine& a, const TransitEdgeLine& b) {
|
|||
/*
|
||||
* An edge payload class for the transit graph.
|
||||
*/
|
||||
class EdgePL : public GeoEdgePL<PFAEDLE_PRECISION> {
|
||||
class EdgePL {
|
||||
public:
|
||||
EdgePL();
|
||||
~EdgePL();
|
||||
|
|
@ -101,7 +101,7 @@ class EdgePL : public GeoEdgePL<PFAEDLE_PRECISION> {
|
|||
void addLines(const std::vector<TransitEdgeLine*>& l);
|
||||
|
||||
// Return the TransitEdgeLines stored for this payload
|
||||
const std::set<const TransitEdgeLine*>& getLines() const;
|
||||
const std::vector<const TransitEdgeLine*>& getLines() const;
|
||||
|
||||
// Returns the last hop of the payload - this is the (n-2)th point in
|
||||
// the payload geometry of length n > 1
|
||||
|
|
@ -123,7 +123,7 @@ class EdgePL : public GeoEdgePL<PFAEDLE_PRECISION> {
|
|||
|
||||
LINE* _l;
|
||||
|
||||
std::set<const TransitEdgeLine*> _lines;
|
||||
std::vector<const TransitEdgeLine*> _lines;
|
||||
|
||||
static void unRefTLine(const TransitEdgeLine* l);
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ struct Component {
|
|||
/*
|
||||
* A node payload class for the transit graph.
|
||||
*/
|
||||
class NodePL : public GeoNodePL<PFAEDLE_PRECISION> {
|
||||
class NodePL {
|
||||
public:
|
||||
NodePL();
|
||||
NodePL(const NodePL& pl); // NOLINT
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue