功能
解析geojson文件,判断经纬度点是否在地理信息面内。
调用示例
bash
//获取多边形
List<List<GeoUtils.Point>> polygonList = fileServer.getPolygon(cityName);
if (GeoUtils.isPointInPolygon(new GeoUtils.Point(lng, lat), polygonList)) {
//匹配成功
resList.add(map);
}
核心工具类
java
package com.hsdsj.common.utils;
import com.alibaba.fastjson2.JSONArray;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Polygon;
import java.util.ArrayList;
import java.util.List;
/**
* 地理工具类:判断点是否在多边形内
*/
public class GeoUtils {
/**
* 经纬度点
*/
public static class Point {
private double longitude; // 经度
private double latitude; // 纬度
public Point(double longitude, double latitude) {
this.longitude = longitude;
this.latitude = latitude;
}
public Point() {
}
public double getLongitude() {
return longitude;
}
public double getLatitude() {
return latitude;
}
public void setLongitude(Double longitude) {
this.longitude=longitude;
}
public void setLatitude(Double latitude) {
this.latitude =latitude;
}
}
/**
* 解析多边形字符串为Point列表
* @param polygonStr 多边形顶点列表字符串,格式:"[[经度1,纬度1],[经度2,纬度2],...]"
* @return 多边形顶点Point列表
*/
public static List<Point> parsePolygon(String polygonStr) {
try {
// 使用fastjson2解析JSON数组
JSONArray jsonArray = JSONArray.parseArray(polygonStr);
List<Point> points = new ArrayList<>();
for (Object obj : jsonArray) {
if (obj instanceof JSONArray) {
JSONArray pointArray = (JSONArray) obj;
if (pointArray.size() >= 2) {
double longitude = pointArray.getDouble(0);
double latitude = pointArray.getDouble(1);
points.add(new Point(longitude, latitude));
}
}
}
return points;
} catch (Exception e) {
// 解析出错时返回空列表
return new ArrayList<>();
}
}
/**
* 判断点是否在多边形内
* @param point 待判断的经纬度点
* @param polygonList 多边形顶点列表(经纬度坐标)
* @return true:在多边形内;false:不在多边形内
*/
public static boolean isPointInPolygon(Point point, List<List<Point>> polygonList) {
for (List<Point> polygon : polygonList) {
// 多边形顶点数量
int vertexCount = polygon.size();
if (vertexCount < 3) {
return false; // 至少3个点才构成多边形
}
for (int i = 0, j = vertexCount - 1; i < vertexCount; j = i++) {
Point p1 = polygon.get(i);
Point p2 = polygon.get(j);
// 检查点是否在多边形的边上
if (isPointOnEdge(point, p1, p2)) {
return true;
}
// 射线算法核心逻辑
if (((p1.getLatitude() > point.getLatitude()) != (p2.getLatitude() > point.getLatitude())) &&
(point.getLongitude() < (p2.getLongitude() - p1.getLongitude()) *
(point.getLatitude() - p1.getLatitude()) / (p2.getLatitude() - p1.getLatitude()) + p1.getLongitude())) {
return true;
}
}
}
return false;
}
/**
* 判断点是否在多边形的边上
* @param point 待判断的点
* @param p1 边的起点
* @param p2 边的终点
* @return true:在边上;false:不在边上
*/
private static boolean isPointOnEdge(Point point, Point p1, Point p2) {
// 点的纬度在p1和p2纬度之间
boolean isLatBetween = (point.getLatitude() >= Math.min(p1.getLatitude(), p2.getLatitude())) &&
(point.getLatitude() <= Math.max(p1.getLatitude(), p2.getLatitude()));
// 点的经度在p1和p2经度之间
boolean isLngBetween = (point.getLongitude() >= Math.min(p1.getLongitude(), p2.getLongitude())) &&
(point.getLongitude() <= Math.max(p1.getLongitude(), p2.getLongitude()));
if (!isLatBetween || !isLngBetween) {
return false;
}
// 计算斜率,判断三点是否共线
double slope = (p2.getLatitude() - p1.getLatitude()) * (point.getLongitude() - p1.getLongitude()) -
(p2.getLongitude() - p1.getLongitude()) * (point.getLatitude() - p1.getLatitude());
// 斜率接近0,视为共线(考虑浮点数精度问题)
return Math.abs(slope) < 1e-9;
}
}
读取json文件
bash
package com.hsdsj.business.extend.server.impl;
import com.hsdsj.business.extend.constants.GanSuConstant;
import com.hsdsj.business.extend.server.IFileServer;
import com.hsdsj.common.core.domain.AjaxResult;
import com.hsdsj.common.utils.GeoUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 文件获取
*
* @author xiaxx
* @since 2025-09-19
*/
@Service
public class FileServiceImpl implements IFileServer {
//@Resource
//RoadMapper oneAccountBusBzMxMapper;
@Override
public List<List<GeoUtils.Point>> getPolygon(String cityName) {
//根据文件名获取文件路径
String filePath = getFilePath(cityName);
if (filePath == null) {
return new ArrayList<>();
}
try (InputStream inputStream = new ClassPathResource(filePath).getInputStream();
InputStreamReader reader = new InputStreamReader(inputStream)) {
JSONTokener tokener = new JSONTokener(reader);
JSONObject jsonObject = new JSONObject(tokener);
JSONArray features = jsonObject.getJSONArray("features");
JSONObject feature = features.getJSONObject(0);
JSONObject geometry = feature.getJSONObject("geometry");
JSONArray ringsArray = geometry.getJSONArray("rings");
List<List<GeoUtils.Point>> pointsList = new ArrayList<>();
// 获取环(多边形外边界)
for (int i = 0; i < ringsArray.length(); i++) {
JSONArray ring = ringsArray.getJSONArray(i);
//转格式
String ringStr = ring.toString();
List<GeoUtils.Point> points = GeoUtils.parsePolygon(ringStr);
pointsList.add(points);
}
// 测试点(示例)
//GeoUtils.Point startPoint = new GeoUtils.Point(119.2828, 34.2607);
//boolean inPolygon = GeoUtils.isPointInPolygon(startPoint, points);
return pointsList;
} catch (IOException e) {
return new ArrayList<>();
} catch (Exception e) {
return new ArrayList<>();
}
}
//根据名称获取文件路径
private String getFilePath(String cityName) {
switch (cityName) {
case GanSuConstant.LZ:
return "file/map/LZ.json";
case GanSuConstant.JYG:
return "file/map/JYG.json";
case GanSuConstant.JC:
return "file/map/JC.json";
case GanSuConstant.BY:
return "file/map/BY.json";
case GanSuConstant.TS:
return "file/map/TS.json";
case GanSuConstant.WW:
return "file/map/WW.json";
case GanSuConstant.ZY:
return "file/map/ZY.json";
case GanSuConstant.JQ:
return "file/map/JQ.json";
case GanSuConstant.PL:
return "file/map/PL.json";
case GanSuConstant.QY:
return "file/map/QY.json";
case GanSuConstant.DX:
return "file/map/DX.json";
case GanSuConstant.LN:
return "file/map/LN.json";
case GanSuConstant.LX:
return "file/map/LX.json";
case GanSuConstant.GN:
return "file/map/GN.json";
default:
return null;
}
}
}
maven依赖
xml
<!--地图相关-->
<dependency>
<groupId>com.vividsolutions</groupId>
<artifactId>jts</artifactId>
<version>1.13</version>
</dependency>