见原文,转自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
|
int
aoi_util
::
build_gridindex
(
)
{
// build index for each aoi
for
(
size_t
j
=
0
;
j
<
aois
.
size
(
)
;
++
j
)
{
aoi_index
idx
;
idx
=
j
;
AOI
*
aoi_ptr
=
&aois
[
j
]
;
build_gridindex
(
aoi_ptr
,
idx
)
;
}
return
0
;
}
|
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
|
int
aoi_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
typedef
grid_index
::
iterator
grid_map_it
;
for
(
size_t
a
=
size_t
(
min_x
/
mesh_size
)
;
a
<=
size_t
(
max_x
/
mesh_size
)
;
a
++
)
{
for
(
size_t
b
=
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
)
;
}
}
}
return
0
;
}
|
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_t
x
,
ll_t
y
)
{
uint32_t
mesh_id
=
get_id_by_xy
(
x
,
y
)
;
typedef
grid_index
::
const_iterator
grid_map_it
;
typedef
index_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
)
)
{
return
aoi_i
;
}
}
}
return
NULL
;
}
|
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
|
bool
AOI
::
is_point_inside
(
ll_t
x
,
ll_t
y
)
{
typedef
vertexes_t
::
iterator
v_iterator
;
v_iterator
it
,
pre_it
;
bool
oddNodes
=
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
;
}
return
oddNodes
;
}
|
4,剩余的一些代码,如如何对grid去hash值,可以自己去实现,贴上我们的实现,仅作参考:
1
2
3
4
|
uint32_t
aoi_util
::
get_id_by_grid
(
uint32_t
a
,
uint32_t
b
)
{
return
(
(
a
&
0xffff
)
<<
16
)
|
(
b
&
0xffff
)
;
}
|