仅当坐标完全匹配时基于 Haversine 的服务器 returns 数据

Haversine based Server returns data only when coordinates are an exact match

我在 Django 中有一个位置感知服务器,它应该 return 只有当用户在数据库条目的给定半径范围内时才发送数据。我在 python 中找到了一个代码片段只是在线(这里或其他地方,我真的不记得了)并且当我针对 0,0 的坐标测试它时它似乎有效,而不是当我设置两个不同的坐标时。我现在有一个数据库条目,在我当前位置的 300 米范围内,半径设置为 10 公里,但由于某种原因,服务器没有 return 将结果返回给我。这段代码我哪里出错了因为我完全不知道如何修复它,python 的新手并且在我的项目到期前 5 天无助地迷失了我的 haversine 元素。 这是我基于 haversine 的查询的代码:

class StoreList(generics.ListAPIView):
permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                  IsOwnerOrReadOnly,)
serializer_class = StoreSerializer

def get_queryset(self):
    lat = self.request.query_params.get('lat', None)
    lon = self.request.query_params.get('lng', None)

    if lat and lon:
        lat = float(lat)
        lon = float(lon)

        # Haversine formula = https://en.wikipedia.org/wiki/Haversine_formula


        lat1 = math.radians(lat)  # lat in radians
        lng1 = math.radians(lon)  # lng in radians

        lat2 = math.asin(math.sin(lat1)*math.cos(distance/R) +
            math.cos(lat1)*math.sin(distance/R)*math.cos(bearing))

        lng2 = lng1 + math.atan2(math.sin(bearing)*math.sin(distance/R)*math.cos(lat1),
            math.cos(distance/R)-math.sin(lat1)*math.sin(lat2))

        lat2 = math.degrees(lat2)
        lng2 = math.degrees(lng2)

        return Store.objects.filter(latitude__gte=lat1, latitude__lte=lat2)\
            .filter(longitude__gte=lng1, longitude__lte=lng2)

此图显示请求已收到且坐标正确但结果集仍然为空:(

您似乎传递的是弧度 lat1lng1,但度数是 lat2lng2。 (您将 lat1lng1 转换为弧度,但从未将它们改回度数。)

切换到像 postgresql(带有 postgis 扩展)或 mysql 5.7 这样的位置感知数据库会容易得多。如果您查看距某个点给定距离的对象,对于此类数据库来说是一个简单的查询,并且是 fully supported by django

Dwithin Returns models where the distance to the geometry field from the lookup geometry are within the given distance from one another. Note that you can only provide Distance objects if the targeted geometries are in a projected system. For geographic geometries, you should use units of the geometry field (e.g. degrees for WGS84) .

Example:

Zipcode.objects.filter(poly__dwithin=(geom, D(m=5)))

这样你的复杂代码就变成了一行代码。地理空间数据库中有很多功能,您会发现它们非常有用。

所以..我发现了算法哪里出了问题..感谢@ncole458的post Answer source

这是功能齐全的服务器代码:

class StoreList(generics.ListAPIView):
permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                  IsOwnerOrReadOnly,)
serializer_class = StoreSerializer

def get_queryset(self):
    lat = self.request.query_params.get('lat', None)
    lon = self.request.query_params.get('lng', None)

    if lat and lon:
        lat = float(lat)
        lon = float(lon)

        # Haversine formula = https://en.wikipedia.org/wiki/Haversine_formula


        """
        lat1 = math.radians(lat)  # lat in radians
        lng1 = math.radians(lon)  # lng in radians

        lat2 = math.asin(math.sin(lat1)*math.cos(distance/R) +
            math.cos(lat1)*math.sin(distance/R)*math.cos(bearing))

        lng2 = lng1 + math.atan2(math.sin(bearing)*math.sin(distance/R)*math.cos(lat1),
            math.cos(distance/R)-math.sin(lat1)*math.sin(lat2))

        lat1 = math.degrees(lat1)
        lat2 = math.degrees(lat2)

        lat2 = math.degrees(lat2)
        lng2 = math.degrees(lng2)
        """
        lat1 = lat - math.degrees(distance / R)
        lat2 = lat + math.degrees(distance / R)
        lng1 = lon - math.degrees(distance / R / math.cos(math.degrees(lat)))
        lng2 = lon + math.degrees(distance / R / math.cos(math.degrees(lat)))

        return Store.objects.filter(latitude__gte=lat1, latitude__lte=lat2)\
            .filter(longitude__gte=lng1, longitude__lte=lng2)