基于SpringBoot和PostGIS的省域“地理难抵点(最纵深处)”检索及可视化实践

目录

前言

1、研究背景

2、研究意义

一、研究目标

1、"地理难抵点"的概念

二、"难抵点"空间检索实现

1、数据获取与处理

2、计算流程

3、难抵点计算

4、WebGIS可视化

三、成果展示

1、华东地区

2、华南地区

3、华中地区

4、华北地区

5、西北地区

6、西南地区

7、东北地区

8、台港澳地区

四、总结

1、研究创新点

2、未来展望


前言

1、研究背景

最近看到一个有趣的内容,就是求解一个Polygon的地理难抵点以及其空间范围。地理难抵点(Pole of Inaccessibility)是指在一个多边形区域内,距离周边边界的最远点。这一概念在地理学、城市规划、资源勘探等领域具有重要意义。例如,在城市规划中,了解一个区域的难抵点有助于评估该区域的可达性和开发潜力;在资源勘探中,难抵点的确定可以帮助确定资源开发的最佳位置。因此,对省域"地理难抵点"的研究具有重要的理论和实践价值。下图是我国上海市、山东省、河南省等6个省的地理难抵点的空间分析结果拼图。

随着地理信息技术的不断发展,地理数据的获取、处理和分析变得更加便捷和高效。SpringBoot和PostGIS作为当前流行的开源技术框架,为地理信息系统的开发和应用提供了强大的支持。SpringBoot是一个开源的Java基础框架,用于创建独立、生产级的基于Spring框架的应用程序。它简化了基于Spring的应用开发,通过提供一系列的"Starters"和自动配置功能,使开发者能够快速搭建和部署应用程序。PostGIS是一个开源的地理信息系统(GIS)扩展,用于PostgreSQL数据库。它允许用户存储、管理、查询和分析地理空间数据,提供了丰富的空间数据类型和函数,支持复杂的地理空间操作,如距离计算、拓扑分析等。

2、研究意义

  1. 理论意义:通过对省域"地理难抵点"的研究,可以进一步丰富地理学的理论体系,为地理空间分析提供新的视角和方法。难抵点的确定有助于深入理解区域的地理特征和空间结构,为地理学研究提供新的数据支持。

  2. 实践意义:在城市规划、资源勘探、环境保护等领域,难抵点的确定具有重要的实践价值。例如,在城市规划中,了解一个区域的难抵点有助于评估该区域的可达性和开发潜力,为城市布局和基础设施建设提供科学依据。在资源勘探中,难抵点的确定可以帮助确定资源开发的最佳位置,提高资源利用效率。

  3. 技术意义:结合SpringBoot和PostGIS技术,可以实现省域"地理难抵点"的高效检索和可视化展示。SpringBoot提供了强大的后端开发框架,PostGIS提供了丰富的地理空间数据处理功能,两者结合可以大大提高地理信息系统的开发效率和性能。通过本研究,可以为地理信息系统的开发和应用提供一种新的技术方案,推动地理信息技术的发展和应用。

本文为省域"地理难抵点"的检索及可视化提供了一种有效的技术方案,具有较高的理论和实践价值。未来,可以进一步优化算法,提高计算效率和准确性;结合更多的地理数据,为地理研究和应用提供更丰富的支持;探索系统的扩展功能,为地理信息系统的开发和应用提供更全面的支持。同时,可以将本研究的技术方案应用于其他地理空间分析任务,推动地理信息技术的发展和应用。通过本文的讲解,您不仅可以了解什么是难抵点,同时掌握如何在PostGIS数据库中求解该难抵点,最后基于Leaflet组件对结果进行可视化。

一、研究目标

本文的目标是基于SpringBoot和PostGIS技术,实现省域"地理难抵点"的高效检索和可视化展示。在正式介绍之前,首先对"地理难抵点"的概念、理论及实践意义进行简单介绍。

1、"地理难抵点"的概念

难抵点(极)这个词听着比较艰涩,但是其英文名称就容易理解的多,即"pole of inaccessibility",指的是对一个多边形而言(可以是凸多边形也可以是凹多边形),存在某个点,在这个点可以画出位于多边形内的半径最大的圆。

