feat(story-2.3): implement home marker and airspace outline rendering

Adds draw_home_marker() in overlay.py (red cross at projected home
position) and draw_airspace() in airspace.py (GeoJSON Polygon
boundaries in blue, graceful FileNotFoundError handling). Includes
airspace fixture and three tests covering all acceptance criteria.
All 70 tests pass; ruff check and format clean.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Matt Edholm
2026-04-22 23:16:03 -04:00
parent 5a18d0867a
commit e8ce0602a4
6 changed files with 144 additions and 29 deletions
+30 -1
View File
@@ -1 +1,30 @@
# stub
from __future__ import annotations
import json
import logging
from PIL import Image, ImageDraw
from planemapper.constants import AIRSPACE_PATH, COLOUR_AIRSPACE
from planemapper.renderer.projection import MapBounds, project
log = logging.getLogger(__name__)
def draw_airspace(image: Image.Image, bounds: MapBounds) -> None:
try:
data = json.loads(AIRSPACE_PATH.read_text(encoding="utf-8"))
except FileNotFoundError:
log.warning("airspace.geojson not found at %s — skipping airspace overlay", AIRSPACE_PATH)
return
draw = ImageDraw.Draw(image)
for feature in data.get("features", []):
geom = feature.get("geometry", {})
if geom.get("type") != "Polygon":
continue
coords = geom.get("coordinates", [[]])[0]
if len(coords) < 2:
continue
# GeoJSON is [lon, lat] — reverse at parse boundary
points = [project(lat, lon, bounds) for lon, lat in coords]
draw.line(points, fill=COLOUR_AIRSPACE, width=2)
+13
View File
@@ -0,0 +1,13 @@
from __future__ import annotations
from PIL import Image, ImageDraw
from planemapper.constants import COLOUR_HOME_MARKER
from planemapper.renderer.projection import MapBounds, project
def draw_home_marker(image: Image.Image, bounds: MapBounds) -> None:
cx, cy = project(bounds.home_lat, bounds.home_lon, bounds)
draw = ImageDraw.Draw(image)
draw.line([(cx - 10, cy), (cx + 10, cy)], fill=COLOUR_HOME_MARKER, width=3)
draw.line([(cx, cy - 10), (cx, cy + 10)], fill=COLOUR_HOME_MARKER, width=3)