Java判断地图坐标系中一个点(经纬度)是否在一个区域内

这篇博客介绍了如何利用交点法判断一个点是否位于地图上的多边形区域内。通过检查点与多边形边界的交点数量,结合X轴射线法,实现了精确的判断。代码示例中包括了`MapPoint`类和`GraphUtils`类,用于处理经纬度坐标和计算几何操作。此外,还提供了`isPointInPolygon`方法,该方法首先判断点是否在多边形的外包矩形内,然后计算射线与多边形边界的交点,最终确定点的位置关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

看到很多评论说判断有问题,我这个判断是高德地图的判断,其他地图不一定可以使用哦。

废话不多说,直接上代码

MapPoint.java

public class MapPoint {
    /**
     * 经度
     */
    private double lng;
    /**
     * 纬度
     */
    private double lat;

    public MapPoint() {

    }

    public MapPoint(double lng, double lat) {
        this.lng = lng;
        this.lat = lat;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof MapPoint) {
            MapPoint mapPoint = (MapPoint) obj;
            return (mapPoint.getLng() == lng && mapPoint.getLat() == lat) ? true : false;
        } else {
            return false;
        }
    }

    public double getLng() {
        return lng;
    }

    public void setLng(double lng) {
        this.lng = lng;
    }

    public double getLat() {
        return lat;
    }

    public void setLat(double lat) {
        this.lat = lat;
    }
}

GraphUtils.java

public class GraphUtils {
    /**
     * 判断点是否在多边形内(基本思路是用交点法)
     *
     * @param point
     * @param boundaryPoints
     * @return
     */
    public static boolean isPointInPolygon(MapPoint point, MapPoint[] boundaryPoints) {
        // 防止第一个点与最后一个点相同  
        if (boundaryPoints != null && boundaryPoints.length > 0
                && boundaryPoints[boundaryPoints.length - 1].equals(boundaryPoints[0])) {
            boundaryPoints = Arrays.copyOf(boundaryPoints, boundaryPoints.length - 1);
        }
        int pointCount = boundaryPoints.length;

        // 首先判断点是否在多边形的外包矩形内,如果在,则进一步判断,否则返回false  
        if (!isPointInRectangle(point, boundaryPoints)) {
            return false;
        }

        // 如果点与多边形的其中一个顶点重合,那么直接返回true  
        for (int i = 0; i < pointCount; i++) {
            if (point.equals(boundaryPoints[i])) {
                return true;
            }
        }

        /**
         * 基本思想是利用X轴射线法,计算射线与多边形各边的交点,如果是偶数,则点在多边形外,否则在多边形内。还会考虑一些特殊情况,如点在多边形顶点上 
         * , 点在多边形边上等特殊情况。 
         */
        // X轴射线与多边形的交点数  
        int intersectPointCount = 0;
        // X轴射线与多边形的交点权值  
        float intersectPointWeights = 0;
        // 浮点类型计算时候与0比较时候的容差  
        double precision = 2e-10;
        // 边P1P2的两个端点  
        MapPoint point1 = boundaryPoints[0], point2;
        // 循环判断所有的边  
        for (int i = 1; i <= pointCount; i++) {
            point2 = boundaryPoints[i % pointCount];

            /**
             * 如果点的y坐标在边P1P2的y坐标开区间范围之外,那么不相交。 
             */
            if (point.getLat() < Math.min(point1.getLat(), point2.getLat())
                    || point.getLat() > Math.max(point1.getLat(), point2.getLat())) {
                point1 = point2;
                continue;
            }
            /**
             * 此处判断射线与边相交 
             */
            if (point.getLat() > Math.min(point1.getLat(), point2.getLat())
                    // 如果点的y坐标在边P1P2的y坐标开区间内
                    && point.getLat() < Math.max(point1.getLat(), point2.getLat())) {
                // 若边P1P2是垂直的
                if (point1.getLng() == point2.getLng()) {
                    if (point.getLng() == point1.getLng()) {
                        // 若点在垂直的边P1P2上,则点在多边形内  
                        return true;
                    } else if (point.getLng() < point1.getLng()) {
                        // 若点在在垂直的边P1P2左边,则点与该边必然有交点  
                        ++intersectPointCount;
                    }
                } else {// 若边P1P2是斜线
                    // 点point的x坐标在点P1和P2的左侧
                    if (point.getLng() <= Math.min(point1.getLng(), point2.getLng())) {
                        ++intersectPointCount;
                    }
                    // 点point的x坐标在点P1和P2的x坐标中间
                    else if (point.getLng() > Math.min(point1.getLng(), point2.getLng())
                            && point.getLng() < Math.max(point1.getLng(), point2.getLng())) {
                        double slopeDiff = getSlopeDiff(point, point1, point2);
                        if (slopeDiff > 0) {
                            // 由于double精度在计算时会有损失,故匹配一定的容差。经试验,坐标经度可以达到0.0001
                            if (slopeDiff < precision) {
                                // 点在斜线P1P2上  
                                return true;
                            } else {
                                // 点与斜线P1P2有交点  
                                intersectPointCount++;
                            }
                        }
                    }
                }
            } else {
                // 边P1P2水平  
                if (point1.getLat() == point2.getLat()) {
                    if (checkPointInLine(point, point1, point2)) {
                        return true;
                    }
                }
                /**
                 * 判断点通过多边形顶点 
                 */
                if (((point.getLat() == point1.getLat() && point.getLng() < point1.getLng()))
                        || (point.getLat() == point2.getLat() && point.getLng() < point2.getLng())) {
                    if (point2.getLat() < point1.getLat()) {
                        intersectPointWeights += -0.5;
                    } else if (point2.getLat() > point1.getLat()) {
                        intersectPointWeights += 0.5;
                    }
                }
            }
            point1 = point2;
        }
        // 偶数在多边形外
        if ((intersectPointCount + Math.abs(intersectPointWeights)) % 2 == 0) {
            return false;
        } else { // 奇数在多边形内  
            return true;
        }
    }

