Fast map matching  0.1.0
network.cpp
1 #include "network/network.hpp"
2 #include "util/debug.hpp"
3 #include "util/util.hpp"
4 #include "algorithm/geom_algorithm.hpp"
5 
6 #include <ogrsf_frmts.h> // C++ API for GDAL
7 #include <math.h> // Calulating probability
8 #include <algorithm> // Partial sort copy
9  // Partial sort copy
10 
11 // Data structures for Rtree
12 #include <boost/geometry/index/rtree.hpp>
13 #include <boost/function_output_iterator.hpp>
14 
15 using namespace FMM;
16 using namespace FMM::CORE;
17 using namespace FMM::MM;
18 using namespace FMM::NETWORK;
19 
20 bool Network::candidate_compare(const Candidate &a, const Candidate &b)
21 {
22  if (a.dist!=b.dist)
23  {
24  return a.dist<b.dist;
25  }
26  else
27  {
28  return a.edge->index<b.edge->index;
29  }
30 }
31 
32 Network::Network(const std::string &filename,
33  const std::string &id_name,
34  const std::string &source_name,
35  const std::string &target_name)
36 {
37  SPDLOG_INFO("Read network from file {}",filename);
38  OGRRegisterAll();
39  GDALDataset *poDS = (GDALDataset*) GDALOpenEx(
40  filename.c_str(), GDAL_OF_VECTOR, NULL, NULL, NULL );
41  if( poDS == NULL ) {
42  SPDLOG_CRITICAL("Open dataset failed.");
43  exit( 1 );
44  }
45  OGRLayer *ogrlayer = poDS->GetLayer(0);
46  int NUM_FEATURES = ogrlayer->GetFeatureCount();
47  // edges= std::vector<Edge>(NUM_FEATURES);
48  // Initialize network edges
49  OGRFeatureDefn *ogrFDefn = ogrlayer->GetLayerDefn();
50  OGRFeature *ogrFeature;
51 
52  // Fetch the field index given field name.
53  int id_idx=ogrFDefn->GetFieldIndex(id_name.c_str());
54  int source_idx=ogrFDefn->GetFieldIndex(source_name.c_str());
55  int target_idx=ogrFDefn->GetFieldIndex(target_name.c_str());
56  if (source_idx<0||target_idx<0||id_idx<0) {
57  SPDLOG_CRITICAL("Id, source or target column not found");
58  GDALClose( poDS );
59  std::exit(EXIT_FAILURE);
60  }
61 
62  if (wkbFlatten(ogrFDefn->GetGeomType()) != wkbLineString)
63  {
64  SPDLOG_CRITICAL("Geometry type of network is {}, should be linestring",
65  OGRGeometryTypeToName(ogrFDefn->GetGeomType()));
66  GDALClose( poDS );
67  std::exit(EXIT_FAILURE);
68  } else {
69  SPDLOG_DEBUG("Geometry type of network is {}",
70  OGRGeometryTypeToName(ogrFDefn->GetGeomType()));
71  }
72  OGRSpatialReference *ogrsr = ogrFDefn->GetGeomFieldDefn(0)->GetSpatialRef();
73  if (ogrsr != nullptr) {
74  srid = ogrsr->GetEPSGGeogCS();
75  if (srid==-1)
76  {
77  srid= 4326;
78  SPDLOG_WARN("SRID is not found, set to 4326 by default");
79  } else {
80  SPDLOG_DEBUG("SRID is {}",srid);
81  }
82  } else {
83  srid= 4326;
84  SPDLOG_WARN("SRID is not found, set to 4326 by default");
85  }
86  // Read data from shapefile
87  EdgeIndex index = 0;
88  while( (ogrFeature = ogrlayer->GetNextFeature()) != NULL){
89  EdgeID id = ogrFeature->GetFieldAsInteger(id_idx);
90  NodeID source = ogrFeature->GetFieldAsInteger(source_idx);
91  NodeID target = ogrFeature->GetFieldAsInteger(target_idx);
92  OGRGeometry *rawgeometry = ogrFeature->GetGeometryRef();
93  LineString geom;
94  if (rawgeometry->getGeometryType()==wkbLineString) {
95  geom = ogr2linestring((OGRLineString*) rawgeometry);
96  } else if (rawgeometry->getGeometryType()==wkbMultiLineString) {
97  SPDLOG_TRACE("Feature id {} s {} t {} is multilinestring",
98  id, source, target);
99  SPDLOG_TRACE("Read only the first linestring");
100  geom = ogr2linestring((OGRMultiLineString*) rawgeometry);
101  } else {
102  SPDLOG_CRITICAL("Unknown geometry type for feature id {} s {} t {}",
103  id, source, target);
104  }
105  NodeIndex s_idx,t_idx;
106  if (node_map.find(source)==node_map.end()) {
107  s_idx = node_id_vec.size();
108  node_id_vec.push_back(source);
109  node_map.insert({source,s_idx});
110  vertex_points.push_back(geom.get_point(0));
111  } else {
112  s_idx = node_map[source];
113  }
114  if (node_map.find(target)==node_map.end()) {
115  t_idx = node_id_vec.size();
116  node_id_vec.push_back(target);
117  node_map.insert({target,t_idx});
118  int npoints = geom.get_num_points();
119  vertex_points.push_back(geom.get_point(npoints-1));
120  } else {
121  t_idx = node_map[target];
122  }
123  edges.push_back({index,id,s_idx,t_idx,geom.get_length(),geom});
124  edge_map.insert({id,index});
125  ++index;
126  OGRFeature::DestroyFeature(ogrFeature);
127  }
128  GDALClose( poDS );
129  num_vertices = node_id_vec.size();
130  SPDLOG_INFO("Number of edges {} nodes {}",edges.size(),num_vertices);
131  SPDLOG_INFO("Field index: id {} source {} target {}",
132  id_idx,source_idx,target_idx);
133  build_rtree_index();
134  SPDLOG_INFO("Read network done.");
135 } // Network constructor
136 
137 int Network::get_node_count() const {
138  return node_id_vec.size();
139 }
140 
141 int Network::get_edge_count() const {
142  return edges.size();
143 }
144 
145 // Get the edge vector
146 const std::vector<Edge> &Network::get_edges() const
147 {
148  return edges;
149 }
150 
151 // Get the ID attribute of an edge according to its index
152 EdgeID Network::get_edge_id(EdgeIndex index) const
153 {
154  return index<edges.size() ? edges[index].id:-1;
155 }
156 
157 EdgeIndex Network::get_edge_index(EdgeID id) const {
158  return edge_map.at(id);
159 }
160 
161 NodeID Network::get_node_id(NodeIndex index) const {
162  return index<num_vertices ? node_id_vec[index] : -1;
163 }
164 
165 NodeIndex Network::get_node_index(NodeID id) const {
166  return node_map.at(id);
167 }
168 
169 Point Network::get_node_geom_from_idx(NodeIndex index) const {
170  return vertex_points[index];
171 }
172 
173 // Construct a Rtree using the vector of edges
174 void Network::build_rtree_index() {
175  // Build an rtree for candidate search
176  SPDLOG_DEBUG("Create boost rtree");
177  // create some Items
178  for (std::size_t i = 0; i < edges.size(); ++i) {
179  // create a boost_box
180  Edge *edge = &edges[i];
181  double x1,y1,x2,y2;
182  ALGORITHM::boundingbox_geometry(edge->geom,&x1,&y1,&x2,&y2);
183  boost_box b(Point(x1,y1), Point(x2,y2));
184  rtree.insert(std::make_pair(b,edge));
185  }
186  SPDLOG_DEBUG("Create boost rtree done");
187 }
188 
189 Traj_Candidates Network::search_tr_cs_knn(Trajectory &trajectory, std::size_t k,
190  double radius) const {
191  return search_tr_cs_knn(trajectory.geom,k,radius);
192 }
193 
194 Traj_Candidates Network::search_tr_cs_knn(const LineString &geom, std::size_t k,
195  double radius) const
196 {
197  int NumberPoints = geom.get_num_points();
198  Traj_Candidates tr_cs(NumberPoints);
199  unsigned int current_candidate_index = num_vertices;
200  for (int i=0; i<NumberPoints; ++i) {
201  // SPDLOG_DEBUG("Search candidates for point index {}",i);
202  // Construct a bounding boost_box
203  double px = geom.get_x(i);
204  double py = geom.get_y(i);
205  Point_Candidates pcs;
206  boost_box b(Point(geom.get_x(i)-radius,geom.get_y(i)-radius),
207  Point(geom.get_x(i)+radius,geom.get_y(i)+radius));
208  std::vector<Item> temp;
209  // Rtree can only detect intersect with a the bounding box of
210  // the geometry stored.
211  rtree.query(boost::geometry::index::intersects(b),
212  std::back_inserter(temp));
213  int Nitems = temp.size();
214  for (unsigned int j=0; j<Nitems; ++j) {
215  // Check for detailed intersection
216  // The two edges are all in OGR_linestring
217  Edge *edge = temp[j].second;
218  double offset;
219  double dist;
220  double closest_x,closest_y;
222  &dist,&offset,&closest_x,&closest_y);
223  if (dist<=radius) {
224  // index, offset, dist, edge, pseudo id, point
225  Candidate c = {0,
226  offset,
227  dist,
228  edge,
229  Point(closest_x,closest_y)};
230  pcs.push_back(c);
231  }
232  }
233  if (pcs.empty()) {
234  return Traj_Candidates();
235  }
236  // KNN part
237  if (pcs.size()<=k) {
238  tr_cs[i]=pcs;
239  } else {
240  tr_cs[i]=Point_Candidates(k);
241  std::partial_sort_copy(
242  pcs.begin(),pcs.end(),
243  tr_cs[i].begin(),tr_cs[i].end(),
244  candidate_compare);
245  }
246  for (int m=0; m<tr_cs[i].size(); ++m) {
247  tr_cs[i][m].index = current_candidate_index+m;
248  }
249  current_candidate_index+=tr_cs[i].size();
250  // SPDLOG_TRACE("current_candidate_index {}",current_candidate_index);
251  }
252  return tr_cs;
253 }
254 
255 const LineString &Network::get_edge_geom(int edge_id) const {
256  return edges[get_edge_index(edge_id)].geom;
257 }
258 
259 LineString Network::complete_path_to_geometry(
260  const LineString &traj, const C_Path &complete_path) const
261 {
262  // if (complete_path->empty()) return nullptr;
263  LineString line;
264  if (complete_path.empty()) return line;
265  int Npts = traj.get_num_points();
266  int NCsegs = complete_path.size();
267  if (NCsegs ==1) {
268  double dist;
269  double firstoffset;
270  double lastoffset;
271  const LineString &firstseg = get_edge_geom(complete_path[0]);
272  ALGORITHM::linear_referencing(traj.get_x(0),traj.get_y(0),firstseg,
273  &dist,&firstoffset);
274  ALGORITHM::linear_referencing(traj.get_x(Npts-1),traj.get_y(Npts-1),
275  firstseg,&dist,&lastoffset);
276  LineString firstlineseg= ALGORITHM::cutoffseg_unique(firstseg, firstoffset,
277  lastoffset);
278  append_segs_to_line(&line,firstlineseg,0);
279  } else {
280  const LineString &firstseg = get_edge_geom(complete_path[0]);
281  const LineString &lastseg = get_edge_geom(complete_path[NCsegs-1]);
282  double dist;
283  double firstoffset;
284  double lastoffset;
285  ALGORITHM::linear_referencing(traj.get_x(0),traj.get_y(0),firstseg,
286  &dist,&firstoffset);
287  ALGORITHM::linear_referencing(traj.get_x(Npts-1),traj.get_y(Npts-1),
288  lastseg,&dist,&lastoffset);
289  LineString firstlineseg= ALGORITHM::cutoffseg(firstseg, firstoffset, 0);
290  LineString lastlineseg= ALGORITHM::cutoffseg(lastseg, lastoffset, 1);
291  append_segs_to_line(&line,firstlineseg,0);
292  if (NCsegs>2) {
293  for(int i=1; i<NCsegs-1; ++i) {
294  const LineString &middleseg = get_edge_geom(complete_path[i]);
295  append_segs_to_line(&line,middleseg,1);
296  }
297  }
298  append_segs_to_line(&line,lastlineseg,1);
299  }
300  return line;
301 }
302 
303 const std::vector<Point> &Network::get_vertex_points() const {
304  return vertex_points;
305 }
306 
307 const Point &Network::get_vertex_point(NodeIndex u) const {
308  return vertex_points[u];
309 }
310 
311 LineString Network::route2geometry(const std::vector<EdgeID> &path) const
312 {
313  LineString line;
314  if (path.empty()) return line;
315  // if (complete_path->empty()) return nullptr;
316  int NCsegs = path.size();
317  for(int i=0; i<NCsegs; ++i) {
318  EdgeIndex e = get_edge_index(path[i]);
319  const LineString &seg = edges[e].geom;
320  if (i==0) {
321  append_segs_to_line(&line,seg,0);
322  } else {
323  append_segs_to_line(&line,seg,1);
324  }
325  }
326  //SPDLOG_DEBUG("Path geometry is {}",line.exportToWkt());
327  return line;
328 }
329 
330 LineString Network::route2geometry(const std::vector<EdgeIndex> &path) const
331 {
332  LineString line;
333  if (path.empty()) return line;
334  // if (complete_path->empty()) return nullptr;
335  int NCsegs = path.size();
336  for(int i=0; i<NCsegs; ++i)
337  {
338  const LineString &seg = edges[path[i]].geom;
339  if (i==0) {
340  append_segs_to_line(&line,seg,0);
341  } else {
342  append_segs_to_line(&line,seg,1);
343  }
344  }
345  //SPDLOG_DEBUG("Path geometry is {}",line.exportToWkt());
346  return line;
347 }
348 
349 void Network::append_segs_to_line(LineString *line,
350  const LineString &segs, int offset)
351 {
352  int Npoints = segs.get_num_points();
353  for(int i=0; i<Npoints; ++i) {
354  if (i>=offset) {
355  line->add_point(segs.get_x(i),segs.get_y(i));
356  }
357  }
358 }
359 
FMM::CORE::Trajectory::geom
LineString geom
Geometry of the trajectory.
Definition: gps.hpp:28
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::CORE::ogr2linestring
LineString ogr2linestring(const OGRLineString *line)
Convert a OGRLineString to a linestring.
Definition: geometry.cpp:19
FMM::MM::Candidate::edge
NETWORK::Edge * edge
candidate edge
Definition: mm_type.hpp:33
FMM::NETWORK::Network::boost_box
boost::geometry::model::box< FMM::CORE::Point > boost_box
Box of a edge.
Definition: network.hpp:41
FMM::NETWORK::Edge::geom
FMM::CORE::LineString geom
the edge geometry
Definition: type.hpp:52
FMM::NETWORK::Edge::index
EdgeIndex index
Index of an edge, which is continuous [0,N-1].
Definition: type.hpp:47
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
Fast map matching.
Definition: geom_algorithm.hpp:17
FMM::CORE::Trajectory
Trajectory class
Definition: gps.hpp:26
FMM::CORE::LineString::get_point
Point get_point(int i) const
Get the i-th point in the line.
Definition: geometry.hpp:98
FMM::ALGORITHM::boundingbox_geometry
void boundingbox_geometry(const FMM::CORE::LineString &linestring, double *x1, double *y1, double *x2, double *y2)
Compute the boundary of an FMM::CORE::LineString and returns the result in the passed x1,...
Definition: geom_algorithm.cpp:151
FMM::NETWORK::EdgeID
int EdgeID
Edge ID in the network, can be discontinuous int.
Definition: type.hpp:23
FMM::MM::Candidate
Candidate edge matched to a GPS point
Definition: mm_type.hpp:26
FMM::MM::Point_Candidates
std::vector< Candidate > Point_Candidates
Point candidates.
Definition: mm_type.hpp:37
FMM::CORE
Core data types.
Definition: geometry.hpp:22
FMM::CORE::LineString
Linestring geometry class.
Definition: geometry.hpp:34
FMM::MM
Class related with map matching.
Definition: composite_graph.hpp:18
FMM::ALGORITHM::cutoffseg_unique
FMM::CORE::LineString cutoffseg_unique(const FMM::CORE::LineString &linestring, double offset1, double offset2)
Cut a linestring at two offset values.
Definition: geom_algorithm.cpp:351
FMM::CORE::LineString::get_length
double get_length() const
Get the length of the line.
Definition: geometry.hpp:135
FMM::NETWORK
Classes related with network and graph.
Definition: graph.hpp:21
FMM::NETWORK::NodeID
int NodeID
Node ID in the network, can be discontinuous int.
Definition: type.hpp:22
FMM::ALGORITHM::linear_referencing
void linear_referencing(double px, double py, const FMM::CORE::LineString &linestring, double *result_dist, double *result_offset)
A linear referencing function.
Definition: geom_algorithm.cpp:246
FMM::ALGORITHM::cutoffseg
FMM::CORE::LineString cutoffseg(const FMM::CORE::LineString &linestring, double offset, int mode)
Added by Diao 18.01.17 modified by Can 18.01.19 modified by Can 18.03.14.
Definition: geom_algorithm.cpp:420
FMM::NETWORK::NodeIndex
unsigned int NodeIndex
Node Index in the network, range from [0,num_vertices-1 ].
Definition: type.hpp:24
FMM::NETWORK::EdgeIndex
unsigned int EdgeIndex
Edge Index in the network, range from [0,num_edges-1 ].
Definition: type.hpp:26
FMM::CORE::LineString::get_num_points
int get_num_points() const
Get the number of points in a line.
Definition: geometry.hpp:115
FMM::CORE::Point
boost::geometry::model::point< double, 2, boost::geometry::cs::cartesian > Point
Point class.
Definition: geometry.hpp:28
FMM::CORE::LineString::get_y
double get_y(int i) const
Get the y coordinate of i-th point in the line.
Definition: geometry.hpp:55
FMM::CORE::LineString::get_x
double get_x(int i) const
Get the x coordinate of i-th point in the line.
Definition: geometry.hpp:46
FMM::NETWORK::Edge
Road edge class.
Definition: type.hpp:45