高考报名时间2022年11月1日还剩 天 距离2023年6月7日高考还有
网站导航
当前位置: 首页 IT 软件开发 后端开发 Java

JTS使用实践

由网友 None 发布 阅读 17950

文章目录JTS使用实践一、前言简介环境二、正文基础说明使用记录创建几何要素操作示例JTS使用实践一、前言简介JTSTopologySuite是一个开源的Java软件库,它为欧几里得平面线性几何提供了一个对象模型以及一组基本的几何函数。

文章目录JTS使用实践一、前言简介环境二、正文基础说明使用记录创建几何要素操作示例JTS使用实践一、前言简介JTSTopologySuite是一个开源的Java软件库,它为欧几里得平面线性几何提供了一个对象模型以及一组基本的几何函数。

文章目录
  • JTS使用实践
  • 一、前言
    • 简介
    • 环境
  • 二、正文
    • 基础说明
    • 使用记录
      • 创建几何要素
      • 操作示例
JTS使用实践 一、前言 简介

JTS Topology Suite(Java Topology Suite)是一个开源的Java软件库,它为欧几里得平面线性几何提供了一个对象模型以及一组基本的几何函数。

环境
  • 开发工具:IntelliJ IDEA
  • JDK:1.8

locationtech(JTS):https://locationtech.github.io/jts/

JTS 特性:https://locationtech.github.io/jts/jts-features.html

GitHub(JTS):https://github.com/locationtech/jts

JTS java doc:http://locationtech.github.io/jts/javadoc/overview-summary.html

GeoTools(JTS):https://docs.geotools.org/latest/userguide/library/jts/index.html

wikipedia(JTS):https://en.wikipedia.org/wiki/JTS_Topology_Suite

wikipedia(WKT):https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry

PostGIS 拓扑关系:https://postgis.net/docs/reference.html#idm15481

polygon 和 multipolygon 的区别:https://gis.stackexchange.com/questions/225368/understanding-difference-between-polygon-and-multipolygon-for-shapefiles-in-qgis/225373

二、正文 基础说明
  • 输入/输出格式:WKT、WKB、GML、Java Swing/AWT Shape
  • WKT 格式
几何类型WKT
PointPOINT (30 10)
LineStringLINESTRING (30 10, 10 30, 40 40)
PolygonPOLYGON ((35 10, 45 45, 15 40, 10 20, 35 10),(20 30, 35 35, 30 20, 20 30))
Polygon-with-holePOLYGON ((35 10, 45 45, 15 40, 10 20, 35 10), (20 30, 35 35, 30 20, 20 30))
MultiPointMULTIPOINT ((10 40), (40 30), (20 20), (30 10))
MultiPointMULTIPOINT (10 40, 40 30, 20 20, 30 10)
MultiLineStringMULTILINESTRING ((10 10, 20 20, 10 40),(40 40, 30 30, 40 20, 30 10))
MultiPolygonMULTIPOLYGON (((30 20, 45 40, 10 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5)))
MultiPolygon-with-holeMULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)), ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (30 20, 20 15, 20 25, 30 20)))
GeometryCollectionGEOMETRYCOLLECTION (POINT (40 10), LINESTRING (10 10, 20 20, 10 40), POLYGON ((40 40, 20 45, 45 30, 40 40)))
  • 拓扑关系
关键字说明参考
equals (相等)如果两个几何在空间中包含相同的一组点,则返回 trueST_Equals
disjoint(不相交)如果两个几何在空间上不相交(它们没有共同点),则返回 trueST_Disjoint
intersects(相交)如果两个几何/地理在 2D 空间上相交(至少有一个共同点),则返回 trueST_Intersects
touches(接触)如果两个几何体至少有一个共同点,但它们的内部不相交,则返回 trueST_Touches
crosses(交叉)如果两个几何具有一些(但不是全部)共同的内部点,则返回 trueST_Crosses
within(内含)如果几何 A 完全在几何 B 内部,则返回 trueST_Within
contains (包含)当且仅当 B 的任何点都不在 A 的外部,并且 B 内部的至少一个点在 A 的内部时,才返回 trueST_Contains
overlaps(重叠)如果两个几何体相交并具有相同的维度,但彼此不完全包含,则返回 trueST_Overlaps
  • 叠加分析
