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