java调用GDAL及JTS实现生成泰森多边形(Voronoi图)的一种方法
目录
一、关于泰森多边形
1.泰森多边形的特性
2.本文的目的
二、实现思路
1.gdal和jts库的maven坐标
2.jts生成泰森多边形的关键代码
3.使用GDAL读取源文件信息的关键代码
4.使用GDAL将生成的泰森多边形写入文件
三、实现结果
1.实现的效果
2.完整代码示例
一、关于泰森多边形
泰森多边形,又称Voronoi图,是由一组由连接两邻点直线的垂直平分线组成的连续多边形组成。

1.泰森多边形的特性
- 每个泰森多边形内仅含有一个离散点数据;
- 泰森多边形内的点到相应离散点的距离最近;
- 位于泰森多边形边上的点到其两边的离散点的距离相等。
2.本文的目的
泰森多边形在地理信息系统(GIS)领域有着广泛的应用,一般可用于点插值,也可以在不直接计算距离的情况进行最邻近分析。目前常见的桌面GIS软件基本都有此功能。本文不讨论泰森多边形的实现算法,仅仅从应用开发的角度出发介绍如何使用已有的java矢量数据读写库、几何处理库来实现泰森多边形的生成。
二、实现思路
GDAL是一种常用的地理空间栅格及矢量数据的读写库其由C/C++编写而成,存在java绑定库,可以被java语言调用。GDAL内置了部分几何处理和空间分析的算法,经作者了解,其暂未内置泰森多边形算法。GDAL在矢量数据的功能方面,支持读写geopackage、shapefile、kml、geojson、gml、xlsx等多种格式的数据。
JTS是一个java语言开发的几何图形处理库,具有较丰富的几何图形处理能力。经了解,JTS内置了泰森多边形算法,即VoronoiDiagramBuilder。基于上述分析,使用java调用GDAL和JTS库实现泰森多边形的生成在技术上是可行的。
1.gdal和jts库的maven坐标
<dependency><groupId>org.gdal</groupId><artifactId>gdal</artifactId><version>3.2.0</version></dependency><dependency><groupId>org.locationtech.jts</groupId><artifactId>jts-core</artifactId><version>1.18.2</version></dependency>
2.jts生成泰森多边形的关键代码
VoronoiDiagramBuilder voronoiBuilder = new VoronoiDiagramBuilder();
voronoiBuilder.setSites(points);
voronoiBuilder.setClipEnvelope(envelope);
Geometry voronoiPolygons = voronoiBuilder.getDiagram(geometryFactory);
其中points为坐标类的Coordinate列表, envelope为泰森多边形的空间范围定义。
points、envelope均需要从源文件中读取,这时可以使用gdal读取有关信息。
3.使用GDAL读取源文件信息的关键代码
Geometry ogrGeo = f.GetGeometryRef();
Coordinate coordinate = new Coordinate(ogrGeo.GetX(), ogrGeo.GetY());
上面的代码是读取矢量文件坐标点的gdal代码,f为gdal的Feature类。此处的Geometry为gdal的Geometry类,非JTS的Geometry类。下面的代码是读取矢量文件范围的gdal代码。
double[] extent = layer.GetExtent();
Envelope envelope = new Envelope(extent[0],extent[1],extent[2],extent[3]);
4.使用GDAL将生成的泰森多边形写入文件
通过gdal读取矢量文件中调用jts获取泰森多边形需要的参数后,jts生成了Geometry类(org.locationtech.jts.geom.Geometry),逐个读取Geometry的面状图形,将面状图形的坐标点生成wkt文本,利用gdal的根据wkt文本创建几何的功能,将坐标串转换为gdal的几何对象,最后调用gdal写矢量图层的方法将数据生成指定格式的文件即可。以下是转换数据的核心代码。
String wkt = voronoiPolygons.getGeometryN(i).toText();
Geometry geometryOut = Geometry.CreateFromWkt(wkt);
三、实现结果
1.实现的效果
通过本文的示例代码,可以实现最基础的泰森多边形的生成,从而应用于所需要的应用场景中。以下是QGIS中查看代码生成的泰森多边形的实现效果,可以看到,除了生成了多边形外,还继承了点的属性数据,与QGIS自带的泰森多边形功能生成的多边形几何形状一致。详细的示例代码请见下一节。

