Repository navigation
perf(drawer): composite same cylindrical projections without reprojecting - #47
Merged
nighthawk merged 4 commits intoOct 27, 2026
Merged
Conversation
…ojecting The SVG tile compositor sent every output pixel through the drawer's inverse projection and the tile source's forward projection, even when both are Mercator. Mercator on Mercator differs only by a longitude shift, so each pixel now maps to the tiles by a shift and a scale. Any other projection still takes the round trip. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
nighthawk
commented
Oct 27, 2026
The direct path was Mercator-only. It's really a property of the projection: an equator-aligned cylindrical projection puts x at `longitudeScale × (λ − reference.x)` and y on latitude alone, so two of the same type differ by a scale and a shift of x. `Projection` gains an optional `longitudeScale` (Mercator, Gall–Peters, Equirectangular) and `cylindricalTransform(to:)`. Both the tile and the single-image samplers use it, so an equirectangular map of an equirectangular Blue Marble skips the round trip too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
So callers that take a projection by name (GeoLogicKit, Lambdaroni's MCP tools) can list the modes and look one up without a mirror enum. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Member
Author
|
Suggested squash-merge message: |
init(reference:phiOne:) converted phiOne from degrees for project and inverse, but computed projectionSize from the degree value, so any non-zero standard parallel gave the wrong width (negative for 60°). The Cassini example also converted its value to radians before passing it in, so it was converted twice; it passes degrees now. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
nighthawk
added a commit
that referenced
this pull request
Oct 28, 2026
…ting (#47) - Projection gains an optional `longitudeScale` (Mercator, Gall–Peters, Equirectangular) and `cylindricalTransform(to:)` - Tile and single-image samplers scale and shift instead of the inverse/forward round trip when map and raster share a cylindrical projection, e.g. Mercator tiles on a Mercator map - ProjectionMode is CaseIterable - Equirectangular's width uses its standard parallel in radians; the Cassini example no longer converts it twice Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #46. Part of letting Maparoni's street tiles render in any projection (maparoni/lambdaroni#290). Once other projections reproject the tiles, a map in the tiles' own projection should still lay them down as they are.
Since #45, both raster samplers send every output pixel through the drawer's
inverseand then the source's forward projection. That applies to Mercator tiles on a Mercator map too.An equator-aligned cylindrical projection puts
x = k·(λ − λ₀), withydepending on latitude alone. Two projections of the same type therefore differ only by a scale and a shift ofx.Projectiongains an optionallongitudeScale, which isk. Mercator, Gall–Peters and Equirectangular have one, and every other projection hasnil.cylindricalTransform(to:)returns the scale and shift between two projections of the same type.ProjectionModealso becomesCaseIterable, so GeoLogicKit can list the modes without a mirror enum (maparoni/GeoLogicKit#244).The tests check the transform against
projectfor all three projections, with mixed centre longitudes andphiOnevalues. They also compare direct and round-trip pixels for both samplers, on zoomed, re-centred maps across the antimeridian. Bilinear sampling gives identical pixels. Nearest sampling can differ on one row, where pixel centres land exactly on a source pixel edge and the round trip'slogandatanround the other way.Testing:
swift test. No manual steps. The Lambdaroni PR covers end-to-end renders on dev.🤖 Generated with Claude Code