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自带的泰森多边形功能生成的多边形几何形状一致。详细的示例代码请见下一节。

本文代码生成的泰森多边形在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读取坐标点并赋值给points
        Feature 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;

    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/708570.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【STM32】飞控设计

【一些入门知识】 1.飞行原理 【垂直运动】 当 mg&#xff1e;F1F2F3F4&#xff0c;此时做下降加速飞行 当 mg&#xff1c;F1F2F3F4&#xff0c;此时做升高加速飞行 当 mgF1F2F3F4 &#xff0c;此时垂直上保持匀速飞行。 【偏航飞行】 ω 4 ω 2 ≠ ω 1 ω 3 就会产生水…

【CT】LeetCode手撕—200. 岛屿数量

目录 题目1-思路2- 实现⭐200. 岛屿数量——题解思路 3- ACM实现 题目 原题连接&#xff1a;200. 岛屿数量 1-思路 利用 dfs 深搜&#xff0c;遇到岛屿直接将岛屿填充为 0 2- 实现 ⭐200. 岛屿数量——题解思路 class Solution {public int numIslands(char[][] grid) {int …

开源WebGIS全流程常用技术栈

1 数据生产 1.1 uDig uDig&#xff08;http://udig.refractions.net/&#xff09;是一个基于Java开源的桌面应用框架&#xff0c;它构建在Eclipse RCP和GeoTools&#xff08;一个开源的Java GIS包)上。可以进行shp格式地图文件的编辑和查看&#xff1b;是一个开源空间数据查看…

5月产品更新 | 10大更新汇总,快来看看你的需求上线了吗?

5月&#xff0c;Smartbi从客户需求出发&#xff0c;并结合企业在数据分析、处理等方面遇到的问题&#xff0c;对数据模型、数据指标等数十项功能进行了优化升级。 Smartbi用户可以在官网下载下载PC端&#xff0c;更新后便可以使用相关功能&#xff0c;也可以在体验中心体验相关…

mybatis之特殊SQL的执行

1.1模糊查询 尝试&#xff1a; //模糊查询用户 List<User> getUserByLike(Param("mohu") String mohu);<select id"getUserByLike" resultType"user">select * from user where username like %#{mohu}% </select>Test publ…

DP:两个数组的dp问题

解决两个数组的dp问题的常用状态表示&#xff1a; 1、选取第一个字符串[0-i]区间以及第二个字符串[0,j]区间作为研究对象 2、根据题目的要求确定状态表示 字符串dp的常见技巧 1、空串是有研究意义的&#xff0c;引入空串可以帮助我们思考虚拟的边界如何进行初始化。 2、如…

jenkins使用注意问题

1.在编写流水线时并不知道当前处在哪个目录&#xff0c;导致名使用不当&#xff0c;以及文件位置不清楚 流水线任务默认路径是&#xff0c;test4_mvn为jenkins任务名 [Pipeline] sh (hide)pwd /var/jenkins_home/workspace/test4_mvn maven任务也是&#xff0c;看来是一样的…

【Linux】Linux环境基础开发工具_6

文章目录 四、Linux环境基础开发工具gdb 未完待续 四、Linux环境基础开发工具 gdb 我们已经可以写代码了&#xff0c;也能够执行代码了&#xff0c;但是代码错了该如何调试呢&#xff1f;Linux中可以使用 gdb 工具进行调试。 我们写一个简单的程序&#xff1a; 但是我们尝试…

微信小程序毕业设计-实验室管理系统项目开发实战(附源码+论文)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;微信小程序毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计…

智慧工地:构筑未来建筑的智能脉络

在科技日新月异的今天&#xff0c;智慧城市的建设已不再局限于城市生活的方方面面&#xff0c;而是深入到了城市发展的每一个细胞——工地。本文旨在深度剖析智慧工地的核心价值、关键技术及对建筑业转型升级的深远影响。 一、智慧工地&#xff1a;定义与愿景 智慧工地是指运…

【智能家居控制系统项目】一、项目系统镜像烧录与系统登录

