MapMath

CHAPTER 10

Bounding boxes and spatial queries

How to compute a bbox from a point and radius for fast database queries — and the edge cases nobody warns you about.

3 min read

Spatial proximity queries — "find all restaurants within 2 km of this point" — are one of the most common operations in location-aware apps. Running Haversine against every row in a million-record database is too slow. The solution is a two-step pattern: use a bounding box to filter cheaply, then Haversine to filter precisely.

Bounding box from a point and radius

31.52, 74.36minLat:30.62maxLat:32.42
minLat: 30.6207
maxLat: 32.4193
minLon: 73.3050
maxLon: 75.4150

Bounding box from a point and radius

A common task: "find all venues within X km of me." Database indexes can't easily do "within X km on a sphere," but they handle "lat between A and B AND lon between C and D" instantly. So we compute a bounding box, query the box, then filter precisely.

Δφ=dR\Delta\varphi = \frac{d}{R} Δλ=dRcosφ\Delta\lambda = \frac{d}{R \cdot \cos\varphi} minLat=φΔφ,maxLat=φ+Δφ\text{minLat} = \varphi - \Delta\varphi, \quad \text{maxLat} = \varphi + \Delta\varphi minLon=λΔλ,maxLon=λ+Δλ\text{minLon} = \lambda - \Delta\lambda, \quad \text{maxLon} = \lambda + \Delta\lambda

(All angles in radians, then convert back to degrees for the query.)

The Δφ formula converts a metre distance to a latitude offset by dividing by Earth's radius — this works because latitude lines are evenly spaced. The Δλ formula includes the cos(φ) correction because longitude lines narrow as you move toward the poles: the same angular step represents fewer metres at high latitudes.

Edge cases: near the poles, cosφ\cos\varphi is tiny so Δλ\Delta\lambda blows up — use [180°,180°][-180°, 180°] for longitude. Near the antimeridian (±180°), the box wraps; you may need two queries.

Worked example

Q: Bounding box for a 5 km radius around Lahore (31.5204, 74.3587).

d=5000 m,R=6,371,008.8d = 5000 \text{ m}, \quad R = 6{,}371{,}008.8 Δφ=5000/6,371,008.8=0.000785 rad0.04497°\Delta\varphi = 5000 / 6{,}371{,}008.8 = 0.000785 \text{ rad} \approx 0.04497° Δλ=0.000785/cos(0.55013)=0.000921 rad0.05279°\Delta\lambda = 0.000785 / \cos(0.55013) = 0.000921 \text{ rad} \approx 0.05279°

Box: lat [31.4754,31.5654][31.4754, 31.5654], lon [74.3059,74.4115][74.3059, 74.4115]

function boundingBox(lat, lon, radiusMeters) {
  const R = 6371008.8;
  const φ = lat * Math.PI / 180;

  const Δφ = (radiusMeters / R) * 180 / Math.PI;
  const Δλ = (radiusMeters / (R * Math.cos(φ))) * 180 / Math.PI;

  return {
    minLat: lat - Δφ,
    maxLat: lat + Δφ,
    minLon: lon - Δλ,
    maxLon: lon + Δλ,
  };
}
Chapter 10 · Paid content

Continue reading "Bounding boxes and spatial queries"

You've reached the end of the free preview. Unlock all 22 paid chapters, including distance math, bearings, polygons, spatial indexing, and 3D map rendering — plus a downloadable PDF and the companion code repo.

  • All 22 paid chapters with worked examples
  • Downloadable PDF for offline reading
  • Companion GitHub repo (JavaScript + Python)
  • Free updates for life

Multiple payment options including Wise, PayPal, and bank transfer.