难抵极(Pole of Inaccessibility,缩写为PIA、POI),请注意这里的POI与兴趣点是两个不同的概念。难抵点是地理学上指最难到达的位置,通常是指离海岸线最远的点,代表着最大程度的大陆性或海洋性。难抵极并不意味着在物理上难以抵达,而仅仅是一个地理学上的概念,但由于其定义,大多数探险家对其产生兴趣。难抵极通常指离海岸线最远的点,无论往哪个方向前进,与海岸线的最近距离都比难抵极与海岸线的最近距离要短。因此地理难抵极或者点的空间检索问题就转变成求解该面内的最大内切圆的圆点及其范围的事宜。

二、"难抵点"空间检索实现

本节将重点介绍"地理难抵点"的空间数据库检索以及SpringBoot的后后台实现。主要介绍空间数据的获取与处理,空间难抵点的计算流程,其次介绍难抵点的计算过程,最后详细介绍如何基于Leaflet进行WebGIS可视化的展示实现。

1、数据获取与处理

本文主要研究省域的最大纵深地点,因此进行空间计算的数据是省域,在之前的系列博客中,我们已经实现将Shapefile中的省域数据导入到PostGIS空间数据库中。在省域信息表中,包含了编码、名称、类型、Geometry字段信息等。其物理表结构如下所示:

表中的数据例子如下:

2、计算流程

省域最大内切圆求解流程图

如上流程图所示,首先会从PostGIS空间数据库中查询出一个Polygon面数据,然后调用空间查询函数ST_MaximumInscribedCircle()计算出一个最大内切圆对象,从最大内切圆对象中可以获取中心圆的经纬度坐标以及圆的半径(请注意,在空间数据库中,半径的单位跟参考坐标系息息相关,例如4326的参考系的返回单位是度,而3857的参考系是米)。然后在SpringBoot中返回输出的GeoJSON和圆心位置坐标和半径,最后在Leaflet中绘制返回的圆。查询SQL如下:

sql 复制代码
SELECT T
	.NAME,
	( mic ).radius AS radius,
	st_x ( ( mic ).center ) lon,
	st_y ( ( mic ).center ) lat,
	st_asgeojson ( T.geom ) geomJson 
FROM
	biz_province T,
	ST_MaximumInscribedCircle ( geom ) AS mic 
WHERE
	T.ID = 1733467199265333250;

在Navicat中执行以上sql后,可以得到以下的结果。以下结果表示圆形的位置坐标是东经119.93563966,北纬29.05648878。半径是1.369497度的一个内切圆。

上述就是基于PostGIS数据库的最大内切圆的求解过程。有了这个基础,下一步来讲解如何在SpringBoot中进行相关的计算。

3、难抵点计算

这里主要说明如何基于SpringBoot来进行后台开发,这里给出涉及的相关实体类和后台数据库操作类。关键代码如下:

java 复制代码
package com.yelang.project.extend.earthquake.domain;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.yelang.framework.handler.PgGeometryTypeHandler;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@TableName(value = "biz_province", autoResultMap = true)
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class Province implements Serializable {
	private static final long serialVersionUID = 7710812916753245132L;
	@TableId
	private Long id;
	private String code;
	private String name;
	private String type;
	@TableField(typeHandler = PgGeometryTypeHandler.class)
	private String geom;
	@TableField(exist=false)
	private String geomJson;
}

上面是省份信息实体类,下面是最大内切圆实体类,

java 复制代码
package com.yelang.project.extend.earthquake.domain;
import java.math.BigDecimal;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
/**
 * - 最大内切圆视图对象,返回圆心中心点的坐标以及圆的半径
 * @author 夜郎king 
 */
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class ProvinceInscribedCircleVO extends Province{
	private static final long serialVersionUID = 4152326858933523374L;
	private BigDecimal lon = new BigDecimal("0");//经度
	private BigDecimal lat = new BigDecimal("0");//纬度
	private BigDecimal radius = new BigDecimal("0");//半径,单位根据坐标系不同而定
}

基于上一节的空间查询的Mapper操作对象关键代码如下:

java 复制代码
static final String INSCRIBED_CIRCLE_BYID = "<script>"
			+ " SELECT t.name,(mic).radius AS radius,st_x((mic).center) lon,st_y((mic).center) lat,st_asgeojson(t.geom) geomJson " 
			+ " FROM biz_province t, ST_MaximumInscribedCircle(geom) AS mic where t.id = #{id} "
