利用JTS构建R树索引

空间索引(Spatial Indexing)

回忆下数据库最基本的操作:增删改查以及稍复杂些的比如连接操作,基本都需要先锁定数据位置,再执行操作。而定位这个步骤,如果没有index,基本都是O(n)的时间复杂度,这是一个非常“耗时”的操作。“找”这个操作就需要定位。注意这里的定位不再是指在存储器上的位置,而是在空间中的位置,这里的空间,是由数据的维度张成的空间。空间数据,也即是这些拥有多维度的数据。这是空间数据的一个比较延展性的说法。但通常,空间数据都focus on 几何类型数据,比如点,线,面,球等,当然这些点、线都是可以任意维度的。对于空间数据的搜索,我们需要空间索引spatial index来提升搜素效率(速度)。目前主流数据(SQL server,MySQL,PostgreSQL,etc)都已加入了对spatial data的支持,这其中最主要的就是数据类型和索引的支持。

R-tree

MBR

为了统一描述空间类型,比如点,线,面等,Guttman首先提出了MBR的概念,即Minimum Bounding Box。MBR的含义是用一个最小的矩形(通常默认矩形的边平行于坐标轴),来框住这个几何体。


MBR

R-tree

R-tree主要吸纳了B+tree的思想,对数据进行分割。


R-tree

JTS生成R树索引

JTS提供了如下的空间数据类型,还提供了读取各种空间描述文件(WTK等),线简化,空间操作(求交,计算距离,计算外包矩形等),建立空间索引等多种算法。
参考这篇文章:https://blog.csdn.net/wk1134314305/article/details/76408181
引入依赖包:

// Gradle
compile group: 'com.vividsolutions', name: 'jts', version: '1.13'
// Maven
<dependency>
<groupId>com.vividsolutions</groupId>
    <artifactId>jts</artifactId>
    <version>1.13</version>
</dependency>

Geometry类:所有的空间数据类型,点,线,面,多点,环,多边形等等都是继承自Geometry类的。
Envelope类:该类就是描述一个空间几何对象的外包矩形,由max_x,max_y,min_x,min_y组成。

JTS常用的方法,以及R树索引基本使用:

package com.geotools.geotoolsdemo;

import com.vividsolutions.jts.geom.*;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @program: geotoolsdemo
 * @description: JTS导入使用
 * @author: zhudan
 * @create: 2020/7/3 11:39
 */
@Component
public class GeometryDemo {
    //使用JTS的GeometryFactory来创建Geometry对象
    @Autowired
    private GeometryFactory geometryFactory = new GeometryFactory();

    /**
     * @Description: 创建一个点
     * @return: com.vividsolutions.jts.geom.Point
     */
    public Point createPoint() {
        Coordinate coord = new Coordinate(118.798128, 31.968592);
        Point point = geometryFactory.createPoint(coord);
        return point;
    }

    /**
     * @Description: 从WKT创建一个点,WKT字符串创建 ,WKT字符串是SQL标准定义的一个实现
     * @return: com.vividsolutions.jts.geom.Point
     */
    public Point createPointByWKT() throws ParseException {
        WKTReader reader = new WKTReader(geometryFactory);
        Point point = (Point) reader.read("POINT (118.798128 31.968592)");
        return point;
    }

    /**
     * @Description: 从WKT创建多个点
     * @return: com.vividsolutions.jts.geom.MultiPoint
     */
    @Autowired
    public MultiPoint createMulPointByWKT(String wellKnownText) throws ParseException {
        WKTReader reader = new WKTReader(geometryFactory);
//        MultiPoint mpoint = (MultiPoint) reader.read("MULTIPOINT(119.013388 31.715519, 119.32488 31.435678)");
        MultiPoint mpoint = (MultiPoint) reader.read(wellKnownText);
        return mpoint;
    }

    /**
     * @Description: create a line
     * @return: com.vividsolutions.jts.geom.LineString
     */
    public LineString createLine() {
        Coordinate[] coords = new Coordinate[]{new Coordinate(119.013388, 31.715519), new Coordinate(119.32488, 31.435678)};
        LineString line = geometryFactory.createLineString(coords);
        return line;
    }

    /**
     * @Description: create a line by WKT
     * @return: com.vividsolutions.jts.geom.LineString
     */
    public LineString createLineByWKT() throws ParseException {
        WKTReader reader = new WKTReader(geometryFactory);
        LineString line = (LineString) reader.read("LINESTRING(119.013388 31.715519, 119.32488 31.435678)");
        return line;
    }

