当前位置: 首页 > news >正文

Java中使用JTS实现WKT字符串读取转换线、查找LineString的list中距离最近的线、LineString做缓冲区扩展并计算点在缓冲区内的方位角

场景

Java中使用JTS对空间几何计算(读取WKT、距离、点在面内、长度、面积、相交等):

Java中使用JTS对空间几何计算(读取WKT、距离、点在面内、长度、面积、相交等)_jts-core_霸道流氓气质的博客-CSDN博客

Java+GeoTools实现WKT数据根据EPSG编码进行坐标系转换:

Java+GeoTools实现WKT数据根据EPSG编码进行坐标系转换_霸道流氓气质的博客-CSDN博客

基于gis的业务场景中,需要在地图中录入区域数据的wkt数据,然后根据某个坐标点判断是属于哪个区域,

以及距离所属区域中最近的端点的方位角,比如坐标点位于某区域东南方向100米。

注:

博客:
霸道流氓气质_C#,架构之路,SpringBoot-CSDN博客

实现

1、参考上面引入jts的依赖。

首先数据库中存储的所有线的WKT数据为

其中region_name为线的名称,region_wkt为线的wkt字符串。

首先从数据库中读取所有的wkt字符串数据,并转换为map类型数据方便处理以及赋值线的名称到linestring的userData字段。

        List<LineString> regionList = new ArrayList<>();Map<String, List<LineString>> regionMap = new HashMap<>();//读取录入的区域位置信息RegionManagement param = RegionManagement.builder().deleteFlag(false).build();List<RegionManagement> regionManagements = regionManagementMapper.selectList(param);for (RegionManagement regionManagement : regionManagements) {LineString lineString = readWKT(regionManagement.getRegionWKT());RegionDTO regionDTO = JSON.parseObject(JSON.toJSONString(regionManagement), RegionDTO.class);regionDTO.setUpdateTime(regionManagement.getUpdateTime().toString());lineString.setUserData(regionDTO);regionList.add(lineString);}//将区域list流处理为map,方便快速查找Map<String, List<RegionManagement>> collect = regionManagements.stream().collect(Collectors.groupingBy(RegionManagement::getRegionName));for (String name : collect.keySet()) {List<LineString> tmp = new ArrayList<>();collect.get(name).forEach(item -> tmp.add(readWKT(item.getRegionWKT())));regionMap.put(name, tmp);}

这里的RegionManagement用来读取数据库中存储的wkt字符串等数据,实现为

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class RegionManagement {private Long id;private String regionName;private String regionWKT;// 0 false ; 1 trueprivate boolean deleteFlag;@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Date updateTime;}

调用读取wkt字符串并转换为jts的LineString对象的方法readWKT实现为

    //读取wkt数据为LineStringpublic LineString readWKT(String regionWKT){GeometryFactory fact = new GeometryFactory();WKTReader reader = new WKTReader(fact);LineString geometry1 = null;try {geometry1 = (LineString) reader.read(regionWKT);} catch (ParseException e) {e.printStackTrace();}return geometry1;}

中间获取所需要的数据的RegionDTO的实现为

import lombok.Data;@Data
public class RegionDTO {private Long id;private String regionName;private String updateTime;
}

2、将要判断方位的坐标值声明为Point2D对象

        //目标点位Point2D.Double carPoint = new Point2D.Double(36582834.745, 4259820.7951);

3、获取距离目标点位最近的线

        //获取离目标点位最近的线LineString lineString = findNearestLine(carPoint, 10D, regionList);

这里调用的findNearestLine方法的实现

    //查找最近的线,jts工具做线的缓冲区,扩展宽度为10public  LineString findNearestLine(java.awt.geom.Point2D.Double point, Double FuzzyLookupRange, List<LineString> lineStringList) {Point a = createPoint(point.getX(), point.getY());return lineStringList.parallelStream().filter((lineString) -> lineString.buffer(FuzzyLookupRange).contains(a)).min((o1, o2) -> {Double ax = o1.distance(a);Double axx = o2.distance(a);return ax.compareTo(axx);}).orElse(null);}

这里调用了createPoint用来创建point对象

    //根据坐标x y创建点对象public static Point createPoint(Double x, Double y) {GeometryFactory a = JTSFactoryFinder.getGeometryFactory();return a.createPoint(new Coordinate(x, y));}

然后使用lineString.buffer方法对线做缓冲区,扩展宽度为10,即将线向外扩充成类似区域的概念,判断点是否在扩充后

的区域内,如果有多个区域,则取距离最小的一个。

LineString.buffer方法的使用可参考:

Geometry (JTS Topology Suite 1.13 API) - Javadoc Extreme)

