由电子围栏引发的经纬度计算
- 什么是电子围栏?
就是跟孙悟空那个一样,画个圈,进入会有信息警告。
- 
类型有哪些? - 圆形的:适用于某个地点,比如说家里,小孩子离开家的半径100米就会发出警告,这个100米是半径参数;
- 线性的:适用于上学,放学路线,比如说离开设定路线100米,就会发出警告,这个100米为距离;
- 多边型:不规则的多边型,适用于区域,比如说学校,把学校画个多边型,离开了这个多边型就会触发警告。
 
当然,还有进入的警告,这个看需求。
花钱的实现方式
- 高德
- 百度
- 腾讯
都有的
腾讯的参考
https://lbs.qq.com/service/placeCloud/placeCloudGuide/cloudOverview

配额限制:

百度的参考
https://lbs.baidu.com/faq/api?title=yingyan/guide/geo-fence
配额限制:

高德地图参考:
https://lbs.amap.com/api/track/lieying-kaifa/api/track_fence
配额限制:

于是我打算自己做一个!
思路
- 对于圆形的围栏,这个我会,小时候我学过点到圆心的距离
- 如果等于半径,就在圆上,如果大于半径,就在圆外,如果小于半径,就在圆内。
 
- 对于线性的围栏,也可以用同样的知识来解决,求当前点与线上每一点的距离,然后找出最小距离的作为目标比较,如果是大于设定的距离,那么在线外,如果小于目标距离,在线内。
- 多边形的,可以通过射线方程计算交点,根据交点个数判断在多边形内还是多边形外:
- 任意射线与多边形的交点个数是奇数,则点在多边形内,是偶数,则点在多边形外
 
数据表结构
- id ID
- fence_name 围栏名称
- type 类型:line shape circle
- points 点列表
- distance 距离(line和circle时必填)
- create_time 创建时间
- update_time 更新时间
主要代码
查询和围栏入库的代码我就不贴了
贴一下关键的代码
求两个经纬度之间的距离
    /**
     * @param lat1 第一点的纬度
     * @param lon1 第一点的经度
     * @param lat2 第二点的纬度
     * @param lon2 第二点的经度
     * @return 两点间的大圆距离(米)
     * socketHandler.distance("12345678", 23.118, 113.368, 23.077114, 113.345843);
     */
    public double distance(String deviceId, double lat1, double lon1, double lat2, double lon2) {
        log.info("distance ==> {} {} {} {} {}", deviceId, lat1, lon1, lat2, lon2);
        Point source = new Point(lon1, lat1);
        redisTemplate.opsForGeo().add(deviceId, source, "source");
        Point target = new Point(lon2, lat2);
        redisTemplate.opsForGeo().add(deviceId, target, "target");
        Distance distance = redisTemplate.opsForGeo().distance(deviceId, "source", "target", Metrics.KILOMETERS);
        if (distance != null) {
            double value = distance.getValue();
            log.info("value ==> {}", value);
            //单位米
            return value * 1000;
        }
        redisTemplate.opsForGeo().remove(deviceId, "source", "target");
        return 0;
    }
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
这里我直接用了redis来求两个经纬度坐标点之间的距离,大家也可以自己写。
点与多边形的关系
 /**
     * 判断一个点是否位于一个多边形内部。
     *
     * @param pointX  目标点的经度
     * @param pointY  目标点的纬度
     * @param polygon 多边形的顶点列表
     * @return 如果点在多边形内则返回 true,否则返回 false
     */
    public static boolean isPointInPolygon(double pointX, double pointY, List<String> polygon) {
        int n = polygon.size();
        boolean inside = false;
        String pointItem1 = polygon.get(0);
        String[] split1 = pointItem1.split(",");
        double p10 = Double.parseDouble(split1[0]);
        double p11 = Double.parseDouble(split1[1]);
        for (int i = 0; i < n + 1; i++) {
            String pointItem2 = polygon.get(i % n);
            String[] split2 = pointItem2.split(",");
            double p20 = Double.parseDouble(split2[0]);
            double p21 = Double.parseDouble(split2[1]);
            if (pointY > Math.min(p11, p21)) {
                if (pointY <= Math.max(p11, p21)) {
                    if (pointX <= Math.max(p10, p20)) {
                        if (p11 != p21) {
                            double xints = (pointY - p11) * (p20 - p10) / (p21 - p11) + p10;
                            if (p10 == p20 || pointX <= xints) {
                                inside = !inside;
                            }
                        }
                    }
                }
            }
            p10 = p20;
            p11 = p21;
        }
        return inside;
    }





