    /**
     * @Description: create multiLine
     * @return: com.vividsolutions.jts.geom.MultiLineString
     */
    public MultiLineString createMLine() {
        Coordinate[] coords1 = new Coordinate[]{new Coordinate(119.013388, 31.715519), new Coordinate(119.32488, 31.435678)};
        LineString line1 = geometryFactory.createLineString(coords1);
        Coordinate[] coords2 = new Coordinate[]{new Coordinate(118.797499, 32.087104), new Coordinate(118.798128, 31.968592)};
        LineString line2 = geometryFactory.createLineString(coords2);
        LineString[] lineStrings = new LineString[2];
        lineStrings[0] = line1;
        lineStrings[1] = line2;
        MultiLineString ms = geometryFactory.createMultiLineString(lineStrings);
        return ms;
    }

    /**
     * @Description: create multiLine by WKT
     * @return: com.vividsolutions.jts.geom.MultiLineString
     */
    public MultiLineString createMLineByWKT() throws ParseException {
        WKTReader reader = new WKTReader(geometryFactory);
        MultiLineString line = (MultiLineString) reader.read("MULTILINESTRING((119.013388 31.715519, 119.32488 31.435678),(118.797499 32.087104,118.798128 31.968592))");
        return line;
    }

    /**
     * @Description: create a polygon(多边形)
     * @return:
     */
    public Polygon createPolygon() {
        Coordinate[] coords = new Coordinate[]{new Coordinate(20, 10), new Coordinate(30, 0), new Coordinate(40, 10),
                new Coordinate(30, 20), new Coordinate(20, 10)};
        Polygon polygon = geometryFactory.createPolygon(coords);
        return polygon;
    }

    /**
     * @Description: create a polygon(多边形) by WKT
     * @return:
     */
    public Polygon createPolygonByWKT() throws ParseException {
        WKTReader reader = new WKTReader(geometryFactory);
        Polygon polygon = (Polygon) reader.read("POLYGON((20 10, 30 0, 40 10, 30 20, 20 10))");
        return polygon;
    }

    /**
     * @Description: create multi polygon(多边形) by WKT
     * @return:
     */
    public MultiPolygon createMulPolygonByWKT() throws ParseException {
        WKTReader reader = new WKTReader(geometryFactory);
        MultiPolygon mpolygon = (MultiPolygon) reader.read("MULTIPOLYGON(((40 10, 30 0, 40 10, 30 20, 40 10),(30 10, 30 0, 40 10, 30 20, 30 10)))");
        return mpolygon;
    }

    /**
     * @Description: create GeometryCollection  contain point or multiPoint or line or multiLine or polygon or multiPolygon
     * @return: com.vividsolutions.jts.geom.GeometryCollection
     */
    public GeometryCollection createGeoCollect() throws ParseException {
        LineString line = createLine();
        Polygon poly = createPolygonByWKT();
        Geometry g1 = geometryFactory.createGeometry(line);
        Geometry g2 = geometryFactory.createGeometry(poly);
        Geometry[] garray = new Geometry[]{g1, g2};
        GeometryCollection gc = geometryFactory.createGeometryCollection(garray);
        return gc;
    }

    /**
     * create a Circle  创建一个圆,圆心(x,y) 半径RADIUS
     *
     * @param x
     * @param y
     * @param RADIUS
     * @return
     */
    public Polygon createCircle(double x, double y, final double RADIUS) {
        final int SIDES = 32;//圆上面的点个数
        Coordinate coords[] = new Coordinate[SIDES + 1];
        for (int i = 0; i < SIDES; i++) {
            double angle = ((double) i / (double) SIDES) * Math.PI * 2.0;
            double dx = Math.cos(angle) * RADIUS;
            double dy = Math.sin(angle) * RADIUS;
            coords[i] = new Coordinate((double) x + dx, (double) y + dy);
        }
        coords[SIDES] = coords[0];
        LinearRing ring = geometryFactory.createLinearRing(coords);
        Polygon polygon = geometryFactory.createPolygon(ring, null);
        return polygon;
    }

    /**
     * @param args
     * @throws ParseException
     */
    public static void main(String[] args) throws ParseException {
        GeometryDemo gt = new GeometryDemo();
        Polygon p1 = gt.createCircle(0, 1, 2);
        //圆上所有的坐标(32个)
//        Coordinate coords[] = p1.getCoordinates();
//        for (Coordinate coord : coords) {
//            System.out.println(coord.x + "," + coord.y);
//        }

        Polygon p2 = gt.createCircle(1, 0, 2);
        STRtree stRtree = new STRtree();
        stRtree.insert(p1.getEnvelopeInternal(), p1);
        stRtree.insert(p2.getEnvelopeInternal(), p2);

        List results = stRtree.query(new Envelope(0, 0, 0, 0));
        for (int i = 0; i < results.size(); i++) {
            System.out.println(results.get(i));
        }
    }
}

参考:
https://zhuanlan.zhihu.com/p/38597148
https://blog.csdn.net/wk1134314305/article/details/76408181

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,692评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,482评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,995评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,223评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,245评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,208评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,091评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,929评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,346评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,570评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,739评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,437评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,037评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,677评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,833评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,760评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,647评论 2 354