关键字说明参考
buffer(缓冲区)返回一个几何图形,该几何图形涵盖距几何图形给定距离内的所有点ST_Buffer
convexHull(凸壳)计算几何的凸壳ST_ConvexHull
intersection(交集)返回表示几何 A 和 B 共享部分的几何ST_Intersection
union(合并)返回表示输入几何的点集合并的几何ST_Union
difference(差异)返回表示几何 A 中不与几何 B 相交的部分的几何ST_Difference
symDifference(对称差异)返回表示几何 A 和 B 不相交部分的几何ST_SymDifference
使用记录
  • 添加依赖


    org.locationtech.jts
    jts-core
    1.18.2

创建几何要素
package com.example;

import org.locationtech.jts.geom.*;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKTReader;
import java.util.List;
import java.util.Map;


public class JTSGeometryUtil {

    // 几何工厂对象
    private GeometryFactory geometryFactory = new GeometryFactory();

    
    public Point getPoint(Double lng, Double lat){
        Coordinate coordinate = new Coordinate(lng, lat);
        return geometryFactory.createPoint(coordinate);
    }

    
    public Point getPointByWKT(Double lng, Double lat) throws ParseException {
        StringBuilder wktSB = new StringBuilder();
        // POINT(111 22)
        wktSB.append("POINT").append("(").append( lng ).append(" ").append( lat ).append(")");
        return (Point) createGeometry(wktSB.toString());
    }

    
    public MultiPoint getMultiPoint(Coordinate [] coordinates){
        return geometryFactory.createMultiPointFromCoords(coordinates);
    }

    
    public MultiPoint getMultiPointByWKT(Coordinate [] coordinates) throws ParseException {
        // MULTIPOINT(111 22 ,111 22)
        String wktStr = createWktString("MULTIPOINT", coordinates);
        return (MultiPoint) createGeometry(wktStr);
    }

    
    public LineString getLineString(Coordinate [] coordinates){
        return geometryFactory.createLineString(coordinates);
    }

    
    public LineString getLineStringByWKT(Coordinate [] coordinates) throws ParseException {
        String wktStr = createWktString("LINESTRING", coordinates);
        return (LineString) createGeometry(wktStr);
    }

    
    public MultiLineString getMultiLineString(List coordList){
        LineString [] lineStrings = new LineString[coordList.size()];
        for(int m=0; m
            lineStrings[m] = getLineString(coordList.get(m));
        }
        return geometryFactory.createMultiLineString(lineStrings);
    }

    
    public MultiLineString getMultiLineStringByWKT(List coordList) throws ParseException {
        String wktStr = createMultiWktString("MULTILINESTRING", coordList);
        return (MultiLineString) createGeometry(wktStr);
    }

    
    public Polygon getPolygon(Coordinate [] coordinates){
        return geometryFactory.createPolygon(coordinates);
    }

    
    public Polygon getPolygon(Coordinate [] shellCoordinates, List holeCoordList){
        LinearRing shell = geometryFactory.createLinearRing(shellCoordinates);
        LinearRing[] holes = new LinearRing[holeCoordList.size()];
        for(int m=0; m
            Coordinate [] holeCoordinates = holeCoordList.get(m);
            holes[m] = geometryFactory.createLinearRing(holeCoordinates);
        }
        return geometryFactory.createPolygon(shell, holes);
    }

    
    public Polygon getPolygonByWKT(Coordinate [] coordinates) throws ParseException {
        String wktStr = createWktStringWithPolygon("POLYGON", coordinates, null);
        return (Polygon) createGeometry(wktStr);
    }

    
    public Polygon getPolygonByWKT(Coordinate [] shellCoordinates, List holeCoordList) throws ParseException {
        String wktStr = createWktStringWithPolygon("POLYGON", shellCoordinates, holeCoordList);
        return (Polygon) createGeometry(wktStr);
    }

    
    public MultiPolygon getMultiPolygon(List coordList){
        Polygon [] polygons = new Polygon[ coordList.size() ];
        for(int i=0; i
            polygons[i] = geometryFactory.createPolygon(coordList.get(i));
        }
        return geometryFactory.createMultiPolygon(polygons);
    }

    
    public MultiPolygon getMultiPolygon(Map> coordinateMap){
        Polygon [] polygons = new Polygon[ coordinateMap.size() ];
        int index = 0;
        for(Map.Entry> item : coordinateMap.entrySet()){
            LinearRing shell = geometryFactory.createLinearRing(item.getKey()); // 面边界
            LinearRing[] holes = new LinearRing[item.getValue().size()]; // 孔洞
            for(int m=0; m
                Coordinate [] holeCoordinates = item.getValue().get(m);
                holes[m] = geometryFactory.createLinearRing(holeCoordinates);
            }
            polygons[index] = geometryFactory.createPolygon(shell, holes);
            index++;
        }
        return geometryFactory.createMultiPolygon(polygons);
    }

    
    public MultiPolygon getMultiPolygonByWKT(List coordList) throws ParseException {
        StringBuilder wktSB = new StringBuilder();
        wktSB.append("MULTIPOLYGON").append("(");
        int index = 0;
        for(Coordinate [] coordinates : coordList){
            if(index > 0) { wktSB.append(","); }
            // 1. 处理面边界
            wktSB.append("(");
            wktSB.append("("); // 面边界start
            wktSB.append(coordinatesToWktStr(coordinates));
            wktSB.append(")"); // 面边界end
            wktSB.append(")");
            index++;
        }
        wktSB.append(")");
        return (MultiPolygon) createGeometry(wktSB.toString());
    }

    
    public MultiPolygon getMultiPolygonByWKT(Map> coordinateMap) throws ParseException {
        StringBuilder wktSB = new StringBuilder();
        wktSB.append("MULTIPOLYGON").append("(");
        int index = 0;
        for(Map.Entry> item : coordinateMap.entrySet()){
            Coordinate [] shellCoordinates = item.getKey();
            List holeCoordList = item.getValue();
            if(index > 0) { wktSB.append(","); }
            wktSB.append("(");
            wktSB.append(coordinatesToWktStr(shellCoordinates, holeCoordList));
            wktSB.append(")");
            index++;
        }
        wktSB.append(")");
        return (MultiPolygon) createGeometry(wktSB.toString());
    }

    
    public Polygon getCircle(double lng, double lat, final double radius) {
        final int arcs = 32; // 弧线点数量
        Coordinate coords[] = new Coordinate[ arcs + 1 ];
        for (int i = 0; i < arcs; i++) { // 角度转弧度计算
            double angle = ((double) i / (double) arcs) * Math.PI * 2.0;
            double dx = Math.cos(angle) * radius;
            double dy = Math.sin(angle) * radius;
            coords[i] = new Coordinate((double) lng + dx, (double) lat + dy);
        }
        coords[arcs] = coords[0]; // 将第一个数据放在最后,形成闭环
        LinearRing ring = geometryFactory.createLinearRing(coords); // 圆环线
        Polygon polygon = geometryFactory.createPolygon(ring, null);
        return polygon;
    }

    
    public Geometry createGeometry(String wktStr) throws ParseException {
        WKTReader wktReader = new WKTReader(geometryFactory);
        return wktReader.read(wktStr);
    }

    
    public String createWktString(String geomType, Coordinate [] coordinates){
        StringBuilder wktSB = new StringBuilder();
        wktSB.append(geomType).append("(");
        wktSB.append(coordinatesToWktStr(coordinates));
        wktSB.append(")");
        return wktSB.toString();
    }

    
    private String coordinatesToWktStr(Coordinate [] coordinates){
        StringBuilder wktSB = new StringBuilder();
        for(int i=0; i
            Coordinate coordinate = coordinates[i];
            wktSB.append( coordinate.getX() ).append(" ").append( coordinate.getY() );
            if(coordinates.length-1 != i){ wktSB.append(","); } // 最后一个坐标不需要加逗号
        }
        return wktSB.toString();
    }

    
    private String coordinatesToWktStr(Coordinate [] shellCoordinates, List holeCoordList){
        StringBuilder wktSB = new StringBuilder();
        // 1. 处理面边界
        wktSB.append("("); // 面边界start
        wktSB.append(coordinatesToWktStr(shellCoordinates));
        wktSB.append(")"); // 面边界end
        // 2. 处理多个孔洞
        if(holeCoordList != null && holeCoordList.size() > 0){
            for(int n=0; n
                Coordinate [] holeCoordinates = holeCoordList.get(n);
                wktSB.append(",");
                wktSB.append("("); // 面边界start
                wktSB.append(coordinatesToWktStr(holeCoordinates));
                wktSB.append(")"); // 面边界end
            }
        }
        return wktSB.toString();
    }

    
    public String createMultiWktString(String geomType, List coordList){
        StringBuilder wktSB = new StringBuilder();
        wktSB.append(geomType).append("(");
        for(int m=0; m
            Coordinate [] coordinates = coordList.get(m);
            wktSB.append("(");
            for(int n=0; n
                Coordinate coordinate = coordinates[n];
                wktSB.append( coordinate.getX() ).append(" ").append( coordinate.getY() );
                if(coordinates.length-1 != n){ wktSB.append(","); } // 最后一个坐标不需要加逗号
            }
            wktSB.append(")");
            if(coordList.size()-1 != m){ wktSB.append(","); } // 最后一个坐标不需要加逗号
        }
        wktSB.append(")");
        return wktSB.toString();
    }

    
    public String createWktStringWithPolygon(String geomType, Coordinate [] shellCoordinates, List holeCoordList){
        StringBuilder wktSB = new StringBuilder();
        wktSB.append(geomType).append("(");
        wktSB.append(coordinatesToWktStr(shellCoordinates, holeCoordList));
        wktSB.append(")");
        return wktSB.toString();
    }
}
操作示例
package com.example;

