def test_migration_seed_data_correctly(self): longitude = 120.1 latitude = 23.234 radius_km = 1 distance = 6371 * ACos( Cos(Radians(latitude)) * Cos(Radians("lat")) * Cos(Radians("lng") - Radians(longitude)) + Sin(Radians(latitude)) * Sin(Radians("lat"))) factories = Factory.objects.annotate(distance=distance).filter( distance__lt=radius_km) self.assertEqual( set([factory.name for factory in factories]), set([ "既有違章工廠 No.2", "既有違章工廠 No.3", "既有違章工廠 No.8", "既有違章工廠 No.9", "既有違章工廠 No.10", "既有違章工廠 No.11", "既有違章工廠 No.12", "既有違章工廠 No.13", "既有違章工廠 No.22", ]), )
def _get_nearby_factories(latitude, longitude, radius): """Return nearby factories based on position and search range.""" # ref: https://stackoverflow.com/questions/574691/mysql-great-circle-distance-haversine-formula distance = 6371 * ACos( Cos(Radians(latitude)) * Cos(Radians("lat")) * Cos(Radians("lng") - Radians(longitude)) + Sin(Radians(latitude)) * Sin(Radians("lat"))) radius_km = radius ids = Factory.objects.annotate(distance=distance).only("id").filter( distance__lt=radius_km).order_by("id") if len(ids) > settings.MAX_FACTORY_PER_GET: ids = _sample(ids, settings.MAX_FACTORY_PER_GET) return (Factory.objects.filter( id__in=[obj.id for obj in ids]).prefetch_related( Prefetch('report_records', queryset=ReportRecord.objects.only("created_at").all()) ).prefetch_related( Prefetch( 'images', queryset=Image.objects.only("id").all())).prefetch_related( Prefetch('documents', queryset=Document.objects.only( 'created_at', 'display_status').all())).all())
def test_migration_seed_data_correctly(): longitude = 120.1 latitude = 23.234 radius_km = 1 distance = 6371 * ACos( Cos(Radians(latitude)) * Cos(Radians("lat")) * Cos(Radians("lng") - Radians(longitude)) + Sin(Radians(latitude)) * Sin(Radians("lat")) ) factories = Factory.objects.annotate(distance=distance).filter( distance__lt=radius_km, ) assert ( list(factories.values_list('name', flat=True)) == Unordered([ "既有違章工廠 No.2", "既有違章工廠 No.3", "既有違章工廠 No.8", "既有違章工廠 No.9", "既有違章工廠 No.10", "既有違章工廠 No.11", "既有違章工廠 No.12", "既有違章工廠 No.13", "既有違章工廠 No.22", ]) )
def filter_cone_search(self, queryset, name, value): """ Executes cone search by annotating each target with separation distance from either the specified RA/Dec or the RA/Dec of the specified target. Formula is from Wikipedia: https://en.wikipedia.org/wiki/Angular_distance The result is converted to radians. Cone search is preceded by a square search to reduce the search radius before annotating the queryset, in order to make the query faster. """ if name == 'cone_search': ra, dec, radius = value.split(',') elif name == 'target_cone_search': target_name, radius = value.split(',') targets = Target.objects.filter( Q(name__icontains=target_name) | Q(aliases__name__icontains=target_name)).distinct() if len(targets) == 1: ra = targets[0].ra dec = targets[0].dec else: return queryset.filter(name=None) ra = float(ra) dec = float(dec) double_radius = float(radius) * 2 queryset = queryset.filter(ra__gte=ra - double_radius, ra__lte=ra + double_radius, dec__gte=dec - double_radius, dec__lte=dec + double_radius) separation = ExpressionWrapper( 180 * ACos((Sin(radians(dec)) * Sin(Radians('dec'))) + (Cos(radians(dec)) * Cos(Radians('dec')) * Cos(radians(ra) - Radians('ra')))) / Pi(), FloatField()) return queryset.annotate(separation=separation).filter( separation__lte=radius)
def cone_search_filter(queryset, ra, dec, radius): """ Executes cone search by annotating each target with separation distance from the specified RA/Dec. Formula is from Wikipedia: https://en.wikipedia.org/wiki/Angular_distance The result is converted to radians. Cone search is preceded by a square search to reduce the search radius before annotating the queryset, in order to make the query faster. :param queryset: Queryset of Target objects :type queryset: Target :param ra: Right ascension of center of cone. :type ra: float :param dec: Declination of center of cone. :type dec: float :param radius: Radius of cone search in degrees. :type radius: float """ ra = float(ra) dec = float(dec) radius = float(radius) double_radius = radius * 2 queryset = queryset.filter(ra__gte=ra - double_radius, ra__lte=ra + double_radius, dec__gte=dec - double_radius, dec__lte=dec + double_radius) separation = ExpressionWrapper( 180 * ACos((Sin(radians(dec)) * Sin(Radians('dec'))) + (Cos(radians(dec)) * Cos(Radians('dec')) * Cos(radians(ra) - Radians('ra')))) / Pi(), FloatField()) return queryset.annotate(separation=separation).filter( separation__lte=radius)
def perimeter(self, mid_point, radius, latitude='latitude', longitude='longitude'): """ Returns a query set of locations in a specified radius (using the Haversine formula). :param mid_point: middle point coordinates of search radius (e.g. tuple of floats) :param radius: search radius in km (default) or miles depending on DISTANCE_UNIT :param latitude: query selector for latitude :param longitude: query selector for longitude :return: Annotated query set of found locations """ earth_radius = dict(EARTH_RADIUS_CHOICES).get(self.DISTANCE_UNIT) distance = (earth_radius * ACos( Cos(Radians(latitude)) * Cos(Radians(mid_point[0])) * Cos(Radians(mid_point[1]) - Radians(longitude)) + Sin(Radians(latitude)) * Sin(Radians(mid_point[0])))) return self.annotate(distance=distance).filter(distance__lte=radius)