美文网首页基于Android的出租车拼车系统
R树建立路网索引(附代码)

R树建立路网索引(附代码)

作者: peng_you | 来源:发表于2018-06-10 20:06 被阅读7次

    R树作为一种可以存储高维数据的数据结构,在时空数据挖掘和空间信息存储方面得到了广泛的应用,在这里我将介绍如何利用R树建立路网的空间索引,并进行测试。

    首先我们必须准备数据,才能开始实验,这里选取的是北京市的路网数据:路网数据如何提取请参考我的这篇文章:

    提取shapefile文件的路网信息

    在这个文章的工作中,我已经完成了对路网信息的提取

    1.在实现R树的建立之前,我们首先必须得知道R树的基本知识,有关R树的详细信息,许多博客都写的非常详细,我推荐这篇文章:R树详解 

    里面详细的讲述了R树的知识。

    但是他博客中提及的伪代码可能大家不太好理解,这里我融合自己的理解,在他的基础上,对他所提及的插入和查询算法伪代码做了补充,并和本项目中R树路网建立的特点做了少许注释

    这里先结合本项目的特点针对性的做简述:

    1.是一种和B树结构类似,存储高维数据的结构;

    2.从下往上看,R树的叶子结点存储的是数据的最小边界矩阵的索引,而他们的父亲结点又为包含叶子结点的最小边界矩阵,以此类推,直到根结点;

    注:在本项目中,叶子节点索引为路网中路段

    根结点包括整个北京市路网的几个矩阵

    一下是插入和查询的伪代码:

    ##插入

    ```

    先定义两个辅助函数:

    1.choose_leaf:

    描述:用来帮助插入新记录时找到插入位置

    输入:新的记录E,根结点T

    输出:一个叶子节点

    If T为叶子节点:返回T

    Else 遍历T节点上的所有矩阵条目X,找到添加E扩张最小的条目,然后设T为X的孩子结点继续执行choose_leaf

    2.adjustTree

    描述:叶子结点的改变向上传递至根结点;

    输入:新的记录E,结点L

    输出:已经调整好各个条目矩阵大小的R树

    Step1:设N为L,如果原结点已经分裂为L和LL,则设NN为LL

    Step2:若N为根结点,返回R树

    Step3:调整N的父亲结点P对应的最小边界矩阵,使其正好覆盖N中所有条目

    Step4:如果传递产生了分裂结点LL,则新建一个条目,为覆盖LL的最小边界矩阵,若P结点能够容纳LL,则加入大P中,反之,对P执行分裂操作,产生P和PP

    Step5:设N为P,若在step4中执行了分裂操作,则设NN为PP,然后,从step2开始再次执行函数(递归)

    然后是主算法:

    函数:Insert

    输入:插入的新记录E,R树

    输出:更新后的R树

    I1:对于给定E,调用choose_leaf找到插入的叶子结点L;

    I2:如果L仍有空间,则将E插入进去,如果没有,还要

    进行分裂操作得到L和LL

    I3:对I2中得到结点进行adjust操作,如果分裂了,LL也

    要进行adjust操作

    I4:如果分裂操作导致根结点分裂,则新建一个根结点,

    包含之前的所有结点

    ```

    ##搜索

    ```

    函数:InterSection

    描述:对给的范围,返回该范围内的所有路网索引

    输入:一个查找矩阵X,R树根结点T

    输出:X覆盖的所有记录

    If T

    是叶子节点:

      then:直接查询X覆盖的所有记录,并返回

    Else T是非叶子节点:

      then:对于该结点上的所有条目,对它们

      的孩子进行InterSection操作

    End

    if

    ```

    2.在基本的理论知识了解以后就是实际的操作过程了,在这里我把过程分为以下四步:

    1.建立R树索引文件Rtree.dat和Rtree.idx

    2.利用python的pickle库将路网信息用一个列表储存并序列化到磁盘上形成AllData文件

    3.打开Rtree,Alldata文件并以路段的最小边界矩阵作为依据,将每条路段索引依次插入到R树中

    4.代码的测试:输入给定坐标x,y,以及范围t,调用InterSection搜索函数,得到查询矩阵[x-t,y-t,x+t,y+t],构建小范围路网(模拟在线匹配中拼车用户发出请求,在一定范围内建立路网的情况)。

    5.对2中的省道路网数据和4中查询到的数据做可视化处理验证准确性

    1-4步骤的代码如下:

    ```

    import shapefile

    import csv

    from rtree import index

    dirname = 'F:/carpool_item/Beijing/xydata/AllData.csv'

    rtreename = 'F:/carpool_item/Beijing/xydata/Rtree'

    fileNames = {'城市快速路': 'F:/carpool_item/Beijing/城市快速路_polyline.shp',\

                '高速': 'F:/carpool_item/Beijing/高速_polyline.shp',\

                '国道': 'F:/carpool_item/Beijing/国道_polyline.shp',\

                '九级路': 'F:/carpool_item/Beijing/九级路_polyline.shp',\

                '省道': 'F:/carpool_item/Beijing/省道_polyline.shp',\

                '县道': 'F:/carpool_item/Beijing/县道_polyline.shp',\

                '乡镇村道': 'F:/carpool_item/Beijing/乡镇村道_polyline.shp'}

    #处理每种路网

    #write csvfile name

    csvFile = open(dirname,'w',newline = '')

    writer = csv.writer(csvFile)

    name = ['id','roadkind','roadname','bbox','points','other']

    writer.writerow(name)

    #build Rtree

    fileIdx = index.Rtree(rtreename)

    id = 0

    for key,value in fileNames.items():

    #read shapefile

        sf = shapefile.Reader(value)

        shapeRecords = sf.shapeRecords()

    #continue write csvfile and bulid rtree

        for shapeRecord in shapeRecords:

            temp = [str(id),str(key),shapeRecord.record[1],str(shapeRecord.shape.bbox),str(shapeRecord.shape.points)]

            fileIdx.insert(id,shapeRecord.shape.bbox)

            id += 1

            writer.writerow(temp)

    csvFile.close()

    ```

    3.在建立R树索引后,我们还需要通过验证来检测我们的索引文件是否正确,在这里以天安门附近的坐标为中心点,在0.64平方千米的范围内进行路网数据的查询,然后把查询结果可视化,以验证准确性,同样放出验证的程序代码:

    ```

    from rtree import index

    import csv

    import pickle

    backName = 'F:/carpool_item/Beijing/xydata/'

    rtreename = 'F:/carpool_item/Beijing/xydata/Rtree'

    pickleName =  'F:/carpool_item/Beijing/xydata/AllData_pickle.txt'

    fileIdx = index.Rtree(rtreename)

    while 1:

        # autitude = float(input('please input autitude: '))

        # longitude = float(input('please input longitude: '))

        autitude = 116.3974750042

        longitude = 39.9087239839

        if autitude == 0:

            print('exit...')

            break

        xmin = autitude - 0.004

        xmax = autitude + 0.004

        ymin = longitude - 0.004

        ymax = longitude + 0.004

        IdxData = list(fileIdx.intersection((xmin,ymin,xmax,ymax)))

        print(len(IdxData))

        print(IdxData)

    #write csvFile

        csvName = backName + str(autitude) + '_' + str(longitude) + '.csv'

        csvFileW = open(csvName,'w',newline = '')

        writer = csv.writer(csvFileW)

        writer.writerow(['adress','autitude','longitude','phone'])

        file = open(pickleName,'rb')

        reader = pickle.load(file)

        file.close()

        for id in IdxData:

            adress = reader[id + 1][2]

            points = list(eval(str(reader[id + 1][4])))

            for point in points:

                autitude = point[0]

                longitude = point[1]

                temp = [adress,str(autitude),str(longitude),str(id)]

                writer.writerow(temp)

        csvFileW.close()

        break

    ```

    下图是可视化的结果,OK,到这一步就算是结束了;

    可视化图

    相关文章

      网友评论

      • 并不想起昵称:讲真技术博客还是用自己搭的网站或者csdn会好看一些
        peng_you:以前搭过一个,不是毕竟不是专业搞前端的很多华丽的东西都不会做,界面也是丑的很啊。
        peng_you:hh,问题是我现在忙得很,都没时间写博客了

      本文标题:R树建立路网索引(附代码)

      本文链接:https://www.haomeiwen.com/subject/lfrqeftx.html