Computes a buffer area around this geometry having the given width. The buffer of a Geometry is the Minkowski sum or difference of the geometry

with a disc of radius abs(distance).

Mathematically-exact buffer area boundaries can contain circular arcs.

To represent these arcs using linear geometry they must be approximated with line segments.

The buffer geometry is constructed using 8 segments per quadrant to approximate the circular arcs. The end cap style is CAP_ROUND.

The buffer operation always returns a polygonal result. The negative or zero-distance buffer of lines and points is always an empty Polygon.

 This is also the result for the buffers of degenerate (zero-area) polygons.

直译:

计算具有给定宽度的几何体周围的缓冲区。几何体的缓冲区是具有半径为abs(距离)的圆盘的几何体的Minkowski和或差。

数学上精确的缓冲区边界可以包含圆弧。要使用线性几何图形表示这些圆弧,必须使用线段对其进行近似。

缓冲区几何结构使用每个象限8个线段来近似圆弧。端盖样式为cap_ROUND。

缓冲区操作总是返回多边形结果。直线和点的负或零距离缓冲区始终为空多边形。

这也是退化(零面积)多边形缓冲区的结果。

然后获取距离最近的线的名称并输出

        //获取离目标点位最近的线LineString lineString = findNearestLine(carPoint, 10D, regionList);String regionName = "区域位置为空";if (lineString != null) {RegionDTO userData = (RegionDTO) lineString.getUserData();regionName = userData.getRegionName();}System.out.println(regionName);