+ "</script>";
/**
 * - 根据省份主键ID查询最大内切圆信息 add by 夜郎king in 2025-02-06
 * @param id 查询省份ID
 * @return 该国对应的最大内切圆信息即当前空间对象的矢量范围
 */
 @Select(INSCRIBED_CIRCLE_BYID)
 ProvinceInscribedCircleVO getInscribedCircleById(@Param("id")Long id);

以上就是关键的难抵点的后台计算代码,其它的业务层和控制层代码都比较简单,这里不进行赘述。

4、WebGIS可视化

这里讲述如何对Polygon的最大内切圆进行展示,同时展示省域的GeoJSON信息,其中有一个地方是需要注意的,就是返回的半径单位的问题。对于返回的半径有多种处理方式,我们可以在后台对数据进行处理,也可以在前端对数据进行处理。相对来说,使用后台的处理方式通用性比较强,前端只需要负责进行空间展示即可。这里给出核心的展示源码:

javascript 复制代码
function previewInscribedCircle(gid,name){
	$.ajax({  
		type:"get",  
		url:prefix + "/inscribedcircle/" + gid,  
		data:{},  
		dataType:"json",  
		cache:false,
		processData:false,
		success:function(result){
		    if(result.code == web_status.SUCCESS){
		        showLayerGroup.clearLayers();
		        var legendData = new Array();
		        var areaData = result.data;
	        	var color = ccolor = getRandomColor();
	        	if(gid == areaData.id){
	        		color = "red";
	        	}
	        	var areaLayer = L.geoJSON(JSON.parse(areaData.geomJson),{style: {color:"red",fillColor:"red",weight:3,"opacity":0.35, fillOpacity: 0.35 }}).addTo(mymap);
		        var myIcon = L.divIcon({
	        		iconSize: null,
	        		className: '',
	        		popupAnchor:[5,5],
	        		shadowAnchor:[5,5],
	        		html: buildShowInfo("#f4a90e",areaData)
	        	});
		        showLayerGroup.addLayer(areaLayer);
		        var radius = areaData.radius * 111320; // 半径,单位为米
                // 在地图上绘制圆
			    var circle = L.circle([areaData.lat, areaData.lon], {
			        color: '#1ab394', // 边框颜色
			        fillColor: '#1ab394', // 填充颜色
			        dashArray:"10,5",//设置虚线样式:每段实线宽10px,间隔5px
			        fillOpacity: 0.39, // 填充透明度
			        radius: radius // 半径
			     }).addTo(showLayerGroup);
		        //中心点位
		        L.marker([areaData.lat, areaData.lon], { icon: myIcon}).addTo(showLayerGroup);
		        mymap.fitBounds(showLayerGroup.getBounds());
		    }
		},
		error:function(){
		    $.modal.alertWarning("获取空间信息失败");
		}
	});
}

请注意,在上述的代码中, var radius = areaData.radius * 111320; // 半径,单位为米,这里的11320代表的是一个常量。后台返回的单位是度的情况下才可以这么计算,请各位在实际实践时注意选择。经过以上的几个环节,我们基本完成了对省域空间面的最大内切圆的求解。

三、成果展示

本节将结对我们的所有省份进行地理区域划分,按照传统的七大区域划分分为东北、华北、华中、华南、华东、西北、西南地区,同时将展示这七大区域的所属省份及其最大内切圆的空间信息展示。下面跟随我们的分析成果来看看每个省的最大纵深点大概在哪个位置吧。

1、华东地区(包括山东、江苏、安徽、浙江、福建、上海);

2、华南地区(包括广东、广西、海南);

3、华中地区(包括湖北、湖南、河南、江西);

4、华北地区(包括北京、天津、河北、山西、内蒙古);

5、西北地区(包括宁夏、新疆、青海、陕西、甘肃);

6、西南地区(包括四川、云南、贵州、西藏、重庆);

7、东北地区(包括辽宁、吉林、黑龙江);

8、台港澳地区(包括台湾、香港、澳门).

1、华东地区

