当前位置: 首页 > java >正文

基于Java和PostGIS的AOI面数据球面面积计算实践

目录

前言

一、计算方法简介

二、球面面积计算

1、AOI数据转Polygon

2、Geotools面积计算

3、GeographicLib面积计算

4、PostGIS面积计算

三、结果分析

1、不同算法结果对比

2、与互联网AOI对比

3、与天地图测面对比

四、总结


前言

        在现代地理信息系统(GIS)中,AOI(Area of Interest)面数据的处理和分析是一个核心任务。AOI面数据通常用于表示地理区域,如城市、国家、自然保护区等。准确计算这些区域的面积对于城市规划、环境监测、资源管理等领域至关重要。然而,由于地球的曲率,传统的平面面积计算方法在处理大范围地理数据时会产生显著误差。在实际应用中,AOI面数据的球面面积计算可以应用于多种场景。例如,在城市规划中,准确计算城市区域的面积有助于评估城市扩展的潜力;在环境监测中,计算自然保护区的面积有助于评估生态系统的健康状况;在资源管理中,计算农田的面积有助于评估农业生产的潜力。因此,基于Java和PostGIS的AOI面数据球面面积计算具有广泛的应用前景。因此,球面面积计算成为解决这一问题的关键。

        在Java中实现球面面积计算时,可以使用JTS Topology Suite(JTS)库来处理空间数据。JTS提供了丰富的几何操作函数,支持点、线、面等空间数据类型的处理。通过JTS,可以方便地读取AOI面数据,并将其转换为球面坐标系。然后,可以应用球面三角剖分方法,计算每个球面三角形的面积,并累加得到总面积。PostGIS的ST_Area函数可以直接计算球面面积,但为了验证自定义算法的准确性,可以将Java计算的结果与PostGIS的结果进行对比。通过对比,可以发现两者之间的差异,并进一步优化自定义算法。

        本文详细讲解如何基于Java语言,分别使用Geotools、GeographicLib和PostGIS空间函数来分别计算对应的AOI数据的球面面积,为了验证计算结果。我们将采用天地图标绘、互联网查询公开数据的方式来验证空间数据的范围面积。天地图标绘由于采样的点趋向于简单,因此可能采集的精度可能有所损失。而使用互联网的数据则由于可能采集的面范围不一致,存在一定的误差。本例将说明三种不同的方式与实际结果的误差值。为大家对面状的球面面积计算有一个参考。

一、计算方法简介

        在实际应用中,AOI面数据通常以矢量数据的形式存储,如Shapefile、GeoJSON等。这些数据包含了地理区域的边界信息,通常由一系列经纬度坐标点组成。为了计算球面面积,需要将这些坐标点转换为球面坐标系,并应用球面几何公式进行计算。PostGIS提供了ST_Area函数,可以直接计算球面面积,但为了更深入地理解计算过程,可以通过Java实现自定义的球面面积计算算法。球面面积计算的核心在于将地理坐标转换为球面坐标系,并应用球面三角剖分方法。球面三角剖分将AOI面数据划分为多个球面三角形,然后计算每个三角形的面积并累加得到总面积。球面三角形的面积计算可以使用L'Huilier公式或球面余弦定理。这些公式考虑了地球的曲率,能够提供更准确的计算结果。

        为了确保球面面积计算的准确性,可以采用多种方法进行验证。例如,可以使用已知面积的地理区域进行测试,比较计算结果与已知面积的差异。此外,还可以使用不同的算法进行对比,如平面面积计算与球面面积计算的对比,以评估球面面积计算的必要性。需要说明的是,在面向GIS的应用当中,对于空间坐标系可以分为地理坐标系和投影坐标系。地理坐标系一般用经纬度标识,它的单位是度,因此直接进行面积计算得出的单位是平方度,是现实中不太好理解的。而投影坐标系是米制单位,通常符合实际的计算结果,如果数据已经是投影坐标,可以直接进行计算就可以得到平方米的面积。

二、球面面积计算

        本节将重点介绍在Java和PostGIS空间数据库中来分别进行球面面积计算的方法。计算之前,我们准备了6组对比的数据,这6组数据来自于高德地图中获取的AOI数据。后续我们将会对这六组数据来进行球面面积求解,在后续的对比中也会对这几组数据进行对比。

