Struct WorldToScreen
A linear EPSG:3857-world → screen-pixel affine derived from a
Viewport — the second half of the S-100 Part 9 projection
(EPSG:3857 → screen pixels) that a PaintOp deliberately
leaves to each rendering backend (see the unit contract on
PaintOp).
public readonly struct WorldToScreen
- Inherited Members
Remarks
The viewport's geographic bounds are projected to EPSG:3857 via
FromLonLat(double, double) and mapped linearly to
the pixel rectangle with origin top-left and screen-space +Y pointing
down (northing decreases downward). The transform is north-up only —
it applies no rotation.
This helper is intentionally framework-neutral (it depends only on Viewport and WebMercator), so a rendering backend that does not use SkiaSharp or Mapsui can project the world coordinates carried on each PaintOp to output pixels without taking a dependency on either backend. It provides only the geometry (world → pixel) projection; size values on the IR are already in display pixels and must not be passed through this transform.
Methods
Create(Viewport)
Builds the world → screen affine for the supplied viewport.
The viewport's geographic corners are projected to EPSG:3857 and mapped to
the [0, WidthPixels] × [0, HeightPixels] pixel rectangle. A viewport
with a zero-width or zero-height projected span yields a zero scale on that
axis (all coordinates collapse to the axis origin).
public static WorldToScreen Create(Viewport viewport)
Parameters
viewportViewportThe display viewport (geographic bounds + pixel size).
Returns
- WorldToScreen
The world → screen affine.
Remarks
When the viewport is expressed in a longitude frame shifted across the
±180° antimeridian (MaxLongitude > 180 or
MinLongitude < −180, as produced by the seam-aware auto-fit —
see SeamAwareBoundsAccumulator), each op's world-X is wrapped
into [minX, minX + Circumference) before
projection so geometry on the far side of the seam registers in the shifted
window. For every normal viewport (which never exceeds ±180°) wrapping is
disabled, so partially off-screen features are never teleported. Wrapping
is also disabled for a viewport spanning a full world or more of
longitude, where every op already lies inside the window unwrapped.
Create(Viewport, bool)
As Create(Viewport), but with control over whether the
antimeridian seam-wrap is applied. When allowSeamWrap
is false, world-X is never wrapped into the viewport's
longitude window even if the viewport is shifted across ±180°. The tiled
renderer passes false because it draws already-continuous
geometry from narrow per-tile viewports, where wrapping would smear
polygons that extend beyond a single tile (see the flag's remarks on the
tiled renderer).
public static WorldToScreen Create(Viewport viewport, bool allowSeamWrap)
Parameters
viewportViewportThe display viewport (geographic bounds + pixel size).
allowSeamWrapbooltrue to wrap world-X into a viewport shifted across the ±180° seam (headless auto-fit); false to disable wrapping (tiled continuous-X rasterisation).
Returns
- WorldToScreen
The world → screen affine.
Project((double X, double Y))
Projects an EPSG:3857 world coordinate to a screen pixel (origin top-left,
+Y down).
public (float X, float Y) Project((double X, double Y) world)