根据MySQL中的半径合并边界框中的长/纬度点

Posted

技术标签:

【中文标题】根据MySQL中的半径合并边界框中的长/纬度点【英文标题】:Merge long/lat points within a bounding box depending on a radius in MySQL 【发布时间】:2014-04-23 06:34:45 【问题描述】:

这是我基本上想要实现的图片:

正如标题所说,我想将它们的半径(例如 25 公里)触摸的长/纬点合并到长/纬点的边界框内。

这是我非常简单的数据库结构:

+-------+-------------+------------+
| id    |        long |        lat |
+-------+-------------+------------+
|     1 |   -90.27137 |   50.00702 |
|     2 |   -92.27137 |   52.00702 |
|     3 |   -87.27137 |   48.00702 |
|     4 |   -91.27137 |   51.00702 |
+-------+-------------+------------+

这是我目前的查询:

set @bottom_lat = -100.27137;
set @bottom_lon = 40.00702;

set @top_lat = -80.27137 ;
set @top_lon = 60.00702 ;
;

SELECT AVG(latitude), AVG(longitude)
FROM destination
WHERE latitude > @bottom_lat AND longitude > @bottom_lon AND latitude < @top_lat AND longitude < @top_lon

所以我的查询只是合并了一个假想的边界框内的所有点,而不考虑半径。

我知道我可能不得不使用 Haversine 公式,但我在数学和 mysql 方面很糟糕,这让事情变得有点困难。事实上,如果我只有一个半径,我最终可以合并点,但每个点都有自己的半径,我正在努力。

这是针对学生项目的,非常感谢任何帮助。

参考资料:

-我在 SQL Fiddle 上的查询:http://sqlfiddle.com/#!2/3a42b/2 (在评论中包含一个用于 Haversine 公式的 SQL Fiddle 示例)

-MySQL 查询中的 Haversine 公式:(用于检查给定半径内的所有点)

SELECT*, ( 6371* acos( cos( radians(
@my_lat) ) * cos( radians( 
destination.latitude ) ) * cos( radians( 
destination.longitude ) - radians(
@my_lon) ) + sin( radians(
@my_lat) ) * sin( radians( 
destination.latitude ) ) ) ) AS distance 
FROM destination
ORDER BY distance limit 1
;

【问题讨论】:

也许看看en.wikipedia.org/wiki/Spatial_database 以及你如何处理缩放级别? 嗨,我去看看,谢谢。我不确定是否理解您的问题,但缩放级别将通过根据此缩放改变每个点的半径来处理。 【参考方案1】:

如果没有 php 或其他编程语言的帮助,此操作可能太复杂而无法执行。以下是您可以在 PHP 中执行此操作的方法:

<?
    $link = mysqli_connect("host", "user", "pass", "database");

    // Grab all the points from the db and push them into an array
    $sql = "SELECT * FROM data";
    $res = $link->query($sql);
    $arr = array();
    for($i = 0; $i < mysqli_num_rows($res); $i++)
        array_push($arr, mysqli_fetch_assoc($res));
    

    // Cycle through the point array, eliminating those points that "touch" 
    $rad = 1000; //radius in KM
    for($i = 0; $i < count($arr); ++$i)
        $lat1 = $arr[$i]['lat'];
        $lon1 = $arr[$i]['long'];
        for($j = 0; $j<count($arr); ++$j)
            if($i != $j && isset($arr[$i]) && isset($arr[$j])) // do not compare a point to itself
                $lat2 = $arr[$j]['lat'];
                $lon2 = $arr[$j]['long'];
                // get the distance between each pair of points using the haversine formula
                $dist = acos( sin($lat1*pi()/180)*sin($lat2*pi()/180) + cos($lat1*pi()/180)*cos($lat2*pi()/180)*cos($lon2*PI()/180-$lon1*pi()/180) ) * 6371;
                if($dist < $rad)
                    echo "Removing point id:".$arr[$i]['id']."<br>";
                    unset($arr[$i]);
                
            
        
    

    //display results
    echo "Remaining points:<br>";
    foreach($arr as $val)
        echo "id=".$val['id']."<br>";
    
?>

此代码对您提供的数据的输出是:

    Removing point id:1
    Removing point id:2
    Remaining points:
    id=3
    id=4

请注意,这只会删除重叠点,不会对位置进行任何平均。你可以很容易地添加它。希望这会有所帮助。

【讨论】:

以上是关于根据MySQL中的半径合并边界框中的长/纬度点的主要内容,如果未能解决你的问题,请参考以下文章

合并,合并火花数据框中的 2 列

根据 Pandas 中的公共列值合并两个数据框

合并重复记录,根据MySql中的条件值保留一些数据

使用 .between() 检查从字典中拉出的长/纬度位置时出错

需要合并数据框中的两列[重复]

地理位置计算:如果点在半径内,则计算它们