1、AOI数据转Polygon

        在高德地图中,AOI数据是一个收尾坐标连接起来的坐标字符串。因此我们需要对这串坐标字符进行解析,转换成我们的空间面数据,后续针对这类数据来进行面积求解。因此首先我们要将字符串的数据转换成Polygon,这里我们以Geotools为例,讲解如何把字符串数组转换成Polygon,核心代码如下:

/**
* - 将AOI字符串转换成Polygon对象
* @return
*/
public static Polygon convertAoi2Polygon(String aoistr) {String [] AOI_Str_Array = aoistr.split(";");// 获取GeometryFactory实例GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);Coordinate[] coords = {};if( AOI_Str_Array.length > 0) {coords = new Coordinate[AOI_Str_Array.length];}//处理坐标for (int i = 0; i < AOI_Str_Array.length; i++) {String loc = AOI_Str_Array[i];String [] latlon = loc.split(",");double lng = Double.parseDouble(latlon[0]);double lat = Double.parseDouble(latlon[1]);//将高德坐标转换成WGS84坐标double [] gcj284 = CoordinateTransformUtil.gcj02towgs84(lng, lat);coords[i] = new Coordinate(gcj284[0], gcj284[1]);}LinearRing shell = geometryFactory.createLinearRing(coords);Polygon polygon = geometryFactory.createPolygon(shell, null);polygon.setSRID(4326);//设置4326的坐标return polygon;
}

2、Geotools面积计算

        这里介绍使用Geotools来实现简化的球面面积近似计算,当然这里的地球半径等使用的一个固定常数,6371008.8。首先需要在Maven中引入以下依赖:

<dependency><groupId>org.geotools</groupId><artifactId>gt-referencing</artifactId><version>28.2</version>
</dependency>

         然后进行球面面积的近似计算,核心方法如下:

// 简化的球面面积近似计算(实际项目需优化)
private static double approximateSphericalArea(Coordinate p1, Coordinate p2) {// 此处为示例逻辑,真实计算需使用积分或地理公式// 例如:使用 Haversine 公式计算梯形面积double R = 6371008.8; // 地球平均半径(米)double dLon = Math.toRadians(p2.x - p1.x);double lat1 = Math.toRadians(p1.y);double lat2 = Math.toRadians(p2.y);return 0.5 * R * R * dLon * (Math.sin(lat2) + Math.sin(lat1));
}

        最后定义一个使用 GeodeticCalculator 逐边计算多边形面积的方法,在这个方法的实现中,我们使用累加的方法来进行计算,核心方法如下:

/*** -使用 GeodeticCalculator 逐边计算多边形面积*/
public static double calculateGeodeticArea(Geometry geometry, CoordinateReferenceSystem crs) throws Exception {if (!(geometry instanceof Polygon)) {throw new IllegalArgumentException("仅支持 Polygon 类型");}Polygon polygon = (Polygon) geometry;Coordinate[] coords = polygon.getExteriorRing().getCoordinates();GeodeticCalculator calculator = new GeodeticCalculator(crs);double totalArea = 0.0;// 使用球面三角形累加算法(类似 JTS 原有逻辑)for (int i = 0; i < coords.length - 1; i++) {Coordinate p1 = coords[i];Coordinate p2 = coords[i + 1];calculator.setStartingGeographicPoint(p1.x, p1.y);calculator.setDestinationGeographicPoint(p2.x, p2.y);// 累加每个边的贡献面积(需自行实现积分逻辑,此处简化)// 实际应参考 JTS 原有算法或使用第三方库(如 GeographicLib)totalArea += approximateSphericalArea(p1, p2);}return Math.abs(totalArea); // 返回绝对值
}

3、GeographicLib面积计算

        如果觉得使用Geotools来计算面积比较繁琐,接下来我们使用一个简化的库,利用这个库可以更便捷的对一个面数据的面积进行求解。这个库就是:GeographicLib-Java。首先依然需要的Pom.xml中引用以下依赖:

<dependency><groupId>net.sf.geographiclib</groupId><artifactId>GeographicLib-Java</artifactId><version>1.52</version>
</dependency>

        计算球面面积的核心方法更加简单,如下所示:

