加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

php – 按坐标之间的距离过滤wordpress帖子

发布时间:2020-12-13 17:48:29 所属栏目:PHP教程 来源:网络整理
导读:我想要做的是通过2个坐标之间的距离过滤一堆wordpress帖子.用户输入的坐标,范围和类别在URL中传递,如下所示: /?cat=0s=5041GWrange=250lat=51.5654368lon=5.071263999999928 然后有一些帖子(不是全部)有一个lat和long字段,我使用插件高级自定义字段创建.这
我想要做的是通过2个坐标之间的距离过滤一堆wordpress帖子.用户输入的坐标,范围和类别在URL中传递,如下所示:

/?cat=0&s=5041GW&range=250&lat=51.5654368&lon=5.071263999999928

然后有一些帖子(不是全部)有一个lat和long字段,我使用插件高级自定义字段创建.这些是我传递给get_posts以获取按类别过滤的帖子的参数:

$args = array(
        'posts_per_page'   => 24,'category'         => $_GET["cat"],'orderby'          => 'post_date','order'            => 'DESC','post_type'        => 'adressen','post_status'      => 'publish',);

现在我要做的就是修改它,以便在实际传递范围和位置时,帖子将被过滤为仅返回位置在用户搜索位置的范围(以千米为单位)内的帖子.我似乎无法找到一个好的解决方案,因为我很难使用wordpress及其插件.我真的很感激我能理解的解决方案.

解决方法

这在计算上可能相当昂贵.直接的方法是获取符合条件的所有帖子,然后循环遍历所有帖子,丢弃指定范围之外的帖子.

由于米和纬度/长度之间没有线性映射,因此出现了困难.这取决于你在地球上的位置.有关详情,请参见this question. PHPcoord library存在为您进行此计算,但由于我提出的答案的略微近似性质,我将使用Haversine formula使用Haversine formula描述的近似方法.

我将使用以下公式:

>计算两个lat / lng坐标之间的距离(以km为单位):

x = Δλ ? cos φm
y = Δφ
d = R ? √(x2 + y2)

其中φ是弧度的纬度,λ是弧度的经度,R是地球的半径(平均半径= 6,371km)
>在给定起始纬度,距离和方位的情况下计算目的地:

φ2 = asin( sin φ1 ? cos δ + cos φ1 ? sin δ ? cos θ )
λ2 = λ1 + atan2( sin θ ? sin δ ? cos φ1,cos δ ? sin φ1 ? sin φ2 )

其中θ是方位(从北向顺时针方向),δ是角距离d / R,d是行进距离.见atan2.

因此,我们将定义以下辅助函数:

const R = 6371; // km

function distance_between_points_rad($lat1,$lng1,$lat2,$lng2){
    // latlng in radians
    $x = ($lng2-$lng1) * cos(($lat1+$lat2)/2);
    $y = ($lat2-$lat1);
    // return distance in km
    return sqrt($x*$x + $y*$y) * R;
}

function get_destination_lat_rad($lat1,$d,$brng){
    return asin( sin($lat1)*cos($d/R) +
                    cos($lat1)*sin($d/R)*cos($brng) );
}

function get_destination_lng_rad($lat1,$brng){
    $lat2 = get_destination_lat_rad($lat1,$brng);
    return $lng1 + atan2(sin($brng)*sin($d/R)*cos($lat1),cos($d/R)-sin($lat1)*sin($lat2));
}

function get_bounding_box_rad($lat,$lng,$range){
    // latlng in radians,$range in km
    $latmin = get_destination_lat_rad($lat,$range,0);
    $latmax = get_destination_lat_rad($lat,deg2rad(180));
    $lngmax = get_destination_lng_rad($lat,deg2rad(90));
    $lngmin = get_destination_lng_rad($lat,deg2rad(270));
    // return approx bounding latlng in radians
    return array($latmin,$latmax,$lngmin,$lngmax);
}

function distance_between_points_deg($lat1,$lng2){
    // latlng in degrees
    // return distance in km
    return distance_between_points_rad(
        deg2rad($lat1),deg2rad($lng1),deg2rad($lat2),deg2rad($lng2) );
}

function get_bounding_box_deg($lat,$range){
    // latlng in degrees,$range in km
    return array_map(rad2deg,get_bounding_box_rad(deg2rad($lat),deg2rad($lng),$range));
}

(Runnable in ideone)

现在,一般过程应是:

>创建一个边界square-ish框,将帖子过滤到一个
很少是正确的.这不应该太计算
昂贵,但是可能会留下一些边缘的近似值
out,并包括一些不适合的帖子.
>优化退货
只发布适合账单的那些帖子.这是计算上的
昂贵的过程,因此是第一阶段.少数帖子被排除在外
第一步仍将被排除在外.边界框可以
可能会变大以适应.

您要使用的查询应包含元信息:
请参阅here以获取有关这些元查询的有用指南

$lat1 = $_GET['lat']; // degrees
$lng1 = $_GET['lng']; // degrees
$range = $_GET['range']; // km

// get the approximate bounding box
$bbox = get_bounding_box_deg($lat1,$range);

// query the posts
$args = array(
    'posts_per_page'   => 24,'meta_query' => array(
        'relation' => 'AND',array(
            'key' => 'lat','value' => array( $bbox[0],$bbox[1] ),'type' => 'numeric','compare' => 'BETWEEN'
        ),array(
            'key' => 'lng','value' => array( $bbox[2],$bbox[3] ),'compare' => 'BETWEEN'
        )
    )
);
$the_query = new WP_Query( $args );

然后在循环中过滤帖子:

// Then filter the posts down in the loop
if ( $the_query->have_posts() ) {
    while ( $the_query->have_posts() ) {
        $the_query->the_post();
        $custom_fields = get_post_custom();
        if (isset($custom_fields['lat']) && isset($custom_fields['lng'])){
             $lat2 = $custom_fields['lat'];
             $lng2 = $custom_fields['lng'];
             $dist = distance_between_points_deg($lat1,$lng2);
             if ($dist <= $range){
                 // post is in range
             } else {
                 // post out of range,discard
             }
        } else {
            // post has no latlng coords
        }
    }
} else {
    // no posts found
}
/* Restore original Post Data */
wp_reset_postdata();

WordPress代码未经测试,如果错误仍然存??在,请道歉.一般的概念是正确的.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读