Skip to content

ProjNET v3: modernized engine with expanded projection/transformation coverage and a built-in EPSG catalog#137

Open
mkaring wants to merge 1837 commits into
NetTopologySuite:developfrom
TKI-Chemnitz:feature/basecamp
Open

ProjNET v3: modernized engine with expanded projection/transformation coverage and a built-in EPSG catalog#137
mkaring wants to merge 1837 commits into
NetTopologySuite:developfrom
TKI-Chemnitz:feature/basecamp

Conversation

@mkaring

@mkaring mkaring commented Jul 24, 2026

Copy link
Copy Markdown

Hello,

this is a massive pull request — it's a major overhaul of ProjNet4GeoAPI that brings the library
very close to feature parity with PROJ.

Most of this work was done earlier this year during the AI Exploration Camp we held at
TKI Chemnitz, where the whole point was to explore what we can actually build with the current
generation of AI tooling. This branch is the result of running that experiment on a real,
non-trivial codebase.

A note on the commit history up front: please don't read too much into it. The ~1,800 commits
were used to track the implementation process of the AI agents step by step — they are not meant to
be a curated, reviewable history. If the content is fine with you, I'm happy to rewrite/squash the
branch into whatever shape you'd like. For what it's worth, this was all done before the GitHub
Copilot pricing change, so an ungodly number of tokens went into it.

Below is a fuller description of what actually changed, and how it was validated.


What this changes (high level)

  • A modernized ProjNET v3 line: the public coordinate-system model is now immutable, the
    library targets net8.0 (AOT/trim-safe) alongside netstandard2.0/netstandard2.1, and the
    runtime no longer depends on proj.db.
  • Projection coverage brought close to PROJ: 152 projection classes / 321 registered aliases
    (186 upstream PROJ_HEAD identifiers were surveyed — parity matrix in docs/projection-coverage.md),
    plus term-by-term fidelity fixes for a long list of projections (omerc, tpeqd, ocea,
    the stereographic variants, exact tmerc/gauss_kruger/utm, krovak, nzmg, loxim, ortho,
    s2/healpix/rhealpix, isea, lagrng, vandg, …).
  • Transformation runtime: affine, geocentric↔geographic, axis-swap & unit conversion, Helmert,
    Molodensky / Molodensky-Badekas, deformation models, TIN shift, Horner, horizontal/vertical/xyz
    grid shifts (NTv2 / GTX / GeoTIFF), prime-meridian and topocentric transforms, 4D
    +proj=axisswap, and full pipeline composition/concatenation. Operation selection prefers
    metadata-backed EPSG operations over equal-parameter identity fallbacks.
  • Formats: WKT1, WKT2:2019, and PROJJSON read and write (including first-class BoundCRS
    and compound/derived CRS), on a new buffered span-based WktTokenizer.
  • A configurable grid-resource subsystem (local search paths, cache, optional network fetch)
    with a public configuration API and PROJNET_GRID_* environment variables — see docs/grids.md.
  • Tooling/infra modernization: NuGet Central Package Management, xUnit v3 on Microsoft.Testing.Platform,
    System.Text.Json in tests (dropped Newtonsoft), Nerdbank.GitVersioning, StyleCop/analyzers
    enforced in-build, and CI for build/parity, benchmarks, CodeQL, and Stryker mutation testing.

References and validation

For the references I mostly used two books:

  • Snyder, John P. — Map Projections: A Working Manual (USGS Professional Paper 1395, 1987)
  • Bugayevskiy, L. M. & Snyder, John P. — Map Projections: A Reference Manual (1995)

Especially the Reference Manual contains a lot of specific implementation detail and
pre-calculated worked examples — those are now all part of the algorithms and the unit tests.
Snyder's Appendix A worked examples, for instance, are used directly as regression test vectors.
The formula citations (chapter/section/page) are embedded in the shipped XML documentation so the
provenance of each projection is explicit.

Secondly, the original PROJ library was used to validate the implementation: I ran specific
coordinates through proj and fed the results into the unit tests as the expected values (there is
a direct proj2proj parity suite for exactly this). The projection code was also compared
term-by-term against PROJ's C++ implementations, including the ellipsoidal-vs-spherical handling and
edge cases (poles, equator, antimeridian, domain boundaries).

