fix: render GeoJSON Multi* geometries on the mesh map#1987
Conversation
MultiPoint, MultiLineString, and MultiPolygon features produced no (or partial) map content. MeshMapContent.overlayContent only branched on Point/LineString/ Polygon, and GeoJSONStyledFeature kept only mkFeature.geometry.first — so every sub-geometry past the first was silently dropped even when a branch existed. After meshtastic#1970 quieted the Point overlay log, the silent drop was easy to miss. Collect all decoded sub-geometries into precomputedOverlays (flattening any MKMultiPolygon/MKMultiPolyline into simple MKPolygon/MKPolyline), and render the overlay layer by switching on overlay type so LineString/Polygon and their Multi* variants are handled uniformly. Add markerCoordinates so Point and MultiPoint both draw annotations, precomputed once at init like the overlays. Also tidy an unused-binding warning in MapDataManager.validateFile. Tests: per-geometry overlay counts (incl. MultiPolygon -> 2, MultiLineString -> 3), marker coordinates for Point/MultiPoint, and empty/malformed -> no overlays.
|
Heads-up on an incoming collision with the The pmtiles branch reworks the map render path and will conflict with this PR in three places:
No change requested on the substance — plan is to land this on |
|
Superseded by #1989. The Map tab MKMapView migration (#1989) removed the SwiftUI The one remaining gap this PR addressed — Closing as superseded. 🙏 |
The MKMapView GeoJSON path (MeshMapMK.rebuildGeoJSONOverlays) drew a marker only for single Point features via AnyCodableValue.toCoordinate(), which returns nil for a MultiPoint's nested coordinate array — so MultiPoint features rendered no markers at all. Add GeoJSONFeature.markerCoordinates (one coordinate for Point, one per sub-coordinate for MultiPoint) plus AnyCodableValue.toCoordinates(), and emit one ClusterMapDecoration per coordinate. MultiPolygon/MultiLineString already render via MKGeoJSONDecoder + the ClusterMapView multi-geometry renderers; this closes the remaining gap from #1987, which targeted the now-removed SwiftUI MeshMapContent renderer. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
What changed?
GeoJSON
MultiPoint,MultiLineString, andMultiPolygonfeatures now render on the mesh map. Previously they produced no (or only partial) map content:MeshMapContent.overlayContentonly branched onPoint/LineString/Polygon, so Multi* geometry types matched no branch and drew nothing.GeoJSONStyledFeaturekept onlymkFeature.geometry.first, so even where a branch existed, every sub-geometry past the first was silently dropped.The fix:
GeoJSONStyledFeaturenow collects all decoded sub-geometries intoprecomputedOverlays, flattening anyMKMultiPolygon/MKMultiPolylinewrapper into simpleMKPolygon/MKPolylineso the render layer handles one uniform list.overlayContentrenders the overlay layer by switching on overlay type (MKPolyline→MapPolyline,MKPolygon→MapPolygon), soLineString/Polygonand their Multi* variants are drawn the same way.markerCoordinates(precomputed at init, like the overlays) draws annotations for bothPointandMultiPoint.MapDataManager.validateFile.Why did it change?
Valid, common GeoJSON that uses Multi* geometries silently produced no/partial map content. The gap was surfaced during the #1970 review (the Point overlay log-spam fix); after #1970 quieted the spurious Point overlay error, the silent drop became even easier to miss. This makes the map render the geometry types that the GeoJSON spec — and typical exported overlays — routinely contain.
How is this tested?
Added model-layer tests in
MeshtasticTests/GeoJSONOverlayConfigTests.swift(Swift Testing). All GeoJSON tests pass (64 total); run via the workspace on an iPhone 16 / iOS 18 simulator (matching CI):.firsttruncation), MultiLineString → 3, LineString → 1, and Point / MultiPoint → 0 overlays.toCoordinates()parsing.Note: a SwiftUI
Mapsnapshot test was evaluated and deliberately not included — MapKit draws overlays asynchronously, so an off-screen snapshot captures a blank base map and can't assert overlay rendering. The deterministic guard lives at the model layer (overlay/marker counts) instead.Known follow-up (out of scope):
GeometryCollectionmember points still aren't drawn as markers.Screenshots/Videos (when applicable)
Checklist
docs/user/ordocs/developer/, and updated accordingly. No doc update needed — this fixes rendering of existing GeoJSON overlay support; no new user-facing settings or views. Requesting theskip-docs-checklabel (external-contributor PR can't self-apply it).