我有一个计算两个GPS坐标之间距离的函数。然后我从数据库中获取所有坐标并循环遍历它们以获得当前的坐标与前一个坐标之间的距离,然后将其添加到特定GPS设备的阵列中。由于某种原因,它返回NaN。我已经尝试将其转换为double,int和舍入数字。
这是我的PHP代码:
function distance($lat1, $lon1, $lat2, $lon2) {
$lat1 = round($lat1, 3);
$lon1 = round($lon1, 3);
$lat2 = round($lat2, 3);
$lon2 = round($lon2, 3);
$theta = $lon1 - $lon2;
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
if($miles < 0) $miles = $miles * -1;
return ($miles * 1.609344);
}
$this->db->query("SELECT * FROM `gps_loc` WHERE `imeiN`='" . $sql . "' AND `updatetime`>=$timeLimit ORDER BY `_id` DESC");
$dist = array();
$dist2 = array();
while($row = $this->db->getResults()) {
$dist2[$row['imeiN']] = 0;
$dist[$row['imeiN']][]["lat"] = $row['lat'];
$dist[$row['imeiN']][count($dist[$row['imeiN']]) - 1]["lng"] = $row['lon'];
}
foreach($dist as $key=>$d) {
$a = 0;
$b = 0;
foreach($dist[$key] as $n) {
if($a > 0) {
$dist2[$key] += $this->distance($n['lat'], $n['lng'], $dist[$key][$a - 1]['lat'], $dist[$key][$a - 1]['lng']);
}
$a++;
}
}
echo json_encode($dist2);
答案 0 :(得分:4)
sin()
和cos()
的范围介于-1和1之间。因此,在您第一次计算$dist
时,结果范围是-2到2.然后将其传递给{ {1}},其参数必须介于-1和1之间。因此acos()
例如给出了NaN。那里的其他所有东西都给了NaN。
我不确定该公式应该是什么,但这就是你的NaN来自哪里。仔细检查你的三角学。
答案 1 :(得分:4)
如果点太靠近,算法会产生NaN。在这种情况下,$ dist获得值1. acos(1)是NaN。所有后续计算也会产生NaN。 你将坐标作为第一步进行舍入,因此更有可能在舍入后值变得相等,并产生NaN
答案 2 :(得分:2)
您从数据库中提取的值可能是字符串,这会导致此问题。
您可能还想查看Kolink在其帖子中提出的问题。
答案 3 :(得分:0)
那是你正在使用的余弦球面定律吗?我转而使用Haversine公式:
function distance($lat1, $lon1, $lat2, $lon2)
{
$radius = 3959; //approximate mean radius of the earth in miles, can change to any unit of measurement, will get results back in that unit
$delta_Rad_Lat = deg2rad($lat2 - $lat1); //Latitude delta in radians
$delta_Rad_Lon = deg2rad($lon2 - $lon1); //Longitude delta in radians
$rad_Lat1 = deg2rad($lat1); //Latitude 1 in radians
$rad_Lat2 = deg2rad($lat2); //Latitude 2 in radians
$sq_Half_Chord = sin($delta_Rad_Lat / 2) * sin($delta_Rad_Lat / 2) + cos($rad_Lat1) * cos($rad_Lat2) * sin($delta_Rad_Lon / 2) * sin($delta_Rad_Lon / 2); //Square of half the chord length
$ang_Dist_Rad = 2 * asin(sqrt($sq_Half_Chord)); //Angular distance in radians
$distance = $radius * $ang_Dist_Rad;
return $distance;
}
您应该能够将地球的半径更改为任何形式的测量,从光年的半径到纳米的半径,并为所使用的单位返回适当的数字。
答案 4 :(得分:0)
感谢这里的所有回复 - 因此我创建了一个函数,它结合了NaN的计算和测试,如果两者都不是NaN - 它平均计算,如果一个是NaN而另一个不是 - 它使用有效的那个,并为其中一个计算失败的坐标提供错误报告:
function distance_slc($lat1, $lon1, $lat2, $lon2) {
$earth_radius = 3960.00; # in miles
$distance = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($lon2-$lon1)) ;
$distance = acos($distance);
$distance = rad2deg($distance);
$distance = $distance * 60 * 1.1515;
$distance1 = round($distance, 4);
// use a second method as well and average
$radius = 3959; //approximate mean radius of the earth in miles, can change to any unit of measurement, will get results back in that unit
$delta_Rad_Lat = deg2rad($lat2 - $lat1); //Latitude delta in radians
$delta_Rad_Lon = deg2rad($lon2 - $lon1); //Longitude delta in radians
$rad_Lat1 = deg2rad($lat1); //Latitude 1 in radians
$rad_Lat2 = deg2rad($lat2); //Latitude 2 in radians
$sq_Half_Chord = sin($delta_Rad_Lat / 2) * sin($delta_Rad_Lat / 2) + cos($rad_Lat1) * cos($rad_Lat2) * sin($delta_Rad_Lon / 2) * sin($delta_Rad_Lon / 2); //Square of half the chord length
$ang_Dist_Rad = 2 * asin(sqrt($sq_Half_Chord)); //Angular distance in radians
$distance2 = $radius * $ang_Dist_Rad;
//echo "distance=$distance and distance2=$distance2\n";
$avg_distance=-1;
$distance1=acos(2);
if((!is_nan($distance1)) && (!is_nan($distance2))){
$avg_distance=($distance1+$distance2)/2;
} else {
if(!is_nan($distance1)){
$avg_distance=$distance1;
try{
throw new Exception("distance1=NAN with lat1=$lat1 lat2=$lat2 lon1=$lon1 lon2=$lon2");
} catch(Exception $e){
trigger_error($e->getMessage());
trigger_error($e->getTraceAsString());
}
}
if(!is_nan($distance2)){
$avg_distance=$distance2;
try{
throw new Exception("distance1=NAN with lat1=$lat1 lat2=$lat2 lon1=$lon1 lon2=$lon2");
} catch(Exception $e){
trigger_error($e->getMessage());
trigger_error($e->getTraceAsString());
}
}
}
return $avg_distance;
}
HTH将来也有人。