import org.locationtech.jts.geom.*;

public class App
{
    public static void main( String[] args )
    {
        App app = new App();
        // 拓扑关系 contains
        app.doContains();

        // 叠加分析 intersection
        app.doIntersection();
    }

    private JTSGeometryUtil jtsGeometryUtil = new JTSGeometryUtil();

    
    public void doContains(){
        // 点
        Point point = jtsGeometryUtil.getPoint(116.403406,39.93397);
        // 面
        Coordinate[] coordinates = new Coordinate[4];
        coordinates[0] = new Coordinate(116.361725,39.95676); // 首尾坐标相同
        coordinates[1] = new Coordinate(116.364887,39.908515);
        coordinates[2] = new Coordinate(116.442501,39.909622);
        coordinates[2] = new Coordinate(116.440488,39.955654);
        coordinates[3] = new Coordinate(116.361725,39.95676); // 首尾坐标相同
        Polygon polygon = jtsGeometryUtil.getPolygon(coordinates);
        // 操作
        boolean result = polygon.contains(point);
        System.out.println(result);
    }

    
    public void doIntersection(){
        // 线一
        Coordinate [] coordinates1 = new Coordinate[2];
        coordinates1[0] = new Coordinate(116.361725,39.95676);
        coordinates1[1] = new Coordinate(116.442501,39.909622);
        LineString lineString1 = jtsGeometryUtil.getLineString(coordinates1);
        // 线二
        Coordinate [] coordinates2 = new Coordinate[2];
        coordinates2[0] = new Coordinate(116.364887,39.908515);
        coordinates2[1] = new Coordinate(116.440488,39.955654);
        LineString lineString2 = jtsGeometryUtil.getLineString(coordinates2);
        // 操作
        Geometry geometry =  lineString1.intersection(lineString2);
        System.out.println(geometry);
    }
}

