Skip to content

Introduce ProjectionKind and capability-based projection dispatch - #237

Closed
trasch wants to merge 1 commit into
mainfrom
generic-projection-kinds
Closed

trasch wants to merge 1 commit into
mainfrom
generic-projection-kinds

Conversation

@trasch

@trasch trasch commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Phase 1 of making the projection system generic ( groundwork for supporting a wider range of CRSs beyond the fixed set of EPSG:4326, EPSG:3857, EPSG:4978 and noSRID).

Instead of switching on specific EPSG codes, algorithms now dispatch on a semantic projection category. New projections registered in a later phase will automatically get sensible default behavior.

New API

  • ProjectionKind enum: .geographic / .planar / .geocentric / .undefined (new file ProjectionKind.swift)
  • Projection.kind, plus convenience flags isGeographic, isPlanar, isGeocentric, hasSRID
  • Projection.wraparoundExtent: Double? — the horizontal wraparound boundary (±180° for EPSG:4326, ±originShift for EPSG:3857, nil for EPSG:4978/noSRID)
  • Projection.crsLength(fromMeters:) — shared meters-to-CRS-units conversion (replaces several duplicated tolerance / 111_325.0 switches)

Refactored to kind/capability dispatch (behavior-neutral)

  • Geodesic ops (distance, bearing, destination, midpoint, rhumb bearing/distance/destination): dispatch on ProjectionKind; geographic/planar/geocentric compute via the EPSG:4326 pivot, noSRID keeps its planar fallback
  • AntimeridianCutting: the duplicated EPSG:4326/EPSG:3857 helper implementations (~150 lines) collapsed into single implementations parameterized by wraparoundExtent; crossesAntimeridian / cutAtAntimeridian dispatch on wraparoundExtent
  • BoundingBox: date-line splits in contains / intersects / intersection, padding, expansion, size and normalized() now dispatch on kind / wraparoundExtent
  • ~20 algorithm files: antimeridian-span checks (projection == .epsg4326 → isGeographic), unit-conversion switches → crsLength(fromMeters:), grid cell sizing → !isGeographic, geocentric-recurse checks → isGeocentric

Intentionally unchanged

Per-CRS switch matrices in Coordinate3D.projected(to:), clamped(), BoundingBox.expanded(byDistance:), Random.worldBox, the WKT/WKB coders and MapTile remain as-is — they become registry data in phase 2.

Also included

  • .swiftformat configuration file for the project's formatting conventions

Testing

  • New tests in ProjectionTests.swift cover kind, the kind flags, wraparoundExtent and crsLength(fromMeters:)
  • Full suite passes: 2424 tests in 172 suites, no behavior changes

Phase 1 of making the projection system generic: replace per-EPSG-code
branches with dispatch on a semantic projection category, so that new
projections registered in a later phase automatically get sensible
default behavior.

New API:
- ProjectionKind enum (geographic / planar / geocentric / undefined)
- Projection.kind, isGeographic, isPlanar, isGeocentric, hasSRID
- Projection.wraparoundExtent (±180° for 4326, ±originShift for 3857)
- Projection.crsLength(fromMeters:) for meter-to-CRS-unit conversion

Refactored to kind/capability dispatch (behavior-neutral):
- Geodesic ops (distance, bearing, destination, midpoint, rhumb *)
- AntimeridianCutting: duplicated 4326/3857 helpers collapsed into
  implementations parameterized by wraparoundExtent
- BoundingBox date-line splits, padding, expansion, size, normalize
- Antimeridian-span checks, unit conversions, grid cell sizing across
  ~20 algorithm files

Also adds a .swiftformat configuration file.

Per-CRS switch matrices (Coordinate3D.projected, coders, MapTile) are
intentionally unchanged; they become registry data in phase 2.
@trasch

trasch commented Sep 15, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by #250, which consolidates the full projection-genericity chain into a single reviewable PR. All commits are unchanged in #250.

@trasch trasch closed this Sep 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant