地图围栏计算

1 篇文章 0 订阅
1 篇文章 0 订阅

背景

在地图功能开发过程中,遇到电子围栏问题。判断一个坐标是否在一个多边形的电子围栏中。

原理

以坐标点向左发射射线,判断射线与围栏的每一条边是否存在交点。将交点统计,为偶数则不在围栏之内,反之则在围栏之内。

代码实现

坐标实体类


import lombok.Data;
import java.math.BigDecimal;

/**
 * 坐标
 *
 * @author zhouyaoming
 * @version 1.0.0
 */
@Data
public class CoordinateForm {

    /**
     * 经度
     */
    private BigDecimal longitude;

    /**
     * 纬度
     */
    private BigDecimal latitude;
}

** 模糊计算**

/**
     * 计算坐标是否在电子围栏之内(模糊计算)
     * @param coordinateForm
     * @param ps
     * @return
     */
    public static boolean isPtInPolys( List<CoordinateForm> ps,CoordinateForm coordinateForm) {
        double ALon = coordinateForm.getLongitude().doubleValue();
        double ALat = coordinateForm.getLatitude().doubleValue();
        int iSum, iCount, iIndex;
        double dLonFirst = 0, dLonSecond = 0, dLatFirst = 0, dLatSecond = 0, dLon;
        if (ps.size() < Constant.THREE) {
            return false;
        }
        iSum = 0;
        iCount = ps.size();
        for (iIndex = 0; iIndex < iCount; iIndex++) {
            dLonFirst = ps.get(iIndex).getLongitude().doubleValue();
            dLatFirst = ps.get(iIndex).getLatitude().doubleValue();
            if (iIndex == iCount - 1) {
                dLonSecond = ps.get(0).getLongitude().doubleValue();
                dLatSecond = ps.get(0).getLatitude().doubleValue();
            } else {
                dLonSecond = ps.get(iIndex + 1).getLongitude().doubleValue();
                dLatSecond = ps.get(iIndex + 1).getLatitude().doubleValue();
            }
            // 以下语句判断A点是否在边的两端点的水平平行线之间,在则可能有交点,开始判断交点是否在左射线上
            if (((ALat >= dLatFirst) && (ALat < dLatSecond)) || ((ALat >= dLatSecond) && (ALat < dLatFirst))) {
                if (Math.abs(dLatFirst - dLatSecond) > 0) {
                    //得到 A点向左射线与边的交点的x坐标:
                    dLon = dLonFirst - ((dLonFirst - dLonSecond) * (dLatFirst - ALat)) / (dLatFirst - dLatSecond);
                    // 如果交点在A点左侧(说明是做射线与 边的交点),则射线与边的全部交点数加一:
                    if (dLon < ALon) {
                        iSum++;
                    }
                }
            }
        }
        if ((iSum % Constant.TWO) != 0) {
            return true;
        }
        return false;
    }

精确计算

/**
     * 计算坐标是否在电子围栏之内(精确计算)
     *
     * @param ps             电子围栏坐标
     * @param coordinateForm 所求坐标位置
     * @return
     */
    public static boolean isPtInPoly(List<CoordinateForm> ps, CoordinateForm coordinateForm) {
        BigDecimal ALon = coordinateForm.getLongitude();
        BigDecimal ALat = coordinateForm.getLatitude();
        int iSum, iCount, iIndex;
        BigDecimal dLonFirst = new BigDecimal(0), dLonSecond = new BigDecimal(0), dLatFirst = new BigDecimal(0), dLatSecond = new BigDecimal(0), dLon;
        if (ps.size() < Constant.THREE) {
            return false;
        }
        iSum = 0;
        iCount = ps.size();
        for (iIndex = 0; iIndex < iCount; iIndex++) {
            dLonFirst = ps.get(iIndex).getLongitude();
            dLatFirst = ps.get(iIndex).getLatitude();
            // 当取最后一个坐标时,将围栏的第一个坐标赋值给坐标second
            if (iIndex == iCount - 1) {
                dLonSecond = ps.get(0).getLongitude();
                dLatSecond = ps.get(0).getLatitude();
            } else {
                dLonSecond = ps.get(iIndex + 1).getLongitude();
                dLatSecond = ps.get(iIndex + 1).getLatitude();
            }
            // 以下语句判断A点是否在边的两端点的水平平行线之间,在则可能有交点,开始判断交点是否在左射线上
            if (((ALat.compareTo(dLatFirst) >= 0) && (ALat.compareTo(dLatSecond) < 0)) || ((ALat.compareTo(dLatSecond) >= 0) && (ALat.compareTo(dLatFirst) < 0))) {
                if (dLatFirst.subtract(dLatSecond).abs().compareTo(new BigDecimal(0)) > 0) {
                    //得到 A点向左射线与边的交点的x坐标:
                    dLon = dLonFirst.subtract((dLonFirst.subtract(dLonSecond)).multiply(dLatFirst.subtract(ALat))).divide(dLatFirst.subtract(dLatSecond), 6, BigDecimal.ROUND_HALF_EVEN);
                    // 如果交点在A点左侧(说明是做射线与 边的交点),则射线与边的全部交点数加一:
                    if (dLon.compareTo(ALon) < 0) {
                        iSum++;
                    }
                }
            }
        }
        if ((iSum % Constant.TWO) != 0) {
            return true;
        }
        return false;
    }
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值