没有了 没有了

最新更新

  • java超详细:判断一个数字是不是素数进阶方法2024-01-13
  • 1265. 逆序打印不可变链表2024-01-13
  • java的图标及由来2024-01-13
  • JAVA调用自己写的包2024-01-13
  • “秒杀系统优化思路” 记录2024-01-13
  • springboot6==springboot前后端分离demo,图片前端上传,后端下载保存到本机2024-01-13
  • 瑞吉外卖项目流程-开发环境搭建(maven项目搭建)2024-01-13
  • springboot整合websocket后运行测试类报错:javax.websocket.server.ServerContainer not available2024-01-13
  • Spring security实现对账户进行加密2024-01-13
  • Java面试——JVM虚拟机2024-01-13
  • jvm类加载器 实践(jvm类加载器有哪些)2024-01-13
  • Annual salary30W+Java开发工程师——3.数组2024-01-13
  • mybatis查询之bind标签2024-01-13
  • Java并发编程知识导航2024-01-13
  • MongoDB(三)SpringBoot整合MongoDB,使用MongoRepository和MongoTemplate2024-01-13
  • 关于前端跨域的一个奇妙问题2024-01-13
  • 关于C#入门学习2024-01-13
  • 爪哇基础知识点的运用实例----简易超市购物系统2024-01-13
  • Spring 注解2024-01-13
  • JMeter业务实现3:排查javax.net.ssl.SSLException: No PrivateKey found for alias:‘xxx‘问题2024-01-13
  • 突破Java面试(9)-如何保证消息队列的顺序性2024-01-13
  • Kafka 生产者数据安全(ACK机制,ACK时机,ACK应答机制,故障处理,Exactly Once)2024-01-13
  • java fx 增删改查2024-01-12
  • java数组排序示例分享2024-01-12
  • Git入门2024-01-12
  • 从字节码角度解释i++和++i2024-01-12
  • 「重磅」Idea插件-Maven360功能亮眼-Bg-BoomV1.0.2发布2024-01-12
  • maven 配置阿里云镜像2024-01-12
  • mybatis-plus EnumTypeHandler映射到错误的枚举类型2024-01-12
  • Servlet之过滤器2024-01-12

