PHP判断地理围栏是否有重合

/* 判断地理围栏是否有重合
* $points 二维数组内含经纬度坐标
* $arr 二维数组,元素内为json格式的二维数组
* return bool true为有重合  false为没有重合
**/
    function in_geo( array $points , array $arr ){
        if( empty( $points ) || !is_array( $points ) ){
            return false;
        }

        if( empty( $arr ) || !is_array( $arr ) ){
            return false;
        }

        # 处理新数据
        $new_points = [];
        foreach ( $points as $k => $v ){
            $new_points[] = [$v['latitude'],$v['longitude']];
        }

        # 获取新数据的中心点
        $center = $this->GetCenterFromDegrees( $new_points );

        # 循环和已存在的区域中心点比对
        foreach ( $arr as $key => $val ){
            # 转为数组格式
            $val = json_decode( $val['points'] , true );

            # 获取中心点坐标
            $val = $this->update_array( $val );

            # 计算距离
            $range = $this->getDistance( $val[0] ,$val[1] , $center[0] , $center[1] );

            $arr[$key]['range'] = $range;
        }

        # 将数组由近到远排序
        $arr = $this->array_sort( $arr );

        # 取最近的一条数据
        $new_arr = json_decode( $arr[0]['points'] , true );

        # 判断新数据是否被包含在一个区域中
        foreach ( $new_arr as $kk => $vv ){
            $geo[] = $vv['longitude'] . ',' . $vv['latitude'];
        }

        for ( $p = 0; $p <= count( $points ) -1; $p++ ){
            $fences = $points[$p]['longitude'] . ',' . $points[$p]['latitude'];
            if( $this->in_fences( $geo , $fences ) ){
                return 1;
            }
        }

        # 获取多边形线段数组
        $arr_line = $this->changeLine( $new_arr );

        # 获取新数据线段数组
        $points_line = $this->changeLine( $points );

        $num = 0;
        for ( $i = 0; $i <= count( $points_line ) -1; $i++ ){
            for ( $j = $i; $j <= count( $points_line ) -1; $j++){
                # 判断是否有线段相交
                $line = $this -> isSegmentsIntersectant( $points_line[$i] , $arr_line[$j] );

                if( $line ){
                    $num++;
                }
            }
        }
        return $num;
    }

以下为算法中运用到的其他算法

	[GetCenterFromDegrees方法](https://blog.csdn.net/weixin_44309184/article/details/97647381)

/*
 * 处理数组删除不必要的元素并获取中心点坐标
 * $data 二维数组
 * return 数组中必要的元素和中心点坐标
 * **/
    function update_array( array $data ){
        if( !is_array( $data ) ) return false;

        if( count( $data ) <= 1 ){
            foreach ( $data as $key => $val ){
                return [ $val['latitude'] , $val['longitude'] ];
            }
        }else {
            foreach ($data as $k => $v) {
                if ( array_key_exists('name', $v ) ) {
                    unset($data[$k]['address']);
                    unset($data[$k]['name']);
                } else {
                    unset($data[$k]['address']);
                }

                $data[$k][0] = $data[$k]['latitude'];
                $data[$k][1] = $data[$k]['longitude'];
                unset($data[$k]['latitude']);
                unset($data[$k]['longitude']);
            }
        }
        return $this->GetCenterFromDegrees( $data );
    }
    
    [getDistance方法](https://blog.csdn.net/weixin_44309184/article/details/97647717)

	/*
     * 对数组根据距离排序
     * **/
    function array_sort( array $data = [] ){
        # 判断是否为空
        if( empty( $data ) ){
            return [];
        }

        # 判断是否为数组
        if( !is_array( $data ) ){
            return [];
        }

        for ( $i = 0; $i < count( $data ); $i++ ){
            $arr = '';
            for ( $j = $i; $j < count( $data ) -1; $j++ ){
                if( $data[$i]['range'] > $data[$j+1]['range'] ){
                    $arr = $data[$i];

                    # 互换位置
                    $data[$i] = $data[$j+1];
                    $data[$j+1] = $arr;
                }
            }

            if ($data[$i]['range'] < 1) {
                $data[$i]['range'] = $data[$i]['range'] * 1000;
                $data[$i]['range'] = round( $data[$i]['range'] ) . 'm';
            } else {
                $data[$i]['range'] = round( $data[$i]['range'] , 2 ) . 'km';
            }

        }

        return $data;
    }

[in_fences方法](https://blog.csdn.net/weixin_44309184/article/details/97763428)


	/*
     * 将多边形拆分为多个线段算法
     * params $arr 需要进行拆解的二维数组
     * return array 返回三维数组
     * **/
    function changeLine( array $arr ){
        if( empty( $arr ) ){
            return [];
        }

        if( count( $arr ) == 1 ){
            return $arr;
        }

        for ( $i = 0; $i < count( $arr ) -1; $i++ ){
            for ( $j = $i +1; $j <= count( $arr ) -1; $j++ ){
                $data[] = [ [ 'x' => $arr[$i]['latitude'] , 'y' => $arr[$i]['longitude'] , 'name' => $arr[$i]['name'] ] , ['x' => $arr[$j]['latitude'] , 'y' => $arr[$j]['longitude'] , 'name' => $arr[$j]['name'] ] ];
            }
        }
        return $data;
    }

	//判断两多边形线段是否相交
    function isSegmentsIntersectant($segA, $segB) {//线线
        $abc = ($segA[0]['x'] - $segB[0]['x']) * ($segA[1]['y'] - $segB[0]['y']) - ($segA[0]['y'] - $segB[0]['y']) * ($segA[1]['x'] - $segB[0]['x']);
        $abd = ($segA[0]['x'] - $segB[1]['x']) * ($segA[1]['y'] - $segB[1]['y']) - ($segA[0]['y'] - $segB[1]['y']) * ($segA[1]['x'] - $segB[1]['x']);
        if ($abc * $abd >= 0) {
            return false;
        }
        $cda = ($segB[0]['x'] - $segA[0]['x']) * ($segB[1]['y'] - $segA[0]['y']) - ($segB[0]['y'] - $segA[0]['y']) * ($segB[1]['x'] - $segA[0]['x']);
        $cdb = $cda + $abc - $abd;
        return !($cda * $cdb >= 0);
    }
该算法并非无问题,如有能人异士可改善,欢迎评论
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值