initial commit
This commit is contained in:
commit
efcd3e1892
106 changed files with 27000 additions and 0 deletions
75
src/pfaedle/router/Comp.h
Normal file
75
src/pfaedle/router/Comp.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_ROUTER_COMP_H_
|
||||
#define PFAEDLE_ROUTER_COMP_H_
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include "util/String.h"
|
||||
|
||||
namespace pfaedle {
|
||||
namespace router {
|
||||
|
||||
using util::editDist;
|
||||
|
||||
// _____________________________________________________________________________
|
||||
inline double statSimi(const std::string& a, const std::string& b) {
|
||||
if (a == b) return 1;
|
||||
|
||||
if (a.empty() || b.empty()) return 0;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (static_cast<double>(editDist(a, b)) /
|
||||
(std::max(static_cast<double>(a.size()),
|
||||
static_cast<double>(b.size()))) <
|
||||
0.05)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
inline double lineSimi(const std::string& a, const std::string& b) {
|
||||
if (a == b) return 1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace router
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_ROUTER_COMP_H_
|
||||
99
src/pfaedle/router/EdgePL.cpp
Normal file
99
src/pfaedle/router/EdgePL.cpp
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#include "pfaedle/router/EdgePL.h"
|
||||
#include "pfaedle/router/Router.h"
|
||||
#include "util/String.h"
|
||||
|
||||
using pfaedle::router::EdgePL;
|
||||
using pfaedle::router::EdgeCost;
|
||||
using pfaedle::router::EdgeList;
|
||||
using pfaedle::trgraph::Node;
|
||||
|
||||
// _____________________________________________________________________________
|
||||
EdgeList* EdgePL::getEdges() { return &_edges; }
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const EdgeList& EdgePL::getEdges() const { return _edges; }
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const FPoint& EdgePL::frontHop() const {
|
||||
if (!_edges.size()) return *_end->pl().getGeom();
|
||||
return _edges.back()->pl().frontHop();
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const FPoint& EdgePL::backHop() const {
|
||||
if (!_edges.size()) return *_start->pl().getGeom();
|
||||
return _edges.front()->pl().backHop();
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const Node* EdgePL::backNode() const { return _end; }
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const Node* EdgePL::frontNode() const { return _start; }
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const util::geo::FLine* EdgePL::getGeom() const {
|
||||
if (!_edges.size()) return 0;
|
||||
if (!_geom.size()) {
|
||||
const trgraph::Node* l = _start;
|
||||
for (auto i = _edges.rbegin(); i != _edges.rend(); i++) {
|
||||
const auto e = *i;
|
||||
if ((e->getFrom() == l) ^ e->pl().isRev()) {
|
||||
_geom.insert(_geom.end(), e->pl().getGeom()->begin(),
|
||||
e->pl().getGeom()->end());
|
||||
} else {
|
||||
_geom.insert(_geom.end(), e->pl().getGeom()->rbegin(),
|
||||
e->pl().getGeom()->rend());
|
||||
}
|
||||
l = e->getOtherNd(l);
|
||||
}
|
||||
}
|
||||
|
||||
return &_geom;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void EdgePL::setStartNode(const trgraph::Node* s) { _start = s; }
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void EdgePL::setEndNode(const trgraph::Node* e) { _end = e; }
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void EdgePL::setStartEdge(const trgraph::Edge* s) { _startE = s; }
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void EdgePL::setEndEdge(const trgraph::Edge* e) { _endE = e; }
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const EdgeCost& EdgePL::getCost() const { return _cost; }
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void EdgePL::setCost(const router::EdgeCost& c) { _cost = c; }
|
||||
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void EdgePL::getAttrs(std::map<std::string, std::string>* obj) 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";
|
||||
}
|
||||
49
src/pfaedle/router/EdgePL.h
Normal file
49
src/pfaedle/router/EdgePL.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_ROUTER_EDGEPL_H_
|
||||
#define PFAEDLE_ROUTER_EDGEPL_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "pfaedle/router/Misc.h"
|
||||
#include "util/geo/GeoGraph.h"
|
||||
|
||||
using util::geograph::GeoEdgePL;
|
||||
|
||||
namespace pfaedle {
|
||||
namespace router {
|
||||
|
||||
class EdgePL : public GeoEdgePL<float> {
|
||||
public:
|
||||
EdgePL() : _cost(), _start(0), _end(0), _startE(0), _endE(0) {}
|
||||
const util::geo::FLine* getGeom() const;
|
||||
void getAttrs(std::map<std::string, std::string>* attrs) const;
|
||||
router::EdgeList* getEdges();
|
||||
const router::EdgeList& getEdges() const;
|
||||
void setStartNode(const trgraph::Node* s);
|
||||
void setEndNode(const trgraph::Node* s);
|
||||
void setStartEdge(const trgraph::Edge* s);
|
||||
void setEndEdge(const trgraph::Edge* s);
|
||||
const router::EdgeCost& getCost() const;
|
||||
void setCost(const router::EdgeCost& c);
|
||||
const FPoint& frontHop() const;
|
||||
const FPoint& backHop() const;
|
||||
const trgraph::Node* frontNode() const;
|
||||
const trgraph::Node* backNode() const;
|
||||
|
||||
private:
|
||||
router::EdgeCost _cost;
|
||||
// the edges are in this field in REVERSED ORDER!
|
||||
router::EdgeList _edges;
|
||||
const trgraph::Node* _start;
|
||||
const trgraph::Node* _end;
|
||||
const trgraph::Edge* _startE;
|
||||
const trgraph::Edge* _endE;
|
||||
mutable util::geo::FLine _geom;
|
||||
};
|
||||
} // namespace router
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_ROUTER_EDGEPL_H_
|
||||
26
src/pfaedle/router/Graph.h
Normal file
26
src/pfaedle/router/Graph.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_ROUTER_GRAPH_H_
|
||||
#define PFAEDLE_ROUTER_GRAPH_H_
|
||||
|
||||
#include "pfaedle/trgraph/Graph.h"
|
||||
#include "pfaedle/router/EdgePL.h"
|
||||
#include "pfaedle/router/NodePL.h"
|
||||
#include "util/graph/DirGraph.h"
|
||||
|
||||
using util::geo::Point;
|
||||
using util::geo::Line;
|
||||
|
||||
namespace pfaedle {
|
||||
namespace router {
|
||||
|
||||
typedef util::graph::Edge<router::NodePL, router::EdgePL> Edge;
|
||||
typedef util::graph::Node<router::NodePL, router::EdgePL> Node;
|
||||
typedef util::graph::DirGraph<router::NodePL, router::EdgePL> Graph;
|
||||
|
||||
} // namespace router
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_ROUTER_GRAPH_H_
|
||||
197
src/pfaedle/router/Misc.h
Normal file
197
src/pfaedle/router/Misc.h
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_ROUTER_MISC_H_
|
||||
#define PFAEDLE_ROUTER_MISC_H_
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include "ad/cppgtfs/gtfs/Feed.h"
|
||||
#include "ad/cppgtfs/gtfs/Route.h"
|
||||
#include "pfaedle/trgraph/Graph.h"
|
||||
|
||||
using ad::cppgtfs::gtfs::Route;
|
||||
using ad::cppgtfs::gtfs::Stop;
|
||||
|
||||
namespace pfaedle {
|
||||
namespace router {
|
||||
|
||||
struct NodeCand {
|
||||
trgraph::Node* nd;
|
||||
double pen;
|
||||
};
|
||||
|
||||
struct RoutingOpts {
|
||||
RoutingOpts()
|
||||
: fullTurnPunishFac(2000),
|
||||
fullTurnAngle(45),
|
||||
passThruStationsPunish(100),
|
||||
oneWayPunishFac(1),
|
||||
oneWayEdgePunish(0),
|
||||
lineUnmatchedPunishFact(0.5),
|
||||
platformUnmatchedPen(0),
|
||||
stationDistPenFactor(0) {}
|
||||
double fullTurnPunishFac;
|
||||
double fullTurnAngle;
|
||||
double passThruStationsPunish;
|
||||
double oneWayPunishFac;
|
||||
double oneWayEdgePunish;
|
||||
double lineUnmatchedPunishFact;
|
||||
double platformUnmatchedPen;
|
||||
double stationDistPenFactor;
|
||||
double nonOsmPen;
|
||||
double levelPunish[8];
|
||||
};
|
||||
|
||||
inline bool operator==(const RoutingOpts& a, const RoutingOpts& b) {
|
||||
return fabs(a.fullTurnPunishFac - b.fullTurnPunishFac) < 0.01 &&
|
||||
fabs(a.fullTurnAngle - b.fullTurnAngle) < 0.01 &&
|
||||
fabs(a.passThruStationsPunish - b.passThruStationsPunish) < 0.01 &&
|
||||
fabs(a.oneWayPunishFac - b.oneWayPunishFac) < 0.01 &&
|
||||
fabs(a.oneWayEdgePunish - b.oneWayEdgePunish) < 0.01 &&
|
||||
fabs(a.lineUnmatchedPunishFact - b.lineUnmatchedPunishFact) < 0.01 &&
|
||||
fabs(a.platformUnmatchedPen - b.platformUnmatchedPen) < 0.01 &&
|
||||
fabs(a.stationDistPenFactor - b.stationDistPenFactor) < 0.01 &&
|
||||
fabs(a.nonOsmPen - b.nonOsmPen) < 0.01 &&
|
||||
fabs(a.levelPunish[0] - b.levelPunish[0]) < 0.01 &&
|
||||
fabs(a.levelPunish[1] - b.levelPunish[1]) < 0.01 &&
|
||||
fabs(a.levelPunish[2] - b.levelPunish[2]) < 0.01 &&
|
||||
fabs(a.levelPunish[3] - b.levelPunish[3]) < 0.01 &&
|
||||
fabs(a.levelPunish[4] - b.levelPunish[4]) < 0.01 &&
|
||||
fabs(a.levelPunish[5] - b.levelPunish[5]) < 0.01 &&
|
||||
fabs(a.levelPunish[6] - b.levelPunish[6]) < 0.01 &&
|
||||
fabs(a.levelPunish[7] - b.levelPunish[7]) < 0.01;
|
||||
}
|
||||
|
||||
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(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 getTotalMeters() const {
|
||||
return meterDist + meterDistLvl1 + meterDistLvl2 + meterDistLvl3 +
|
||||
meterDistLvl4 + meterDistLvl5 + meterDistLvl6 + meterDistLvl7;
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
inline bool operator<=(const EdgeCost& a, const EdgeCost& b) {
|
||||
return a.getValue() <= b.getValue();
|
||||
}
|
||||
|
||||
inline bool operator==(const EdgeCost& a, const EdgeCost& b) {
|
||||
return a.getValue() == b.getValue();
|
||||
}
|
||||
|
||||
inline bool operator>(const EdgeCost& a, const EdgeCost& b) {
|
||||
return a.getValue() > b.getValue();
|
||||
}
|
||||
|
||||
|
||||
inline int angSmaller(const FPoint& f, const FPoint& m, const FPoint& t,
|
||||
double ang) {
|
||||
if (util::geo::innerProd(m, f, t) < ang) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef std::set<trgraph::Node*> NodeSet;
|
||||
typedef std::set<trgraph::Edge*> EdgeSet;
|
||||
typedef std::unordered_map<const Stop*, trgraph::Node*> FeedStops;
|
||||
|
||||
typedef std::vector<NodeCand> NodeCandGroup;
|
||||
typedef std::vector<NodeCandGroup> NodeCandRoute;
|
||||
|
||||
typedef std::vector<trgraph::Edge*> EdgeList;
|
||||
typedef std::vector<trgraph::Node*> NodeList;
|
||||
|
||||
struct EdgeListHop {
|
||||
EdgeList edges;
|
||||
const trgraph::Node* start;
|
||||
const trgraph::Node* end;
|
||||
};
|
||||
|
||||
typedef std::vector<EdgeListHop> EdgeListHops;
|
||||
|
||||
typedef std::set<Route::TYPE> MOTs;
|
||||
} // namespace router
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_ROUTER_MISC_H_
|
||||
36
src/pfaedle/router/NodePL.h
Normal file
36
src/pfaedle/router/NodePL.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_ROUTER_NODEPL_H_
|
||||
#define PFAEDLE_ROUTER_NODEPL_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "pfaedle/trgraph/Graph.h"
|
||||
#include "util/geo/GeoGraph.h"
|
||||
|
||||
using util::geograph::GeoNodePL;
|
||||
|
||||
namespace pfaedle {
|
||||
namespace router {
|
||||
|
||||
class NodePL : public GeoNodePL<float> {
|
||||
public:
|
||||
NodePL() : _n(0) {}
|
||||
NodePL(const pfaedle::trgraph::Node* n) : _n(n) {} // NOLINT
|
||||
|
||||
const util::geo::FPoint* getGeom() const {
|
||||
return !_n ? 0 : _n->pl().getGeom();
|
||||
}
|
||||
void getAttrs(std::map<std::string, std::string>* attrs) const {
|
||||
if (_n) _n->pl().getAttrs(attrs);
|
||||
}
|
||||
|
||||
private:
|
||||
const pfaedle::trgraph::Node* _n;
|
||||
};
|
||||
} // namespace router
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_ROUTER_NODEPL_H_
|
||||
615
src/pfaedle/router/Router.cpp
Normal file
615
src/pfaedle/router/Router.cpp
Normal file
|
|
@ -0,0 +1,615 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#include <omp.h>
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "pfaedle/router/Comp.h"
|
||||
#include "pfaedle/router/Router.h"
|
||||
#include "pfaedle/router/RoutingAttrs.h"
|
||||
#include "util/geo/output/GeoGraphJsonOutput.h"
|
||||
#include "util/graph/Dijkstra.h"
|
||||
#include "util/graph/EDijkstra.h"
|
||||
#include "util/log/Log.h"
|
||||
|
||||
using pfaedle::router::Router;
|
||||
using pfaedle::router::EdgeCost;
|
||||
using pfaedle::router::CostFunc;
|
||||
using pfaedle::router::DistHeur;
|
||||
using pfaedle::router::NCostFunc;
|
||||
using pfaedle::router::NDistHeur;
|
||||
using pfaedle::router::CombCostFunc;
|
||||
using pfaedle::router::EdgeListHop;
|
||||
using pfaedle::router::EdgeListHops;
|
||||
using pfaedle::router::RoutingOpts;
|
||||
using pfaedle::router::RoutingAttrs;
|
||||
using pfaedle::router::HopBand;
|
||||
using pfaedle::router::NodeCandRoute;
|
||||
using util::graph::EDijkstra;
|
||||
using util::graph::Dijkstra;
|
||||
|
||||
// _____________________________________________________________________________
|
||||
EdgeCost NCostFunc::operator()(const trgraph::Node* from,
|
||||
const trgraph::Edge* e,
|
||||
const trgraph::Node* to) const {
|
||||
UNUSED(to);
|
||||
if (!from) return EdgeCost();
|
||||
|
||||
int oneway = e->pl().oneWay() == 2;
|
||||
int32_t stationSkip = 0;
|
||||
|
||||
double transitLinePen = 0; // transitLineCmp(e->pl());
|
||||
|
||||
return EdgeCost(e->pl().lvl() == 0 ? e->pl().getLength() : 0,
|
||||
e->pl().lvl() == 1 ? e->pl().getLength() : 0,
|
||||
e->pl().lvl() == 2 ? e->pl().getLength() : 0,
|
||||
e->pl().lvl() == 3 ? e->pl().getLength() : 0,
|
||||
e->pl().lvl() == 4 ? e->pl().getLength() : 0,
|
||||
e->pl().lvl() == 5 ? e->pl().getLength() : 0,
|
||||
e->pl().lvl() == 6 ? e->pl().getLength() : 0,
|
||||
e->pl().lvl() == 7 ? e->pl().getLength() : 0, 0, stationSkip,
|
||||
e->pl().getLength() * oneway, oneway,
|
||||
e->pl().getLength() * transitLinePen, 0, &_rOpts);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
EdgeCost CostFunc::operator()(const trgraph::Edge* from, const trgraph::Node* n,
|
||||
const trgraph::Edge* to) const {
|
||||
if (!from) return EdgeCost();
|
||||
|
||||
uint32_t fullTurns = 0;
|
||||
int oneway = from->pl().oneWay() == 2;
|
||||
int32_t stationSkip = 0;
|
||||
|
||||
if (n) {
|
||||
if (from->getFrom() == to->getTo() && from->getTo() == to->getFrom()) {
|
||||
// trivial full turn
|
||||
fullTurns = 1;
|
||||
} else if (n->getDeg() > 2) {
|
||||
// otherwise, only intersection angles will be punished
|
||||
fullTurns = router::angSmaller(from->pl().backHop(), *n->pl().getGeom(),
|
||||
to->pl().frontHop(), _rOpts.fullTurnAngle);
|
||||
}
|
||||
|
||||
if (from->pl().isRestricted() && !_res.may(from, to, n)) oneway = 1;
|
||||
|
||||
// for debugging
|
||||
n->pl().setVisited();
|
||||
|
||||
if (_tgGrp && n->pl().getSI() && n->pl().getSI()->getGroup() != _tgGrp)
|
||||
stationSkip = 1;
|
||||
}
|
||||
|
||||
double transitLinePen = transitLineCmp(from->pl());
|
||||
|
||||
return EdgeCost(from->pl().lvl() == 0 ? from->pl().getLength() : 0,
|
||||
from->pl().lvl() == 1 ? from->pl().getLength() : 0,
|
||||
from->pl().lvl() == 2 ? from->pl().getLength() : 0,
|
||||
from->pl().lvl() == 3 ? from->pl().getLength() : 0,
|
||||
from->pl().lvl() == 4 ? from->pl().getLength() : 0,
|
||||
from->pl().lvl() == 5 ? from->pl().getLength() : 0,
|
||||
from->pl().lvl() == 6 ? from->pl().getLength() : 0,
|
||||
from->pl().lvl() == 7 ? from->pl().getLength() : 0, fullTurns,
|
||||
stationSkip, from->pl().getLength() * oneway, oneway,
|
||||
from->pl().getLength() * transitLinePen, 0, &_rOpts);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
double CostFunc::transitLineCmp(const trgraph::EdgePL& e) const {
|
||||
double best = 1;
|
||||
for (const auto* l : e.getLines()) {
|
||||
double cur = _rAttrs.simi(l);
|
||||
|
||||
if (cur < 0.0001) return cur;
|
||||
if (cur < best) best = cur;
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
NDistHeur::NDistHeur(const RoutingOpts& rOpts,
|
||||
const std::set<trgraph::Node*>& tos)
|
||||
: _rOpts(rOpts), _maxCentD(0) {
|
||||
size_t c = 0;
|
||||
double x = 0, y = 0;
|
||||
for (auto to : tos) {
|
||||
x += to->pl().getGeom()->get<0>();
|
||||
y += to->pl().getGeom()->get<1>();
|
||||
c++;
|
||||
}
|
||||
|
||||
x /= c;
|
||||
y /= c;
|
||||
_center = FPoint(x, y);
|
||||
|
||||
for (auto to : tos) {
|
||||
double cur = static_cast<double>(static_cast<double>(
|
||||
util::geo::webMercMeterDist(*to->pl().getGeom(), _center)));
|
||||
if (cur > _maxCentD) _maxCentD = cur;
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
DistHeur::DistHeur(uint8_t minLvl, const RoutingOpts& rOpts,
|
||||
const std::set<trgraph::Edge*>& tos)
|
||||
: _rOpts(rOpts), _lvl(minLvl), _maxCentD(0) {
|
||||
size_t c = 0;
|
||||
double x = 0, y = 0;
|
||||
for (auto to : tos) {
|
||||
x += to->getFrom()->pl().getGeom()->get<0>();
|
||||
y += to->getFrom()->pl().getGeom()->get<1>();
|
||||
c++;
|
||||
}
|
||||
|
||||
x /= c;
|
||||
y /= c;
|
||||
_center = FPoint(x, y);
|
||||
|
||||
for (auto to : tos) {
|
||||
double cur = static_cast<double>(static_cast<double>(
|
||||
util::geo::webMercMeterDist(*to->getFrom()->pl().getGeom(), _center) *
|
||||
_rOpts.levelPunish[_lvl]));
|
||||
if (cur > _maxCentD) _maxCentD = cur;
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
EdgeCost DistHeur::operator()(const trgraph::Edge* a,
|
||||
const std::set<trgraph::Edge*>& b) const {
|
||||
double cur = static_cast<double>(static_cast<double>(
|
||||
util::geo::webMercMeterDist(*a->getTo()->pl().getGeom(), _center) *
|
||||
_rOpts.levelPunish[_lvl]));
|
||||
|
||||
UNUSED(b);
|
||||
|
||||
return EdgeCost(cur - _maxCentD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
EdgeCost NDistHeur::operator()(const trgraph::Node* a,
|
||||
const std::set<trgraph::Node*>& b) const {
|
||||
double cur = static_cast<double>(static_cast<double>(
|
||||
util::geo::webMercMeterDist(*a->pl().getGeom(), _center)));
|
||||
|
||||
UNUSED(b);
|
||||
|
||||
return EdgeCost(cur - _maxCentD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
double CombCostFunc::operator()(const router::Edge* from, const router::Node* n,
|
||||
const router::Edge* to) const {
|
||||
UNUSED(n);
|
||||
UNUSED(from);
|
||||
return to->pl().getCost().getValue();
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
Router::Router(const trgraph::Graph& g, size_t numThreads)
|
||||
: _g(g), _cache(numThreads) {
|
||||
for (size_t i = 0; i < numThreads; i++) {
|
||||
_cache[i] = new Cache();
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
Router::~Router() {
|
||||
for (size_t i = 0; i < _cache.size(); i++) {
|
||||
delete _cache[i];
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
bool Router::compConned(const NodeCandGroup& a, const NodeCandGroup& b) const {
|
||||
for (auto n1 : a) {
|
||||
for (auto n2 : b) {
|
||||
if (n1.nd->pl().getComp() == n2.nd->pl().getComp()) return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
HopBand Router::getHopBand(const NodeCandGroup& a, const NodeCandGroup& b,
|
||||
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest) const {
|
||||
double pend = 0;
|
||||
for (size_t i = 0; i < a.size(); i++) {
|
||||
for (size_t j = 0; j < b.size(); j++) {
|
||||
double d = util::geo::webMercMeterDist(*a[i].nd->pl().getGeom(),
|
||||
*b[j].nd->pl().getGeom());
|
||||
if (d > pend) pend = d;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
CostFunc costF(rAttrs, rOpts, rest, tgGrpTo, pend * 50);
|
||||
|
||||
std::set<trgraph::Edge *> from, to;
|
||||
|
||||
// TODO(patrick): test if the two sets share a common connected component
|
||||
|
||||
for (auto n : a)
|
||||
from.insert(n.nd->getAdjListOut().begin(), n.nd->getAdjListOut().end());
|
||||
|
||||
for (auto n : b)
|
||||
to.insert(n.nd->getAdjListOut().begin(), n.nd->getAdjListOut().end());
|
||||
|
||||
LOG(VDEBUG) << "Doing pilot run between " << from.size() << "->" << to.size()
|
||||
<< " candidates";
|
||||
|
||||
EdgeList el;
|
||||
EdgeCost ret = costF.inf();
|
||||
DistHeur distH(0, rOpts, to);
|
||||
|
||||
if (compConned(a, b))
|
||||
ret = EDijkstra::shortestPath(from, to, costF, distH, &el);
|
||||
|
||||
if (el.size() < 2 && costF.inf() <= ret) {
|
||||
LOG(VDEBUG) << "Pilot run: no connection between candidate groups,"
|
||||
<< " setting max distance to 1";
|
||||
return HopBand{0, 1, 0, 0};
|
||||
}
|
||||
|
||||
// cache the found path, will save a few dijkstra iterations
|
||||
nestedCache(&el, from, costF, rAttrs);
|
||||
|
||||
auto na = el.back()->getFrom();
|
||||
auto nb = el.front()->getFrom();
|
||||
|
||||
double maxStrD = 0;
|
||||
|
||||
for (auto e : to) {
|
||||
double d = static_cast<double>(static_cast<double>(
|
||||
util::geo::webMercMeterDist(*el.front()->getFrom()->pl().getGeom(),
|
||||
*e->getTo()->pl().getGeom())));
|
||||
if (d > maxStrD) maxStrD = d;
|
||||
}
|
||||
|
||||
// TODO(patrick): derive the punish level here automatically
|
||||
double maxD = std::max(ret.getValue(), pend * rOpts.levelPunish[2]) * 3;
|
||||
double minD = ret.getValue();
|
||||
|
||||
LOG(VDEBUG) << "Pilot run: min distance between two groups is "
|
||||
<< ret.getValue() << " (between nodes " << na << " and " << nb
|
||||
<< "), using a max routing distance of " << maxD << ". The max"
|
||||
<< " straight line distance from the pilot target to any other "
|
||||
"target node was"
|
||||
<< " " << maxStrD << ".";
|
||||
|
||||
return HopBand{minD, maxD, el.front(), maxStrD};
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
EdgeListHops Router::routeGreedy(const NodeCandRoute& route,
|
||||
const RoutingAttrs& rAttrs,
|
||||
const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest) const {
|
||||
if (route.size() < 2) return EdgeListHops();
|
||||
EdgeListHops ret(route.size() - 1);
|
||||
|
||||
for (size_t i = 0; i < route.size() - 1; i++) {
|
||||
const trgraph::StatGroup* tgGrp = 0;
|
||||
std::set<trgraph::Node *> from, to;
|
||||
for (auto c : route[i]) from.insert(c.nd);
|
||||
for (auto c : route[i + 1]) to.insert(c.nd);
|
||||
if (route[i + 1].begin()->nd->pl().getSI())
|
||||
tgGrp = route[i + 1].begin()->nd->pl().getSI()->getGroup();
|
||||
|
||||
NCostFunc cost(rAttrs, rOpts, rest, tgGrp);
|
||||
NDistHeur dist(rOpts, to);
|
||||
|
||||
NodeList nodesRet;
|
||||
EdgeListHop hop;
|
||||
Dijkstra::shortestPath(from, to, cost, dist, &hop.edges, &nodesRet);
|
||||
|
||||
if (nodesRet.size() > 1) {
|
||||
// careful: nodesRet is reversed!
|
||||
hop.start = nodesRet.back();
|
||||
hop.end = nodesRet.front();
|
||||
} else {
|
||||
// just take the first candidate if no route could be found
|
||||
hop.start = *from.begin();
|
||||
hop.end = *to.begin();
|
||||
}
|
||||
|
||||
ret[i] = hop;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
EdgeListHops Router::routeGreedy2(const NodeCandRoute& route,
|
||||
const RoutingAttrs& rAttrs,
|
||||
const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest) const {
|
||||
if (route.size() < 2) return EdgeListHops();
|
||||
EdgeListHops ret(route.size() - 1);
|
||||
|
||||
for (size_t i = 0; i < route.size() - 1; i++) {
|
||||
const trgraph::StatGroup* tgGrp = 0;
|
||||
std::set<trgraph::Node *> from, to;
|
||||
|
||||
if (i == 0)
|
||||
for (auto c : route[i]) from.insert(c.nd);
|
||||
else
|
||||
from.insert(const_cast<trgraph::Node*>(ret[i - 1].end));
|
||||
|
||||
for (auto c : route[i + 1]) to.insert(c.nd);
|
||||
|
||||
if (route[i + 1].begin()->nd->pl().getSI())
|
||||
tgGrp = route[i + 1].begin()->nd->pl().getSI()->getGroup();
|
||||
|
||||
NCostFunc cost(rAttrs, rOpts, rest, tgGrp);
|
||||
NDistHeur dist(rOpts, to);
|
||||
|
||||
NodeList nodesRet;
|
||||
EdgeListHop hop;
|
||||
Dijkstra::shortestPath(from, to, cost, dist, &hop.edges, &nodesRet);
|
||||
if (nodesRet.size() > 1) {
|
||||
// careful: nodesRet is reversed!
|
||||
hop.start = nodesRet.back();
|
||||
hop.end = nodesRet.front();
|
||||
} else {
|
||||
// just take the first candidate if no route could be found
|
||||
hop.start = *from.begin();
|
||||
hop.end = *to.begin();
|
||||
}
|
||||
|
||||
ret[i] = hop;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
EdgeListHops Router::route(const NodeCandRoute& route,
|
||||
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest,
|
||||
router::Graph* cgraph) const {
|
||||
if (route.size() < 2) return EdgeListHops();
|
||||
EdgeListHops ret(route.size() - 1);
|
||||
|
||||
CombCostFunc ccost(rOpts);
|
||||
router::Node* source = cgraph->addNd();
|
||||
router::Node* sink = cgraph->addNd();
|
||||
CombNodeMap nodes;
|
||||
CombNodeMap nextNodes;
|
||||
|
||||
for (size_t i = 0; i < route[0].size(); i++) {
|
||||
for (const auto* e : route[0][i].nd->getAdjListOut()) {
|
||||
// we can be sure that each edge is exactly assigned to only one
|
||||
// node because the transitgraph is directed
|
||||
nodes[e] = cgraph->addNd(route[0][i].nd);
|
||||
cgraph->addEdg(source, nodes[e])
|
||||
->pl()
|
||||
.setCost(EdgeCost(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
route[0][i].pen, 0));
|
||||
}
|
||||
}
|
||||
|
||||
size_t iters = EDijkstra::ITERS;
|
||||
double itPerSecTot = 0;
|
||||
size_t n = 0;
|
||||
for (size_t i = 0; i < route.size() - 1; i++) {
|
||||
nextNodes.clear();
|
||||
HopBand hopBand = getHopBand(route[i], route[i + 1], rAttrs, rOpts, rest);
|
||||
|
||||
const trgraph::StatGroup* tgGrp = 0;
|
||||
if (route[i + 1].begin()->nd->pl().getSI())
|
||||
tgGrp = route[i + 1].begin()->nd->pl().getSI()->getGroup();
|
||||
|
||||
std::set<trgraph::Edge*> froms;
|
||||
for (const auto& fr : route[i]) {
|
||||
froms.insert(fr.nd->getAdjListOut().begin(),
|
||||
fr.nd->getAdjListOut().end());
|
||||
}
|
||||
|
||||
for (auto eFr : froms) {
|
||||
router::Node* cNodeFr = nodes.find(eFr)->second;
|
||||
|
||||
EdgeSet tos;
|
||||
std::map<trgraph::Edge*, router::Edge*> edges;
|
||||
std::map<trgraph::Edge*, double> pens;
|
||||
std::unordered_map<trgraph::Edge*, EdgeList*> edgeLists;
|
||||
std::unordered_map<trgraph::Edge*, EdgeCost> costs;
|
||||
|
||||
assert(route[i + 1].size());
|
||||
|
||||
for (const auto& to : route[i + 1]) {
|
||||
assert(to.nd->getAdjListOut().size());
|
||||
for (auto eTo : to.nd->getAdjListOut()) {
|
||||
tos.insert(eTo);
|
||||
if (!nextNodes.count(eTo)) nextNodes[eTo] = cgraph->addNd(to.nd);
|
||||
if (i == route.size() - 2) cgraph->addEdg(nextNodes[eTo], sink);
|
||||
|
||||
auto* ce = cgraph->addEdg(cNodeFr, nextNodes[eTo]);
|
||||
edges[eTo] = ce;
|
||||
pens[eTo] = to.pen;
|
||||
|
||||
edgeLists[eTo] = ce->pl().getEdges();
|
||||
ce->pl().setStartNode(eFr->getFrom());
|
||||
// for debugging
|
||||
ce->pl().setStartEdge(eFr);
|
||||
|
||||
ce->pl().setEndNode(to.nd);
|
||||
// for debugging
|
||||
ce->pl().setEndEdge(eTo);
|
||||
}
|
||||
}
|
||||
|
||||
size_t iters = EDijkstra::ITERS;
|
||||
auto t1 = TIME();
|
||||
|
||||
assert(tos.size());
|
||||
assert(froms.size());
|
||||
|
||||
hops(eFr, froms, tos, tgGrp, edgeLists, &costs, rAttrs, rOpts, rest,
|
||||
hopBand);
|
||||
double itPerSec =
|
||||
(static_cast<double>(EDijkstra::ITERS - iters)) / TOOK(t1, TIME());
|
||||
n++;
|
||||
itPerSecTot += itPerSec;
|
||||
|
||||
LOG(VDEBUG) << "from " << eFr << ": 1-" << tos.size() << " ("
|
||||
<< route[i + 1].size() << " nodes) hop took "
|
||||
<< EDijkstra::ITERS - iters << " iterations, "
|
||||
<< TOOK(t1, TIME()) << "ms (tput: " << itPerSec << " its/ms)";
|
||||
for (auto& kv : edges) {
|
||||
kv.second->pl().setCost(
|
||||
EdgeCost(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pens[kv.first], 0) +
|
||||
costs[kv.first]);
|
||||
|
||||
if (kv.second->pl().getEdges()->size()) {
|
||||
if (kv.second->pl().getEdges() &&
|
||||
kv.second->pl().getEdges()->size()) {
|
||||
// the reach edge is included, but we dont want it in the geometry
|
||||
kv.second->pl().getEdges()->erase(
|
||||
kv.second->pl().getEdges()->begin());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::swap(nodes, nextNodes);
|
||||
}
|
||||
|
||||
LOG(VDEBUG) << "Hops took " << EDijkstra::ITERS - iters << " iterations,"
|
||||
<< " average tput was " << (itPerSecTot / n) << " its/ms";
|
||||
|
||||
iters = EDijkstra::ITERS;
|
||||
std::vector<router::Edge*> res;
|
||||
EDijkstra::shortestPath(source, sink, ccost, &res);
|
||||
size_t j = 0;
|
||||
|
||||
LOG(VDEBUG) << "Optim graph solve took " << EDijkstra::ITERS - iters
|
||||
<< " iterations.";
|
||||
|
||||
for (auto i = res.rbegin(); i != res.rend(); i++) {
|
||||
const auto e = *i;
|
||||
if (e->getFrom() != source && e->getTo() != sink) {
|
||||
assert(e->pl().frontNode());
|
||||
assert(e->pl().backNode());
|
||||
|
||||
ret[j] = EdgeListHop{std::move(*e->pl().getEdges()), e->pl().frontNode(),
|
||||
e->pl().backNode()};
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
assert(ret.size() == j);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void Router::hops(trgraph::Edge* from, const std::set<trgraph::Edge*>& froms,
|
||||
const std::set<trgraph::Edge*> tos,
|
||||
const trgraph::StatGroup* tgGrp,
|
||||
const std::unordered_map<trgraph::Edge*, EdgeList*>& edgesRet,
|
||||
std::unordered_map<trgraph::Edge*, EdgeCost>* rCosts,
|
||||
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest, HopBand hopB) const {
|
||||
std::set<trgraph::Edge*> rem;
|
||||
|
||||
CostFunc cost(rAttrs, rOpts, rest, tgGrp, hopB.maxD);
|
||||
|
||||
const auto& cached = getCachedHops(from, tos, edgesRet, rCosts, rAttrs);
|
||||
|
||||
for (auto e : cached) {
|
||||
// shortcut: if the nodes lie in two different connected components,
|
||||
// the distance between them is trivially infinite
|
||||
if (e == from || e->getFrom() == from->getFrom() ||
|
||||
from->getFrom()->pl().getComp() != e->getTo()->pl().getComp() ||
|
||||
e->pl().oneWay() == 2 || from->pl().oneWay() == 2) {
|
||||
(*rCosts)[e] = cost.inf();
|
||||
} else {
|
||||
rem.insert(e);
|
||||
}
|
||||
}
|
||||
|
||||
LOG(VDEBUG) << "From cache: " << tos.size() - rem.size()
|
||||
<< ", have to cal: " << rem.size();
|
||||
|
||||
if (rem.size()) {
|
||||
DistHeur dist(from->getFrom()->pl().getComp()->minEdgeLvl, rOpts, rem);
|
||||
const auto& ret = EDijkstra::shortestPath(from, rem, cost, dist, edgesRet);
|
||||
for (const auto& kv : ret) {
|
||||
nestedCache(edgesRet.at(kv.first), froms, cost, rAttrs);
|
||||
|
||||
(*rCosts)[kv.first] = kv.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void Router::nestedCache(const EdgeList* el,
|
||||
const std::set<trgraph::Edge*>& froms,
|
||||
const CostFunc& cost,
|
||||
const RoutingAttrs& rAttrs) const {
|
||||
if (el->size() == 0) return;
|
||||
// iterate over result edges backwards
|
||||
EdgeList curEdges;
|
||||
EdgeCost curCost;
|
||||
|
||||
size_t j = 0;
|
||||
|
||||
for (auto i = el->begin(); i < el->end(); i++) {
|
||||
if (curEdges.size()) {
|
||||
curCost = curCost + cost(*i, (*i)->getTo(), curEdges.back());
|
||||
}
|
||||
|
||||
curEdges.push_back(*i);
|
||||
|
||||
if (froms.count(*i)) {
|
||||
EdgeCost startC = cost(0, 0, *i) + curCost;
|
||||
cache(*i, el->front(), startC, &curEdges, rAttrs);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
std::set<pfaedle::trgraph::Edge*> Router::getCachedHops(
|
||||
trgraph::Edge* from, const std::set<trgraph::Edge*>& tos,
|
||||
const std::unordered_map<trgraph::Edge*, EdgeList*>& edgesRet,
|
||||
std::unordered_map<trgraph::Edge*, EdgeCost>* rCosts,
|
||||
const RoutingAttrs& rAttrs) const {
|
||||
std::set<trgraph::Edge*> ret;
|
||||
for (auto to : tos) {
|
||||
if ((*_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;
|
||||
} else {
|
||||
ret.insert(to);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void Router::cache(trgraph::Edge* from, trgraph::Edge* to, const EdgeCost& c,
|
||||
EdgeList* edges, const RoutingAttrs& rAttrs) const {
|
||||
if (from == to) return;
|
||||
(*_cache[omp_get_thread_num()])[rAttrs][from][to] =
|
||||
std::pair<EdgeCost, EdgeList>(c, *edges);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
size_t Router::getCacheNumber() const { return _cache.size(); }
|
||||
194
src/pfaedle/router/Router.h
Normal file
194
src/pfaedle/router/Router.h
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_ROUTER_ROUTER_H_
|
||||
#define PFAEDLE_ROUTER_ROUTER_H_
|
||||
|
||||
#include <mutex>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include "pfaedle/osm/Restrictor.h"
|
||||
#include "pfaedle/router/Graph.h"
|
||||
#include "pfaedle/router/Misc.h"
|
||||
#include "pfaedle/router/RoutingAttrs.h"
|
||||
#include "pfaedle/trgraph/Graph.h"
|
||||
#include "util/graph/Dijkstra.h"
|
||||
#include "util/graph/EDijkstra.h"
|
||||
|
||||
using util::graph::EDijkstra;
|
||||
using util::graph::Dijkstra;
|
||||
|
||||
namespace pfaedle {
|
||||
namespace router {
|
||||
|
||||
typedef std::unordered_map<const trgraph::Edge*, router::Node*> CombNodeMap;
|
||||
typedef std::pair<size_t, size_t> HId;
|
||||
typedef std::map<
|
||||
RoutingAttrs,
|
||||
std::unordered_map<const trgraph::Edge*,
|
||||
std::unordered_map<const trgraph::Edge*,
|
||||
std::pair<EdgeCost, EdgeList> > > >
|
||||
Cache;
|
||||
|
||||
struct HopBand {
|
||||
double minD;
|
||||
double maxD;
|
||||
const trgraph::Edge* nearest;
|
||||
double maxInGrpDist;
|
||||
};
|
||||
|
||||
struct CostFunc
|
||||
: public EDijkstra::CostFunc<trgraph::NodePL, trgraph::EdgePL, EdgeCost> {
|
||||
CostFunc(const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& res, const trgraph::StatGroup* tgGrp,
|
||||
double max)
|
||||
: _rAttrs(rAttrs),
|
||||
_rOpts(rOpts),
|
||||
_res(res),
|
||||
_max(max),
|
||||
_tgGrp(tgGrp),
|
||||
_inf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _max, 0) {}
|
||||
|
||||
const RoutingAttrs& _rAttrs;
|
||||
const RoutingOpts& _rOpts;
|
||||
const osm::Restrictor& _res;
|
||||
double _max;
|
||||
const trgraph::StatGroup* _tgGrp;
|
||||
EdgeCost _inf;
|
||||
|
||||
EdgeCost operator()(const trgraph::Edge* from, const trgraph::Node* n,
|
||||
const trgraph::Edge* to) const;
|
||||
EdgeCost inf() const { return _inf; }
|
||||
|
||||
double transitLineCmp(const trgraph::EdgePL& e) const;
|
||||
};
|
||||
|
||||
struct NCostFunc
|
||||
: public Dijkstra::CostFunc<trgraph::NodePL, trgraph::EdgePL, EdgeCost> {
|
||||
NCostFunc(const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& res, const trgraph::StatGroup* tgGrp)
|
||||
: _rAttrs(rAttrs),
|
||||
_rOpts(rOpts),
|
||||
_res(res),
|
||||
_tgGrp(tgGrp),
|
||||
_inf(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
std::numeric_limits<double>::infinity(), 0) {}
|
||||
|
||||
const RoutingAttrs& _rAttrs;
|
||||
const RoutingOpts& _rOpts;
|
||||
const osm::Restrictor& _res;
|
||||
const trgraph::StatGroup* _tgGrp;
|
||||
EdgeCost _inf;
|
||||
|
||||
EdgeCost operator()(const trgraph::Node* from, const trgraph::Edge* e,
|
||||
const trgraph::Node* to) const;
|
||||
EdgeCost inf() const { return _inf; }
|
||||
|
||||
double transitLineCmp(const trgraph::EdgePL& e) const;
|
||||
};
|
||||
|
||||
struct DistHeur
|
||||
: public EDijkstra::HeurFunc<trgraph::NodePL, trgraph::EdgePL, EdgeCost> {
|
||||
DistHeur(uint8_t minLvl, const RoutingOpts& rOpts,
|
||||
const std::set<trgraph::Edge*>& tos);
|
||||
|
||||
const RoutingOpts& _rOpts;
|
||||
uint8_t _lvl;
|
||||
FPoint _center;
|
||||
double _maxCentD;
|
||||
EdgeCost operator()(const trgraph::Edge* a,
|
||||
const std::set<trgraph::Edge*>& b) const;
|
||||
};
|
||||
|
||||
struct NDistHeur
|
||||
: public Dijkstra::HeurFunc<trgraph::NodePL, trgraph::EdgePL, EdgeCost> {
|
||||
NDistHeur(const RoutingOpts& rOpts, const std::set<trgraph::Node*>& tos);
|
||||
|
||||
const RoutingOpts& _rOpts;
|
||||
FPoint _center;
|
||||
double _maxCentD;
|
||||
EdgeCost operator()(const trgraph::Node* a,
|
||||
const std::set<trgraph::Node*>& b) const;
|
||||
};
|
||||
|
||||
struct CombCostFunc
|
||||
: public EDijkstra::CostFunc<router::NodePL, router::EdgePL, double> {
|
||||
explicit CombCostFunc(const RoutingOpts& rOpts) : _rOpts(rOpts) {}
|
||||
|
||||
const RoutingOpts& _rOpts;
|
||||
|
||||
double operator()(const router::Edge* from, const router::Node* n,
|
||||
const router::Edge* to) const;
|
||||
double inf() const { return std::numeric_limits<double>::infinity(); }
|
||||
};
|
||||
|
||||
/*
|
||||
* Finds the most likely route of schedule-based vehicle between stops in a
|
||||
* physical transportation network
|
||||
*/
|
||||
class Router {
|
||||
public:
|
||||
// Init this router with caches for numThreads threads
|
||||
Router(const trgraph::Graph& g, size_t numThreads);
|
||||
~Router();
|
||||
|
||||
// Find the most likely path through the graph for a node candidate route.
|
||||
EdgeListHops route(const NodeCandRoute& route, const RoutingAttrs& rAttrs,
|
||||
const RoutingOpts& rOpts, const osm::Restrictor& rest,
|
||||
router::Graph* cgraph) const;
|
||||
|
||||
// Find the most likely path through cgraph for a node candidate route, but
|
||||
// based on a greedy node to node approach
|
||||
EdgeListHops routeGreedy(const NodeCandRoute& route,
|
||||
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest) const;
|
||||
|
||||
// Find the most likely path through cgraph for a node candidate route, but
|
||||
// based on a greedy node to node set approach
|
||||
EdgeListHops routeGreedy2(const NodeCandRoute& route,
|
||||
const RoutingAttrs& rAttrs,
|
||||
const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest) const;
|
||||
|
||||
// Return the number of thread caches this router was initialized with
|
||||
size_t getCacheNumber() const;
|
||||
|
||||
private:
|
||||
const trgraph::Graph& _g;
|
||||
|
||||
mutable std::vector<Cache*> _cache;
|
||||
HopBand getHopBand(const NodeCandGroup& a, const NodeCandGroup& b,
|
||||
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest) const;
|
||||
|
||||
void hops(trgraph::Edge* from, const std::set<trgraph::Edge*>& froms,
|
||||
const std::set<trgraph::Edge*> to, const trgraph::StatGroup* tgGrp,
|
||||
const std::unordered_map<trgraph::Edge*, EdgeList*>& edgesRet,
|
||||
std::unordered_map<trgraph::Edge*, EdgeCost>* rCosts,
|
||||
const RoutingAttrs& rAttrs, const RoutingOpts& rOpts,
|
||||
const osm::Restrictor& rest, HopBand hopB) const;
|
||||
|
||||
std::set<trgraph::Edge*> getCachedHops(
|
||||
trgraph::Edge* from, const std::set<trgraph::Edge*>& to,
|
||||
const std::unordered_map<trgraph::Edge*, EdgeList*>& edgesRet,
|
||||
std::unordered_map<trgraph::Edge*, EdgeCost>* rCosts,
|
||||
const RoutingAttrs& rAttrs) const;
|
||||
|
||||
void cache(trgraph::Edge* from, trgraph::Edge* to, const EdgeCost& c,
|
||||
EdgeList* edges, const RoutingAttrs& rAttrs) const;
|
||||
|
||||
void nestedCache(const EdgeList* el, const std::set<trgraph::Edge*>& froms,
|
||||
const CostFunc& cost, const RoutingAttrs& rAttrs) const;
|
||||
|
||||
bool compConned(const NodeCandGroup& a, const NodeCandGroup& b) const;
|
||||
};
|
||||
} // namespace router
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_ROUTER_ROUTER_H_
|
||||
64
src/pfaedle/router/RoutingAttrs.h
Normal file
64
src/pfaedle/router/RoutingAttrs.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_ROUTER_ROUTINGATTRS_H_
|
||||
#define PFAEDLE_ROUTER_ROUTINGATTRS_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "pfaedle/trgraph/EdgePL.h"
|
||||
|
||||
using pfaedle::trgraph::TransitEdgeLine;
|
||||
|
||||
namespace pfaedle {
|
||||
namespace router {
|
||||
|
||||
struct RoutingAttrs {
|
||||
RoutingAttrs() : fromString(""), toString(""), shortName(""), _simiCache() {}
|
||||
std::string fromString;
|
||||
std::string toString;
|
||||
std::string shortName;
|
||||
|
||||
mutable std::map<const TransitEdgeLine*, double> _simiCache;
|
||||
|
||||
double simi(const TransitEdgeLine* line) const {
|
||||
auto i = _simiCache.find(line);
|
||||
if (i != _simiCache.end()) return i->second;
|
||||
|
||||
double cur = 1;
|
||||
if (router::lineSimi(line->shortName, shortName) > 0.5) cur -= 0.33;
|
||||
|
||||
if (line->toStr.empty() || router::statSimi(line->toStr, toString) > 0.5)
|
||||
cur -= 0.33;
|
||||
|
||||
if (line->fromStr.empty() ||
|
||||
router::statSimi(line->fromStr, fromString) > 0.5)
|
||||
cur -= 0.33;
|
||||
|
||||
_simiCache[line] = cur;
|
||||
|
||||
return cur;
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator==(const RoutingAttrs& a, const RoutingAttrs& b) {
|
||||
return a.shortName == b.shortName && a.toString == b.toString &&
|
||||
a.fromString == b.fromString;
|
||||
}
|
||||
|
||||
inline bool operator!=(const RoutingAttrs& a, const RoutingAttrs& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
inline bool operator<(const RoutingAttrs& a, const RoutingAttrs& b) {
|
||||
return a.fromString < b.fromString ||
|
||||
(a.fromString == b.fromString && a.toString < b.toString) ||
|
||||
(a.fromString == b.fromString && a.toString == b.toString &&
|
||||
a.shortName < b.shortName);
|
||||
}
|
||||
|
||||
} // namespace router
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_ROUTER_ROUTINGATTRS_H_
|
||||
627
src/pfaedle/router/ShapeBuilder.cpp
Normal file
627
src/pfaedle/router/ShapeBuilder.cpp
Normal file
|
|
@ -0,0 +1,627 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#include <omp.h>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include "ad/cppgtfs/gtfs/Feed.h"
|
||||
#include "pfaedle/eval/Collector.h"
|
||||
#include "pfaedle/osm/OsmBuilder.h"
|
||||
#include "pfaedle/router/ShapeBuilder.h"
|
||||
#include "pfaedle/trgraph/StatGroup.h"
|
||||
#include "util/geo/output/GeoGraphJsonOutput.h"
|
||||
#include "util/geo/output/GeoJsonOutput.h"
|
||||
#include "util/graph/EDijkstra.h"
|
||||
#include "util/log/Log.h"
|
||||
|
||||
using util::geo::FPoint;
|
||||
using util::geo::extendBox;
|
||||
using util::geo::Box;
|
||||
using util::geo::minbox;
|
||||
using util::geo::FLine;
|
||||
using util::geo::webMercMeterDist;
|
||||
using util::geo::webMercToLatLng;
|
||||
using util::geo::latLngToWebMerc;
|
||||
using util::geo::output::GeoGraphJsonOutput;
|
||||
using pfaedle::router::ShapeBuilder;
|
||||
using pfaedle::router::FeedStops;
|
||||
using pfaedle::router::NodeCandGroup;
|
||||
using pfaedle::router::NodeCandRoute;
|
||||
using pfaedle::router::RoutingAttrs;
|
||||
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 ad::cppgtfs::gtfs::ShapePoint;
|
||||
|
||||
// _____________________________________________________________________________
|
||||
ShapeBuilder::ShapeBuilder(Feed* feed, MOTs mots,
|
||||
const config::MotConfig& motCfg,
|
||||
eval::Collector* ecoll, const config::Config& cfg)
|
||||
: _feed(feed),
|
||||
_mots(mots),
|
||||
_motCfg(motCfg),
|
||||
_ecoll(ecoll),
|
||||
_cfg(cfg),
|
||||
_crouter(_g, omp_get_num_procs()),
|
||||
_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()) {
|
||||
_stops[st.getStop()] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
FeedStops* ShapeBuilder::getFeedStops() { return &_stops; }
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const NodeCandGroup& ShapeBuilder::getNodeCands(const Stop* s) const {
|
||||
if (_stops.find(s) == _stops.end() || _stops.at(s) == 0) {
|
||||
return _emptyNCG;
|
||||
}
|
||||
return _stops.at(s)->pl().getSI()->getGroup()->getNodeCands(s);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
FLine ShapeBuilder::shapeL(const router::NodeCandRoute& ncr,
|
||||
const router::RoutingAttrs& rAttrs) {
|
||||
const router::EdgeListHops& res = route(ncr, rAttrs);
|
||||
|
||||
FLine 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);
|
||||
}
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
FLine ShapeBuilder::shapeL(Trip* trip) {
|
||||
return shapeL(getNCR(trip), getRAttrs(trip));
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
EdgeListHops ShapeBuilder::route(const router::NodeCandRoute& ncr,
|
||||
const router::RoutingAttrs& rAttrs) const {
|
||||
router::Graph g;
|
||||
|
||||
if (_cfg.solveMethod == "global") {
|
||||
const router::EdgeListHops& ret =
|
||||
_crouter.route(ncr, rAttrs, _motCfg.routingOpts, _restr, &g);
|
||||
|
||||
// write combination graph
|
||||
if (!_cfg.shapeTripId.empty() && _cfg.writeCombGraph) {
|
||||
LOG(INFO) << "Outputting combgraph.json...";
|
||||
std::ofstream pstr(_cfg.dbgOutputPath + "/combgraph.json");
|
||||
GeoGraphJsonOutput o;
|
||||
o.print(g, pstr);
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else if (_cfg.solveMethod == "greedy") {
|
||||
return _crouter.routeGreedy(ncr, rAttrs, _motCfg.routingOpts, _restr);
|
||||
} else if (_cfg.solveMethod == "greedy2") {
|
||||
return _crouter.routeGreedy2(ncr, rAttrs, _motCfg.routingOpts, _restr);
|
||||
} else {
|
||||
LOG(ERROR) << "Unknown solution method " << _cfg.solveMethod;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return EdgeListHops();
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
pfaedle::router::Shape ShapeBuilder::shape(Trip* trip) const {
|
||||
LOG(VDEBUG) << "Map-matching shape for trip #" << trip->getId() << " of mot "
|
||||
<< trip->getRoute()->getType() << "(sn=" << trip->getShortname()
|
||||
<< ", rsn=" << trip->getRoute()->getShortName()
|
||||
<< ", rln=" << trip->getRoute()->getLongName() << ")";
|
||||
Shape ret;
|
||||
ret.hops = route(getNCR(trip), getRAttrs(trip));
|
||||
ret.avgHopDist = avgHopDist(trip);
|
||||
|
||||
LOG(VDEBUG) << "Finished map-matching for #" << trip->getId();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
pfaedle::router::Shape ShapeBuilder::shape(Trip* trip) {
|
||||
LOG(VDEBUG) << "Map-matching shape for trip #" << trip->getId() << " of mot "
|
||||
<< trip->getRoute()->getType() << "(sn=" << trip->getShortname()
|
||||
<< ", rsn=" << trip->getRoute()->getShortName()
|
||||
<< ", rln=" << trip->getRoute()->getLongName() << ")";
|
||||
|
||||
Shape ret;
|
||||
ret.hops = route(getNCR(trip), getRAttrs(trip));
|
||||
ret.avgHopDist = avgHopDist(trip);
|
||||
|
||||
LOG(VDEBUG) << "Finished map-matching for #" << trip->getId();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void ShapeBuilder::shape(pfaedle::netgraph::Graph* ng) {
|
||||
TrGraphEdgs gtfsGraph;
|
||||
|
||||
LOG(INFO) << "Clustering trips...";
|
||||
Clusters clusters = clusterTrips(_feed, _mots);
|
||||
LOG(INFO) << "Clustered trips into " << clusters.size() << " clusters.";
|
||||
|
||||
std::map<ad::cppgtfs::gtfs::Shape*, size_t> shpUsage;
|
||||
for (auto t : _feed->getTrips()) {
|
||||
if (t.second->getShape()) shpUsage[t.second->getShape()]++;
|
||||
}
|
||||
|
||||
// to avoid unfair load balance on threads
|
||||
std::random_shuffle(clusters.begin(), clusters.end());
|
||||
|
||||
size_t iters = EDijkstra::ITERS;
|
||||
size_t totiters = EDijkstra::ITERS;
|
||||
size_t oiters = EDijkstra::ITERS;
|
||||
size_t j = 0;
|
||||
|
||||
auto t1 = TIME();
|
||||
auto t2 = TIME();
|
||||
double totAvgDist = 0;
|
||||
size_t totNumTrips = 0;
|
||||
|
||||
#pragma omp parallel for num_threads(_numThreads)
|
||||
for (size_t i = 0; i < clusters.size(); i++) {
|
||||
j++;
|
||||
|
||||
if (j % 10 == 0) {
|
||||
#pragma omp critical
|
||||
{
|
||||
LOG(INFO) << "@ " << j << " / " << clusters.size() << " ("
|
||||
<< (static_cast<int>((j * 1.0) / clusters.size() * 100))
|
||||
<< "%, " << (EDijkstra::ITERS - oiters) << " iters, tput "
|
||||
<< (static_cast<double>(EDijkstra::ITERS - oiters)) /
|
||||
TOOK(t1, TIME())
|
||||
<< " iters/ms"
|
||||
<< ", " << (10.0 / (TOOK(t1, TIME()) / 1000))
|
||||
<< " trips/sec)";
|
||||
|
||||
oiters = EDijkstra::ITERS;
|
||||
t1 = TIME();
|
||||
}
|
||||
}
|
||||
|
||||
// explicitly call const version of shape here for thread safety
|
||||
const Shape& cshp =
|
||||
const_cast<const ShapeBuilder&>(*this).shape(clusters[i][0]);
|
||||
totAvgDist += cshp.avgHopDist;
|
||||
|
||||
if (_cfg.buildTransitGraph) {
|
||||
#pragma omp critical
|
||||
{ writeTransitGraph(cshp, >fsGraph, clusters[i]); }
|
||||
}
|
||||
|
||||
std::vector<double> distances;
|
||||
ad::cppgtfs::gtfs::Shape* shp =
|
||||
getGtfsShape(cshp, clusters[i][0], &distances);
|
||||
|
||||
LOG(DEBUG) << "Took " << EDijkstra::ITERS - iters << " iterations.";
|
||||
iters = EDijkstra::ITERS;
|
||||
|
||||
totNumTrips += clusters[i].size();
|
||||
|
||||
for (auto t : clusters[i]) {
|
||||
if (_cfg.evaluate) {
|
||||
_ecoll->add(t, t->getShape(), shp, distances);
|
||||
}
|
||||
|
||||
if (t->getShape() && shpUsage[t->getShape()] > 0) {
|
||||
shpUsage[t->getShape()]--;
|
||||
if (shpUsage[t->getShape()] == 0) {
|
||||
_feed->getShapes().remove(t->getShape()->getId());
|
||||
delete t->getShape();
|
||||
}
|
||||
}
|
||||
setShape(t, shp, distances);
|
||||
}
|
||||
}
|
||||
|
||||
LOG(INFO) << "Done.";
|
||||
LOG(INFO) << "Matched " << totNumTrips << " trips in " << clusters.size()
|
||||
<< " clusters.";
|
||||
LOG(INFO) << "Took " << (EDijkstra::ITERS - totiters)
|
||||
<< " iterations in total.";
|
||||
LOG(INFO) << "Took " << TOOK(t2, TIME()) << " ms in total.";
|
||||
LOG(INFO) << "Total avg. tput "
|
||||
<< (static_cast<double>(EDijkstra::ITERS - totiters)) /
|
||||
TOOK(t2, TIME())
|
||||
<< " iters/sec";
|
||||
LOG(INFO) << "Total avg. trip tput "
|
||||
<< (clusters.size() / (TOOK(t2, TIME()) / 1000)) << " trips/sec";
|
||||
LOG(INFO) << "Avg hop distance was "
|
||||
<< (totAvgDist / static_cast<double>(clusters.size())) << " meters";
|
||||
|
||||
if (_cfg.buildTransitGraph) {
|
||||
LOG(INFO) << "Building transit network graph...";
|
||||
buildTrGraph(>fsGraph, ng);
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void ShapeBuilder::setShape(Trip* t, 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]);
|
||||
i++;
|
||||
}
|
||||
|
||||
t->setShape(s);
|
||||
|
||||
std::lock_guard<std::mutex> guard(_shpMutex);
|
||||
_feed->getShapes().add(s);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
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));
|
||||
|
||||
assert(shp.hops.size() == t->getStopTimes().size() - 1);
|
||||
|
||||
size_t seq = 0;
|
||||
double dist = -1;
|
||||
double lastDist = -1;
|
||||
hopDists->push_back(0);
|
||||
FPoint last(0, 0);
|
||||
for (const auto& hop : shp.hops) {
|
||||
const trgraph::Node* l = hop.start;
|
||||
if (hop.edges.size() == 0) {
|
||||
FPoint ll = webMercToLatLng<float>(hop.start->pl().getGeom()->get<0>(),
|
||||
hop.start->pl().getGeom()->get<1>());
|
||||
|
||||
if (dist > -0.5)
|
||||
dist += webMercMeterDist(last, *hop.start->pl().getGeom());
|
||||
else
|
||||
dist = 0;
|
||||
|
||||
last = *hop.start->pl().getGeom();
|
||||
|
||||
if (dist - lastDist > 0.01) {
|
||||
ret->addPoint(ShapePoint(ll.get<1>(), ll.get<0>(), dist, seq));
|
||||
seq++;
|
||||
lastDist = dist;
|
||||
}
|
||||
|
||||
dist += webMercMeterDist(last, *hop.end->pl().getGeom());
|
||||
last = *hop.end->pl().getGeom();
|
||||
|
||||
if (dist - lastDist > 0.01) {
|
||||
ll = webMercToLatLng<float>(hop.end->pl().getGeom()->get<0>(),
|
||||
hop.end->pl().getGeom()->get<1>());
|
||||
ret->addPoint(ShapePoint(ll.get<1>(), ll.get<0>(), 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()) {
|
||||
for (size_t i = 0; i < e->pl().getGeom()->size(); i++) {
|
||||
const FPoint& cur = (*e->pl().getGeom())[i];
|
||||
if (dist > -0.5)
|
||||
dist += webMercMeterDist(last, cur);
|
||||
else
|
||||
dist = 0;
|
||||
last = cur;
|
||||
if (dist - lastDist > 0.01) {
|
||||
FPoint ll = webMercToLatLng<float>(cur.get<0>(), cur.get<1>());
|
||||
ret->addPoint(ShapePoint(ll.get<1>(), ll.get<0>(), dist, seq));
|
||||
seq++;
|
||||
lastDist = dist;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int64_t i = e->pl().getGeom()->size() - 1; i >= 0; i--) {
|
||||
const FPoint& cur = (*e->pl().getGeom())[i];
|
||||
if (dist > -0.5)
|
||||
dist += webMercMeterDist(last, cur);
|
||||
else
|
||||
dist = 0;
|
||||
last = cur;
|
||||
if (dist - lastDist > 0.01) {
|
||||
FPoint ll = webMercToLatLng<float>(cur.get<0>(), cur.get<1>());
|
||||
ret->addPoint(ShapePoint(ll.get<1>(), ll.get<0>(), dist, seq));
|
||||
seq++;
|
||||
lastDist = dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
l = e->getOtherNd(l);
|
||||
}
|
||||
|
||||
hopDists->push_back(lastDist);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
std::string ShapeBuilder::getFreeShapeId(Trip* trip) {
|
||||
std::string ret;
|
||||
std::lock_guard<std::mutex> guard(_shpMutex);
|
||||
while (!ret.size() || _feed->getShapes().get(ret)) {
|
||||
_curShpCnt++;
|
||||
ret = "shp_";
|
||||
ret += std::to_string(trip->getRoute()->getType());
|
||||
ret += "_" + std::to_string(_curShpCnt);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const RoutingAttrs& ShapeBuilder::getRAttrs(const Trip* trip) {
|
||||
auto i = _rAttrs.find(trip);
|
||||
|
||||
if (i == _rAttrs.end()) {
|
||||
router::RoutingAttrs ret;
|
||||
|
||||
const auto& lnormzer = _motCfg.osmBuildOpts.lineNormzer;
|
||||
|
||||
ret.shortName = lnormzer(trip->getRoute()->getShortName());
|
||||
|
||||
if (ret.shortName.empty()) ret.shortName = lnormzer(trip->getShortname());
|
||||
|
||||
if (ret.shortName.empty())
|
||||
ret.shortName = lnormzer(trip->getRoute()->getLongName());
|
||||
|
||||
ret.fromString = _motCfg.osmBuildOpts.statNormzer(
|
||||
trip->getStopTimes().begin()->getStop()->getName());
|
||||
ret.toString = _motCfg.osmBuildOpts.statNormzer(
|
||||
(--trip->getStopTimes().end())->getStop()->getName());
|
||||
|
||||
return _rAttrs
|
||||
.insert(std::pair<const Trip*, router::RoutingAttrs>(trip, ret))
|
||||
.first->second;
|
||||
} else {
|
||||
return i->second;
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const RoutingAttrs& ShapeBuilder::getRAttrs(const Trip* trip) const {
|
||||
return _rAttrs.find(trip)->second;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
BBoxIdx ShapeBuilder::getPaddedGtfsBox(const Feed* feed, double pad,
|
||||
const MOTs& mots,
|
||||
const std::string& tid) {
|
||||
osm::BBoxIdx box(pad);
|
||||
for (const auto& t : feed->getTrips()) {
|
||||
if (!tid.empty() && t.second->getId() != tid) continue;
|
||||
if (mots.count(t.second->getRoute()->getType())) {
|
||||
Box<float> cur = minbox<float>();
|
||||
for (const auto& st : t.second->getStopTimes()) {
|
||||
cur = extendBox(
|
||||
Point<float>(st.getStop()->getLng(), st.getStop()->getLat()), cur);
|
||||
}
|
||||
box.add(cur);
|
||||
}
|
||||
}
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void ShapeBuilder::buildGraph() {
|
||||
LOG(INFO) << "Reading " << _cfg.osmPath << " ... ";
|
||||
osm::OsmBuilder osmBuilder;
|
||||
|
||||
osm::BBoxIdx box = getPaddedGtfsBox(_feed, 2500, _mots, _cfg.shapeTripId);
|
||||
|
||||
osmBuilder.read(_cfg.osmPath, _motCfg.osmBuildOpts, &_g, box, _cfg.gridSize,
|
||||
getFeedStops(), &_restr);
|
||||
|
||||
for (auto& feedStop : *getFeedStops()) {
|
||||
if (feedStop.second) {
|
||||
feedStop.second->pl().getSI()->getGroup()->writePens(
|
||||
_motCfg.osmBuildOpts.trackNormzer,
|
||||
_motCfg.routingOpts.platformUnmatchedPen,
|
||||
_motCfg.routingOpts.stationDistPenFactor,
|
||||
_motCfg.routingOpts.nonOsmPen);
|
||||
}
|
||||
}
|
||||
|
||||
LOG(INFO) << "Done.";
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
NodeCandRoute ShapeBuilder::getNCR(Trip* trip) const {
|
||||
router::NodeCandRoute ncr(trip->getStopTimes().size());
|
||||
|
||||
size_t i = 0;
|
||||
|
||||
for (const auto& st : trip->getStopTimes()) {
|
||||
ncr[i] = getNodeCands(st.getStop());
|
||||
i++;
|
||||
}
|
||||
return ncr;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
double ShapeBuilder::avgHopDist(Trip* trip) const {
|
||||
size_t i = 0;
|
||||
double sum = 0;
|
||||
|
||||
const Stop* prev = 0;
|
||||
|
||||
for (const auto& st : trip->getStopTimes()) {
|
||||
if (!prev) {
|
||||
prev = st.getStop();
|
||||
continue;
|
||||
}
|
||||
auto a = util::geo::latLngToWebMerc<float>(prev->getLat(), prev->getLng());
|
||||
auto b = util::geo::latLngToWebMerc<float>(st.getStop()->getLat(),
|
||||
st.getStop()->getLng());
|
||||
sum += util::geo::webMercMeterDist(a, b);
|
||||
|
||||
prev = st.getStop();
|
||||
i++;
|
||||
}
|
||||
return sum / static_cast<double>(i);
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
Clusters ShapeBuilder::clusterTrips(Feed* f, MOTs mots) {
|
||||
// building an index [start station, end station] -> [cluster]
|
||||
|
||||
std::map<StopPair, std::vector<size_t>> clusterIdx;
|
||||
|
||||
size_t j = 0;
|
||||
|
||||
Clusters ret;
|
||||
for (const auto& trip : f->getTrips()) {
|
||||
// if (trip.second->getId() != "L5Cvl_T01") continue;
|
||||
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()))
|
||||
continue;
|
||||
bool found = false;
|
||||
auto spair = StopPair(trip.second->getStopTimes().begin()->getStop(),
|
||||
trip.second->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);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
ret.push_back({trip.second});
|
||||
// explicit call to write render attrs to cache
|
||||
getRAttrs(trip.second);
|
||||
clusterIdx[spair].push_back(ret.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
bool ShapeBuilder::routingEqual(const Stop* a, const Stop* b) {
|
||||
if (a == b) return true; // trivial
|
||||
|
||||
auto namea = _motCfg.osmBuildOpts.statNormzer(a->getName());
|
||||
auto nameb = _motCfg.osmBuildOpts.statNormzer(b->getName());
|
||||
if (namea != nameb) return false;
|
||||
|
||||
auto tracka = _motCfg.osmBuildOpts.trackNormzer(a->getPlatformCode());
|
||||
auto trackb = _motCfg.osmBuildOpts.trackNormzer(b->getPlatformCode());
|
||||
if (tracka != trackb) return false;
|
||||
|
||||
FPoint ap = util::geo::latLngToWebMerc<float>(a->getLat(), a->getLng());
|
||||
FPoint bp = util::geo::latLngToWebMerc<float>(b->getLat(), b->getLng());
|
||||
|
||||
double d = util::geo::webMercMeterDist(ap, bp);
|
||||
|
||||
if (d > 1) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
bool ShapeBuilder::routingEqual(Trip* a, Trip* b) {
|
||||
if (a->getStopTimes().size() != b->getStopTimes().size()) return false;
|
||||
if (getRAttrs(a) != getRAttrs(b)) return false;
|
||||
|
||||
auto stb = b->getStopTimes().begin();
|
||||
for (const auto& sta : a->getStopTimes()) {
|
||||
if (!routingEqual(sta.getStop(), stb->getStop())) {
|
||||
return false;
|
||||
}
|
||||
stb++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
const pfaedle::trgraph::Graph* ShapeBuilder::getGraph() const { return &_g; }
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void ShapeBuilder::writeTransitGraph(const Shape& shp, TrGraphEdgs* edgs,
|
||||
const Cluster& cluster) const {
|
||||
for (auto hop : shp.hops) {
|
||||
for (const auto* e : hop.edges) {
|
||||
if (e->pl().isRev()) e = _g.getEdg(e->getTo(), e->getFrom());
|
||||
(*edgs)[e].insert(cluster.begin(), cluster.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
void ShapeBuilder::buildTrGraph(TrGraphEdgs* edgs,
|
||||
pfaedle::netgraph::Graph* ng) const {
|
||||
std::unordered_map<trgraph::Node*, pfaedle::netgraph::Node*> nodes;
|
||||
|
||||
for (auto ep : *edgs) {
|
||||
auto e = ep.first;
|
||||
pfaedle::netgraph::Node* from = 0;
|
||||
pfaedle::netgraph::Node* to = 0;
|
||||
if (nodes.count(e->getFrom())) from = nodes[e->getFrom()];
|
||||
if (nodes.count(e->getTo())) to = nodes[e->getTo()];
|
||||
if (!from) {
|
||||
from = ng->addNd(*e->getFrom()->pl().getGeom());
|
||||
nodes[e->getFrom()] = from;
|
||||
}
|
||||
if (!to) {
|
||||
to = ng->addNd(*e->getTo()->pl().getGeom());
|
||||
nodes[e->getTo()] = to;
|
||||
}
|
||||
|
||||
ng->addEdg(from, to,
|
||||
pfaedle::netgraph::EdgePL(*e->pl().getGeom(), ep.second));
|
||||
}
|
||||
}
|
||||
120
src/pfaedle/router/ShapeBuilder.h
Normal file
120
src/pfaedle/router/ShapeBuilder.h
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
// Copyright 2018, University of Freiburg,
|
||||
// Chair of Algorithms and Data Structures.
|
||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||
|
||||
#ifndef PFAEDLE_ROUTER_SHAPEBUILDER_H_
|
||||
#define PFAEDLE_ROUTER_SHAPEBUILDER_H_
|
||||
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "ad/cppgtfs/gtfs/Feed.h"
|
||||
#include "pfaedle/config/MotConfig.h"
|
||||
#include "pfaedle/config/PfaedleConfig.h"
|
||||
#include "pfaedle/eval/Collector.h"
|
||||
#include "pfaedle/netgraph/Graph.h"
|
||||
#include "pfaedle/osm/Restrictor.h"
|
||||
#include "pfaedle/router/Misc.h"
|
||||
#include "pfaedle/router/Router.h"
|
||||
#include "pfaedle/trgraph/Graph.h"
|
||||
|
||||
namespace pfaedle {
|
||||
namespace router {
|
||||
|
||||
using ad::cppgtfs::gtfs::Stop;
|
||||
using ad::cppgtfs::gtfs::Trip;
|
||||
using ad::cppgtfs::gtfs::Feed;
|
||||
|
||||
struct Shape {
|
||||
router::EdgeListHops hops;
|
||||
double avgHopDist;
|
||||
};
|
||||
|
||||
typedef std::vector<Trip*> Cluster;
|
||||
typedef std::vector<Cluster> Clusters;
|
||||
typedef std::pair<const Stop*, const Stop*> StopPair;
|
||||
typedef std::unordered_map<const Trip*, router::RoutingAttrs> TripRAttrs;
|
||||
typedef std::unordered_map<const trgraph::Edge*, std::set<const Trip*>>
|
||||
TrGraphEdgs;
|
||||
|
||||
/*
|
||||
* Layer class for the router. Provides an interface for direct usage with
|
||||
* GTFS data
|
||||
*/
|
||||
class ShapeBuilder {
|
||||
public:
|
||||
ShapeBuilder(Feed* feed, MOTs mots, const config::MotConfig& motCfg,
|
||||
eval::Collector* ecoll, const config::Config& cfg);
|
||||
|
||||
void shape(pfaedle::netgraph::Graph* ng);
|
||||
|
||||
router::FeedStops* getFeedStops();
|
||||
|
||||
const NodeCandGroup& getNodeCands(const Stop* s) const;
|
||||
|
||||
util::geo::FLine shapeL(const router::NodeCandRoute& ncr,
|
||||
const router::RoutingAttrs& rAttrs);
|
||||
util::geo::FLine shapeL(Trip* trip);
|
||||
|
||||
pfaedle::router::Shape shape(Trip* trip) const;
|
||||
pfaedle::router::Shape shape(Trip* trip);
|
||||
|
||||
const trgraph::Graph* getGraph() const;
|
||||
|
||||
static osm::BBoxIdx getPaddedGtfsBox(const Feed* feed, double pad,
|
||||
const MOTs& mots,
|
||||
const std::string& tid);
|
||||
|
||||
private:
|
||||
Feed* _feed;
|
||||
MOTs _mots;
|
||||
config::MotConfig _motCfg;
|
||||
eval::Collector* _ecoll;
|
||||
config::Config _cfg;
|
||||
trgraph::Graph _g;
|
||||
router::Router _crouter;
|
||||
|
||||
router::FeedStops _stops;
|
||||
|
||||
NodeCandGroup _emptyNCG;
|
||||
|
||||
size_t _curShpCnt, _numThreads;
|
||||
|
||||
std::mutex _shpMutex;
|
||||
|
||||
TripRAttrs _rAttrs;
|
||||
|
||||
osm::Restrictor _restr;
|
||||
|
||||
void writeMotStops();
|
||||
void buildGraph();
|
||||
|
||||
Clusters clusterTrips(Feed* f, MOTs mots);
|
||||
void writeTransitGraph(const Shape& shp, TrGraphEdgs* edgs,
|
||||
const Cluster& cluster) const;
|
||||
void buildTrGraph(TrGraphEdgs* edgs, pfaedle::netgraph::Graph* ng) const;
|
||||
|
||||
std::string getFreeShapeId(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,
|
||||
const std::vector<double>& dists);
|
||||
|
||||
router::NodeCandRoute getNCR(Trip* trip) const;
|
||||
double avgHopDist(Trip* trip) const;
|
||||
const router::RoutingAttrs& getRAttrs(const Trip* trip) const;
|
||||
const router::RoutingAttrs& getRAttrs(const Trip* trip);
|
||||
bool routingEqual(Trip* a, Trip* b);
|
||||
bool routingEqual(const Stop* a, const Stop* b);
|
||||
router::EdgeListHops route(const router::NodeCandRoute& ncr,
|
||||
const router::RoutingAttrs& rAttrs) const;
|
||||
};
|
||||
} // namespace router
|
||||
} // namespace pfaedle
|
||||
|
||||
#endif // PFAEDLE_ROUTER_SHAPEBUILDER_H_
|
||||
Loading…
Add table
Add a link
Reference in a new issue