建立网格索引(代码)
见原文,转自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); 
} 
 | 
                    
                

                
            
        
浙公网安备 33010602011771号