当前位置: 首页 > 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 开方是整数 就找得到 不是…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】

微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来&#xff0c;Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?

uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件&#xff0c;用于在原生应用中加载 HTML 页面&#xff1a; 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

C++.OpenGL (20/64)混合(Blending)

混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...

Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换

目录 关键点 技术实现1 技术实现2 摘要&#xff1a; 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式&#xff08;自动驾驶、人工驾驶、远程驾驶、主动安全&#xff09;&#xff0c;并通过实时消息推送更新车…...

逻辑回归暴力训练预测金融欺诈

简述 「使用逻辑回归暴力预测金融欺诈&#xff0c;并不断增加特征维度持续测试」的做法&#xff0c;体现了一种逐步建模与迭代验证的实验思路&#xff0c;在金融欺诈检测中非常有价值&#xff0c;本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...