Fast map matching  0.1.0
fmm_algorithm.cpp
1 //
2 // Created by Can Yang on 2020/3/22.
3 //
4 
5 #include "mm/fmm/fmm_algorithm.hpp"
6 #include "algorithm/geom_algorithm.hpp"
7 #include "util/util.hpp"
8 #include "util/debug.hpp"
9 
10 using namespace FMM;
11 using namespace FMM::CORE;
12 using namespace FMM::NETWORK;
13 using namespace FMM::PYTHON;
14 using namespace FMM::MM;
15 
16 FastMapMatchConfig::FastMapMatchConfig(int k_arg, double r_arg,
17  double gps_error) :
18  k(k_arg), radius(r_arg), gps_error(gps_error) {
19 };
20 
22  SPDLOG_INFO("FMMAlgorithmConfig");
23  SPDLOG_INFO("k {} radius {} gps_error {}", k, radius, gps_error);
24 };
25 
27  const boost::property_tree::ptree &xml_data) {
28  int k = xml_data.get("config.parameters.k", 8);
29  double radius = xml_data.get("config.parameters.r", 300.0);
30  double gps_error = xml_data.get("config.parameters.gps_error", 50.0);
32 };
33 
35  const cxxopts::ParseResult &arg_data) {
36  int k = arg_data["candidates"].as<int>();
37  double radius = arg_data["radius"].as<double>();
38  double gps_error = arg_data["error"].as<double>();
40 };
41 
43  if (gps_error <= 0 || radius <= 0 || k <= 0) {
44  SPDLOG_CRITICAL("Invalid mm parameter k {} r {} gps error {}",
45  k, radius, gps_error);
46  return false;
47  }
48  return true;
49 }
50 
52  const FastMapMatchConfig &config) {
53  SPDLOG_TRACE("Count of points in trajectory {}", traj.geom.get_num_points());
54  SPDLOG_TRACE("Search candidates");
55  Traj_Candidates tc = network_.search_tr_cs_knn(
56  traj.geom, config.k, config.radius);
57  SPDLOG_TRACE("Trajectory candidate {}", tc);
58  if (tc.empty()) return MatchResult{};
59  SPDLOG_TRACE("Generate transition graph");
60  TransitionGraph tg(tc, config.gps_error);
61  SPDLOG_TRACE("Update cost in transition graph");
62  // The network will be used internally to update transition graph
63  update_tg(&tg, traj, config);
64  SPDLOG_TRACE("Optimal path inference");
65  TGOpath tg_opath = tg.backtrack();
66  SPDLOG_TRACE("Optimal path size {}", tg_opath.size());
67  MatchedCandidatePath matched_candidate_path(tg_opath.size());
68  std::transform(tg_opath.begin(), tg_opath.end(),
69  matched_candidate_path.begin(),
70  [](const TGNode *a) {
71  return MatchedCandidate{
72  *(a->c), a->ep, a->tp, a->sp_dist
73  };
74  });
75  O_Path opath(tg_opath.size());
76  std::transform(tg_opath.begin(), tg_opath.end(),
77  opath.begin(),
78  [](const TGNode *a) {
79  return a->c->edge->id;
80  });
81  std::vector<int> indices;
82  const std::vector<Edge> &edges = network_.get_edges();
83  C_Path cpath = ubodt_->construct_complete_path(tg_opath, edges,
84  &indices);
85  SPDLOG_TRACE("Cpath {}", cpath);
86  SPDLOG_TRACE("Complete path inference");
87  LineString mgeom = network_.complete_path_to_geometry(
88  traj.geom, cpath);
89  SPDLOG_TRACE("Complete path inference done");
90  return MatchResult{
91  traj.id, matched_candidate_path, opath, cpath, indices, mgeom};
92 }
93 
94 PyMatchResult FastMapMatch::match_wkt(
95  const std::string &wkt, const FastMapMatchConfig &config) {
96  LineString line = wkt2linestring(wkt);
97  std::vector<double> timestamps;
98  Trajectory traj{0, line, timestamps};
99  MatchResult result = match_traj(traj, config);
100  PyMatchResult output;
101  output.id = result.id;
102  output.opath = result.opath;
103  output.cpath = result.cpath;
104  output.mgeom = result.mgeom;
105  output.indices = result.indices;
106  for (int i = 0; i < result.opt_candidate_path.size(); ++i) {
107  const MatchedCandidate &mc = result.opt_candidate_path[i];
108  output.candidates.push_back(
109  {i,
110  mc.c.edge->id,
111  graph_.get_node_id(mc.c.edge->source),
112  graph_.get_node_id(mc.c.edge->target),
113  mc.c.dist,
114  mc.c.offset,
115  mc.c.edge->length,
116  mc.ep,
117  mc.tp,
118  mc.sp_dist}
119  );
120  output.pgeom.add_point(mc.c.point);
121  }
122  return output;
123 };
124 
125 double FastMapMatch::get_sp_dist(const Candidate *ca, const Candidate *cb) {
126  double sp_dist = 0;
127  if (ca->edge->id == cb->edge->id && ca->offset <= cb->offset) {
128  sp_dist = cb->offset - ca->offset;
129  } else if (ca->edge->target == cb->edge->source) {
130  // Transition on the same OD nodes
131  sp_dist = ca->edge->length - ca->offset + cb->offset;
132  } else {
133  Record *r = ubodt_->look_up(ca->edge->target, cb->edge->source);
134  // No sp path exist from O to D.
135  if (r == nullptr) return ubodt_->get_delta();
136  // calculate original SP distance
137  sp_dist = r->cost + ca->edge->length - ca->offset + cb->offset;
138  }
139  return sp_dist;
140 }
141 
142 void FastMapMatch::update_tg(
143  TransitionGraph *tg,
144  const Trajectory &traj, const FastMapMatchConfig &config) {
145  SPDLOG_TRACE("Update transition graph");
146  std::vector<TGLayer> &layers = tg->get_layers();
147  std::vector<double> eu_dists = ALGORITHM::cal_eu_dist(traj.geom);
148  int N = layers.size();
149  for (int i = 0; i < N - 1; ++i) {
150  update_layer(i, &(layers[i]), &(layers[i + 1]),
151  eu_dists[i]);
152  }
153  SPDLOG_TRACE("Update transition graph done");
154 }
155 
156 void FastMapMatch::update_layer(int level,
157  TGLayer *la_ptr,
158  TGLayer *lb_ptr,
159  double eu_dist) {
160  SPDLOG_TRACE("Update layer");
161  TGLayer &lb = *lb_ptr;
162  for (auto iter_a = la_ptr->begin(); iter_a != la_ptr->end(); ++iter_a) {
163  NodeIndex source = iter_a->c->index;
164  for (auto iter_b = lb_ptr->begin(); iter_b != lb_ptr->end(); ++iter_b) {
165  double sp_dist = get_sp_dist(iter_a->c, iter_b->c);
166  double tp = TransitionGraph::calc_tp(sp_dist, eu_dist);
167  if (iter_a->cumu_prob + tp * iter_b->ep >= iter_b->cumu_prob) {
168  iter_b->cumu_prob = iter_a->cumu_prob + tp * iter_b->ep;
169  iter_b->prev = &(*iter_a);
170  iter_b->tp = tp;
171  iter_b->sp_dist = sp_dist;
172  }
173  }
174  }
175  SPDLOG_TRACE("Update layer done");
176 }
FMM::MM::TransitionGraph
Transition graph class in HMM.
Definition: transition_graph.hpp:54
FMM::MM::MatchedCandidatePath
std::vector< MatchedCandidate > MatchedCandidatePath
A vector of candidates, used for representing the matching result of a trajectory.
Definition: mm_type.hpp:64
FMM::CORE::Trajectory::geom
LineString geom
Geometry of the trajectory.
Definition: gps.hpp:28
FMM::PYTHON::PyMatchResult::mgeom
CORE::LineString mgeom
Geometry of the matched path.
Definition: pyfmm.hpp:45
FMM::MM::Traj_Candidates
std::vector< Point_Candidates > Traj_Candidates
trajectory candidates
Definition: mm_type.hpp:38
FMM::CORE::LineString::add_point
void add_point(double x, double y)
Add a point to the end of the current line.
Definition: geometry.hpp:79
FMM::MM::Candidate::point
FMM::CORE::Point point
boost point
Definition: mm_type.hpp:34
FMM::MM::TGOpath
std::vector< const TGNode * > TGOpath
The optimal path of nodes in the transition graph.
Definition: transition_graph.hpp:46
FMM::MM::Candidate::edge
NETWORK::Edge * edge
candidate edge
Definition: mm_type.hpp:33
FMM::MM::MatchedCandidate::c
Candidate c
Candidate matched to a point.
Definition: mm_type.hpp:54
FMM::MM::MatchResult
Map matched result representation.
Definition: mm_type.hpp:69
FMM::PYTHON::PyMatchResult::candidates
std::vector< PyCandidate > candidates
Candidate matched to each point.
Definition: pyfmm.hpp:43
FMM::MM::TransitionGraph::backtrack
TGOpath backtrack()
Backtrack the transition graph to find an optimal path.
Definition: transition_graph.cpp:62
FMM::MM::FastMapMatchConfig::radius
double radius
Search radius.
Definition: fmm_algorithm.hpp:41
FMM::MM::FastMapMatchConfig::gps_error
double gps_error
GPS error.
Definition: fmm_algorithm.hpp:42
FMM::NETWORK::Edge::id
EdgeID id
Edge ID, can be discontinuous integers.
Definition: type.hpp:48
FMM::PYTHON::PyMatchResult
POD Match result type used in Python API.
Definition: pyfmm.hpp:39
FMM::MM::C_Path
std::vector< FMM::NETWORK::EdgeID > C_Path
Complete path, ids of a sequence of topologically connected edges.
Definition: mm_type.hpp:47
FMM::MM::Candidate::dist
double dist
distance from original point p to map matched point p'
Definition: mm_type.hpp:32
FMM::MM::MatchResult::cpath
C_Path cpath
the complete path, containing ids of a sequence of topologically connected edges traversed by the tra...
Definition: mm_type.hpp:77
FMM::MM::FastMapMatchConfig::load_from_xml
static FastMapMatchConfig load_from_xml(const boost::property_tree::ptree &xml_data)
Load configuration from xml data.
Definition: fmm_algorithm.cpp:26
FMM
Fast map matching.
Definition: geom_algorithm.hpp:17
FMM::PYTHON::PyMatchResult::indices
std::vector< int > indices
index of matched edge in the cpath
Definition: pyfmm.hpp:44
FMM::CORE::Trajectory
Trajectory class
Definition: gps.hpp:26
FMM::NETWORK::Network::search_tr_cs_knn
FMM::MM::Traj_Candidates search_tr_cs_knn(FMM::CORE::Trajectory &trajectory, std::size_t k, double radius) const
Search for k nearest neighboring (KNN) candidates of a trajectory within a search radius.
Definition: network.cpp:189
FMM::PYTHON::PyMatchResult::pgeom
CORE::LineString pgeom
Point position matched for each GPS point.
Definition: pyfmm.hpp:46
FMM::MM::MatchResult::mgeom
CORE::LineString mgeom
the geometry of the matched path
Definition: mm_type.hpp:81
FMM::MM::FastMapMatchConfig::print
void print() const
Print information about this configuration.
Definition: fmm_algorithm.cpp:21
FMM::MM::MatchResult::id
int id
id of the trajectory to be matched
Definition: mm_type.hpp:70
FMM::MM::Candidate
Candidate edge matched to a GPS point
Definition: mm_type.hpp:26
FMM::MM::MatchedCandidate::tp
double tp
transition probability to previous matched candidate
Definition: mm_type.hpp:56
FMM::MM::Candidate::offset
double offset
offset distance from the start of polyline to p'
Definition: mm_type.hpp:31
FMM::MM::FastMapMatchConfig::k
int k
Number of candidates.
Definition: fmm_algorithm.hpp:40
FMM::CORE
Core data types.
Definition: geometry.hpp:22
FMM::PYTHON::PyMatchResult::opath
MM::O_Path opath
Edge ID matched for each point of the trajectory
Definition: pyfmm.hpp:41
FMM::CORE::LineString
Linestring geometry class.
Definition: geometry.hpp:34
FMM::MM::MatchResult::opt_candidate_path
MatchedCandidatePath opt_candidate_path
A vector of candidate matched to each point of a trajectory.
Definition: mm_type.hpp:71
FMM::MM
Class related with map matching.
Definition: composite_graph.hpp:18
FMM::MM::MatchResult::opath
O_Path opath
the optimal path, containing id of edges matched to each point in a trajectory
Definition: mm_type.hpp:74
FMM::NETWORK
Classes related with network and graph.
Definition: graph.hpp:21
FMM::MM::O_Path
std::vector< FMM::NETWORK::EdgeID > O_Path
Optimal path, edge id matched to each point in the trajectory.
Definition: mm_type.hpp:44
FMM::MM::FastMapMatch::match_traj
MatchResult match_traj(const CORE::Trajectory &traj, const FastMapMatchConfig &config)
Match a trajectory to the road network.
Definition: fmm_algorithm.cpp:51
FMM::PYTHON::PyMatchResult::id
int id
id of a trajectory
Definition: pyfmm.hpp:40
FMM::MM::Record::cost
double cost
distance from source to target
Definition: ubodt.hpp:29
FMM::CORE::wkt2linestring
LineString wkt2linestring(const std::string &wkt)
Convert a wkt into a linestring.
Definition: geometry.cpp:42
FMM::MM::FastMapMatch::update_tg
void update_tg(TransitionGraph *tg, const CORE::Trajectory &traj, const FastMapMatchConfig &config)
Update probabilities in a transition graph.
Definition: fmm_algorithm.cpp:142
FMM::MM::MatchResult::indices
std::vector< int > indices
index of opath edge in cpath
Definition: mm_type.hpp:80
FMM::MM::MatchedCandidate
A candidate matched to a point.
Definition: mm_type.hpp:53
FMM::MM::TransitionGraph::get_layers
std::vector< TGLayer > & get_layers()
Get a reference to the inner layers of the transition graph.
Definition: transition_graph.cpp:86
FMM::NETWORK::Edge::source
NodeIndex source
source node index
Definition: type.hpp:49
FMM::NETWORK::NodeIndex
unsigned int NodeIndex
Node Index in the network, range from [0,num_vertices-1 ].
Definition: type.hpp:24
FMM::MM::FastMapMatchConfig::validate
bool validate() const
Check if the configuration is valid or not.
Definition: fmm_algorithm.cpp:42
FMM::ALGORITHM::cal_eu_dist
std::vector< double > cal_eu_dist(const FMM::CORE::LineString &trajectory)
Calculate segment length of a trajectory.
Definition: geom_algorithm.cpp:7
FMM::MM::Record
Record type of the upper bounded origin destination table
Definition: ubodt.hpp:23
FMM::PYTHON::PyMatchResult::cpath
MM::C_Path cpath
Edge ID traversed by the matched path.
Definition: pyfmm.hpp:42
FMM::CORE::LineString::get_num_points
int get_num_points() const
Get the number of points in a line.
Definition: geometry.hpp:115
FMM::NETWORK::Edge::length
double length
length of the edge polyline
Definition: type.hpp:51
FMM::MM::TGNode
A node in the transition graph.
Definition: transition_graph.hpp:29
FMM::MM::MatchedCandidate::sp_dist
double sp_dist
shortest path distance to previous matched candidate
Definition: mm_type.hpp:57
FMM::MM::TGLayer
std::vector< TGNode > TGLayer
A layer of nodes in the transition graph.
Definition: transition_graph.hpp:42
FMM::MM::FastMapMatchConfig
Configuration class for fmm algorithm.
Definition: fmm_algorithm.hpp:30
FMM::PYTHON
Data type for Python API.
Definition: pyfmm.hpp:19
FMM::NETWORK::Edge::target
NodeIndex target
target node index
Definition: type.hpp:50
FMM::MM::MatchedCandidate::ep
double ep
emission probability
Definition: mm_type.hpp:55
FMM::MM::FastMapMatchConfig::load_from_arg
static FastMapMatchConfig load_from_arg(const cxxopts::ParseResult &arg_data)
Load configuration from argument data.
Definition: fmm_algorithm.cpp:34