Where it helped, the implementation and tests also cross-check against additional authoritative
sources whose citations you'll find in the code and fixtures:

  • IOGP Geomatics Guidance Note 7, Part 2 (publication 373-7-2, 2019) — the EPSG method formulas,
    used to independently verify ellipsoidal formulations (e.g. Hotine Oblique Mercator variants A/B,
    Lambert Conformal Conic 1SP/2SP).
  • IOGP GIGS (Geospatial Integrity of Geoscience Software) conformance vectors — datum / geographic
    / projected series.
  • ISO 19111 + the OGC WKT2:2019 specification — for the CRS metadata model and serialization.

The EPSG catalog

I also got the EPSG catalog in its entirety into the library — all known EPSG coordinate systems
are now contained within it (7,217 CRS definitions; common lookups such as 4326/3857 work out
of the box). The whole thing is implemented in C# directly, via a code generator that reads the
EPSG WKT export at build time, so there is no runtime proj.db dependency.

I tried to keep the initial startup time, the lookup time, and the memory footprint as low as
reasonably possible: the generator emits on-demand, switch-based lookup paths split across focused
partial files instead of large eager arrays, so nothing pays for CRS definitions it never touches.

Scale of the change

Measured against the upstream develop merge base (94079f12, "Increase version minor"):
720 files changed, +302,944 / −14,886. The insertion count looks enormous, but it is dominated by
generated data and tests rather than hand-written code:

Area ~Added Notes
Generated EPSG catalog (src/ProjNet/Data) ~142,000 code-generated .g.cs / switch lookups
Tests + fixtures (test/ProjNet.Tests) ~81,000 GIE / GIGS / proj2proj / deformation / tinshift / grid fixtures
Core engine (src/ProjNet/CoordinateSystems) ~60,000 projections, transformations, CRS model
WKT / IO (src/ProjNet/IO) ~7,600 WKT1/WKT2/PROJJSON, span tokenizer, grid loaders
Benchmarks, API baseline, docs, licensing ~8,000 see below

Testing

  • Test stack is xUnit v3 / Microsoft.Testing.Platform. At the last milestone checkpoint the suite
    reported 3,024 passing / 807 skipped, 0 failures, on a 0-warning build.
  • Validation fixtures: GIE (PROJ geodetic-integrity examples), GIGS (IOGP conformance),
    proj2proj parity (values produced by proj), Snyder Appendix A numerical vectors, plus
    deformation-model, TIN-shift, and grid (NTv2/GTX/GeoTIFF) fixtures.
  • The public API is guarded by a shipped baseline (PublicAPI.Shipped.txt) so API drift is caught
    in CI, and there are BenchmarkDotNet suites for WKT parsing and projection/transform throughput.

Breaking changes

The one intentional, source-breaking change is that the public model is now immutable: mutating
setters were replaced by With…(…) clone helpers, a few types were sealed, and [Serializable] was
removed from the public surface (VerticalDatum now emits VERT_DATUM[…] rather than DATUM[…]).
Full before/after migration recipes are in MIGRATION-v3.md. The projection fidelity fixes can
change output coordinates for the affected projections — those are correctness fixes, not API breaks,
but downstream consumers may need to refresh stored numeric baselines.

Licensing / attribution

Still LGPL-2.1-or-later, with per-file SPDX headers and consolidated attribution in NOTICE.md
and LICENSES/. PROJ-derived portions are attributed under the PROJ-MIT text, and the vendored
NKG/Kartverket grid fixtures under CC-BY-4.0.

How to review

Diffing the tree against currentupstream develop is the meaningful view (the per-commit
history, as noted, is throwaway and can be reshaped on request).
Good entry points for reading:
README.md, CHANGELOG.md, MIGRATION-v3.md, docs/ (concepts, cookbook, grids,
projection-coverage), and src/ProjNet/ENGINEERING_GOVERNANCE.md.

Happy to split this up, squash the history, or adjust scope however makes it easiest to review.

mkaring and others added 30 commits April 20, 2026 08:40
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
mkaring and others added 29 commits April 20, 2026 08:42
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update CompatibilitySuppressions.xml to record the approved v3 API deltas that remain intentionally accepted while dotnet pack validates against the 2.1.0 baseline. Document the rule in engineering governance so future public API work keeps the package validation gate in sync.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Refresh the workflow action references to the latest available release tags across CI, benchmarks, CodeQL, and mutation testing. Keep the existing workflows unchanged functionally while moving off older action lines and newer artifact/cache backends.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mkaring mkaring changed the title Updating Proj4NET to match latest features of proj and contain the full epsg catalog ProjNET v3: modernized engine with expanded projection/transformation coverage and a built-in EPSG catalog Jul 24, 2026
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.

1 participant