|----|------|------------------|
| 序号 | 省份名称 | 纵深点 |
| 1 | 山东省 | 莱芜区附近,离济南有一定距离 |
| 2 | 江苏省 | 靖江市附近,离南京有一定距离 |
| 3 | 安徽省 | 庐江县附近,离合肥有一定距离 |
| 4 | 浙江省 | 位于金华市附近,离杭州有一定距离 |
| 5 | 福建省 | 塔前镇附近,离福州有一定距离 |
| 6 | 上海市 | 闵行区 |

2、华南地区

|----|---------|----------------|
| 序号 | 省份名称 | 纵深点 |
| 1 | 广东省 | 清远市附近,离广州有一定距离 |
| 2 | 广西壮族自治区 | 来宾市附近,离南宁有一定距离 |
| 3 | 海南省 | 红毛镇附近,离海口有一定距离 |

3、华中地区

|----|------|----------------|
| 序号 | 省份名称 | 纵深点 |
| 1 | 河南省 | 颍阳镇附近,离郑州有一定距离 |
| 2 | 湖北省 | 柴湖镇附近,离武汉有一定距离 |
| 3 | 湖南省 | 荣华乡附近,离长沙有一定距离 |
| 4 | 江西省 | 拖船镇附近,离南昌有一定距离 |

4、华北地区

|----|--------|------------------|
| 序号 | 省份名称 | 纵深点 |
| 1 | 北京市 | 延寿镇附近 |
| 2 | 河北省 | 安国市附近,离石家庄有一定距离 |
| 3 | 内蒙古自治区 | 牙克石市附近,离呼和浩特很远 |
| 4 | 山西省 | 位于清徐县附近,离太原有一定距离 |
| 5 | 天津市 | 西堤头镇附近 |

5、西北地区

|----|----------|------------------|
| 序号 | 省份名称 | 纵深点 |
| 1 | 甘肃省 | 敦煌市附近,距离兰州很远 |
| 2 | 宁夏回族自治区 | 同心镇附近,离银川有一定距离 |
| 3 | 青海省 | 离西宁有距离 |
| 4 | 陕西省 | 位于新场镇附近,离西安有一定距离 |
| 5 | 新疆维吾尔自治区 | 尉犁县附近,离乌鲁木齐远 |

6、西南地区

|----|-------|------------------|
| 序号 | 省份名称 | 纵深点 |
| 1 | 重庆市 | 璧山区附近 |
| 2 | 贵州省 | 瓮安县附近,离贵阳有一定距离 |
| 3 | 四川省 | 康定市附近,离成都有距离 |
| 4 | 云南省 | 位于新场镇附近,离西安有一定距离 |
| 5 | 西藏自治区 | 离拉萨远 |

7、东北地区

|----|------|------------------|
| 序号 | 省份名称 | 纵深点 |
| 1 | 黑龙江省 | 铁力市附近,离哈尔滨有一定距离 |
| 2 | 吉林省 | 八道河子镇附近,离长春有一定距离 |
| 3 | 辽宁省 | 鸡冠山乡附近,离沈阳有一定距离 |

8、台港澳地区

四、总结

以上就是本文的主要内容,本文为省域"地理难抵点"的检索及可视化提供了一种有效的技术方案,具有较高的理论和实践价值。未来,可以进一步优化算法,提高计算效率和准确性;结合更多的地理数据,为地理研究和应用提供更丰富的支持;探索系统的扩展功能,为地理信息系统的开发和应用提供更全面的支持。

1、研究创新点

本研究将SpringBoot和PostGIS技术相结合,实现了省域"地理难抵点"的高效检索和可视化展示。这种技术融合为地理信息系统的开发和应用提供了一种新的技术方案,具有较高的创新性和实用性。

2、未来展望

在难抵点计算过程中,通过优化算法和数据库查询,提高了计算效率和准确性。同时,结合实际应用需求,探索了系统的扩展功能,为地理信息系统的开发和应用提供了更全面的支持。行文仓促,难免有许多不足之处,如有不足,在此恳请各位专家博主在评论区不吝留言指出,不胜感激。

只有站在前人的肩膀上才能看得更高更远,本文在编写过程中参考以下内容:

1、难抵点------海岸线两侧的极点

2、「地图故事」全国各省的难抵点(最纵深处)分别在什么地方?