建立网格索引(代码)
见原文,转自http://longriver.me/?p=355
-
空间检索中网格索引的引入
-
网页的检索需要对每篇文档建立倒排索引,空间检索中,需要对每个地域建立网格索引。
-
简单说就是要将地域划分成一个个的网格(mesh),每个网格有个单独的id,唯一标示,利用局部性原理,给出一个点,检索附近的点的时候,只需要计算相邻网格中的点,省去了全局的计算。图1 给出了网格的示例
-
一般会应用场景是,给定一个点,计算器最近邻的几个地点,或者是判断一个坐标点是否落在一个区域内
-
图1,将一个地域划分为网格,并给每个网格唯一id
图2,AOI:圆明园,天安门,森林公园
假设一种空间检索的应用场景,现在有一堆面状的区域,我们知道这些面状区域(AOI area of interest)的轮廓如图2,我们有一些坐标点,那么如何判断这些坐标点是否落在aoi里,落到了哪个区域里呢?
完成这项工作,需要三步:
- 1,为面状区域制作索引,不要求很精确
- 2,求出每个检索点落在那个网格中
- 3,判断检索点是否落在AOI中(判断点是否在一个多边形中)
1.为面状区域建立索引
1
2
3
4
5
6
7
8
9
10
11
|
intaoi_util::build_gridindex()
{
// build index for each aoi
for(size_tj=0;j<aois.size();++j){
aoi_index idx;
idx=j;
AOI*aoi_ptr=&aois[j];
build_gridindex(aoi_ptr,idx);
}
return0;
}
|
Mesh_size 可以根据一共检索区域的大小来进行设定,在我们的应用场景下设为1000,指每个网格的大小为1000m。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
intaoi_util::build_gridindex(AOI *aoi_ptr,aoi_index idx)
{
ll_t min_x,min_y,max_x,max_y;
//get every aoi's leftmost rightmost ,ceiling,bottom
min_x=aoi_ptr->min_boundx();
min_y=aoi_ptr->min_boundy();
max_x=aoi_ptr->max_boundx();
max_y=aoi_ptr->max_boundy();
// get every grid id
typedefgrid_index::iterator grid_map_it;
for(size_ta=size_t(min_x/mesh_size);a<=size_t(max_x/mesh_size);a++){
for(size_tb=size_t(min_y/mesh_size);b<=size_t(max_y/mesh_size);b++){
uint32_t id=get_id_by_grid(a,b);
grid_map_it it=grid2index.find(id);
if(it==grid2index.end()){
index_value idx_vl;
idx_vl.push_back(idx);
// each grid may have more than one aoi
grid2index.insert(std::pair<uint32_t,index_value>(id,idx_vl));
}else{
it->second.push_back(idx);
}
}
}
return0;
}
|
2,为每个检索点找到所在的mesh 和每个mesh中的aoi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
AOI*aoi_util::get_aoi_for_point(ll_tx,ll_ty)
{
uint32_t mesh_id=get_id_by_xy(x,y);
typedefgrid_index::const_iterator grid_map_it;
typedefindex_value::iterator index_value_it;
index_value idx_list;
grid_map_it it=grid2index.find(mesh_id);
if(it!=grid2index.end()){
idx_list =it->second;
for(index_value_it iv_it=idx_list.begin();iv_it!=idx_list.end();++iv_it){
aoi_index idx= *iv_it;
AOI *aoi_i=&(aois[idx]);
// determine if poinxy in this aoi
if(aoi_i->is_point_inside(x,y)){
returnaoi_i;
}
}
}
returnNULL;
}
|
3,判断一个point 是否在aoi里面,一个aoi其本质上是一个多边形,由顶点描述,因此现在有很多现成的算法讲如何判断一个点是否落在多边形中,参照这边博文http://alienryderflex.com/polygon/讲的非常详细,代码实现如下,具体原理,请阅读博文。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
boolAOI::is_point_inside(ll_tx,ll_ty)
{
typedefvertexes_t::iterator v_iterator;
v_iterator it,pre_it;
booloddNodes=0;
// vertexes are polygon’s vertexes vector
it=pre_it=vertexes.begin();
for(;it!=vertexes.end();++it)
{
if((it->second<y&&pre_it->second>=y)
||(pre_it->second<y&&it->second>=y)
&&(it->first<=x||it->second<=x)){
oddNodes^=(it->first+(y-it->second)/(pre_it->second-it->second)\
*(pre_it->first-it->first)<x);
}
pre_it=it;
}
returnoddNodes;
}
|
4,剩余的一些代码,如如何对grid去hash值,可以自己去实现,贴上我们的实现,仅作参考:
1
2
3
4
|
uint32_t aoi_util::get_id_by_grid(uint32_ta,uint32_tb)
{
return((a&0xffff)<<16)|(b&0xffff);
}
|
posted on 2014-03-26 21:36 Harveyaot 阅读(3236) 评论(0) 编辑 收藏 举报