4、获取坐标点相对于该线的方位角

        String azimuth;if (!regionName.equals("区域位置为空")) {List<LineString> lineStringList = regionMap.get(regionName);LineString closeLine;if (lineStringList.size() > 1) {closeLine = findNearestLine(carPoint, 10D, lineStringList);} else {closeLine = lineStringList.get(0);}//获取线的两个端点Point startPoint = closeLine.getStartPoint();Point endPoint = closeLine.getEndPoint();//获取点位到两个端点的距离double startDistance = startPoint.distance(createPoint(carPoint.getX(), carPoint.getY()));double endDistance = endPoint.distance(createPoint(carPoint.getX(), carPoint.getY()));//获取较近的点作为参考点判断方位距离if (startDistance <= endDistance) {//获取方位角azimuth = regionName + DirectionUtil.getAzimuth(startPoint.getX(), startPoint.getY(), carPoint.getX(), carPoint.getY()) + "方向路口" + BigDecimal.valueOf(startDistance).intValue() + "米";} else {azimuth = regionName + DirectionUtil.getAzimuth(endPoint.getX(), endPoint.getY(), carPoint.getX(), carPoint.getY()) + "方向路口" + BigDecimal.valueOf(endDistance).intValue() + "米";}} else {azimuth = "[" + carPoint.getX() + "," + carPoint.getY() + "]";}System.out.println(azimuth);

其中获取方位角的工具类DirectionUtil.getAzimuth实现

import org.locationtech.jts.geom.LineSegment;public class DirectionUtil {/*** 笛卡尔坐标系*/enum DirectionEnum {DUE_EAST("正东", "==0 || ==360"),DUE_NORTHEAST("东北", "==45"),DUE_NORTH("正北", "==90"),NORTH_NORTHWEST("西北", "90<theta<135"),DUE_WEST("正西", "==180"),WEST_SOUTHWEST("西南", "180<theta<225"),DUE_SOUTH("正南", "==270"),DUE_SOUTHEAST("东南", "==315");private String direction;private String describe;DirectionEnum(String direction, String describe) {this.direction = direction;this.describe = describe;}public String getDirection() {return direction;}public void setDirection(String direction) {this.direction = direction;}public String getDescribe() {return describe;}public void setDescribe(String describe) {this.describe = describe;}}/*** 获取方位角** @param x1 观测点x* @param y1 观测点y* @param x2 目标点x* @param y2 目标点y* @return 返回距离观测点的方位角*/public static String getAzimuth(double x1, double y1, double x2, double y2) {LineSegment lineSegment = new LineSegment(x1, y1, x2, y2);double angle1 = lineSegment.angle();double angle = Math.toDegrees(lineSegment.angle());if (angle < 0) {angle = angle + 360;}if ((0 < angle && angle < 12.5) || (347.5 < angle && angle < 360)) {return DirectionEnum.DUE_EAST.getDirection();} else if (12.5 < angle && angle < 77.5) {return DirectionEnum.DUE_NORTHEAST.getDirection();} else if (77.5 < angle && angle < 102.5) {return DirectionEnum.DUE_NORTH.getDirection();} else if (102.5 < angle && angle < 167.5) {return DirectionEnum.NORTH_NORTHWEST.getDirection();} else if (167.5 < angle && angle < 192.5) {return DirectionEnum.DUE_WEST.getDirection();} else if (192.5 < angle && angle < 257.5) {return DirectionEnum.WEST_SOUTHWEST.getDirection();} else if (257.5 < angle && angle < 282.5) {return DirectionEnum.DUE_SOUTH.getDirection();} else if (282.5 < angle && angle < 347.5) {return DirectionEnum.WEST_SOUTHWEST.getDirection();} else {return "ERROR";}}
}

逻辑就是对比目标点到线的两个端点的距离,取较近的进行判断,然后做方位角判断。

运行效果测试

相关文章:

Java中使用JTS实现WKT字符串读取转换线、查找LineString的list中距离最近的线、LineString做缓冲区扩展并计算点在缓冲区内的方位角

场景 Java中使用JTS对空间几何计算(读取WKT、距离、点在面内、长度、面积、相交等)&#xff1a; Java中使用JTS对空间几何计算(读取WKT、距离、点在面内、长度、面积、相交等)_jts-core_霸道流氓气质的博客-CSDN博客 JavaGeoTools实现WKT数据根据EPSG编码进行坐标系转换&…...

【异步VS多线程】异步VS多线程区别

异步VS多线程区别 1、异步 异步概念&#xff1a;异步是并发编程的一种形式&#xff0c;在同一时刻可以独立于主程序外&#xff0c;可以并发执行另外一些任务。异步的实现方式有两种&#xff1a; 第一种&#xff1a;通过 async TASK来实现异步&#xff0c;第二种&#xff1a;通…...

【nosql】redis之高可用(主从复制、哨兵、集群)搭建

redis群集有三种模式 redis群集有三种模式&#xff0c;分别是主从同步/复制、哨兵模式、Cluster集群&#xff0c;下面会讲解一下三种模式的工作方式&#xff0c;以及如何搭建cluster群集 ●主从复制&#xff1a;主从复制是高可用Redis的基础&#xff0c;哨兵和集群都是在主从…...

js如何实现数组去重的常用方法

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 使用 Set&#xff08;ES6&#xff09;⭐ 使用 filter 和 indexOf⭐ 使用 reduce⭐ 使用对象属性⭐ 使用 includes 方法&#xff08;ES6&#xff09;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方…...

XREAL Air 2 Pro发布,加入电致变色技术,拓展AR眼镜使用场景

【2023年9月6日 中国北京】继刚刚宣布XREAL Air在全球销量突破20万台后&#xff0c;全球领先的消费级AR眼镜品牌XREAL今日于中国市场正式推出XREAL Air 2系列新品。全新Air 2系列包含两款AR眼镜产品&#xff1a;在显示、佩戴舒适性、音频等核心维度全面升级&#xff0c;体验全面…...

Go基础11-理解Go语言的包导入

Go语言是使用包&#xff08;package&#xff09;作为基本单元来组织源码的&#xff0c;可以说一个Go程序就是由一些包链接在一起构建而成的。虽然与Java、Python等语言相比这算不上什么创新&#xff0c;但与祖辈C语言的头文件包含机制相比则是“先进”了许多。 编译速度快是这种…...

【MySQL数据库原理】在MySQL Workbench界面运行SQL代码——学生管理系统

在 MySQL Workbench 8.0 中&#xff0c;你可以使用以下步骤新建内容并运行 MySQL 语言代码&#xff1a; 1、打开 MySQL Workbench 并连接到你的 MySQL 数据库服务器。 2、在左侧的导航栏中&#xff0c;展开你的连接以查看数据库。选择你要在其中运行 SQL 代码的数据库。 3…...

高分三号1米分辨率飞机检测识别数据集

二、背景介绍 合成孔径雷达(Synthetic Aperture Radar, SAR) 是一种主动式的微波成像系统&#xff0c;它不受光照、云雾 和气候等自然条件影响&#xff0c;具备全天时、全天候对地 观测的能力&#xff0c;已成为遥感领域重要的信息获取平 台。近年来&#xff0c;随着遥感成像技…...

Unity 之Material 类型和 MeshRenderer 组件中的 Materials 之间有一些重要的区别

文章目录 区别代码例子 区别 在Unity中&#xff0c;Material 类型和 MeshRenderer 组件中的 Materials 之间有一些重要的区别。 Material 类型&#xff1a; Material 是 Unity 中用来定义渲染属性的资源。它包含了一系列定义了如何绘制一个对象的属性&#xff0c;比如颜色、纹…...

【LeetCode-简单题】977. 有序数组的平方

文章目录 题目方法一&#xff1a;双指针方法二&#xff1a; 题目 方法一&#xff1a;双指针 class Solution { // 方法一 &#xff1a;双指针public int[] sortedSquares(int[] nums) {int left 0;int right nums.length -1 ;int[] res new int[nums.length];//结果集新数组…...

【笔试强训选择题】Day39.习题(错题)解析

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;笔试强训选择题 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01;&#xff01;&#xff…...

Prometheus-Alertmanager 警报管理器-部署和设置

文章目录 一、介绍二、核心概念1 Grouping 分组2 Inhibition 抑制3 Silences 静默&#xff08;静音&#xff09;5 High Availability 高可用性 三、部署1 二进制方式下载配置 systemd 2 docker-compose 方式 四、配置1 配置文件介绍1.1 全局配置1.2 receiver 接收器标准接收器相…...

恒运资本:小盘股的优点?投资小盘股要注意哪些方面?

股市是一个充溢时机和危险的当地&#xff0c;不同出资者有不同的偏好&#xff0c;有的人喜爱追逐大盘蓝筹股&#xff0c;有的人则钟情于小盘股。那么小盘股的长处&#xff1f;出资小盘股要注意哪些方面&#xff1f;恒运资本也为我们准备了相关内容&#xff0c;以供参考。 小盘股…...

LeetCode:2. 两数之和

这个解题思路来自代码随想录&#xff1a;代码随想录 (programmercarl.com) class Solution { public:vector<int> twoSum(vector<int>& nums, int target) {std::unordered_map <int,int> map;for(int i 0; i < nums.size(); i) {// 遍历当前元素&am…...

OpenCV(二十四):可分离滤波

目录 1.可分离滤波的原理 2.可分离滤波函数sepFilter2D() 3.示例代码 1.可分离滤波的原理 可分离滤波的原理基于滤波器的可分离性。对于一个二维滤波器&#xff0c;如果它可以表示为水平方向和垂直方向两个一维滤波器的卷积&#xff0c;那么它就是可分离的。也就是说&#x…...

【JS进阶】防抖与节流

防抖与节流 1.防抖 1.1 为什么要防抖&#xff1f; 在项目中&#xff0c;有的操作是高频触发的&#xff0c;但是其实触发一次就好了&#xff0c;比如我们短时间内多次缩放页面&#xff0c;那么我们不应该每次缩放都去执行操作&#xff0c;应该只做一次就好。再比如说监听输入…...

【css】linear-gradient()的用法

linear-gradient() CSS函数创建一个由两种或多种颜色沿一条直线进行线性过渡的图像,其结果是<gradient>数据类型的对象,此对象是一种特殊的<image> 数据类型。 语法 /* 渐变轴为 45 度&#xff0c;从蓝色渐变到红色 */ linear-gradient(45deg, blue, red);/* 从右…...

java: 读取snakeyaml-1.26.jar各种jar包时出错; error in opening zip file

可能的问题 jar有问题idea没有权限等等其他问题。但执行后报错就是读取不了&#xff0c;还报error in opening zip file这个错。 解决问题 我的错就是jar包有问题。我先后进行了很多次把jar包位置里的东西全部删除&#xff0c;然后重新maven下载但是不管用。最后从网站上下载…...

医疗知识图谱 neo4j

开源项目&#xff1a; https://github.com/liuhuanyong/QASystemOnMedicalKG 一.效果 二.需要安装&#xff1a; pip install pyahocorasick pip install py2neo 三.需要修改&#xff1a; 需要改的点&#xff1a; 1.改连接的方式 2.改读文件的方式 MedicalGraph 运行&am…...

【LeetCode-简单题】367. 有效的完全平方数

文章目录 题目方法一&#xff1a;二分查找 题目 方法一&#xff1a;二分查找 找 1 - num 之间的 mid&#xff0c; 开方是整数 就找得到 mid&#xff0c; 不是整数自然找不到mid class Solution { // 二分查找 &#xff1b;找 1 - num 之间的mid 开方是整数 就找得到 不是…...

vben-admin中渲染table表格时怎么处理不同的数据结构

最近在用vben admin开发后台管理系统&#xff0c;vben admin这个后管端框架封装的非常细&#xff0c;颗粒度非常细&#xff0c;如果了解里面的组件或者api用法&#xff0c;那开发起来非常快。如果不了解&#xff0c;那就非常痛苦了&#xff0c;目前关于vben admin这块的开发问题…...

从零开始在树莓派上搭建WordPress博客网站并实现公网访问

文章目录 序幕概述1. 安装 PHP2. 安装MySQL数据库3. 安装 Wordpress4. 设置您的 WordPress 数据库设置 MySQL/MariaDB创建 WordPress 数据库 5. WordPress configuration6. 将WordPress站点发布到公网安装相对URL插件修改config.php配置 7. 支持好友链接样式8. 定制主题 序幕 …...

Go基础18-理解方法的本质以选择正确的receiver类型

Go语言虽然不支持经典的面向对象语法元素&#xff0c;比如类、对象、继承等&#xff0c;但Go语言也有方法。和函数相比&#xff0c;Go语言中的方法在声明形式上仅仅多了一个参数&#xff0c;Go称之为receiver参数。receiver参数是方法与类型之间的纽带。 Go方法的一般声明形式…...

Go基础12-理解Go语言表达式的求值顺序

Go语言在变量声明、初始化以及赋值语句上相比其先祖C语言做了一些改进&#xff0c;诸如&#xff1a; ● 支持在同一行声明和初始化多个变量&#xff08;不同类型也可以&#xff09; var a, b, c 5, "hello", 3.45 a, b, c : 5, "hello", 3.45 // 短变量…...

OJ练习第165题——修车的最少时间

修车的最少时间 力扣链接&#xff1a;2594. 修车的最少时间 题目描述 给你一个整数数组 ranks &#xff0c;表示一些机械工的 能力值 。ranksi 是第 i 位机械工的能力值。能力值为 r 的机械工可以在 r * n2 分钟内修好 n 辆车。 同时给你一个整数 cars &#xff0c;表示总…...

纯前端实现 导入 与 导出 Excel

最近经常在做 不规则Excel的导入&#xff0c;或者一些普通Excel的导出&#xff0c;当前以上说的都是纯前端来实现&#xff1b;下面我们来聊聊经常用到的Excel导出与导入的实现方案&#xff0c;本文实现技术栈以 Vue2 JS 为例 导入分类&#xff1a; 调用 API 完全由后端来解析数…...

关于一次两段式提交和数据库恢复数据我的一些想法

binlog是服务层的功能&#xff0c;而redolog是innodb引擎的功能&#xff0c;binlog主要用于主从复制&#xff0c;redolog主要用做数据的恢复&#xff0c;我们必须保证binlog和redolog日志数据的一致性。恢复数据时也必须遵守此一致性。 1.如果只写一次redolog会出现什么问题&a…...

阿里巴巴springcloud的gateway网关如何用继承接口WebExceptionHandler定义一个json格式的404错误页面实例

如果你想通过实现 WebExceptionHandler 接口来定义一个返回 JSON 格式的 404 错误页面的实例&#xff0c;可以按照以下方式操作&#xff1a; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.ster…...

『力扣每日一题07』字符串最后一个单词的长度

气死我啦&#xff0c;今天这道题花了快一个小时&#xff0c;我学完了答案的解法&#xff0c;放上去在线 OJ &#xff0c;一直报错&#xff0c;找来找去都找不到自己错在哪&#xff0c;明明跟答案一模一样。后来还是学了另一种解法&#xff0c;才跑出来的(̥̥̥̥̥̥̥̥o̥̥…...

成都睿趣科技:抖音开店初期要注意什么

随着社交媒体和短视频平台的崛起&#xff0c;抖音已经成为了一个风靡全球的短视频应用&#xff0c;拥有着庞大的用户群体。因此&#xff0c;越来越多的创业者开始在抖音上开设自己的线上店铺&#xff0c;希望借助这个平台赚取丰厚的利润。然而&#xff0c;在抖音开店初期&#…...

百度seo优化技巧/seo网络推广报价

only-child :empty 元素内容为空 &#xff1a;not...

中港海通网站是谁做的/任务放单平台

本文转自网络&#xff0c;对疑问的地方做了修改 官方参考文献&#xff1a;http://www.mongovue.com/tutorials/ MongoVUE 是个比较好用的MongoDB客户端&#xff0c;需要注册&#xff0c;但是可以变成永久使用&#xff0c; 一、基础操作 新增一个连接 进入的界面形如 二、进阶操…...

建设银行行号网站查询是什么意思/seo网站优化方案书

阅读前提问&#xff0c;文章结尾有答案a [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]print(a[-1:] a[-1])这个输出是True or False&#xff1f;今天来和大家一起讨论一下切片的知识点&#xff0c;列表的切片相信大家都用过&#xff0c;切片操作的基本语法比较简单&#xff0c;但是内在逻…...

为什么python不适合开发网站/郑州seo哪家好

本篇文章主要为大家介绍下php如何获取本周的所有日期&#xff0c;或者最近七天的所有日期。希望可以帮助到有需要的朋友#####获取本周所有日期&#xff1a;/*获取本周所有日期*/function get_week($time , $formatY-m-d){$time $time ! ? $time : time();//获取当前周几$we…...

seo快速提高网站转化率/凡科官网免费制作小程序

2019独角兽企业重金招聘Python工程师标准>>> svn代码版本管理1.0开发&#xff0c;做dev1.0的branch此时的目录结构svn://proj/ trunk/ (不负担开发任务) branches/ dev_1.0 (copy from trunk) tags/…...

wordpress做门户网/南昌seo专业团队

java jcp昨天&#xff0c;亚马逊宣布他们已加入Java Community Process 。 AWS开发人员工具中的Artifacts and Languages组经理Yishai Galatzer在一篇博客文章中写道&#xff1a;“亚马逊运行着数千种Java生产服务&#xff1b; 我们和我们的客户都严重依赖JDK&#xff08;Java开…...