我需要能够为给定的WGS84纬度和WGS84经度以及距离计算边界框或圆,但不知道从哪里开始!
与纬度/经度起点的距离应为10Km或更小。
有人可以给我一些指示/如何执行此操作的示例
我需要能够为给定的WGS84纬度和WGS84经度以及距离计算边界框或圆,但不知道从哪里开始!
与纬度/经度起点的距离应为10Km或更小。
有人可以给我一些指示/如何执行此操作的示例
Answers:
WGS-什么?WGS-84?根据您需要的准确性,您可能需要了解更多信息-我的猜测是这就是为什么您被否决的原因,尽管没有人愿意发表评论说为什么。
有两种方法:
使用WGS-84基准,一个纬度约为10001.965729 / 90公里(从赤道到极点的距离,除以90度)或111.113公里。这是近似值,这是因为地球的形状,并且因为当您接近极点时距离会发生变化(使用纬度而不是经度的一个原因-最终,一度经度的距离为零!)地球也不是完美的球。这两个都是在我的第二个答案中使用更复杂的基于投影和基准的方法的原因。
10001.965729km = 90 degrees
1km = 90/10001.965729 degrees = 0.0089982311916 degrees
10km = 0.089982311915998 degrees
这是使用十进制度,而不是度/分钟/秒。
因此,您的边界框就是您的点,正负0.08999度。或者,您可以将此数字用作半径,从而给您一个边界圆。
任何阅读此内容的GIS人员都会发抖。不过,根据您在世界上的位置,它基本上是准确的。对于半径10公里的地方,应该没问题。
使用投影库并指定您的基准面等。它得到了广泛的使用,因此Google会返回大量结果,以解决有关此问题的问题,并且有Delphi包装器。如果您在使用时遇到问题,请在此处发布另一个问题-该问题不在此范围内。Proj4网站上有使用基本API的示例,尽管这些都是C语言的,但应该相当容易翻译。他们的API参考是最佳起点,其次是FAQ。
除非您知道要使用的特定坐标或用于创建坐标的坐标,否则我将使用WGS-84作为基本基准(地球的表示形式)。它是常用的并且非常准确。
如果您的位置来自Google地图(例如),请指定Mercator投影。您可能要使用其他投影,或者使用UTM坐标而不是纬度和经度,这取决于数据源以及您是否希望在较小的局部区域获得高精度。(UTM有多个区域,所有区域都会改变变形,因此在该区域内它是非常准确的;如果将区域用作其外部的坐标,则随着移开,变形会大大增加。如果查看从一个角度投影的整个地球区域,它可能不会被识别,但是在一个区域内,UTM的翻译效果将尽可能好。坐标通常以米为单位,而不是以度数为单位,因此如果您需要10公里,坐标可能对您更有用半径。10km很容易在一个区域内,您只需要根据中心坐标选择适当的区域。唯一棘手的一点是当您接近边界时:这是常见的情况,很好,只要在选择使用哪一种方面保持一致。Proj4还可以让您平移投影,因此您可以从Mercator WGS-84 lat / long到UTM区域n,或从两个UTM区域来回。)
假设您要在数据库中进行查询,您可能想进行快速(不准确)搜索,然后精确计算出所生成位置的距离。那是你的情况吗?
以下函数(在PHP中,抱歉)将大致计算纬度和经度之间的差异。这种差异取决于搜索点的纬度。使用它们(容差较小)可以在数据库中进行快速搜索。只需使用纬度+ -deltaLatitude和经度+ -deltaLongitude即可计算该框。
deltaLatitude[rad] = distance[m] / earthRadius[m]
deltaLongitude[rad] = distance[m] / (cos(latitude[rad]) * $earthRadius[m])
/**
* Calculates the deltas in latitude and longitude to use, for a db search
* around a location in the database.
* @param float $distance Radius to use for the search [m]
* @param float $latitude Latitude of the location, we need the angle deltas for [deg decimal]
* @param float $deltaLatitude Calculated delta in latitude [deg]
* @param float $deltaLongitude Calculated delta in longitude [deg]
* @param float $earthRadius Mean earth radius in [m]
*/
public static function angleFromSphericDistance($distance, $latitude,
&$deltaLatitude, &$deltaLongitude, $earthRadius = 6371000)
{
$lat = deg2rad($latitude);
$radiusOnLatitude = cos($lat) * $earthRadius;
$deltaLatitude = $distance / $earthRadius;
$deltaLongitude = $distance / $radiusOnLatitude;
$deltaLatitude = rad2deg($deltaLatitude);
$deltaLongitude = rad2deg($deltaLongitude);
}
使用Haversine公式,您可以计算球面上的距离。将其用于找到的每个位置,以获取“精确”距离。这样,您可以测试两个地方是否在一定半径内(以圆圈代替方框)。
/**
* Calculates the great-circle distance between two points, with
* the Haversine formula.
* @param float $latitudeFrom Latitude of start point in [deg decimal]
* @param float $longitudeFrom Longitude of start point in [deg decimal]
* @param float $latitudeTo Latitude of target point in [deg decimal]
* @param float $longitudeTo Longitude of target point in [deg decimal]
* @param float $earthRadius Mean earth radius in [m]
* @return float Distance between points in [m] (same as earthRadius)
*/
public static function haversineGreatCircleDistance(
$latitudeFrom, $longitudeFrom, $latitudeTo, $longitudeTo, $earthRadius = 6371000)
{
// convert from degrees to radians
$latFrom = deg2rad($latitudeFrom);
$lonFrom = deg2rad($longitudeFrom);
$latTo = deg2rad($latitudeTo);
$lonTo = deg2rad($longitudeTo);
$latDelta = $latTo - $latFrom;
$lonDelta = $lonTo - $lonFrom;
$angle = 2 * asin(sqrt(pow(sin($latDelta / 2), 2) +
cos($latFrom) * cos($latTo) * pow(sin($lonDelta / 2), 2)));
return $angle * $earthRadius;
}
要测试纬度/经度是否在边界圆之内或之外,您需要计算从参考纬度/经度到要测试的纬度/经度点的距离。由于您的距离为10km或更小,因此,由于简单起见,我将尝试使用等角近似法而不是Haversine来获取距离。要获取以公里为单位的距离:
x = (lonRef - lon) * cos ( latRef )
y = latRef - lat
distance = EarthRadius * sqrt( x*x + y*y )
重要说明:这些公式中的经/纬度以弧度而非度为单位。EarthRadius的典型值为6371 km,它将以km为单位返回距离。现在,这是一个简单的测试,您的距离是在圆内还是圆外。如果边界圆有效,我会同意的。
对于边界矩形,我假设您希望通过与赤道平行来定义矩形。然后,我将使用范围/轴承计算(轴承为45度,135度,225度和315度)来计算边界框的角。从那里开始,我假设您不在两极,而是在多边形测试中使用一个点。
以下是用于在SQL-Server 2012中构建边界框的T-SQL代码。在我的情况下,我获得了Lat,Long的十进制值。在使用SQL STDistance
函数验证结果是否确实在特定距离之内之前,我使用它来快速限制行数。地理功能在SQL Server中非常昂贵,因此通过构建边界框,我可以大大减少必须执行的次数。
DECLARE @Lat DECIMAL(20, 13) = 35.7862
,@Long DECIMAL(20, 13) = -80.3095
,@Radius DECIMAL(7, 2) = 5
,@Distance DECIMAL(10, 2)
,@Earth_Radius INT = 6371000;
SET @Distance = @Radius * 1609.344;
DECLARE @NorthLat DECIMAL(20, 13) = @Lat + DEGREES(@distance / @Earth_Radius)
,@SouthLat DECIMAL(20, 13) = @Lat - DEGREES(@distance / @Earth_Radius)
,@EastLong DECIMAL(20, 13) = @Long + DEGREES(@distance / @Earth_Radius / COS(RADIANS(@Lat)))
,@WestLong DECIMAL(20, 13) = @Long - DEGREES(@distance / @Earth_Radius / COS(RADIANS(@Lat)));
SELECT *
FROM CustomerPosition AS cp
WHERE (
cp.Lat >= @SouthLat
AND cp.Lat <= @NorthLat )
AND (
cp.Long >= @WestLong
AND cp.Long <= @EastLong )