Php 计算起点半径内位置的最佳方法
我的目标是在我的最新项目中创建一个特性,最好使用PHP。当每个用户注册时,他们将输入他们的邮政编码。然后,希望我能用开放式街道地图将其转换为lat/long 无论如何,我希望能够找到位于当前用户附近的其他用户。 我见过很多人使用哈弗森公式,但是这意味着用户查询其他用户的详细信息来计算距离。我可以缓存这个,但随着新用户的注册,它很快就会过时 运行以下查询会对我的系统产生什么样的影响Php 计算起点半径内位置的最佳方法,php,mysql,postal-code,haversine,Php,Mysql,Postal Code,Haversine,我的目标是在我的最新项目中创建一个特性,最好使用PHP。当每个用户注册时,他们将输入他们的邮政编码。然后,希望我能用开放式街道地图将其转换为lat/long 无论如何,我希望能够找到位于当前用户附近的其他用户。 我见过很多人使用哈弗森公式,但是这意味着用户查询其他用户的详细信息来计算距离。我可以缓存这个,但随着新用户的注册,它很快就会过时 运行以下查询会对我的系统产生什么样的影响 sql = "SELECT zipcode, ( 3959 * acos( cos( radians( {$coor
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";
sql=“选择zipcode,(3959*acos(弧度({$coords['latitude']}))
*cos(弧度(纬度))*cos(弧度(经度)
-弧度({$coords['longitude']}))
+sin(弧度({$coords['latitude']}))*sin(弧度(latitude)))
由于与zipcodes的距离在4.1版中有对mySql的GIS和空间扩展,请参见。从描述中,您会发现,它用于解决您在这里遇到的问题:
地理信息系统
存储和查找具有
一个或多个空间属性,例如
作为大小和位置,用于
处理这样的对象。一个简单的例子
将是一个存储
使用地理信息的城镇地址
坐标,如果这是静态的
然后将数据与其他数据结合起来
信息,例如
出租车司机室,然后可以使用此数据
找到离某个特定区域最近的驾驶室
地点
它为MySql添加了以下内容:
- 空间关键点和点类型:
创建表地址(
地址字符(80)不为空,
地址_loc点不为空,
主键(地址),
空间键(地址)
))
- 转换例程
插入地址值('Foobar street 12',GeomFromText('POINT(2671 2500)'))
- GIS计算功能
挑选
c、 出租车司机,
圆形(GLength(线条从WKB(线条(二进制)(c.cab_loc)),
AsBinary(a.address_loc))))
作为距离
从c驾驶室,地址a
按距离订购ASC限制1
(上面链接中的例子)不可否认,这是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>
函数getDistance(lat1、lng1、lat2、lng2)
{
p1=新高度(lat1,lng1);
p2=新的VELatLong(lat2,lng2);
英里=真;
p1.纬度=纬度(p1.纬度);
p1.经度=纬度(p1.经度);
p2.纬度=纬度(p2.纬度);
p2.经度=拉特朗托拉迪安(p2.经度);
var R=6371;//地球的平均半径,单位为km
var dLat=p2.纬度-p1.纬度;
var dLong=p2.经度-p1.经度;
变量a=Math.sin(dLat/2)*Math.sin(dLat/2)+
数学cos(p1.纬度)*数学cos(p2.纬度)*数学sin(dLong/2)*
sin数学(dLong/2);
var c=2*Math.atan2(Math.sqrt(a),Math.sqrt(1-a));
var disKm=R*c;
var disMiles=disKm*0.6214;
警报(英里数?disMiles:disKm);
}
//将以度为单位的横向/纵向转换为弧度
函数拉托拉迪安(点)
{
返回点*Math.PI/180;
}
哦,VELatLong对象来自虚拟地球API(),但基本上是一个美化的结构,因此您应该能够找到合适的替代品如果您愿意将“在某个半径内”的定义放宽为非特定的圆,那么问题可以大大简化。如果您简化为“正方形”,您可以通过2个简单的“between”子句(一个用于lat,一个用于long)找到“radius”内的所有位置。例如:
当然,在使用更精确的方法计算到位置的实际距离之前,这可以用于选择位置的子集。除了坐标系在二维基础上工作之外。我查了一下格伦特,没有任何迹象表明它考虑了球面几何,或者做了毕达哥拉斯定理以外的计算。这看起来很棒!今晚下班后我要把它读一遍,看起来就像我要找的一样!真的。。。虽然从技术上讲,这歧视了生活在国际日期线或南北极附近的人:-)是的,这就是为什么“广场”在引号中的原因:)这也很棒!我很久以前从未与lat合作过。因此,理论上,我可以对从中返回的数据子集执行我的原始查询。好主意!半径的单位是米、公里还是英里?它的单位是度(或弧度,取决于数据的存储方式?)。你必须做一些数学运算才能从公里/英里换算。纬度很容易转换,经度有点复杂,但是你应该可以很容易地找到公式。OP不是问PHP(标签可能应该被删除),而是问SQL查询。实际上,他确实说过他想用PHP实现这个项目,并且他对在指定半径内匹配用户的任何方法都感兴趣。感谢您的输入。这不完全是我想要的,但它确实让我对所需的数学有了一点了解!这真的是一个与PHP相关的问题吗?听起来更像是SQL问题。首选语言是PHP/MySQL。我不知道是否有任何使用PHP实现这一点的方法可能被忽略了(显然除了在PHP中执行计算之外)。
SELECT * FROM location WHERE
lat BETWEEN (my_lat - radius) AND (my_lat + radius)
AND long BETWEEN (my_long - radius) AND (my_long + radius);