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、距离、点在面内、长度、面积、相交等): Java中使用JTS对空间几何计算(读取WKT、距离、点在面内、长度、面积、相交等)_jts-core_霸道流氓气质的博客-CSDN博客 JavaGeoTools实现WKT数据根据EPSG编码进行坐标系转换&…...
【异步VS多线程】异步VS多线程区别
异步VS多线程区别 1、异步 异步概念:异步是并发编程的一种形式,在同一时刻可以独立于主程序外,可以并发执行另外一些任务。异步的实现方式有两种: 第一种:通过 async TASK来实现异步,第二种:通…...

【nosql】redis之高可用(主从复制、哨兵、集群)搭建
redis群集有三种模式 redis群集有三种模式,分别是主从同步/复制、哨兵模式、Cluster集群,下面会讲解一下三种模式的工作方式,以及如何搭建cluster群集 ●主从复制:主从复制是高可用Redis的基础,哨兵和集群都是在主从…...

js如何实现数组去重的常用方法
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 使用 Set(ES6)⭐ 使用 filter 和 indexOf⭐ 使用 reduce⭐ 使用对象属性⭐ 使用 includes 方法(ES6)⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方…...

XREAL Air 2 Pro发布,加入电致变色技术,拓展AR眼镜使用场景
【2023年9月6日 中国北京】继刚刚宣布XREAL Air在全球销量突破20万台后,全球领先的消费级AR眼镜品牌XREAL今日于中国市场正式推出XREAL Air 2系列新品。全新Air 2系列包含两款AR眼镜产品:在显示、佩戴舒适性、音频等核心维度全面升级,体验全面…...
Go基础11-理解Go语言的包导入
Go语言是使用包(package)作为基本单元来组织源码的,可以说一个Go程序就是由一些包链接在一起构建而成的。虽然与Java、Python等语言相比这算不上什么创新,但与祖辈C语言的头文件包含机制相比则是“先进”了许多。 编译速度快是这种…...

【MySQL数据库原理】在MySQL Workbench界面运行SQL代码——学生管理系统
在 MySQL Workbench 8.0 中,你可以使用以下步骤新建内容并运行 MySQL 语言代码: 1、打开 MySQL Workbench 并连接到你的 MySQL 数据库服务器。 2、在左侧的导航栏中,展开你的连接以查看数据库。选择你要在其中运行 SQL 代码的数据库。 3…...

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

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

【LeetCode-简单题】977. 有序数组的平方
文章目录 题目方法一:双指针方法二: 题目 方法一:双指针 class Solution { // 方法一 :双指针public int[] sortedSquares(int[] nums) {int left 0;int right nums.length -1 ;int[] res new int[nums.length];//结果集新数组…...

【笔试强训选择题】Day39.习题(错题)解析
作者简介:大家好,我是未央; 博客首页:未央.303 系列专栏:笔试强训选择题 每日一句:人的一生,可以有所作为的时机只有一次,那就是现在!!!ÿ…...

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

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

LeetCode:2. 两数之和
这个解题思路来自代码随想录:代码随想录 (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.可分离滤波的原理 可分离滤波的原理基于滤波器的可分离性。对于一个二维滤波器,如果它可以表示为水平方向和垂直方向两个一维滤波器的卷积,那么它就是可分离的。也就是说&#x…...

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

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

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

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

【LeetCode-简单题】367. 有效的完全平方数
文章目录 题目方法一:二分查找 题目 方法一:二分查找 找 1 - num 之间的 mid, 开方是整数 就找得到 mid, 不是整数自然找不到mid class Solution { // 二分查找 ;找 1 - num 之间的mid 开方是整数 就找得到 不是…...

利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...

HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...

嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...