前言 完成本章节将可以获得本项目的系统UI界面功能。本章节主要介绍如何烧录项目系统镜像以及进入系统。配套的视频介绍可以点击跳转到智能家居项目复刻配套视频 1.系统功能页面介绍 完成本章全部步骤&#xff0c;我们将可使用以下项目系统功能界面。 1.1 家居总览界面 主界面…

Zynq学习笔记--AXI4-Stream到视频输出IP是如何工作的?

目录 1. 简介 2. 原理详解 2.1 示例工程 2.2 AXI4-Stream to Video Out 3. Master/Slave Timing Mode 3.1 Slave Timing Mode 3.2 Master Timing Mode 4. 总结 1. 简介 本文主要介绍了 AXI4-Stream 到视频输出 的内容。其中&#xff0c;示例工程展示了一个具体的设计&…

八爪鱼现金流-023-独具特色的加密解决方案

大家一起来记账。 八爪鱼现金流。 独具特色的加密解决方案。金额数据加密后存储到数据库。 保证数据私密性。欢迎试用。 八爪鱼现金流。 点击【八爪鱼现金流-022-mybatis插件加密和国密SM4算法】文章查看详情。

MySQL从入门到高级 --- 15.优化 16.pymysql

文章目录 第十五章 && 第十六章&#xff1a;15.优化15.1 查询SQL执行效率15.2 定位低效率执行SQL15.3 explain分析执行计划 - 基本使用15.4 explain分析执行计划 - id15.5 explain分析执行计划 - select_type15.6 explain分析执行计划 - type15.7 explain分析执行计划 …

实验室管理系统实用性体现在哪些方面?

随着技术的不断进步和应用的不断深入&#xff0c;在当今的检验检测行业中&#xff0c;实验室管理系统的实用性成为了保证质量检测工作正常有效开展的基础&#xff0c;其重要性不言而喻。而实验室信息管理系统&#xff08;LIMS&#xff09;实用性不仅体现在其对实验室日常运作的…

项目实战--文档搜索引擎

在我们的学习过程中&#xff0c;会阅读很多的文档&#xff0c;例如jdk的API文档&#xff0c;但是在这样的大型文档中&#xff0c;如果没有搜索功能&#xff0c;我们是很难找到我们想查阅的内容的&#xff0c;于是我们可以实现一个搜索引擎来帮助我们阅读文档。 1. 实现思路 1…

ESP32基础应用之esp32连接腾讯云并使用微信小程序控制的智能灯

文章目录 1. 项目简介1.1 功能接收1.2 使用资源1.3 测试平台 2 腾讯云物联网开发平台3 esp32设备开发3.1 准备参考例程3.2 vscode平台创建测试工程3.3 修改工程 问题总结使用PowerShell命令行终端生成的二维码不能用 1. 项目简介 1.1 功能接收 实现腾讯云创建项目与设备&…

09-Spark架构

相比MapReduce僵化的Map与Reduce分阶段计算&#xff0c;Spark计算框架更有弹性和灵活性&#xff0c;运行性能更佳。 1 Spark的计算阶段 MapReduce一个应用一次只运行一个map和一个reduceSpark可根据应用复杂度&#xff0c;分割成更多的计算阶段&#xff08;stage&#xff09;…

怎么脚本ai创作?分享三个方法

怎么脚本ai创作&#xff1f;在数字化时代&#xff0c;AI技术正逐渐渗透到我们生活的方方面面&#xff0c;其中AI脚本创作软件的出现&#xff0c;极大地提高了创作效率&#xff0c;降低了创作门槛。今天&#xff0c;就为大家推荐三款备受好评的AI脚本创作软件&#xff0c;其中聪…

React-Redux

什么是Redux&#xff1f; Redux是React最常用的集中状态管理工具&#xff0c;类似于Vue中的Pinia&#xff08;Vuex&#xff09;&#xff0c;可以独立于框架运行 作用&#xff1a;通过集中管理的方式管理应用的状态