Skip to content

Commit c802df8

Browse files
committed
Fix bounding box calculation for spatial queries (closes django-haystack#718)
Thanks @jasisz for the fix
1 parent 4543b93 commit c802df8

File tree

5 files changed

+21
-14
lines changed

5 files changed

+21
-14
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,4 @@ Thanks to
8686
* Revolution Systems & The Python Software Foundation for funding a significant portion of the port to Python 3!
8787
* Artem Kostiuk (postatum) for patch allowing to search for slash character in ElasticSearch since Lucene 4.0.
8888
* Luis Barrueco (luisbarrueco) for a simple fix regarding updating indexes using multiple backends.
89+
* Szymon Teżewski (jasisz) for an update to the bounding-box calculation for spatial queries

docs/spatial.rst

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,9 +218,7 @@ finding results within an area.
218218

219219
``within`` is a bounding box comparison. A bounding box is a rectangular area
220220
within which to search. It's composed of a bottom-left point & a top-right
221-
point, though provided you give two opposing corners in either order, Haystack
222-
will determine the right coordinates. It is faster but slighty sloppier than
223-
its counterpart.
221+
point. It is faster but slighty sloppier than its counterpart.
224222

225223
Examples::
226224

haystack/backends/elasticsearch_backend.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -418,17 +418,17 @@ def build_search_kwargs(self, query_string, sort_by=None, start_offset=0, end_of
418418
if within is not None:
419419
from haystack.utils.geo import generate_bounding_box
420420

421-
((min_lat, min_lng), (max_lat, max_lng)) = generate_bounding_box(within['point_1'], within['point_2'])
421+
((south, west), (north, east)) = generate_bounding_box(within['point_1'], within['point_2'])
422422
within_filter = {
423423
"geo_bounding_box": {
424424
within['field']: {
425425
"top_left": {
426-
"lat": max_lat,
427-
"lon": min_lng
426+
"lat": north,
427+
"lon": west
428428
},
429429
"bottom_right": {
430-
"lat": min_lat,
431-
"lon": max_lng
430+
"lat": south,
431+
"lon": east
432432
}
433433
}
434434
},

haystack/utils/geo.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,14 @@ def ensure_distance(dist):
6161
return dist
6262

6363

64-
def generate_bounding_box(point_1, point_2):
64+
def generate_bounding_box(bottom_left, top_right):
6565
"""
66-
Takes two opposite corners of a bounding box (in any order) & generates
66+
Takes two opposite corners of a bounding box (order matters!) & generates
6767
a two-tuple of the correct coordinates for the bounding box.
6868
6969
The two-tuple is in the form ``((min_lat, min_lng), (max_lat, max_lng))``.
7070
"""
71-
lng_1, lat_1 = point_1.get_coords()
72-
lng_2, lat_2 = point_2.get_coords()
71+
west, lat_1 = bottom_left.get_coords()
72+
east, lat_2 = top_right.get_coords()
7373
min_lat, max_lat = min(lat_1, lat_2), max(lat_1, lat_2)
74-
min_lng, max_lng = min(lng_1, lng_2), max(lng_1, lng_2)
75-
return ((min_lat, min_lng), (max_lat, max_lng))
74+
return ((min_lat, west), (max_lat, east))

tests/spatial/tests.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,15 @@ def test_generate_bounding_box(self):
5454
self.assertEqual(max_lat, 38.973081081164715)
5555
self.assertEqual(max_lng, -95.23362278938293)
5656

57+
def test_generate_bounding_box_crossing_line_date(self):
58+
downtown_bottom_left = Point(95.23947, 38.9637903)
59+
downtown_top_right = Point(-95.23362278938293, 38.973081081164715)
60+
((south, west), (north, east)) = generate_bounding_box(downtown_bottom_left, downtown_top_right)
61+
self.assertEqual(south, 38.9637903)
62+
self.assertEqual(west, 95.23947)
63+
self.assertEqual(north, 38.973081081164715)
64+
self.assertEqual(east, -95.23362278938293)
65+
5766

5867
class SpatialSolrNoDistanceTestCase(TestCase):
5968
fixtures = ['sample_spatial_data.json']

0 commit comments

Comments
 (0)