3

我的目标是在我的最新项目中创建一个功能,最好使用 PHP。当每个用户注册时,他们将输入他们的邮政编码。然后希望我将使用 Open Street Map 将其转换为纬度/经度。

无论如何,我希望能够找出位于当前用户附近的其他用户。我见过很多人使用 Haversine 公式,但这意味着用户查询了其他所有用户的详细信息以计算距离。我可以缓存它,但随着新用户的注册,它很快就会过时。

运行以下查询会对我的系统产生什么样的影响?

sql = "SELECT zipcode, ( 3959 * acos( cos( radians( {$coords['latitude']} ) ) 
    * cos( radians( latitude ) ) * cos( radians( longitude ) 
    - radians( {$coords['longitude']} ) ) 
    + sin( radians( {$coords['latitude']} ) ) * sin( radians( latitude ) ) ) ) 
    AS distance FROM zipcodes HAVING distance <= {$radius} ORDER BY distance";

这是从某人的博客中提取的。

我没有任何关于注册率或用户数量的数据,因为它仍在开发中。

如果我能使用任何反馈或其他方法在特定范围内找到匹配的用户,我将不胜感激。

4

3 回答 3

2

在 4.1 版中有对 mySql 的 GIS 和空间扩展,请参见此处。从描述中您会发现,它用于解决您在此处遇到的问题:

GIS(地理信息系统)存储和查找具有一个或多个空间属性(例如大小和位置)的对象,并用于处理这些对象。一个简单的例子是使用地理坐标在城镇中存储地址的系统。如果这个相当静态的数据随后与其他信息(例如出租车的位置)相结合,那么该数据可用于找到离某个位置最近的出租车。

它向 MySql 添加了一些内容,例如:

  • 空间键和 POINT 类型:

    CREATE TABLE 地址(地址 CHAR(80) NOT NULL, address_loc POINT NOT NULL, PRIMARY KEY(address), SPATIAL KEY(address_loc) );

  • 转换例程

    INSERT INTO address VALUES('Foobar street 12', GeomFromText('POINT(2671 2500)') );

  • GIS计算功能

    SELECT c.cabdriver, ROUND( GLength(LineStringFromWKB(LineString(AsBinary(c.cab_loc), AsBinary(a.address_loc)))) ) 作为距离 cab c 的距离,按距离 ASC LIMIT 1 排序;

(示例取自上面的链接)

于 2009-07-28T13:28:06.657 回答
1

如果您愿意将“在一定半径内”的定义放宽为不具体是圆,则可以大大简化问题。如果您简化为“正方形”,您可以使用 2 个简单的“介于”子句(一个代表纬度,一个代表长)在“半径”内找到所有位置。例如:

SELECT * FROM location WHERE
  lat BETWEEN (my_lat - radius) AND (my_lat + radius)
  AND long BETWEEN (my_long - radius) AND (my_long + radius);

当然,这可用于选择您的位置子集,然后再使用更准确的方法计算到它们的实际距离。

于 2009-07-28T13:35:58.397 回答
0

诚然,这是 Javascript 而不是 PHP,但我想转换它是微不足道的。

它计算两点之间的距离,考虑到地球的曲率。不久前在物流应用程序中使用它,然后用使用正确道路路线的代码替换它。

可能对你有用......

<script type="text/javascript">
function getDistance(lat1,lng1,lat2,lng2)
 {
  p1 = new VELatLong(lat1,lng1);
  p2 = new VELatLong(lat2,lng2);
  miles = true;
  p1.Latitude= latLonToRadians(p1.Latitude);
  p1.Longitude= latLonToRadians(p1.Longitude);
  p2.Latitude= latLonToRadians(p2.Latitude);
  p2.Longitude= latLonToRadians(p2.Longitude);
  var R = 6371; // earth's mean radius in km
  var dLat  = p2.Latitude- p1.Latitude;
  var dLong = p2.Longitude- p1.Longitude;
  var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
  Math.cos(p1.Latitude) * Math.cos(p2.Latitude) * Math.sin(dLong/2) * 
Math.sin(dLong/2);
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  var disKm = R * c;
  var disMiles = disKm * 0.6214;
  alert (miles ? disMiles : disKm);
 }
 //  convert lat/long in degrees to radians
 function latLonToRadians( point )
 {
  return point * Math.PI / 180;
 }
</script>

哦,VELatLong 对象来自 Virtual Earth API ( http://msdn.microsoft.com/en-us/library/bb412519.aspx ),但基本上是一个美化的结构,所以你应该能够找到合适的替代品

于 2009-07-28T13:34:19.723 回答