public static double calculateExactGeodeticArea(Polygon polygon) {Geodesic geodesic = Geodesic.WGS84;PolygonArea areaCalc = new PolygonArea(geodesic, false);for (Coordinate coord : polygon.getExteriorRing().getCoordinates()) {areaCalc.AddPoint(coord.y, coord.x); // 注意经纬度顺序}PolygonResult result = areaCalc.Compute();return Math.abs(result.area); // 单位:平方米
}

4、PostGIS面积计算

        在空间数据库中进行球面面积的计算比较简单,为了求解平方米的单位,我们可以将数据转换成geograghy的类型来进行球面的计算,在使用空间面积函数st_area即可实现面积的求解,这里以某小学的空间面数据为例,讲解如何在PostGIS数据库中实现球面面积求解。具体可以体现为以下的SQL:

SELECTst_area ( ST_GeomFromText ( 'POLYGON ((112.87852 28.190856,112.879078 28.190562,112.879613 28.19024,112.880025 28.18993,112.880453 28.189525,112.880568 28.189433,112.880562 28.189324,112.880064 28.188912,112.879793 28.188709,112.879188 28.18857,112.878529 28.188726,112.87848 28.188768,112.878465 28.188882,112.87852 28.190856))', 4326 -- 指定 SRID) :: geography );

        在数据库终端运行以下的SQL以后可以得到以下的执行结果,其结果就是面积结果。

32860.61062525073

三、结果分析

        这里将统一对生成的结果进行一个简单的对比和分析。通过对比和说明,结合实际的情况,可以看到那种计算方法更加接近实际情况。

1、不同算法结果对比

        在应用程序中我们使用6组数据分别调用Geotools和GeographicLib-Java库,其中的一个小学我们还使用了PostGIS的空间函数直接求解的方式。调用代码如下:

public static void main(String[] args) throws NoSuchAuthorityCodeException, FactoryException, Exception {//计算梅溪湖的AOI 面积Polygon polygon = convertAoi2Polygon(MXH_AOI);System.out.println("梅溪湖的球面面积为:" + calculateExactGeodeticArea(polygon));System.out.println("m2 " + calculateGeodeticArea(polygon, CRS.decode("EPSG:4326")));System.out.println("*************************************************************");polygon = convertAoi2Polygon(MXQX_AOI);System.out.println("梅溪青秀的球面面积为:" + calculateExactGeodeticArea(polygon));System.out.println("m2 " + calculateGeodeticArea(polygon, CRS.decode("EPSG:4326")));System.out.println("*************************************************************");polygon = convertAoi2Polygon(YMGY_AOI);System.out.println("杨梅公园的球面面积为:" + calculateExactGeodeticArea(polygon));System.out.println("m2 " + calculateGeodeticArea(polygon, CRS.decode("EPSG:4326")));System.out.println("**************************************************************");polygon = convertAoi2Polygon(BBG_AOI);System.out.println("梅溪新天地的球面面积为:" + calculateExactGeodeticArea(polygon));System.out.println("m2 " + calculateGeodeticArea(polygon, CRS.decode("EPSG:4326")));System.out.println("************************************************************");polygon = convertAoi2Polygon(THL_AOI);System.out.println("桃花岭风景区的球面面积为:" + calculateExactGeodeticArea(polygon));System.out.println("m2 " + calculateGeodeticArea(polygon, CRS.decode("EPSG:4326")));System.out.println("*************************************************************");polygon = convertAoi2Polygon(YYSX_AOI);System.out.println("实验小学的球面面积为:" + calculateExactGeodeticArea(polygon));System.out.println("m2 " + calculateGeodeticArea(polygon, CRS.decode("EPSG:4326")));
}

        程序运行结果如下:

        这里把面积的结果整理成以下表格。请注意,在以下的表格中,面积的单位是平方米:

序号

AOI名称

GeographicLib

Geotools
1梅溪湖风景区3003365.93972519833007843.6566917896
2梅溪青秀33133.08818446487633182.49462517351
3杨梅公园20309.346586976220339.625071160495
4步步高梅溪新天地234694.91455752775235044.35333895683
5桃花岭风景区5551323.143812265559616.194570124
6岳麓区实验小学32884.2097526374332933.23007472232

        通过以上的表格可以看到,两种不同的计算方式的结果还是有一些差异,不过这些差异并不大。 

2、与互联网AOI对比

        以桃花岭公园为例,桃花岭景区位于湖南长沙岳麓区,是岳麓山风景名胜区的重要组成部分。桃花岭公园规划面积约4360亩。景区内包括洪寺庵水库、腊八寺遗址等重要景点。

        将4360亩换算成平方米,大约是3583333.33平方米, 实际上我们算出来的面积有5551323.14381226,当然我们通过高德AOI获取的数据与原始的面积可能存在一些出入,所以导致了在计算与互联网公式面积的一个差异,当然如果有更准去的数据,也可以在评论区留言修正。

3、与天地图测面对比

        在上面的小节中,可能出现实际的面积与计算的结果有较大的出入的问题,接下来我们以某小学等为例,使用天地图的测面积方法来实现面积的预估,看与实际的差距有多大,首先来看下天地图中的面积测算。该小学的面积大约是3.46公顷,合34500平方米。

         来看后台的计算的结果分别是:32884.20975263743(GeographicLib)和32933.23007472232(Geotools),再来看PostGIS中的计算结果是:32860.61062525073,可以看到对于该小学的面积计算,三者都是比较接近的。同时三者与实际的面积也相差不大。

四、总结

        以上就是本文的主要内容。通过实验的方式可以看到,使用PostGIS生成的面积最小,而GeographicLib其次,而使用Geotools的生成是最大的。当然,这与Geotools中的地球半径等客观因素油酸。总之,基于Java和PostGIS的AOI面数据球面面积计算是一个复杂但重要的任务。通过结合Java的编程能力和PostGIS的空间数据处理能力,可以构建一个高效、准确的球面面积计算系统。在实际应用中,需要考虑多种因素,如数据精度、投影方式、地球模型等,并通过多种方法进行验证,以确保计算结果的准确性。通过模块化设计和JDBC集成,可以提高系统的灵活性和可维护性,满足不同应用场景的需求。行文仓促,定有不足之处,欢迎各位朋友在评论区批评指正,不胜感激。

http://www.xdnf.cn/news/5822.html

相关文章:

  • Kaamel隐私合规洞察:Facebook美容定向广告事件分析
  • Docker环境下的Apache NiFi安装实践踩坑记录
  • 蓝桥杯 16. 外卖店优先级
  • 数据结构——例题1
  • 基于Qt的app开发第八天
  • C++设计模式——单例模式
  • 微信小程序 自定义图片分享-绘制数据图片以及信息文字
  • React系列——HOC高阶组件的封装与使用
  • 使用ZYNQ芯片和LVGL框架实现用户高刷新UI设计系列教程(第十二讲)
  • (2)python开发经验
  • 下周,Coinbase将被纳入标普500指数
  • windows c++ (9) 程序内注册服务并修改登录账户
  • 使用 `aiohttp` 构建高效的异步网络爬虫系统
  • 一次讲清 FP32 / FP16 / BF16 / INT8 / INT4
  • VR和眼动控制集群机器人的方法
  • 青少年编程与数学 02-019 Rust 编程基础 10课题、函数、闭包和迭代器
  • 机器学习中分类模型的常用评价指标
  • 设计模式系列(03):设计原则(二):DIP、ISP、LoD
  • SpringBoot与Eventuate Tram整合 - 实现转账最终一致性系统
  • 解锁生命周期评价密码:OpenLCA、GREET 与 R 语言的融合应用
  • 基于 Amazon Bedrock 和 Amazon Connect 打造智能客服自助服务 – 设计篇
  • 【阿里云】阿里云 Ubuntu 服务器无法更新 systemd(Operation not permitted)的解决方法
  • Java Solon v3.3.0 发布(国产优秀应用开发基座)
  • Spring Boot Swagger 安全防护全解析:从旧版实践到官方规范
  • Spring Boot 跨域问题全解:原理、解决方案与最佳实践
  • Tomcat和Nginx的主要区别
  • 【MySQL】第三弹——表的CRUD进阶(一)数据库约束
  • 地址簿模块-01.需求分析
  • D-Pointer(Pimpl)设计模式(指向实现的指针)
  • 在VSCode中接入DeepSeek的指南