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

该博客详细介绍了如何在WordPress中通过PHP代码,结合Haversine公式,根据用户输入的经纬度和范围,精确过滤出在指定区域内的帖子。作者提供了一套函数来计算两点间的距离,并应用到Meta查询中优化查询性能。
摘要由CSDN通过智能技术生成

我想要做的是通过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 ⋅ √(x² + y²)

其中φ是弧度的纬度,λ是弧度的经度,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, $lng1, $d, $brng){

return asin( sin($lat1)*cos($d/R) +

cos($lat1)*sin($d/R)*cos($brng) );

}

function get_destination_lng_rad($lat1, $lng1, $d, $brng){

$lat2 = get_destination_lat_rad($lat1, $lng1, $d, $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, $lng, $range, 0);

$latmax = get_destination_lat_rad($lat, $lng, $range, deg2rad(180));

$lngmax = get_destination_lng_rad($lat, $lng, $range, deg2rad(90));

$lngmin = get_destination_lng_rad($lat, $lng, $range, deg2rad(270));

// return approx bounding latlng in radians

return array($latmin, $latmax, $lngmin, $lngmax);

}

function distance_between_points_deg($lat1, $lng1, $lat2, $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, $lng, $range){

// latlng in degrees, $range in km

return array_map(rad2deg,

get_bounding_box_rad(deg2rad($lat), deg2rad($lng), $range));

}

现在,一般过程应是:

>创建一个边界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, $lng1, $range);

// query the posts

$args = array(

'posts_per_page' => 24,

'category' => $_GET["cat"],

'orderby' => 'post_date',

'order' => 'DESC',

'post_type' => 'adressen',

'post_status' => 'publish',

'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] ),

'type' => 'numeric',

'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, $lng1, $lat2, $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代码未经测试,如果错误仍然存​​在,请道歉.一般的概念是正确的.

标签:wordpress,php,filtering

来源: https://codeday.me/bug/20190612/1222947.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值