12

这可能不清楚,也可能不清楚,如果我不在基地,请给我留言,或者您需要更多信息。也许已经有一个解决方案可以满足我在 PHP 中的需求。

我正在寻找一个可以从经度或纬度值中添加或减去距离的函数。

原因:我有一个包含所有纬度和经度的数据库,并希望形成一个查询来提取 X 公里(或英里)内的所有城市。我的查询看起来像这样......

Select * From Cities Where (Longitude > X1 and Longitude < X2) And (Latitude > Y1 and Latitude < Y2)

 Where X1 = Longitude - (distance)
 Where X2 = Longitude + (distance)

 Where Y1 = Latitude - (distance)
 Where Y2 = Latitude + (distance)

我正在使用 PHP,使用 MySql 数据库。

也欢迎任何建议!:)

4

10 回答 10

17

这是一个 MySQL 查询,它将完全按照您的要求进行。请记住,这样的事情通常是近似值,因为地球不是完美的球形,也没有考虑到山脉、丘陵、山谷等。我们在AcademicHomes.com上使用 PHP 和 MySQL 上的这段代码,它返回 $ 内的记录$latitude, $longitude 的半径英里。

$res = mysql_query("SELECT
    * 
FROM
    your_table
WHERE
    (
        (69.1 * (latitude - " . $latitude . ")) * 
        (69.1 * (latitude - " . $latitude . "))
    ) + ( 
        (69.1 * (longitude - " . $longitude . ") * COS(" . $latitude . " / 57.3)) * 
        (69.1 * (longitude - " . $longitude . ") * COS(" . $latitude . " / 57.3))
    ) < " . pow($radius, 2) . " 
ORDER BY 
    (
        (69.1 * (latitude - " . $latitude . ")) * 
        (69.1 * (latitude - " . $latitude . "))
    ) + ( 
        (69.1 * (longitude - " . $longitude . ") * COS(" . $latitude . " / 57.3)) * 
        (69.1 * (longitude - " . $longitude . ") * COS(" . $latitude . " / 57.3))
    ) ASC");
于 2009-05-01T13:18:36.387 回答
3

编辑:如果您在某个地方拥有世界上所有城市及其纬度的列表。并且很长。值,您可以进行查找。在这种情况下,请参阅下面的第一个链接,了解计算纬度上一个经度宽度的公式替代文字

替代文字

老实说,这个问题背后的复杂性是,你最好使用谷歌地图等服务来获取你的数据。具体来说,地球不是一个完美的球体,两度之间的距离会随着您离赤道的近/远而变化。

有关我的意思的示例,请参见http://en.wikipedia.org/wiki/Geographic_coordinate_system,并查看Google Maps API

于 2009-04-30T21:07:42.960 回答
1

根据您包含的城市数量,您可以预先计算列表。我们在这里为一个内部应用程序执行此操作,其中 +100m 的不准确性对于我们的设置来说太大了。它的工作原理是有一个 location1、location2、distance 的两个键表。然后,我们可以非常快速地从 location1 拉回位置 x 距离。

此外,由于计算可以离线完成,它不会影响系统的运行。用户还可以获得更快的结果。

于 2009-05-01T08:47:54.587 回答
1

我尝试使用上面的代码,当点之间的距离在 20-30 英里范围内时,答案偏离了太多,我可以接受几英里的错误。与我的一位制图伙伴交谈,我们想出了这个。代码是 python,但你可以很容易地翻译它。为了避免不断转换为弧度,我重新编写了我的数据库,将纬度/经度点从度数转换为弧度。关于这一点的好处是,数学的最大部分大多只完成一次。

ra = 3963.1906 # radius @ equator in miles, change to km  if you want distance in km
rb = 3949.90275  # radius @ poles in miles, change to km  if you want distance in km
ra2 = ra * ra
rb2 = rb * rb

phi = self.lat

big_ol_constant = (math.pow(ra2*math.cos(phi), 2) + pow(rb2*math.sin(phi), 2))/ (pow(ra*math.cos(phi), 2) + pow(rb*math.sin(phi), 2))

sqlWhere = "%(distance)g > sqrt((power(lat - %(lat)g,2) + power(lng-%(lng)g,2)) * %(big_ol_constant)g)" % {
    'big_ol_constant': big_ol_constant, 'lat': self.lat, 'lng': self.lng, 'distance': distance}

# This is the Django portion of it, where the ORM kicks in.  sqlWhere is what you would put after the WHERE part of your SQL Query.
qs = ZipData.objects.extra(where=[sqlWhere]);

当距离很小时似乎非常准确,并且在距离增加到 200 英里时在 10 英里左右(当然,到那时,你会遇到“乌鸦飞翔”与“铺砌的道路”的问题)。

这是我上面提到的模型 ZipData。

class ZipData(models.Model):
    zipcode = ZipCodeField(null=False, blank=False, verbose_name="ZipCode", primary_key=True)
    city = models.CharField(max_length=32, null=False, blank=False)
    state = models.CharField(max_length=2)
    lat = models.FloatField(null=False, blank=False)
    lng = models.FloatField(null=False, blank=False)

额外说明一下,您可以在GeoNames.org上获得大量与邮政编码相关的地理数据,他们甚至还有一些您可以使用的 Web 服务 API。

于 2010-06-07T14:30:36.897 回答
0

有很多(不好的选择)

  • 使用数学公式(将 X1-X2 和 Y1-Y2 视为向量)计算距离。

  • 提前创建一个包含所有组合的查找表并保持距离。

  • 考虑使用 MySQL 的 GIS 特定扩展。这是我发现的一篇文章。

于 2009-04-30T20:48:35.190 回答
0

lessthandot.com 实际上有 3 种不同的方法来做到这一点。您必须稍微滚动浏览博客,但它们就在那里。 http://blogs.lessthandot.com/

于 2009-04-30T20:58:47.583 回答
0

下面的函数来自nerddinner的(在 codeplex 上可用的 ASP.NET MVC 示例应用程序)数据库 (MSSQL)。

ALTER FUNCTION [dbo].[DistanceBetween] (@Lat1 as real,
                @Long1 as real, @Lat2 as real, @Long2 as real)
RETURNS real
AS
BEGIN

DECLARE @dLat1InRad as float(53);
SET @dLat1InRad = @Lat1 * (PI()/180.0);
DECLARE @dLong1InRad as float(53);
SET @dLong1InRad = @Long1 * (PI()/180.0);
DECLARE @dLat2InRad as float(53);
SET @dLat2InRad = @Lat2 * (PI()/180.0);
DECLARE @dLong2InRad as float(53);
SET @dLong2InRad = @Long2 * (PI()/180.0);

DECLARE @dLongitude as float(53);
SET @dLongitude = @dLong2InRad - @dLong1InRad;
DECLARE @dLatitude as float(53);
SET @dLatitude = @dLat2InRad - @dLat1InRad;
/* Intermediate result a. */
DECLARE @a as float(53);
SET @a = SQUARE (SIN (@dLatitude / 2.0)) + COS (@dLat1InRad)
                 * COS (@dLat2InRad)
                 * SQUARE(SIN (@dLongitude / 2.0));
/* Intermediate result c (great circle distance in Radians). */
DECLARE @c as real;
SET @c = 2.0 * ATN2 (SQRT (@a), SQRT (1.0 - @a));
DECLARE @kEarthRadius as real;
/* SET kEarthRadius = 3956.0 miles */
SET @kEarthRadius = 6376.5;        /* kms */

DECLARE @dDistance as real;
SET @dDistance = @kEarthRadius * @c;
return (@dDistance);
END

我猜这可能会有所帮助。

于 2009-04-30T21:30:29.660 回答
0

您可以使用毕达哥拉斯定理来计算两对纬度/经度点的接近度。

如果您有两个位置(Alpha 和 Beta),您可以计算它们之间的距离:

SQRT( POW(Alpha_lat - Beta_lat,2) + POW(Alpha_lon - Beta_lon,2) )
于 2009-05-01T09:50:13.547 回答
0

使用来自以下 URL 的设置,我构建了下面的查询。(请注意我使用 codeIgnitor 来查询数据库)

http://howto-use-mysql-spatial-ext.blogspot.com/2007/11/using-circular-area-selection.html

function getRadius($point="POINT(-29.8368 30.9096)", $radius=2)
{
    $km = 0.009;
    $center = "GeomFromText('$point')";
    $radius = $radius*$km;
    $bbox = "CONCAT('POLYGON((',
        X($center) - $radius, ' ', Y($center) - $radius, ',',
        X($center) + $radius, ' ', Y($center) - $radius, ',',
        X($center) + $radius, ' ', Y($center) + $radius, ',',
        X($center) - $radius, ' ', Y($center) + $radius, ',',
        X($center) - $radius, ' ', Y($center) - $radius, '
    ))')";

    $query = $this->db->query("
    SELECT id, AsText(latLng) AS latLng, (SQRT(POW( ABS( X(latLng) - X({$center})), 2) + POW( ABS(Y(latLng) - Y({$center})), 2 )))/0.009 AS distance
    FROM crime_listing
    WHERE Intersects( latLng, GeomFromText($bbox) )
    AND SQRT(POW( ABS( X(latLng) - X({$center})), 2) + POW( ABS(Y(latLng) - Y({$center})), 2 )) < $radius
    ORDER BY distance
        ");

    if($query->num_rows()>0){
        return($query->result());
    }else{
        return false;
    }
}
于 2009-12-01T10:17:01.833 回答
0

不要重新发明轮子。这是一个空间查询。使用MySQL 内置的空间扩展,将经纬度坐标数据存储在原生 MySQL 几何列类型中。然后使用距离函数查询彼此之间指定距离内的点。

免责声明:这是基于阅读文档,我自己没有尝试过。

于 2009-12-02T13:19:35.670 回答