Search code examples
pythondjangodjango-rest-frameworkhaversinelocation-aware

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


I have a location aware server in Django that's supposed to return data only when the user is within a given radius of the database entry.. I found a code snippet in python that does just that online (here or elsewhere, I really can't remember) and it seemed to work when I tested it against coordinates of 0,0 and not when I set two different coordinates. I now have a database entry that is within 300 meters of my current location and the radius is set to 10 kilometers but for some reason the server is not returning the results back to me. where am I going wrong with this code cos I'm totally clueless on how to fix it, newbie to python and helplessly lost and out of my element with haversine with 5 days till my project is due. here is my code for the haversine based query:

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)

this image shows that the request was received and the coordinates are right but the resultset is still empty :(

Server out put


Solution

  • So.. I found out where the algorithm was going wrong.. thanks to @ncole458's post Answer source

    here is the fully functional server code:

    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)