Haversine 公式,PHP,如果条件适用,则添加到第二个表中

Posted

技术标签:

【中文标题】Haversine 公式,PHP,如果条件适用,则添加到第二个表中【英文标题】:Haversine formula, PHP, to add in 2nd table if conditions apply 【发布时间】:2020-01-06 10:22:39 【问题描述】:

我正在尝试实现Haversine Formula 来检查表格的纬度/经度。我的 android 应用程序将所有传入位置存储在数据库中的特定表中,inregistrari。我的目标是获得公式来测试基于经度和纬度的新传入位置,如果新值与alerte(第二个表)中现有值之间的距离超过 50m,则到insert 位置进入两个表(alerteinregistrari),否则,仅在 inregistrari 中。必须使用存储在alerte 中的所有位置来验证新值。所以,最后我会得到一张包含所有位置的表(inregistrari),而第二张表只有在 50m 内没有任何其他位置的位置(alerte)。我试图实现( 6371 * acos( cos( radians(37) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) * sin( radians( lat ) ) ) ),但无法让它按照我想要的方式工作。由于php,我寻求指导,我实际上对此还不是很熟悉。作为第一步,我设法在两个表中直接创建PHP 到自动insert,现在我只需要实现Haversine。提前致谢!

php尝试实现haversine:

case 'alerta':

            if(isTheseParametersAvailable(array('latitudine', 'longitudine', 'id_alerta_tip', 'ID_user')))

                $problema = $_POST['id_alerta_tip'];
                $latitudine = $_POST['latitudine'];
                $longitudine = $_POST['longitudine'];
                $id = $_POST['ID_user'];

                $stmt = $conn->prepare("SELECT latitudine, longitudine FROM inregistrari WHERE latitudine = ? AND longitudine = ?");
                $stmt->bind_param("ss", $latitudine, $longitudine);
                $stmt->execute();
                $stmt->store_result();

                if($stmt->num_rows < 1)
                $stmt = $conn->prepare("INSERT INTO inregistrari (ID_user, id_alerta_tip, latitudine, longitudine) VALUES (?, ?, ?, ?)");
                $stmt->bind_param("ssss", $id, $problema, $latitudine, $longitudine);
                $stmt->execute();
                $stmt->store_result();
                $stmt = $conn->prepare("SELECT * FROM alerte WHERE id_alerta_tip = ?");
                $stmt->bind_param("s",$problema);
                $stmt->execute();
                $stmt->store_result();
                while($row = mysqli_fetch_array($stmt))
                
                    $latitudine1=$row[latitudine];
                    $longitudine1=$row[longitudine];
                    function getDistance($latitude1, $longitude1, $latitude2, $longitude2)   
                    $earth_radius = 6371;  
                    $dLat = deg2rad($latitude2 - $latitude1);  
                    $dLon = deg2rad($longitude2 - $longitude1);  
                    $a = sin($dLat/2) * sin($dLat/2) + cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * sin($dLon/2) * sin($dLon/2);  
                    $c = 2 * asin(sqrt($a));  
                    $d = $earth_radius * $c;  
                    return $d;  
                      
                    if(getDistance($latitudine,$longitudine,$latitudine1,$longitudine1)<0.05)
                    
                        $stmt = $conn->prepare("INSERT INTO alerte(id_utilizator, latitudine, longitudine, tip_problema) VALUES ('$id','$latitudine', '$longitudine', '$problema')");
                        $stmt->execute();
                    

                

                $stmt = $conn->prepare("SELECT id_alerta FROM alerte WHERE latitudine = ? AND longitudine = ?");
                $stmt->bind_param("ss", $latitudine, $longitudine);
                $stmt->execute();
                $stmt->store_result();
                if($stmt->num_rows > 0)
                $stmt->bind_result($id_alerta);
                $stmt->fetch();
                $stmt= $conn->prepare("UPDATE inregistrari SET ID_Alerta_Primarie = ? WHERE latitudine = ? AND longitudine = ?");
                $stmt->bind_param("iss",$id_alerta ,$latitudine, $longitudine);
                $stmt->execute();   
                $stmt->close();
                else
                    $response['error'] = false; 
                    $response['message'] = 'Alerta nu a putut fi inregistrata';
                
                    $response['error'] = false; 
                    $response['message'] = 'Alerta raportata';                      
                else
                    $response['error'] = false; 
                    $response['message'] = 'Alerta nu a putut fi inregistrata';
                
            else
                    $response['error'] = false; 
                    $response['message'] = 'Alerta nu a putut fi inregistrata';
                
            break;

我尝试实现while 来一次获取每一行,但它不起作用。代码在while 语句之前停止运行。谢谢!

【问题讨论】:

【参考方案1】:

这是实际的Haversine 公式:

R = earth’s radius (mean radius = 6,371km)
Δlat = lat2− lat1
Δlong = long2− long1
a = sin²(Δlat/2) + cos(lat1).cos(lat2).sin²(Δlong/2)
c = 2.atan2(√a, √(1−a))
d = R.c
Angles need to be in radians to pass to Trigonometric functions

这是 MySQL 的等价物:

SELECT *, 
 ( 3959 * acos( cos( radians(55.864237) ) * cos( radians( latitude ) ) 
 * cos( radians( longitude ) - radians(-4.251806) ) + sin( radians(55.864237) ) 
 * sin( radians( latitude ) ) ) ) AS distance 
FROM postcodes HAVING distance < 20 
ORDER BY distance LIMIT 1;

我在这里检查 20 英里内的任何区域,但您可以根据需要将其设置为短或长。查询开头的 3959 数字是用于英里的数字,如果您使用公里,则应将此数字更改为 6371。我已将其限制为 1 行,因为我只想要最接近的匹配,但是您可能想要在其他情况下更改此设置!

这是 Haversine 的 Wiki http://en.wikipedia.org/wiki/Haversine_formula

祝你好运!

【讨论】:

以上是关于Haversine 公式,PHP,如果条件适用,则添加到第二个表中的主要内容,如果未能解决你的问题,请参考以下文章

谷歌地图 - 使用PHP无法运行的Haversine公式

MySQL 大圆距离(Haversine 公式)

php中两个坐标之间的距离使用haversine

如何使用 Haversine 公式计算行驶距离(不是位移)?

如何在 ColdFusion 中锻炼 Haversine 公式

Haversine 公式 - 结果太高