查找“X”内的城市 公里(或英里)

发布于 2024-07-18 14:20:48 字数 525 浏览 10 评论 0 原文

这可能不清楚,也可能不清楚,如果我有误,请给我评论,或者您需要更多信息。 也许已经有一个解决方案可以满足我在 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 数据库。

也欢迎任何建议! :)

This may or may not be clear, leave me a comment if I am off base, or you need more information. Perhaps there is a solution out there already for what I want in PHP.

I am looking for a function that will add or subtract a distance from a longitude OR latitude value.

Reason: I have a database with all Latitudes and Longitudes in it and want to form a query to extract all cities within X kilometers (or miles). My query would look something like this...

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)

I am working in PHP, with a MySql Database.

Open to any suggestions also! :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

凝望流年 2024-07-25 14:20:49

我尝试使用上面的代码,当点之间的距离在 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。

I Tried using the above code, and the answers were off by too much when the distance between points was in the 20-30 mile range, and I'm ok with a few miles of error. Talked with a mapping buddy of mine and we came up with this one instead. The code is python, but you can translate it pretty easily. In order to avoid the constant conversion to radians, I redid my database, converting the lat/lng points from degrees to Radians. The nice part about this is that the largest part of the math is mostly done once.

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]);

Seems to be very accurate when distance apart is small, and within 10 miles or so as the distance grows to 200 miles, (of course by then, you have issues with "as the crow flies" vs "paved roads").

Here is the model ZipData that I mention above.

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)

An extra note, is that you can gets LOTS of geo data related to postal codes at GeoNames.org and they even have some webservice APIs you can use as well.

逐鹿 2024-07-25 14:20:49

有很多(不好的选择)

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

  • 预先创建一个包含所有组合的查找表并保留距离。

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

There are many (bad options)

  • Calculate the distance using the mathematical formula (treat X1-X2 and Y1-Y2) as vectors.

  • Create a lookup table in advance with all the combinations and keep the distances.

  • Consider using a GIS-specific extension of MySQL. Here is one article I found about this.

白芷 2024-07-25 14:20:49

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

lessthandot.com actually has 3 different ways to do this. you'll have to scroll through the blogs a little but they're there.
http://blogs.lessthandot.com/

全部不再 2024-07-25 14:20:49

下面的函数来自 nerddinner 的(ASP.NET MVC 示例应用程序可在 codeplex 上使用)数据库 (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

我猜这可能会有帮助。

The function below is from the nerddinner's (ASP.NET MVC sample application available on codeplex) database (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

I am guessing this could be helpful.

撑一把青伞 2024-07-25 14:20:49

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

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

SQRT( POW(Alpha_lat - Beta_lat,2) + POW(Alpha_lon - Beta_lon,2) )

You can use Pythagoras' Theorem to calculate the proximity of two pairs of lat/lon points.

If you have two locations (Alpha and Beta) you can calculate their distance apart with:

SQRT( POW(Alpha_lat - Beta_lat,2) + POW(Alpha_lon - Beta_lon,2) )
誰認得朕 2024-07-25 14:20:49

使用以下 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;
    }
}

Using the setup from the following URL, Ive built the query below. (Please note Im using codeIgnitor to query the database)

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;
    }
}
Smile简单爱 2024-07-25 14:20:49

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

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

Don't reinvent the wheel. This is a spatial query. Use MySQL's built-in spatial extensions to store the latitude-longitude coordinate data in the native MySQL geometry column type. Then use the Distance function to query for points that are within a specified distance of one another.

Disclaimer: this is based on reading the documentation, I haven't tried this myself.

痴情换悲伤 2024-07-25 14:20:48

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

$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");

This is a MySQL query that will do exactly what you want. Keep in mind things like this are approximations generally, as the earth is not perfectly spherical nor does this take into account mountains, hills, valleys, etc.. We use this code on AcademicHomes.com with PHP and MySQL, it returns records within $radius miles of $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");
与酒说心事 2024-07-25 14:20:48

编辑:如果您在某个地方有世界上所有城市及其纬度的列表。 又长。 值,你可以进行查找。 在这种情况下,请参阅下面的第一个链接,了解计算纬度上一个纵向度数宽度的公式 alt text :

alt text

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

有关我的意思的示例,请参阅 http://en.wikipedia.org/wiki/Geographic_coefficient_system ,然后查看Google Maps API

EDIT: If you have, somewhere, a list of all of the cities in the world along with their lat. and long. values, you can do a lookup. In this case, see my first link below for the formula to calculate the width of one longitudinal degree at latitude alt text :

alt text

Honestly, the complications behind this problem are such that you'd be far better off using a service such as Google Maps to get your data. Specifically, the Earth is not a perfect sphere, and the distance between two degrees varies as you are closer to / further from the equator.

See http://en.wikipedia.org/wiki/Geographic_coordinate_system for examples of what I mean, and check out the Google Maps API.

书间行客 2024-07-25 14:20:48

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

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

Depending on how many cities you are including, you can precompute the list. We do this here for an internal application where an inaccuracy of +100m is too much for our setup. It works by having a two key table of location1, location2, distance. We can then pull back locations x distance from location1 very quickly.

Also since the calcs can be done offline, it doesn't impact the running of the system. Users also get faster results.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文