Skip to content

fix: render GeoJSON Multi* geometries on the mesh map#1987

Closed
bruschill wants to merge 1 commit into
meshtastic:mainfrom
bruschill:fix/geojson-multi-geometry-rendering
Closed

fix: render GeoJSON Multi* geometries on the mesh map#1987
bruschill wants to merge 1 commit into
meshtastic:mainfrom
bruschill:fix/geojson-multi-geometry-rendering

Conversation

@bruschill

@bruschill bruschill commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

What changed?

GeoJSON MultiPoint, MultiLineString, and MultiPolygon features now render on the mesh map. Previously they produced no (or only partial) map content:

  • MeshMapContent.overlayContent only branched on Point / LineString / Polygon, so Multi* geometry types matched no branch and drew nothing.
  • GeoJSONStyledFeature kept only mkFeature.geometry.first, so even where a branch existed, every sub-geometry past the first was silently dropped.

The fix:

  • GeoJSONStyledFeature now collects all decoded sub-geometries into precomputedOverlays, flattening any MKMultiPolygon / MKMultiPolyline wrapper into simple MKPolygon / MKPolyline so the render layer handles one uniform list.
  • overlayContent renders the overlay layer by switching on overlay type (MKPolylineMapPolyline, MKPolygonMapPolygon), so LineString/Polygon and their Multi* variants are drawn the same way.
  • A new markerCoordinates (precomputed at init, like the overlays) draws annotations for both Point and MultiPoint.
  • Tidied an unused-binding warning in 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):

  • Overlay counts per geometry: single Polygon → 1, MultiPolygon → 2 (the direct regression guard against the old .first truncation), MultiLineString → 3, LineString → 1, and Point / MultiPoint → 0 overlays.
  • Marker coordinates: Point → 1, MultiPoint → N, malformed sub-coords skipped, Polygon → none; plus toCoordinates() parsing.
  • Empty/malformed input: empty MultiPolygon and malformed coordinates → empty overlay set (the error/empty-result branches).
xcodebuild test -workspace Meshtastic.xcworkspace -scheme Meshtastic \
  -destination 'platform=iOS Simulator,name=iPhone 16,OS=18.x' \
  -only-testing:MeshtasticTests/GeoJSONStyledFeatureOverlayTests \
  -only-testing:MeshtasticTests/GeoJSONFeatureMarkerCoordinatesTests
# ** TEST SUCCEEDED **

Note: a SwiftUI Map snapshot 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): GeometryCollection member points still aren't drawn as markers.

Screenshots/Videos (when applicable)

Checklist

  • My code adheres to the project's coding and style guidelines.
  • I have conducted a self-review of my code.
  • I have commented my code, particularly in complex areas.
  • I have verified whether these changes require updates to the in-app documentation under docs/user/ or docs/developer/, and updated accordingly. No doc update needed — this fixes rendering of existing GeoJSON overlay support; no new user-facing settings or views. Requesting the skip-docs-check label (external-contributor PR can't self-apply it).
  • I have tested the change to ensure that it works as intended.

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.
@garthvh

garthvh commented Jun 27, 2026

Copy link
Copy Markdown
Member

Heads-up on an incoming collision with the feat/pmtiles-mapkit-shim branch — this is a good fix (the .first sub-geometry drop is a real bug we currently ship), but it'll need reconciliation, so flagging early.

The pmtiles branch reworks the map render path and will conflict with this PR in three places:

  1. createOverlay() removal. This PR removes createOverlay() and replaces precomputedOverlay (singular) with precomputedOverlays: [MKOverlay]. The pmtiles branch adds a new consumer, MeshMapMK.swift, that calls styled.createOverlay() — so after both land that's a compile break, not just a merge marker. Whoever merges second needs to update MeshMapMK to iterate precomputedOverlays.

  2. MeshMapContent.swift. This PR edits the rendering loops there, but the pmtiles branch moves overlay rendering out of MeshMapContent into MeshMapMK + GeoJSONOverlayManager, so some of the edits here target code paths that branch has removed.

  3. GeoJSONOverlayConfigTests.swift. Both this PR and the pmtiles branch add this file → add/add conflict; the two test sets will need to be merged.

No change requested on the substance — plan is to land this on main first, then rebase pmtiles and port the plural-overlay API + this fix into the relocated render path. Just didn't want us to collide silently.

@garthvh

garthvh commented Jun 29, 2026

Copy link
Copy Markdown
Member

Superseded by #1989.

The Map tab MKMapView migration (#1989) removed the SwiftUI MeshMapContent renderer that this PR patched, and its new architecture already renders MultiPolygon / MultiLineString correctly via MKGeoJSONDecoder + the ClusterMapView multi-geometry renderers.

The one remaining gap this PR addressed — MultiPoint markers (which now render nothing, since toCoordinate() returns nil for the nested coordinate array) — is carried forward in #2000, ported onto the new MeshMapMK overlay path.

Closing as superseded. 🙏

@garthvh garthvh closed this Jun 29, 2026
garthvh added a commit that referenced this pull request Jun 29, 2026
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants