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;

    }
}

  • 14
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要使用GDAL库在Java生成CAD像,需要按照以下步骤进行操作: 1. 安装GDAL库及其Java绑定 GDAL是一个开源的地理空间数据处理库,可以用于读取、写入和转换各种格式的地理空间数据。GDALJava绑定可以让Java程序员使用GDAL的功能。在开始之前,请确保已经安装了GDAL库及其Java绑定。 2. 读取数据 使用GDAL库可以读取各种格式的地理空间数据,包括CAD格式。在这个例子中,我们将使用GDAL库读取CAD格式的数据。 ``` String filename = "input.dwg"; Dataset dataset = gdal.Open(filename); ``` 3. 将数据转换为矢量数据 一旦读取了CAD格式的数据,就需要将其转换为矢量数据。这可以通过使用GDAL库提供的矢量转换工具来完成。 ``` String format = "DXF"; Driver driver = ogr.GetDriverByName(format); DataSource dstDs = driver.CreateDataSource("output.dxf"); Layer layer = dstDs.CreateLayer("output", null, ogr.wkbUnknown); layer.CreateFields(dataset.GetLayer(0).GetLayerDefn()); Feature feature; while ((feature = dataset.GetLayer(0).GetNextFeature()) != null) { layer.CreateFeature(feature); } ``` 在这个例子中,我们将CAD格式的数据转换为DXF格式的矢量数据。使用`ogr.GetDriverByName(format)`方法获取对应的矢量转换工具,然后使用`driver.CreateDataSource("output.dxf")`方法创建输出数据源。接下来,我们使用`dstDs.CreateLayer("output", null, ogr.wkbUnknown)`方法创建层,然后使用`layer.CreateFields(dataset.GetLayer(0).GetLayerDefn())`方法创建字段。最后,我们遍历CAD格式的数据,并使用`layer.CreateFeature(feature)`方法将其添加到矢量数据中。 4. 将矢量数据转换为CAD格式 现在,我们已经将CAD格式的数据转换为矢量数据,接下来需要将其转换回CAD格式。这可以通过使用GDAL库提供的CAD转换工具来完成。 ``` format = "DWG"; driver = ogr.GetDriverByName(format); dstDs = driver.CreateDataSource("output.dwg"); layer = dstDs.CreateLayer("output", null, ogr.wkbUnknown); layer.CreateFields(dataset.GetLayer(0).GetLayerDefn()); feature = layer.GetNextFeature(); while (feature != null) { layer.CreateFeature(feature); feature = layer.GetNextFeature(); } ``` 在这个例子中,我们将DXF格式的矢量数据转换回CAD格式的数据。使用`ogr.GetDriverByName(format)`方法获取对应的CAD转换工具,然后使用`driver.CreateDataSource("output.dwg")`方法创建输出数据源。接下来,我们使用`dstDs.CreateLayer("output", null, ogr.wkbUnknown)`方法创建层,然后使用`layer.CreateFields(dataset.GetLayer(0).GetLayerDefn())`方法创建字段。最后,我们遍历矢量数据,并使用`layer.CreateFeature(feature)`方法将其添加到CAD格式的数据中。 5. 完整代码 下面是完整的代码: ``` import org.gdal.ogr.DataSource; import org.gdal.ogr.Driver; import org.gdal.ogr.Feature; import org.gdal.ogr.Layer; import org.gdal.ogr.ogr; import org.gdal.gdal.Dataset; public class CadGenerator { public static void main(String[] args) { String filename = "input.dwg"; ogr.RegisterAll(); Dataset dataset = gdal.Open(filename); if (dataset == null) { System.out.println("Failed to open file: " + filename); return; } String format = "DXF"; Driver driver = ogr.GetDriverByName(format); if (driver == null) { System.out.println("Failed to get driver: " + format); return; } DataSource dstDs = driver.CreateDataSource("output.dxf"); if (dstDs == null) { System.out.println("Failed to create data source"); return; } Layer layer = dstDs.CreateLayer("output", null, ogr.wkbUnknown); if (layer == null) { System.out.println("Failed to create layer"); return; } layer.CreateFields(dataset.GetLayer(0).GetLayerDefn()); Feature feature; while ((feature = dataset.GetLayer(0).GetNextFeature()) != null) { layer.CreateFeature(feature); } format = "DWG"; driver = ogr.GetDriverByName(format); if (driver == null) { System.out.println("Failed to get driver: " + format); return; } dstDs = driver.CreateDataSource("output.dwg"); if (dstDs == null) { System.out.println("Failed to create data source"); return; } layer = dstDs.CreateLayer("output", null, ogr.wkbUnknown); if (layer == null) { System.out.println("Failed to create layer"); return; } layer.CreateFields(dataset.GetLayer(0).GetLayerDefn()); feature = layer.GetNextFeature(); while (feature != null) { layer.CreateFeature(feature); feature = layer.GetNextFeature(); } } } ``` 在这个例子中,我们使用GDAL库读取CAD格式的数据,并将其转换为DXF格式的矢量数据,然后将其转换回CAD格式的数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我一时想不起

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值