java实现GeoJSON地理信息对经纬度点的匹配

功能

解析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>
相关推荐
jiayong232 小时前
Tomcat性能优化面试题
java·性能优化·tomcat
毕设源码-钟学长2 小时前
【开题答辩全过程】以 基于Python的健康食谱规划系统的设计与实现为例,包含答辩的问题和答案
开发语言·python
秋刀鱼程序编程2 小时前
Java基础入门(五)----面向对象(上)
java·开发语言
纪莫2 小时前
技术面:MySQL篇(InnoDB的锁机制)
java·数据库·java面试⑧股
Remember_9932 小时前
【LeetCode精选算法】滑动窗口专题二
java·开发语言·数据结构·算法·leetcode
Filotimo_2 小时前
在java开发中,cron表达式概念
java·开发语言·数据库
码农水水2 小时前
京东Java面试被问:HTTP/2的多路复用和头部压缩实现
java·开发语言·分布式·http·面试·php·wpf
你怎么知道我是队长3 小时前
C语言---未定义行为
java·c语言·开发语言