Compare commits

..

No commits in common. "main" and "cmake-3.1" have entirely different histories.

23 changed files with 212 additions and 236 deletions

View file

@ -1,4 +1,4 @@
/build /build
/Dockerfile /Dockerfile
gtfs-out /push-docker-image.sh

View file

@ -1,33 +0,0 @@
name: GTFS Shapes Generation
on: [push]
jobs:
modify_routes:
runs-on: docker
steps:
- name: Download sample feed
run: curl -o sample-feed.zip https://download.data.public.lu/resources/horaires-et-arrets-des-transport-publics-gtfs/20240530-080402/gtfs-20240529-20240621.zip
- name: Download OSM data
run: curl -o luxembourg-latest.osm.pbf https://download.geofabrik.de/europe/luxembourg-latest.osm.pbf
- name: Convert OSM data to .osm
run: |
apt update && \
apt install -y osmctools && \
osmconvert luxembourg-latest.osm.pbf -o=luxembourg-latest.osm
- name: Run Shape Generation
uses: gtfs-actions/generate-shapes@main
with:
gtfs_file: sample-feed.zip
osm_file: luxembourg-latest.osm
mot: bus
output_file: modified-feed.zip
- name: Upload modified feed
uses: actions/upload-artifact@v3
with:
name: modified-feed
path: modified-feed.zip

110
.github/workflows/build.yml vendored Normal file
View file

@ -0,0 +1,110 @@
name: Build
'on':
- push
jobs:
ubuntu-20-04-build-gcc:
runs-on: ubuntu-20.04
steps:
- name: Checkout repository code
uses: actions/checkout@v2
- name: Checkout submodules
run: git submodule update --init --recursive
- name: update apt
run: sudo apt update
- name: install dependencies
run: sudo apt install -y cmake gcc g++
- name: cmake
run: mkdir build && cd build && cmake ..
- name: make
run: cd build && make
- name: tests
run: cd build && ctest --output-on-failure
ubuntu-latest-build-gcc:
runs-on: ubuntu-latest
steps:
- name: Checkout repository code
uses: actions/checkout@v2
- name: Checkout submodules
run: git submodule update --init --recursive
- name: update apt
run: sudo apt update
- name: install dependencies
run: sudo apt install -y cmake gcc g++
- name: cmake
run: mkdir build && cd build && cmake ..
- name: make
run: cd build && make
- name: tests
run: cd build && ctest --output-on-failure
ubuntu-20-04-build-clang:
runs-on: ubuntu-20.04
steps:
- name: Checkout repository code
uses: actions/checkout@v2
- name: Checkout submodules
run: git submodule update --init --recursive
- name: update apt
run: sudo apt update
- name: install dependencies
run: sudo apt install -y cmake clang
- name: cmake
run: mkdir build && cd build && cmake ..
shell: bash
env:
CC: clang
CXX: clang++
- name: make
run: cd build && make
- name: tests
run: cd build && ctest --output-on-failure
ubuntu-latest-build-clang:
runs-on: ubuntu-latest
steps:
- name: Checkout repository code
uses: actions/checkout@v2
- name: Checkout submodules
run: git submodule update --init --recursive
- name: update apt
run: sudo apt update
- name: install dependencies
run: sudo apt install -y cmake clang
- name: cmake
run: mkdir build && cd build && cmake ..
shell: bash
env:
CC: clang
CXX: clang++
- name: make
run: cd build && make
- name: tests
run: cd build && ctest --output-on-failure
macos-latest-build:
runs-on: macOS-latest
steps:
- name: Checkout repository code
uses: actions/checkout@v2
- name: Checkout submodules
run: git submodule update --init --recursive
- name: install dependencies
run: brew install cmake
- name: cmake
run: mkdir build && cd build && cmake ..
- name: make
run: cd build && make
- name: tests
run: cd build && ctest --output-on-failure
macos-12-build:
runs-on: macOS-12
steps:
- name: Checkout repository code
uses: actions/checkout@v2
- name: Checkout submodules
run: git submodule update --init --recursive
- name: install dependencies
run: brew install cmake
- name: cmake
run: mkdir build && cd build && cmake ..
- name: make
run: cd build && make
- name: tests
run: cd build && ctest --output-on-failure

View file

@ -1,4 +1,4 @@
cmake_minimum_required (VERSION 3.5) cmake_minimum_required (VERSION 3.1)
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
project (pfaedle) project (pfaedle)

View file

@ -1,9 +1,9 @@
FROM debian:bookworm-slim AS builder FROM debian:buster-slim AS builder
WORKDIR /app WORKDIR /app
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y g++ cmake git libzip-dev zlib1g-dev libbz2-dev apt-get install -y g++ cmake git
ADD . /app ADD . /app
RUN mkdir build && \ RUN mkdir build && \
@ -13,10 +13,10 @@ RUN mkdir build && \
pwd && \ pwd && \
make install make install
FROM debian:bookworm-slim FROM debian:buster-slim
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y libzip4 zlib1g libbz2-1.0 && \ apt-get install -y libgomp1 && \
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*
COPY --from=builder /usr/local/etc/pfaedle /usr/local/etc/pfaedle COPY --from=builder /usr/local/etc/pfaedle /usr/local/etc/pfaedle

View file