2.完整代码示例
package com.hjzx.util;import org.gdal.ogr.*;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.triangulate.VoronoiDiagramBuilder;import java.io.File;
import java.util.*;public class Voronoi {public static void main(String[] args) {String vectorPath = "E:\\随机点.gpkg";String outPath = "E:\\泰森多边形.shp";boolean success = createVoronoiByVector(vectorPath, outPath, "ESRI Shapefile");}/*** 生成泰森多边形* @param vectorPath 矢量数据的绝对路径* @param outPath 要输出的泰森多边形绝对路径* @param outDriverName 要输出的数据格式对应的驱动字符串* @return 是否生成成功*/public static boolean createVoronoiByVector(String vectorPath, String outPath, String outDriverName) {ogr.RegisterAll();DataSource dataSource = ogr.Open(vectorPath);System.out.printf("输入的矢量文件路径:%s\t", vectorPath);if (dataSource == null) {System.out.println("打开数据源失败");return false;}Driver driver = dataSource.GetDriver();if (driver == null) {System.out.println("打开驱动失败");return false;}System.out.printf("打开驱动成功:驱动名称:%s\n", driver.getName());//这里简化了操作,只读取了第1个图层Layer layer = dataSource.GetLayer(0);if (layer == null) {System.out.printf("打开矢量图层失败,文件路径:%s", vectorPath);return false;}if (ogrConstants.wkbPoint != layer.GetGeomType()) {System.out.printf("矢量图层不是点状几何图形,无法生成泰森多边形,文件路径:%s", vectorPath);return false;}//gdal获取矢量图层范围double[] extent = layer.GetExtent();// 创建JTS几何工厂GeometryFactory geometryFactory = new GeometryFactory();// 创建一组点List<Coordinate> points = new ArrayList<>();//gdal读取坐标点并赋值给pointsFeature feature;//使用Map集合存储坐标与要素的对应关系Map<Coordinate, Feature> gdalKeyValue = new HashMap<>();while ((feature = layer.GetNextFeature()) != null) {Geometry ogrGeo = feature.GetGeometryRef();//将gdal矢量要素的点转换到JTS中去Coordinate coordinate = new Coordinate(ogrGeo.GetX(), ogrGeo.GetY());points.add(coordinate);gdalKeyValue.put(coordinate, feature);}System.out.printf("输入矢量数据要素转换为坐标点列表成功,要素数量:%d\n", points.size());Envelope envelope = new Envelope(extent[0], extent[1], extent[2], extent[3]);VoronoiDiagramBuilder voronoiBuilder = new VoronoiDiagramBuilder();voronoiBuilder.setSites(points);voronoiBuilder.setClipEnvelope(envelope);org.locationtech.jts.geom.Geometry voronoiPolygons = voronoiBuilder.getDiagram(geometryFactory);int geometryCount = voronoiPolygons.getNumGeometries();System.out.printf("泰森多边形几何图形创建成功,要素数量:%d\n", geometryCount);System.out.println("开始写入泰森多边形矢量文件!");//获取数据数据源的驱动Driver outDriver = ogr.GetDriverByName(outDriverName);if (outDriver == null) {System.out.printf("打开输出文件的驱动失败,驱动字符串:%s\t", outDriverName);return false;}DataSource outDataSource = outDriver.CreateDataSource(outPath);Vector<String> options = new Vector<>();options.add("ENCODING=UTF-8");/*将文件名作为图层名*/File file = new File(outPath);String name = file.getName();name = name.substring(0, name.lastIndexOf("."));//创建输出矢量图层,沿用源坐标系Layer layerOut = outDataSource.CreateLayer(name, layer.GetSpatialRef(), ogr.wkbMultiPolygon, options);//沿用源文件字段FeatureDefn featureDefn = layer.GetLayerDefn();System.out.printf("输入源文件要素定义数量:%d\n", featureDefn.GetFieldCount());FeatureDefn featureDefnOut = new FeatureDefn();//给输出图层创建字段for (int i = 0; i < featureDefn.GetFieldCount(); i++) {featureDefnOut.AddFieldDefn(featureDefn.GetFieldDefn(i));layerOut.CreateField(featureDefn.GetFieldDefn(i));}for (int i = 0; i < geometryCount; i++) {//取出泰森多边形中的每个面对应的Coordinate对象Coordinate coordinate = (Coordinate) voronoiPolygons.getGeometryN(i).getUserData();String wkt = voronoiPolygons.getGeometryN(i).toText();Geometry geometryOut = Geometry.CreateFromWkt(wkt);//根据Coordinate对象到hashMap中获取矢量要素Feature featureOut = gdalKeyValue.get(coordinate);//改变要素的几何图形featureOut.SetGeometry(geometryOut);//创建要素到要输出的图层layerOut.CreateFeature(featureOut);}//保存数据outDataSource.SyncToDisk();//销毁输出数据源layerOut.delete();outDataSource.delete();//销毁输入数据源layer.delete();dataSource.delete();System.out.printf("创建泰森多边形文件成功,文件路径:%s\n", outPath);return true;}
}
相关文章:

java调用GDAL及JTS实现生成泰森多边形(Voronoi图)的一种方法
目录 一、关于泰森多边形 1.泰森多边形的特性 2.本文的目的 二、实现思路 1.gdal和jts库的maven坐标 2.jts生成泰森多边形的关键代码 3.使用GDAL读取源文件信息的关键代码 4.使用GDAL将生成的泰森多边形写入文件 三、实现结果 1.实现的效果 2.完整代码示例 一、关于…...

Type-C音频转接器方案
在数字化时代,音频设备作为我们生活中不可或缺的一部分,其连接方式的便捷性和高效性显得尤为重要。Type-C音频转接器,作为一种新型的音频连接解决方案,正逐渐走进我们的生活,以其独特的优势改变着我们的音频体验。 一、…...

linux 服务器上离线安装 node nvm
因为是离线环境 如果你是可以访问外网的 下面内容仅供参考 也可以继续按步骤来 node 安装路径 Node.js — Download Node.js nvm 安装路径 Tags nvm-sh/nvm GitHub 后来发现 nvm安装后 nvm use 版本号 报错 让我去nvm install 版本 我是内网环境 install不了 下面 你要 把安…...
Web前端三大主流框架:React、Angular和Vue的比较与选择
Web前端三大主流框架:React、Angular和Vue的比较与选择 Web前端技术的快速发展为开发者提供了丰富的工具和框架,其中React、Angular和Vue是当前最受欢迎的三大框架。这三个框架各有特点,适用于不同的项目需求和开发团队。本文将对React、Ang…...

C# MemoryCache 缓存应用
摘要 缓存是一种非常常见的性能优化技术,在开发过程中经常会用到。.NET提供了内置的内存缓存类 MemoryCache,它可以很方便地存储数据并在后续的请求中快速读取,从而提高应用程序的响应速度。 正文 通过使用 Microsoft.Extensions.Caching.Me…...
【学习笔记】Linux前置准备
视频学习资料 基础: 黑马0基础(前面四章即可,包含软件基础安装配置) 进阶: 黑马程序员-Linux系统编程 黑马程序员-Linux网络编程 我也还没看,看了眼目录感觉把八股里面很多场景都讲到了,感觉有…...

各种空气能热泵安装图
空气能热泵安装图 循环式空气能热泵安装图 直热循环式空气能热泵安装图 泳池空气能热泵安装图 循环式水源热泵热安装系统原理图 直热循环式水源热泵安装系统图 空气水源热泵安装图...

软件杯 题目:基于深度学习的中文对话问答机器人
文章目录 0 简介1 项目架构2 项目的主要过程2.1 数据清洗、预处理2.2 分桶2.3 训练 3 项目的整体结构4 重要的API4.1 LSTM cells部分:4.2 损失函数:4.3 搭建seq2seq框架:4.4 测试部分:4.5 评价NLP测试效果:4.6 梯度截断…...

UI学习笔记(一)
UI学习 一:UIView基础frame属性隐藏视图对象:UIView的层级关系 二:UIWindow对象三:UIViewController基础UIViewController使用 四:定时器与视图移动五:UISwitch控件六:滑动条和进度条七…...

【C语言训练题库】扫雷->简单小游戏!
🔥博客主页🔥:【 坊钰_CSDN博客 】 欢迎各位点赞👍评论✍收藏⭐ 目录 1. 题目 2. 解析 3. 代码 4. 小结 1. 题目 小sun上课的时候非常喜欢玩扫雷。他现小sun有一个初始的雷矩阵,他希望你帮他生成一个扫雷矩阵。 扫雷…...

WMS仓储管理系统高效驱动制造企业物料管理
在现代制造业的快速发展中,仓储管理作为供应链的核心环节,其效率直接影响到企业的生产力和市场竞争力。随着科技的进步,实施WMS仓储管理系统逐渐成为推动仓储管理向智能化转型的关键力量。本文将深入探讨WMS仓储管理系统如何以创新的方式驱动…...
python使用appium打开程序后,为什么没有操作后程序就自动退出了
当使用Appium打开应用程序并在没有执行任何操作后它自动退出,这可能是由于几个不同的原因。以下是一些可能的原因和相应的解决方案: 应用程序的默认行为: 有些应用程序在启动后如果没有用户交互,可能会因为超时或其他逻辑而自动关…...
MacBook M系列芯片安装php8.2
适用于M1\M2\M3等系列的MacBook,记录下安装过程 安装brew 打开终端,执行如下命令: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"安装zsh(非必须) …...

OlSoul系统调校程序v2024.06.05
软件介绍 OlSoul是一款能够适配用于Win各个系统的系统调校软件,OlSoul内置有众多调校功能可以直接使用,如有启用无线网络功能、启用打印机功能、系统快速休眠与休眠开关、快捷方式小箭头去除功能等,具体的调校功能多达几十项,可自…...
图像特征提取 python
1. 边缘检测 (Edge Detection) 1.1 Sobel 算子 Sobel 算子是一种边缘检测算子,通过计算图像梯度来检测边缘。 import cv2 import numpy as np# 读取图像 image cv2.imread(image.jpg, 0)# 应用 Sobel 算子 sobel_x cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize5)…...

width: 100%和 width: 100vw这两种写法有什么区别
width: 100%; 和 width: 100vw; 是两种不同的 CSS 写法,它们在实际应用中会有不同的效果。以下是这两种写法的主要区别: width: 100%; 定义:将元素的宽度设置为其包含块(通常是父元素)宽度的 100%。效果:元…...
如何在另一台电脑上使用相同的Python环境和依赖包
如果您想在另一台电脑上使用相同的Python环境和依赖包,有几种方法可以实现: 使用requirements.txt: 在您当前的虚拟环境中,您可以使用pip freeze > requirements.txt命令生成一个包含所有已安装包及其版本的文件。然后&#x…...
Vue3 响应式 API:工具函数(一)
isRef() isRef 是一个简单的工具函数,它接受一个参数并返回一个布尔值,指示该参数是否是一个由 ref 创建的响应式引用。 在某些情况下,你可能需要编写一些通用逻辑或函数,这些逻辑或函数需要处理不同类型的响应式数据(…...
开发常用软件
开发相关 代码编译 Visual Studio 2019 Visual Studio 2022 代码测试工具 LINQPad Premium 5 LINQPad 7 打包工具 Advanced Installer 反编译工具 ILSpy dnSpy spy 数据库相关 SQLite Expert Professional 5 DLL扫描工具 depends 界面设计 SvgToXaml Materi…...

conntrack如何限制您的k8s网关
1.1 conntrack 介绍 对于那些不熟悉的人来说,conntrack简单来说是Linux内核的一个子系统,它跟踪所有进入、出去或通过系统的网络连接,允许它监控和管理每个连接的状态,这对于诸如NAT(网络地址转换)、防火墙和保持会话连续性等任务至关重要。它作为Netfilter的一部分运行,…...

龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...

css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...

【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
Docker拉取MySQL后数据库连接失败的解决方案
在使用Docker部署MySQL时,拉取并启动容器后,有时可能会遇到数据库连接失败的问题。这种问题可能由多种原因导致,包括配置错误、网络设置问题、权限问题等。本文将分析可能的原因,并提供解决方案。 一、确认MySQL容器的运行状态 …...

渗透实战PortSwigger靶场:lab13存储型DOM XSS详解
进来是需要留言的,先用做简单的 html 标签测试 发现面的</h1>不见了 数据包中找到了一个loadCommentsWithVulnerableEscapeHtml.js 他是把用户输入的<>进行 html 编码,输入的<>当成字符串处理回显到页面中,看来只是把用户输…...
【WebSocket】SpringBoot项目中使用WebSocket
1. 导入坐标 如果springboot父工程没有加入websocket的起步依赖,添加它的坐标的时候需要带上版本号。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dep…...