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:
Patrick Brosi 2019-01-10 16:52:59 +01:00
parent 2cc2d2dc23
commit 63f0b61ea1
60 changed files with 4532 additions and 1576 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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;