@ -25,27 +25,27 @@ For a quick visual inspection of the shape quality, see for example the schedule
Fetch this repository and init submodules: Fetch this repository and init submodules:
```shell ```
$ git clone --recurse-submodules https://github.com/ad-freiburg/pfaedle git clone --recurse-submodules https://github.com/ad-freiburg/pfaedle
``` ```
```shell ```
$ mkdir build && cd build mkdir build && cd build
$ cmake .. cmake ..
$ make -j make -j
``` ```
To install, type To install, type
```shell ```
$ make install make install
``` ```
# General Usage # General Usage
## Generating shapes for a GTFS feed ## Generating shapes for a GTFS feed
```shell ```
$ pfaedle -x <OSM FILE> <GTFS INPUT FEED> pfaedle -x <OSM FILE> <GTFS INPUT FEED>
``` ```
A shape'd version of the input GTFS feed will be written to `./gtfs-out`. A shape'd version of the input GTFS feed will be written to `./gtfs-out`.
@ -55,7 +55,7 @@ input feed. To drop all existing shapes, use the `-D` flag.
For example, you may generate (and replace existing, see `-D` flag) shapes for the GTFS dataset for Freiburg like this: For example, you may generate (and replace existing, see `-D` flag) shapes for the GTFS dataset for Freiburg like this:
```shell ```
$ wget https://fritz.freiburg.de/csv_Downloads/VAGFR.zip $ wget https://fritz.freiburg.de/csv_Downloads/VAGFR.zip
$ wget http://download.geofabrik.de/europe/germany/baden-wuerttemberg/freiburg-regbez-latest.osm.bz2 $ wget http://download.geofabrik.de/europe/germany/baden-wuerttemberg/freiburg-regbez-latest.osm.bz2
$ pfaedle -D -x freiburg-regbez-latest.osm.bz2 VAGFR.zip $ pfaedle -D -x freiburg-regbez-latest.osm.bz2 VAGFR.zip
@ -81,20 +81,16 @@ run.
## via Docker ## via Docker
You can use the [Docker image](https://github.com/orgs/ad-freiburg/packages/container/package/pfaedle) by mounting the OSM & GTFS data into the container: You can use the [`adfreiburg/pfaedle` Docker image](https://hub.docker.com/r/adfreiburg/pfaedle) by mounting the OSM & GTFS data into the container:
```shell ```shell
$ docker pull ghcr.io/ad-freiburg/pfaedle:latest docker run -i --rm \
$ docker run -i --rm \
# mount OSM data # mount OSM data
--volume /path/to/osm/data:/osm \ --volume /path/to/osm/data:/osm \
# mount GTFS data # mount GTFS data
--volume /path/to/gtfs/data:/gtfs \ --volume /path/to/gtfs/data:/gtfs \
# mount default output folder gtfs-out
--volume /path/to/output-dir:/gtfs-out \
ghcr.io/ad-freiburg/pfaedle:latest \
# tell pfaedle where to find the data # tell pfaedle where to find the data
-x /osm/osm-data.xml.bz2 -i /gtfs/myfeed.zip adfreiburg/pfaedle -x /osm/osm-data.xml -i /gtfs
``` ```
## Debugging ## Debugging
@ -109,7 +105,3 @@ The following flags may be useful for debugging:
# Configuration # Configuration
A default configuration file `pfaedle.cfg` can be found in this repo and will be installed with `make install`. Custom configuration files can be specified with the `-c` flag. If no `-c` flag is set, `pfaedle` will parse and merge the following cfg files in the given order (if present): `<install prefix>/etc/pfaedle/pfaedle.cfg`, `$HOME/.config/pfaedle/pfaedle.cfg`, `<CWD>/pfaedle.cfg`. Values given in later files will overwrite earlier defined values. A default configuration file `pfaedle.cfg` can be found in this repo and will be installed with `make install`. Custom configuration files can be specified with the `-c` flag. If no `-c` flag is set, `pfaedle` will parse and merge the following cfg files in the given order (if present): `<install prefix>/etc/pfaedle/pfaedle.cfg`, `$HOME/.config/pfaedle/pfaedle.cfg`, `<CWD>/pfaedle.cfg`. Values given in later files will overwrite earlier defined values.
# Attribution
Note that the `shapes.txt` produced by `pfaedle` is based on OpenStreetMap data, which is licensed under ODbL 1.0 (see [here](https://osm.org/copyright)). If you copy, distribute, transmit or adapt the shapefied GTFS feed, please credit the contributors of OpenStreetMap.

View file

@ -1,30 +0,0 @@
name: 'Generate shapes from OSM data'
description: 'Use pfaedle to generate shapes from OSM data for a GTFS feed.'
inputs:
gtfs_file:
description: 'Path to GTFS .zip file.'
required: true
osm_file:
description: 'Path to OSM .pbf file.'
required: true
mot:
description: 'Mode of transport to generate shapes for.'
required: false
default: 'all'
output_file:
description: 'Path to output GTFS .zip file.'
required: true
runs:
using: 'docker'
image: 'Dockerfile'
args:
- '-i'
- ${{ inputs.gtfs_file }}
- '-x'
- ${{ inputs.osm_file }}
- '-m'
- ${{ inputs.mot }}
- '-o'
- ${{ inputs.output_file }}

View file

@ -1341,9 +1341,6 @@ osm_filter_keep:
waterway=river waterway=river
motorboat=yes motorboat=yes
ferry=yes ferry=yes
amenity=ferry_terminal
mooring=ferry
station=ferry
# Nodes that are stations. # Nodes that are stations.
# Only nodes that have been kept during the filtering above will be # Only nodes that have been kept during the filtering above will be

6
push-docker-image.sh Normal file
View file

@ -0,0 +1,6 @@
#!/bin/sh
set -ex
set -o pipefail
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
docker push adfreiburg/pfaedle

@ -1 +1 @@
Subproject commit d26d5794d396141905d71ecb8cd4f45e0120cba7 Subproject commit 8e1dd71097cbc2fa1136522a2e2ba3cb574efe96

View file

@ -86,9 +86,6 @@ enum class RetCode {
std::string getFileNameMotStr(const MOTs& mots); std::string getFileNameMotStr(const MOTs& mots);
std::vector<std::string> getCfgPaths(const Config& cfg); std::vector<std::string> getCfgPaths(const Config& cfg);
// _____________________________________________________________________________
void gtfsWarnCb(std::string msg) { LOG(WARN) << msg; }
// _____________________________________________________________________________ // _____________________________________________________________________________
int main(int argc, char** argv) { int main(int argc, char** argv) {
// disable output buffering for standard output // disable output buffering for standard output
@ -138,9 +135,7 @@ int main(int argc, char** argv) {
if (!cfg.writeOverpass && !cfg.writeOsmfilter) if (!cfg.writeOverpass && !cfg.writeOsmfilter)
LOG(INFO) << "Reading GTFS feed " << cfg.feedPaths[0] << " ..."; LOG(INFO) << "Reading GTFS feed " << cfg.feedPaths[0] << " ...";
try { try {
ad::cppgtfs::Parser p(cfg.feedPaths[0], false, ad::cppgtfs::Parser p(cfg.feedPaths[0]);
cfg.parseAdditionalGTFSFields,
cfg.verbosity ? gtfsWarnCb : 0);
p.parse(&gtfs[0]); p.parse(&gtfs[0]);
} catch (const ad::cppgtfs::ParserException& ex) { } catch (const ad::cppgtfs::ParserException& ex) {
LOG(ERROR) << "Could not parse input GTFS feed, reason was:"; LOG(ERROR) << "Could not parse input GTFS feed, reason was:";
@ -197,7 +192,7 @@ int main(int argc, char** argv) {
for (size_t i = 0; i < cfg.feedPaths.size(); i++) { for (size_t i = 0; i < cfg.feedPaths.size(); i++) {
ShapeBuilder::getGtfsBox(&gtfs[i], cmdCfgMots, cfg.shapeTripId, true, ShapeBuilder::getGtfsBox(&gtfs[i], cmdCfgMots, cfg.shapeTripId, true,
&box, maxSpeed, 0, cfg.verbosity); &box, maxSpeed, 0);
} }
OsmBuilder osmBuilder; OsmBuilder osmBuilder;
std::vector<pfaedle::osm::OsmReadOpts> opts; std::vector<pfaedle::osm::OsmReadOpts> opts;
@ -219,7 +214,7 @@ int main(int argc, char** argv) {
BBoxIdx box(BOX_PADDING); BBoxIdx box(BOX_PADDING);
for (size_t i = 0; i < cfg.feedPaths.size(); i++) { for (size_t i = 0; i < cfg.feedPaths.size(); i++) {
ShapeBuilder::getGtfsBox(&gtfs[i], cmdCfgMots, cfg.shapeTripId, true, ShapeBuilder::getGtfsBox(&gtfs[i], cmdCfgMots, cfg.shapeTripId, true,
&box, maxSpeed, 0, cfg.verbosity); &box, maxSpeed, 0);
} }
OsmBuilder osmBuilder; OsmBuilder osmBuilder;
std::vector<pfaedle::osm::OsmReadOpts> opts; std::vector<pfaedle::osm::OsmReadOpts> opts;
@ -274,9 +269,9 @@ int main(int argc, char** argv) {
pfaedle::osm::OsmBuilder osmBuilder; pfaedle::osm::OsmBuilder osmBuilder;
pfaedle::osm::BBoxIdx box(BOX_PADDING); pfaedle::osm::BBoxIdx box(BOX_PADDING);
ShapeBuilder::getGtfsBox( ShapeBuilder::getGtfsBox(&gtfs[0], usedMots, cfg.shapeTripId,
&gtfs[0], usedMots, cfg.shapeTripId, cfg.dropShapes, &box, cfg.dropShapes, &box,
motCfg.osmBuildOpts.maxSpeed, &hopDists, cfg.verbosity); motCfg.osmBuildOpts.maxSpeed, &hopDists);
T_START(osmBuild); T_START(osmBuild);

View file

@ -111,8 +111,6 @@ void ConfigReader::help(const char* bin) {
<< "Disable hop cache \n" << "Disable hop cache \n"
<< std::setw(35) << " --stats" << std::setw(35) << " --stats"
<< "write stats to stats.json\n" << "write stats to stats.json\n"
<< std::setw(35) << " -W [ --warn ]"
<< "enable verbose warning messages\n"
<< std::setw(35) << " -P" << std::setw(35) << " -P"
<< "additional parameter string (in cfg file format)\n"; << "additional parameter string (in cfg file format)\n";
} }
@ -146,12 +144,10 @@ void ConfigReader::read(Config* cfg, int argc, char** argv) {
{"stats", no_argument, 0, 14}, {"stats", no_argument, 0, 14},
{"no-hop-cache", no_argument, 0, 15}, {"no-hop-cache", no_argument, 0, 15},
{"gaussian-noise", required_argument, 0, 16}, {"gaussian-noise", required_argument, 0, 16},
{"warn", no_argument, 0, 'W'},
{"keep-additional-gtfs-fields", no_argument, 0, 'F'},
{0, 0, 0, 0}}; {0, 0, 0, 0}};
int c; char c;
while ((c = getopt_long(argc, argv, ":o:hvi:c:x:Dm:g:X:T:d:pP:FW", ops, 0)) != while ((c = getopt_long(argc, argv, ":o:hvi:c:x:Dm:g:X:T:d:pP:", ops, 0)) !=
-1) { -1) {
switch (c) { switch (c) {
case 1: case 1:
@ -223,12 +219,6 @@ void ConfigReader::read(Config* cfg, int argc, char** argv) {
case 16: case 16:
cfg->gaussianNoise = atof(optarg); cfg->gaussianNoise = atof(optarg);
break; break;
case 'W':
cfg->verbosity = 1;
break;
case 'F':
cfg->parseAdditionalGTFSFields = true;
break;
case 'v': case 'v':
std::cout << "pfaedle " << VERSION_FULL << std::endl; std::cout << "pfaedle " << VERSION_FULL << std::endl;
exit(0); exit(0);

View file

@ -9,7 +9,6 @@
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <vector> #include <vector>
#include "ad/cppgtfs/gtfs/Route.h" #include "ad/cppgtfs/gtfs/Route.h"
#include "util/geo/Geo.h" #include "util/geo/Geo.h"
@ -37,10 +36,8 @@ struct Config {
noTrie(false), noTrie(false),
noHopCache(false), noHopCache(false),
writeStats(false), writeStats(false),
parseAdditionalGTFSFields(false),
gridSize(2000 / util::geo::M_PER_DEG), gridSize(2000 / util::geo::M_PER_DEG),
gaussianNoise(0), gaussianNoise(0) {}
verbosity(0) {}
std::string dbgOutputPath; std::string dbgOutputPath;
std::string solveMethod; std::string solveMethod;
std::string shapeTripId; std::string shapeTripId;
@ -65,10 +62,8 @@ struct Config {
bool noTrie; bool noTrie;
bool noHopCache; bool noHopCache;
bool writeStats; bool writeStats;
bool parseAdditionalGTFSFields;
double gridSize; double gridSize;
double gaussianNoise; double gaussianNoise;
uint8_t verbosity;
std::string toString() { std::string toString() {
std::stringstream ss; std::stringstream ss;
@ -90,8 +85,6 @@ struct Config {
<< "no-a-star: " << noAStar << "\n" << "no-a-star: " << noAStar << "\n"
<< "no-trie: " << noTrie << "\n" << "no-trie: " << noTrie << "\n"
<< "no-hop-cache: " << noHopCache << "\n" << "no-hop-cache: " << noHopCache << "\n"
<< "verbosity: " << verbosity << "\n"
<< "parse-additional-gtfs-fields: " << parseAdditionalGTFSFields << "\n"
<< "write-stats: " << writeStats << "\n" << "write-stats: " << writeStats << "\n"
<< "feed-paths: "; << "feed-paths: ";

View file

@ -345,22 +345,6 @@ void Writer::write(gtfs::Feed* sourceFeed, const std::string& path) const {
cannotWrite(curFileTg); cannotWrite(curFileTg);
} }
} }
curFile = getTmpFName(gtfsPath, ".pfaedle-tmp", "attributions.txt");
curFileTg = gtfsPath + "/attributions.txt";
fs.open(curFile.c_str());
if (!fs.good()) cannotWrite(curFile, curFileTg);
writeAttribution(sourceFeed, &fs);
fs.close();
if (toZip) {
#ifdef LIBZIP_FOUND
moveIntoZip(za, curFile, "attributions.txt");
#endif
} else {
if (std::rename(curFile.c_str(), curFileTg.c_str()))
cannotWrite(curFileTg);
}
} catch (...) { } catch (...) {
#ifdef LIBZIP_FOUND #ifdef LIBZIP_FOUND
zip_discard(za); zip_discard(za);
@ -379,18 +363,6 @@ void Writer::write(gtfs::Feed* sourceFeed, const std::string& path) const {
} }
} }
// ____________________________________________________________________________
void Writer::writeAttribution(gtfs::Feed*, std::ostream* os) const {
auto csvw = ad::cppgtfs::Writer::getAttributionCsvw(os);
csvw->flushLine();
csvw->writeString("OpenStreetMap contributors");
csvw->writeString("https://www.openstreetmap.org/copyright");
csvw->writeInt(1);
csvw->flushLine();
}
// ____________________________________________________________________________ // ____________________________________________________________________________
void Writer::writeFeedInfo(gtfs::Feed* f, std::ostream* os) const { void Writer::writeFeedInfo(gtfs::Feed* f, std::ostream* os) const {
auto csvw = ad::cppgtfs::Writer::getFeedInfoCsvw(os); auto csvw = ad::cppgtfs::Writer::getFeedInfoCsvw(os);
@ -454,15 +426,14 @@ void Writer::writeAgency(gtfs::Feed* sourceFeed, std::ostream* os) const {
ad::cppgtfs::Writer w; ad::cppgtfs::Writer w;
auto csvw = auto csvw = ad::cppgtfs::Writer::getAgencyCsvw(os);
ad::cppgtfs::Writer::getAgencyCsvw(os, sourceFeed->getAgencyAddFlds());
csvw->flushLine(); csvw->flushLine();
ad::cppgtfs::gtfs::flat::Agency fa; ad::cppgtfs::gtfs::flat::Agency fa;
auto flds = Parser::getAgencyFlds(csvp.get()); auto flds = Parser::getAgencyFlds(csvp.get());
while (p.nextAgency(csvp.get(), &fa, flds)) { while (p.nextAgency(csvp.get(), &fa, flds)) {
w.writeAgency(fa, csvw.get(), sourceFeed->getAgencyAddFlds()); w.writeAgency(fa, csvw.get());
} }
} }
@ -472,15 +443,14 @@ void Writer::writeStops(gtfs::Feed* sourceFeed, std::ostream* os) const {
auto csvp = p.getCsvParser("stops.txt"); auto csvp = p.getCsvParser("stops.txt");
ad::cppgtfs::Writer w; ad::cppgtfs::Writer w;
auto csvw = auto csvw = ad::cppgtfs::Writer::getStopsCsvw(os);
ad::cppgtfs::Writer::getStopsCsvw(os, sourceFeed->getStopAddFlds());
csvw->flushLine(); csvw->flushLine();
ad::cppgtfs::gtfs::flat::Stop s; ad::cppgtfs::gtfs::flat::Stop s;
auto flds = Parser::getStopFlds(csvp.get()); auto flds = Parser::getStopFlds(csvp.get());
while (p.nextStop(csvp.get(), &s, flds)) { while (p.nextStop(csvp.get(), &s, flds)) {
w.writeStop(s, csvw.get(), sourceFeed->getStopAddFlds()); w.writeStop(s, csvw.get());
} }
} }
@ -488,13 +458,11 @@ void Writer::writeStops(gtfs::Feed* sourceFeed, std::ostream* os) const {
void Writer::writeRoutes(gtfs::Feed* sourceFeed, std::ostream* os) const { void Writer::writeRoutes(gtfs::Feed* sourceFeed, std::ostream* os) const {
ad::cppgtfs::Writer w; ad::cppgtfs::Writer w;
auto csvw = auto csvw = ad::cppgtfs::Writer::getRoutesCsvw(os);
ad::cppgtfs::Writer::getRoutesCsvw(os, sourceFeed->getRouteAddFlds());
csvw->flushLine(); csvw->flushLine();
for (auto r : sourceFeed->getRoutes()) { for (auto r : sourceFeed->getRoutes()) {
w.writeRoute(r.second->getFlat(), csvw.get(), w.writeRoute(r.second->getFlat(), csvw.get());
sourceFeed->getRouteAddFlds());
} }
} }
@ -643,13 +611,12 @@ bool Writer::writeTrips(gtfs::Feed* sourceFeed, std::ostream* os) const {
ad::cppgtfs::Writer w; ad::cppgtfs::Writer w;
bool hasFreqs = false; bool hasFreqs = false;
auto csvw = auto csvw = ad::cppgtfs::Writer::getTripsCsvw(os);
ad::cppgtfs::Writer::getTripsCsvw(os, sourceFeed->getTripAddFlds());
csvw->flushLine(); csvw->flushLine();
for (auto t : sourceFeed->getTrips()) { for (auto t : sourceFeed->getTrips()) {
if (t.getFrequencies().size()) hasFreqs = true; if (t.getFrequencies().size()) hasFreqs = true;
w.writeTrip(t.getFlat(), csvw.get(), sourceFeed->getTripAddFlds()); w.writeTrip(t.getFlat(), csvw.get());
} }
return hasFreqs; return hasFreqs;

View file

@ -40,7 +40,6 @@ class Writer {
void writeStopTimes(Feed* f, std::ostream* os) const; void writeStopTimes(Feed* f, std::ostream* os) const;
void writeLevels(Feed* f, std::ostream* os) const; void writeLevels(Feed* f, std::ostream* os) const;
void writePathways(Feed* f, std::ostream* os) const; void writePathways(Feed* f, std::ostream* os) const;
void writeAttribution(Feed* f, std::ostream* os) const;
static void cannotWrite(const std::string& file, const std::string& file2); static void cannotWrite(const std::string& file, const std::string& file2);
static void cannotWrite(const std::string& file); static void cannotWrite(const std::string& file);

View file

@ -5,12 +5,10 @@
#ifndef PFAEDLE_OSM_OSM_H_ #ifndef PFAEDLE_OSM_OSM_H_
#define PFAEDLE_OSM_OSM_H_ #define PFAEDLE_OSM_OSM_H_
#include <stdint.h>
#include <set> #include <set>
#include <string> #include <string>
#include <unordered_map>
#include <utility> #include <utility>
#include <unordered_map>
#include <vector> #include <vector>
namespace pfaedle { namespace pfaedle {

View file

@ -137,12 +137,18 @@ void OsmBuilder::read(const std::string& path, const OsmReadOpts& opts,
LOG(DEBUG) << "Snapping stations..."; LOG(DEBUG) << "Snapping stations...";
snapStats(opts, g, bbox, gridSize, res, orphanStations); snapStats(opts, g, bbox, gridSize, res, orphanStations);
LOG(DEBUG) << "Deleting orphan edges...";
deleteOrphEdgs(g, opts);
LOG(DEBUG) << "Collapsing edges..."; LOG(DEBUG) << "Collapsing edges...";
collapseEdges(g); collapseEdges(g);
LOG(DEBUG) << "Writing edge geoms..."; LOG(DEBUG) << "Writing edge geoms...";
writeGeoms(g, opts); writeGeoms(g, opts);
LOG(DEBUG) << "Deleting orphan edges...";
deleteOrphEdgs(g, opts);
LOG(DEBUG) << "Deleting orphan nodes..."; LOG(DEBUG) << "Deleting orphan nodes...";
deleteOrphNds(g, opts); deleteOrphNds(g, opts);
@ -1560,6 +1566,30 @@ void OsmBuilder::deleteOrphNds(Graph* g, const OsmReadOpts& opts) {
} }
} }
// _____________________________________________________________________________
void OsmBuilder::deleteOrphEdgs(Graph* g, const OsmReadOpts& opts) {
size_t ROUNDS = 3;
for (size_t c = 0; c < ROUNDS; c++) {
for (auto i = g->getNds().begin(); i != g->getNds().end();) {
if ((*i)->getInDeg() + (*i)->getOutDeg() != 1 || (*i)->pl().getSI() ||
(*i)->pl().isTurnCycle()) {
++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);
}
}
}
// _____________________________________________________________________________ // _____________________________________________________________________________
bool OsmBuilder::edgesSim(const Edge* a, const Edge* b) { bool OsmBuilder::edgesSim(const Edge* a, const Edge* b) {
if (static_cast<bool>(a->pl().oneWay()) ^ static_cast<bool>(b->pl().oneWay())) if (static_cast<bool>(a->pl().oneWay()) ^ static_cast<bool>(b->pl().oneWay()))

View file

@ -180,6 +180,7 @@ class OsmBuilder {
double gridSize, Restrictor* res, double gridSize, Restrictor* res,
const NodeSet& orphanStations); const NodeSet& orphanStations);
static void writeGeoms(Graph* g, const OsmReadOpts& opts); static void writeGeoms(Graph* g, const OsmReadOpts& opts);
static void deleteOrphEdgs(Graph* g, const OsmReadOpts& opts);
static void deleteOrphNds(Graph* g, const OsmReadOpts& opts); static void deleteOrphNds(Graph* g, const OsmReadOpts& opts);
static double dist(const Node* a, const Node* b); static double dist(const Node* a, const Node* b);

View file

@ -5,11 +5,8 @@
#ifndef PFAEDLE_OSM_OSMFILTER_H_ #ifndef PFAEDLE_OSM_OSMFILTER_H_
#define PFAEDLE_OSM_OSMFILTER_H_ #define PFAEDLE_OSM_OSMFILTER_H_
#include <stdint.h>
#include <string> #include <string>
#include <vector> #include <vector>
#include "pfaedle/osm/Osm.h" #include "pfaedle/osm/Osm.h"
#include "pfaedle/osm/OsmReadOpts.h" #include "pfaedle/osm/OsmReadOpts.h"

View file

@ -73,7 +73,7 @@ ShapeBuilder::ShapeBuilder(
_router(router) { _router(router) {
pfaedle::osm::BBoxIdx box(BOX_PADDING); pfaedle::osm::BBoxIdx box(BOX_PADDING);
ShapeBuilder::getGtfsBox(feed, mots, cfg.shapeTripId, cfg.dropShapes, &box, ShapeBuilder::getGtfsBox(feed, mots, cfg.shapeTripId, cfg.dropShapes, &box,
_motCfg.osmBuildOpts.maxSpeed, 0, cfg.verbosity); _motCfg.osmBuildOpts.maxSpeed, 0);
_eGrid = EdgeGrid(cfg.gridSize, cfg.gridSize, box.getFullBox(), false); _eGrid = EdgeGrid(cfg.gridSize, cfg.gridSize, box.getFullBox(), false);
_nGrid = NodeGrid(cfg.gridSize, cfg.gridSize, box.getFullBox(), false); _nGrid = NodeGrid(cfg.gridSize, cfg.gridSize, box.getFullBox(), false);
@ -270,11 +270,6 @@ EdgeCandGroup ShapeBuilder::getEdgCands(const Stop* s) const {
{}}); {}});
} }
if (ret.size() == 1 && _cfg.verbosity) {
LOG(WARN) << "No snapping candidate found for stop '" << s->getName()
<< "' (" << s->getId() << ")";
}
return ret; return ret;
} }
@ -326,7 +321,7 @@ std::pair<std::vector<LINE>, Stats> ShapeBuilder::shapeL(Trip* trip) {
LOG(INFO) << "Matched 1 trip in " << std::fixed << std::setprecision(2) LOG(INFO) << "Matched 1 trip in " << std::fixed << std::setprecision(2)
<< stats.solveTime << " ms."; << stats.solveTime << " ms.";
// print to line // print to line
return {getGeom(hops, getRAttrs(trip), &colors, trip, 1), stats}; return {getGeom(hops, getRAttrs(trip), &colors), stats};
} catch (const std::runtime_error& e) { } catch (const std::runtime_error& e) {
LOG(ERROR) << e.what(); LOG(ERROR) << e.what();
return {std::vector<LINE>(), stats}; return {std::vector<LINE>(), stats};
@ -346,6 +341,7 @@ std::map<size_t, EdgeListHops> ShapeBuilder::shapeify(
const TripTrie<pfaedle::gtfs::Trip>* trie, HopCache* hopCache) const { const TripTrie<pfaedle::gtfs::Trip>* trie, HopCache* hopCache) const {
LOG(VDEBUG) << "Map-matching trie " << trie; LOG(VDEBUG) << "Map-matching trie " << trie;
// TODO(patrick): assumes the trie is not empty, check this!
assert(trie->getNdTrips().size()); assert(trie->getNdTrips().size());
assert(trie->getNdTrips().begin()->second.size()); assert(trie->getNdTrips().begin()->second.size());
RoutingAttrs rAttrs = getRAttrs(trie->getNdTrips().begin()->second[0]); RoutingAttrs rAttrs = getRAttrs(trie->getNdTrips().begin()->second[0]);
@ -562,16 +558,15 @@ void ShapeBuilder::setShape(Trip* t, const ad::cppgtfs::gtfs::Shape& s,
// _____________________________________________________________________________ // _____________________________________________________________________________
ad::cppgtfs::gtfs::Shape ShapeBuilder::getGtfsShape( ad::cppgtfs::gtfs::Shape ShapeBuilder::getGtfsShape(
const EdgeListHops& hops, Trip* t, size_t numOthers, const EdgeListHops& hops, Trip* t, const RoutingAttrs& rAttrs,
const RoutingAttrs& rAttrs, std::vector<float>* hopDists, std::vector<float>* hopDists, uint32_t* bestColor) {
uint32_t* bestColor) {
ad::cppgtfs::gtfs::Shape ret(getFreeShapeId(t)); ad::cppgtfs::gtfs::Shape ret(getFreeShapeId(t));
assert(hops.size() == t->getStopTimes().size() - 1); assert(hops.size() == t->getStopTimes().size() - 1);
std::map<uint32_t, double> colors; std::map<uint32_t, double> colors;
const std::vector<LINE>& gl = getGeom(hops, rAttrs, &colors, t, numOthers); const std::vector<LINE>& gl = getGeom(hops, rAttrs, &colors);
const std::vector<float>& measures = getMeasure(gl); const std::vector<float>& measures = getMeasure(gl);
size_t seq = 0; size_t seq = 0;
@ -656,8 +651,7 @@ const RoutingAttrs& ShapeBuilder::getRAttrs(const Trip* trip) const {
void ShapeBuilder::getGtfsBox(const Feed* feed, const MOTs& mots, void ShapeBuilder::getGtfsBox(const Feed* feed, const MOTs& mots,
const std::string& tid, bool dropShapes, const std::string& tid, bool dropShapes,
osm::BBoxIdx* box, double maxSpeed, osm::BBoxIdx* box, double maxSpeed,
std::vector<double>* hopDists, std::vector<double>* hopDists) {
uint8_t verbosity) {
for (const auto& t : feed->getTrips()) { for (const auto& t : feed->getTrips()) {
if (!tid.empty() && t.getId() != tid) continue; if (!tid.empty() && t.getId() != tid) continue;
if (tid.empty() && !t.getShape().empty() && !dropShapes) continue; if (tid.empty() && !t.getShape().empty() && !dropShapes) continue;
@ -701,21 +695,11 @@ void ShapeBuilder::getGtfsBox(const Feed* feed, const MOTs& mots,
if (reqToTime > (BUFFER + toTime) * 3 * MAX_ROUTE_COST_DOUBLING_STEPS && if (reqToTime > (BUFFER + toTime) * 3 * MAX_ROUTE_COST_DOUBLING_STEPS &&
reqFromTime > reqFromTime >
(BUFFER + fromTime) * 3 * MAX_ROUTE_COST_DOUBLING_STEPS) { (BUFFER + fromTime) * 3 * MAX_ROUTE_COST_DOUBLING_STEPS) {
if (verbosity) { LOG(DEBUG) << "Skipping station " << st.getStop()->getId() << " ("
LOG(WARN) << st.getStop()->getName() << ") @ "
<< "Skipping station '" << st.getStop()->getName() << "' (" << st.getStop()->getLat() << ", " << st.getStop()->getLng()
<< st.getStop()->getId() << ") @ " << st.getStop()->getLat()
<< ", " << st.getStop()->getLng()
<< " for bounding box as the vehicle cannot realistically " << " for bounding box as the vehicle cannot realistically "
"reach and leave it in the scheduled time"; "reach and leave it in the scheduled time";
} else {
LOG(DEBUG)
<< "Skipping station '" << st.getStop()->getName() << "' ("
<< st.getStop()->getId() << ") @ " << st.getStop()->getLat()
<< ", " << st.getStop()->getLng()
<< " for bounding box as the vehicle cannot realistically "
"reach and leave it in the scheduled time";
}
continue; continue;
} }
@ -837,8 +821,9 @@ double ShapeBuilder::timePen(int candTime, int schedTime) const {
// _____________________________________________________________________________ // _____________________________________________________________________________
EdgeCandGroup ShapeBuilder::timeExpand(const EdgeCand& ec, int time) const { EdgeCandGroup ShapeBuilder::timeExpand(const EdgeCand& ec, int time) const {
EdgeCandGroup ret; EdgeCandGroup ret;
// TODO(patrick): heuristic for time expansion variance, currently // TODO(patrick): heuristic for time expansion variance
// unused // for (int i = -5; i < 6; i++) {
// for (int i = -10; i < 1; i++) {
for (int i = 0; i < 1; i++) { for (int i = 0; i < 1; i++) {
EdgeCand ecNew = ec; EdgeCand ecNew = ec;
// in 30 sec steps // in 30 sec steps
@ -969,10 +954,9 @@ void ShapeBuilder::buildNetGraph(TrGraphEdgs* edgs,
} }
// _____________________________________________________________________________ // _____________________________________________________________________________
std::vector<LINE> ShapeBuilder::getGeom(const EdgeListHops& hops, std::vector<LINE> ShapeBuilder::getGeom(
const RoutingAttrs& rAttrs, const EdgeListHops& hops, const RoutingAttrs& rAttrs,
std::map<uint32_t, double>* colors, std::map<uint32_t, double>* colors) const {
Trip* t, size_t numOthers) const {
std::vector<LINE> ret; std::vector<LINE> ret;
for (size_t i = hops.size(); i > 0; i--) { for (size_t i = hops.size(); i > 0; i--) {
@ -980,23 +964,6 @@ std::vector<LINE> ShapeBuilder::getGeom(const EdgeListHops& hops,
if (!hop.start || !hop.end) { if (!hop.start || !hop.end) {
// no hop was found, use the fallback geometry // no hop was found, use the fallback geometry
if (_cfg.verbosity) {
const auto stopFr = t->getStopTimes()[hops.size() - i].getStop();
const auto stopTo = t->getStopTimes()[hops.size() - i + 1].getStop();
LOG(WARN) << "No viable hop found between stops '" << stopFr->getName()
<< "' (" << stopFr->getId() << ") and '" << stopTo->getName()
<< "' (" << stopTo->getId() << ") for trip " << t->getId()
<< " of type '"
<< ad::cppgtfs::gtfs::flat::Route::getTypeString(
t->getRoute()->getType())
<< "'"
<< (numOthers > 1 ? " (and " + std::to_string(numOthers) +
" similar trips)"
: "")
<< ", falling back to straight line";
}
if (hop.start) { if (hop.start) {
if (hop.progrStart > 0) { if (hop.progrStart > 0) {
auto l = getLine(hop.start); auto l = getLine(hop.start);
@ -1192,9 +1159,8 @@ void ShapeBuilder::shapeWorker(
uint32_t color; uint32_t color;
const ad::cppgtfs::gtfs::Shape& shp = const ad::cppgtfs::gtfs::Shape& shp = getGtfsShape(
getGtfsShape(hops.at(leaf.first), leaf.second[0], hops.at(leaf.first), leaf.second[0], rAttrs, &distances, &color);
leaf.second.size(), rAttrs, &distances, &color);
if (_cfg.buildTransitGraph) { if (_cfg.buildTransitGraph) {
writeTransitGraph(hops.at(leaf.first), gtfsGraph, leaf.second); writeTransitGraph(hops.at(leaf.first), gtfsGraph, leaf.second);

View file

@ -12,7 +12,6 @@
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "ad/cppgtfs/gtfs/Feed.h" #include "ad/cppgtfs/gtfs/Feed.h"
#include "pfaedle/Def.h" #include "pfaedle/Def.h"
#include "pfaedle/config/MotConfig.h" #include "pfaedle/config/MotConfig.h"
@ -74,7 +73,7 @@ class ShapeBuilder {
static void getGtfsBox(const pfaedle::gtfs::Feed* feed, const MOTs& mots, static void getGtfsBox(const pfaedle::gtfs::Feed* feed, const MOTs& mots,
const std::string& tid, bool dropShapes, const std::string& tid, bool dropShapes,
osm::BBoxIdx* box, double maxSpeed, osm::BBoxIdx* box, double maxSpeed,
std::vector<double>* hopDists, uint8_t verbosity); std::vector<double>* hopDists);
private: private:
pfaedle::gtfs::Feed* _feed; pfaedle::gtfs::Feed* _feed;
@ -104,7 +103,6 @@ class ShapeBuilder {
std::string getFreeShapeId(pfaedle::gtfs::Trip* t); std::string getFreeShapeId(pfaedle::gtfs::Trip* t);
ad::cppgtfs::gtfs::Shape getGtfsShape(const EdgeListHops& shp, ad::cppgtfs::gtfs::Shape getGtfsShape(const EdgeListHops& shp,
pfaedle::gtfs::Trip* t, pfaedle::gtfs::Trip* t,
size_t numOthers,
const RoutingAttrs& rAttrs, const RoutingAttrs& rAttrs,
std::vector<float>* hopDists, std::vector<float>* hopDists,
uint32_t* bestColor); uint32_t* bestColor);
@ -128,8 +126,7 @@ class ShapeBuilder {
void buildIndex(); void buildIndex();
std::vector<LINE> getGeom(const EdgeListHops& shp, const RoutingAttrs& rAttrs, std::vector<LINE> getGeom(const EdgeListHops& shp, const RoutingAttrs& rAttrs,
std::map<uint32_t, double>* colors, Trip* t, std::map<uint32_t, double>* colors) const;
size_t numOthers) const;
double timePen(int candTime, int schedTime) const; double timePen(int candTime, int schedTime) const;
LINE getLine(const EdgeListHop& hop, const RoutingAttrs&, LINE getLine(const EdgeListHop& hop, const RoutingAttrs&,

View file

@ -193,6 +193,7 @@ size_t TripTrie<TRIP>::getMatchChild(size_t parentNid,
const std::string& platform, POINT pos, const std::string& platform, POINT pos,
int time, bool timeEx) const { int time, bool timeEx) const {
for (size_t child : _nds[parentNid].childs) { for (size_t child : _nds[parentNid].childs) {
// TODO(patrick): use similarity classification here?
if (_nds[child].stopName == stopName && _nds[child].platform == platform && if (_nds[child].stopName == stopName && _nds[child].platform == platform &&
util::geo::dist(_nds[child].pos, pos) < 1 && util::geo::dist(_nds[child].pos, pos) < 1 &&
(!timeEx || _nds[child].time == time)) { (!timeEx || _nds[child].time == time)) {

@ -1 +1 @@
Subproject commit d1c30e9ec4cb68803be073d35beb6af2b860bda4 Subproject commit af1ced1c82539675b8c9d49c19136224e4af07a9