    private static double getSlopeDiff(MapPoint point, MapPoint point1, MapPoint point2) {
        double slopeDiff = 0.0d;
        if (point1.getLat() > point2.getLat()) {
            slopeDiff = (point.getLat() - point2.getLat()) / (point.getLng() - point2.getLng())
                    - (point1.getLat() - point2.getLat()) / (point1.getLng() - point2.getLng());
        } else {
            slopeDiff = (point.getLat() - point1.getLat()) / (point.getLng() - point1.getLng())
                    - (point2.getLat() - point1.getLat()) / (point2.getLng() - point1.getLng());
        }
        return slopeDiff;
    }

    private static boolean checkPointInLine(MapPoint point, MapPoint point1, MapPoint point2) {
        if (point.getLng() <= Math.max(point1.getLng(), point2.getLng())
                && point.getLng() >= Math.min(point1.getLng(), point2.getLng())) {
            // 若点在水平的边P1P2上,则点在多边形内
            return true;
        }
        return false;
    }

    /**
     * 判断点是否在矩形内在矩形边界上,也算在矩形内(根据这些点,构造一个外包矩形)
     *
     * @param point          点对象
     * @param boundaryPoints 矩形边界点
     * @return
     */
    public static boolean isPointInRectangle(MapPoint point, MapPoint[] boundaryPoints) {
        // 西南角点
        MapPoint southWestPoint = getSouthWestPoint(boundaryPoints);
        // 东北角点
        MapPoint northEastPoint = getNorthEastPoint(boundaryPoints);
        return (point.getLng() >= southWestPoint.getLng() && point.getLng() <= northEastPoint.getLng()
                && point.getLat() >= southWestPoint.getLat() && point.getLat() <= northEastPoint.getLat());

    }

    /**
     * 根据这组坐标,画一个矩形,然后得到这个矩形西南角的顶点坐标
     *
     * @param vertexs
     * @return
     */
    private static MapPoint getSouthWestPoint(MapPoint[] vertexs) {
        double minLng = vertexs[0].getLng(), minLat = vertexs[0].getLat();
        for (MapPoint bmapPoint : vertexs) {
            double lng = bmapPoint.getLng();
            double lat = bmapPoint.getLat();
            if (lng < minLng) {
                minLng = lng;
            }
            if (lat < minLat) {
                minLat = lat;
            }
        }
        return new MapPoint(minLng, minLat);
    }

    /**
     * 根据这组坐标,画一个矩形,然后得到这个矩形东北角的顶点坐标
     *
     * @param vertexs
     * @return
     */
    private static MapPoint getNorthEastPoint(MapPoint[] vertexs) {
        double maxLng = 0.0d, maxLat = 0.0d;
        for (MapPoint bmapPoint : vertexs) {
            double lng = bmapPoint.getLng();
            double lat = bmapPoint.getLat();
            if (lng > maxLng) {
                maxLng = lng;
            }
            if (lat > maxLat) {
                maxLat = lat;
            }
        }
        return new MapPoint(maxLng, maxLat);
    }

}  

使用方式

GraphUtils.isPointInPolygon(MapPoint point,List<MapPoint> boundaryPoints)

返回值是true,说明在区域内,否则不在

文末小彩蛋,自建摸鱼网站,各大网站热搜一览,上班和摸鱼很配哦!

Java地图中,可以通过几个点来确定一个区域的位置,并且可以获取该区域中的设备。一种常见的做法是使用经纬度坐标系来表示地图上的点和区域。 首先,需要使用一种合适的地图数据来构建地图,例如使用Google Maps API提供的地图数据。然后,可以使用Java地图库,如Google Maps Java API或者Leaflet等,在Java程序中加载地图数据。 要确定一个区域的位置,可以通过在地图上选择几个点来标记该区域的边界。这些点的经纬度坐标可以通过用户在地图上的操作获得,或者通过其他方式获取。例如,可以使用鼠标点击事件监听用户在地图上的点击操作,并记录用户点击的点的经纬度坐标。 一旦确定了区域的边界点,可以使用Java地图库提供的函数或方法来计算该区域的位置。通常,使用多边形或矩形的方式来表示一个区域。可以根据指定的边界点构建一个多边形或矩形对象,然后使用相关的函数判断一个点是否在该区域内。 在确定了区域的位置后,可以获取该区域中的设备。这可以通过使用Java地图库提供的功能来实现。可以在区域中定义一个设备的类或对象,然后在地图上显示这些设备的位置。用户可以通过操作地图上的设备标记来获取相关设备的信息。 总的来说,通过在Java地图中确定区域的位置并获取该区域中的设备,需要使用合适的地图数据和Java地图库,并通过选择标记点的方式确定区域的边界,使用相关的函数判断是否区域内,并在地图上显示设备的位置和获取设备的信息。
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

sum墨

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

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

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

打赏作者

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

抵扣说明:

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

余额充值