空间索引技术的核心是:根据搜索条件,比如一个矩形,迅速找到与该矩形相交的所有空间对象集合。当数据量巨大,矩形框相对于全图很小时,这个集合相对于全图数据集大为缩小,在这个缩小的集合上再处理各种复杂的搜索,效率就会大大提高。
(1)、四叉树索引
(1)四分区域标识
分别定义了一个平面区域的四个子区域索引号,右上为第一象限0,左上为第二象限1,左下为第三象限2,右下为第四象限3。
typedef enum
{
UR = 0,// UR第一象限
UL = 1, // UL为第二象限
LL = 2, // LL为第三象限
LR = 3 // LR为第四象限
}QuadrantEnum;
(2)空间对象数据结构
空间对象数据结构是对地理空间对象的近似,在空间索引中,相当一部分都是采用MBR作为近似。
/*空间对象MBR信息*/
typedef struct SHPMBRInfo
{
int nID; //空间对象ID号
MapRect Box; //空间对象MBR范围坐标
}SHPMBRInfo;
nID是空间对象的标识号,Box是空间对象的最小外包矩形(MBR)。
(3)四叉树节点数据结构
四叉树节点是四叉树结构的主要组成部分,主要用于存储空间对象的标识号和MBR,也是四叉树算法操作的主要部分。
/*四叉树节点类型结构*/
typedef struct QuadNode
{
MapRect Box; //节点所代表的矩形区域
int nShpCount; //节点所包含的所有空间对象个数
SHPMBRInfo* pShapeObj; //空间对象指针数组
int nChildCount; //子节点个数
QuadNode *children[4]; //指向节点的四个孩子
}QuadNode;
quadtree structure is used to provide a primary filter for range rectangle queries. The query() method returns a list of all objects which may intersect the query rectangle. Note that it may return objects which do not in fact intersect.
四叉树的空间索引结构的二维矩形的高效查询。如果其他类型的空间对象需要被索引他们可以通过自己的最小外包矩形来表示
四叉树结构是用来提供一个初级过滤器为矩形范围查询。在query()方法返回一个可以相交的查询区域内的所有对象的列表。请注意,它可能会返回其实不相交的对象。
public class QuadTreeDemo {
private Quadtree quadTree = new Quadtree();
public void buildQuadTree(){
Envelope enve = new Envelope(0, 1, 0, 1);
Envelope enve1 = new Envelope(0, 1, 0, -1);
Envelope enve2 = new Envelope(0, -2, 0, 2);
Envelope enve3 = new Envelope(0, -3, 0, -3);
quadTree.insert(enve, "first");
quadTree.insert(enve1, "second");
quadTree.insert(enve2, "third");
quadTree.insert(enve3, "fourth");
}
public void query(Envelope enve){
List<String> StrList = quadTree.query(enve);
for(String str:StrList) {
System.out.println(str);
}
}
public static void main(String[] args) {
QuadTreeDemo qd = new QuadTreeDemo();
qd.buildQuadTree();
Envelope enve = new Envelope(0.1, 0.5, 0.1, 0.5);
qd.query(enve);
System.out.println("------分割线--------");
Envelope enve1 = new Envelope(0.5, 0.5, 0.5, -0.5);
qd.query(enve1);
}
}
输出结果:
------分割线--------
second
first
k-d树是一个二叉树,每个节点表示一个空间范围。表1给出的是k-d树每个节点中主要包含的数据结构。
域名 | 数据类型 | 描述 |
Node-data | 数据矢量 | 数据集中某个数据点,是n维矢量(这里也就是k维) |
Range | 空间矢量 | 该节点所代表的空间范围 |
split | 整数 | 垂直于分割超平面的方向轴序号 |
Left | k-d树 | 由位于该节点分割超平面左子空间内所有数据点所构成的k-d树 |
Right | k-d树 | 由位于该节点分割超平面右子空间内所有数据点所构成的k-d树 |
parent | k-d树 | 父节点 |
以上述举的实例来看,过程如下:
由于此例简单,数据维度只有2维,所以可以简单地给x,y两个方向轴编号为0,1,也即split={0,1}。
(1)确定split域的首先该取的值。分别计算x,y方向上数据的方差得知x方向上的方差最大,所以split域值首先取0,也就是x轴方向;
(2)确定Node-data的域值。根据x轴方向的值2,5,9,4,8,7排序选出中值为7,所以Node-data = (7,2)。这样,该节点的分割超平面就是通过(7,2)并垂直于split = 0(x轴)的直线x = 7;
(3)确定左子空间和右子空间。分割超平面x = 7将整个空间分为两部分,如图2所示。x < = 7的部分为左子空间,包含3个节点{(2,3),(5,4),(4,7)};另一部分为右子空间,包含2个节点{(9,6),(8,1)}。
This implementation supports detecting and snapping points which are closer than a given
tolerance value. If the same point (up to tolerance) is inserted more than once a new node is
not created but the count of the existing node is incremented.
public class KDTreeDemo {
private KdTree kdTree = new KdTree();
public void builKDTree(){
Coordinate p1 = new Coordinate(0,0);
Coordinate p2 = new Coordinate(1,1);
Coordinate p3 = new Coordinate(2,2);
Coordinate p4 = new Coordinate(3,3);
Coordinate p5 = new Coordinate(4,4);
Coordinate p6 = new Coordinate(5,5);
kdTree.insert(p1, "first");
kdTree.insert(p2, "second");
kdTree.insert(p3, "third");
kdTree.insert(p4, "fourth");
kdTree.insert(p5, "Fifth");
kdTree.insert(p6, "Sixth");
}
public void query(Envelope enve){
List<KdNode> StrList = kdTree.query(enve);
for(KdNode node:StrList) {
System.out.println(node.getData());
}
}
public static void main(String[] args) {
KDTreeDemo kd = new KDTreeDemo();
kd.builKDTree();
Envelope enve = new Envelope(-1,2,-1,2);
kd.query(enve);
System.out.println("------分割线--------");
Envelope enve1 = new Envelope(2, 4, 2, 4);
kd.query(enve1);
}
}
输出结果:
second
third
------分割线--------
third
fourth
Fifth
搜索算法:
记R树的根节点记为T。搜索算法要求输入一个搜索矩形S,输出所有与S相交的索引记录。
步骤S1:搜索子树——如果T不是一个叶节点,则检查其中的每一个条目E,如果EI与S相交,则对Ep所指向的那个子树根节点调用Search算法。这里注意,Search算法接收的输入为一个根节点,所以在描述算法的时候,原文称对子树根节点调用Search算法,而不是对子树调用Search算法。
步骤S2:搜索叶节点——如果T是一个叶节点,则检查其中的每个条目E,如果EI与S相交,则E就是需要返回的检索结果之一。
public class STRtreeDemo {
private STRtree strTree = new STRtree();
private GeometryFactory gf = new GeometryFactory();
public LineString createLineByWKT(String lineStr)throws ParseException{
WKTReader reader = new WKTReader(gf);
LineString line = (LineString) reader.read(lineStr);
return line;
}
public void buildStrTree() throws ParseException{
strTree.insert(createLineByWKT("LineString(1 1, 2 2,3 0,6 10)").getEnvelopeInternal(), "first");
strTree.insert(createLineByWKT("LineString(0 0, 2 0)").getEnvelopeInternal(), "second");
strTree.insert(createLineByWKT("LineString(-1 1, 2 0)").getEnvelopeInternal(), "third");
strTree.insert(createLineByWKT("LineString(-1 -1, -2 -2)").getEnvelopeInternal(), "fourth");
}
public void query(Envelope enve){
List<String> StrList = strTree.query(enve);
for(String str:StrList) {
System.out.println(str);
}
}
public static void main(String[] args) throws ParseException {
STRtreeDemo qd = new STRtreeDemo();
qd.buildStrTree();
Envelope enve = new Envelope(1, 1.5, 1, 1.5);
qd.query(enve);
System.out.println("------分割线--------");
Envelope enve1 = new Envelope(0.5, 0.5, 0.5, -0.5);
qd.query(enve1);
}
}
输出结果:
first
------分割线--------
second
third
"Sort-Interval-Recursive".
一维版本的STR-压缩的R-树