全站最新

  • 阅读下面的文言文,完成小题朱云,字游,鲁人也,徙平陵。少时通轻侠,借客报仇。长八尺余,容貌甚壮,以勇力闻。年四十,乃变节从博士白子友受《易》,又事前将
  • 发现美
  • 下列是小思平时用来调节情绪的一些做法,不可取的是A.与同学发生误会争执时,用幽默的语音化解僵局,平息怒气B.考试失利的时候,把试卷撕得粉碎,发泄心中的不快C
  • 2023考研法硕:从犯的特征及认定
  • 司法廉洁教育心得体会:廉洁司法 始于正心
  • 瑞巴派特联合雷贝拉唑三联疗法治疗Hp感染相关性消化性溃疡的效果观察
  • 企业采用权益法核算长期股权投资,被投资单位宣告分派股票股利,投资企业应进行的账务处理为( )
  • 播音主持艺考男生要画眼线吗
  • flask中的wtforms使用方法
  • 2023山西工程技术学院在四川招生人数、录取分数线、位次(文科+理科)
  • 详解探码Dyson大数据采集系统功能
  • 成长的记忆
  • 20世纪50年代,我国发生的下列事件中,未改变生产资料私有制的是 [ ]A.农业合作化运动 B.没收官僚资本企业C.土地改革运动
  • 成都纺织高等专科学校产品设计
  • 《假如给我三天光明》读后感

本类最新

  • java超详细:判断一个数字是不是素数进阶方法
  • 1265. 逆序打印不可变链表
  • java的图标及由来
  • JAVA调用自己写的包
  • “秒杀系统优化思路” 记录
  • springboot6==springboot前后端分离demo,图片前端上传,后端下载保存到本机
  • 瑞吉外卖项目流程-开发环境搭建(maven项目搭建)
  • springboot整合websocket后运行测试类报错:javax.websocket.server.ServerContainer not available
  • Spring security实现对账户进行加密
  • Java面试——JVM虚拟机
  • jvm类加载器 实践(jvm类加载器有哪些)
  • Annual salary30W+Java开发工程师——3.数组
  • mybatis查询之bind标签
  • Java并发编程知识导航
  • MongoDB(三)SpringBoot整合MongoDB,使用MongoRepository和MongoTemplate

资讯热点

  • 试题 算法训练 传球游戏 Java
  • dpdk课程学习之练习笔记三(tcp的简单实现)
  • JAVA方法的调用、重载、命令行传参、可变参数以及递归整理和计算器的编写
  • JSON复杂数据处理之Json树形结构数据转Java对象并存储到数据库的实现
  • 我做了个违背程序员的决定,开源了这份SPRING全家桶神级手册
  • ACM模式如何构建二叉树
  • Java中的BiFunction
  • JAVA中Collections工具类sort()排序方法
  • nested exception is org.apache.ibatis.exceptions.TooManyResultsException: Expected one result
  • 5.按继承层次对类排序
  • java学习之Mybatis
  • 操作系统高频面试题
  • java初学者分享之路
  • Spring的Async使用与源码
  • sentinel 流控规则持久化