data/MapProjection.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <QList> | ||
| 4 | #include <QPoint> | ||
| 5 | #include <QPointF> | ||
| 6 | #include <QRectF> | ||
| 7 | #include <QSizeF> | ||
| 8 | |||
| 9 | // Web Mercator projection and the map viewport (Sprint 103 S103.4.2, D-11): | ||
| 10 | // the projection online tiles need, so the offline outline and the tiles | ||
| 11 | // line up. World coordinates are normalised to [0, 1] × [0, 1] (x east, | ||
| 12 | // y south; latitude clipped to ±85.0511°, the square Mercator world); a | ||
| 13 | // zoom level z shows the world at 256 · 2^z logical pixels like the slippy | ||
| 14 | // tile scheme. Pure and deterministic (rule 14). | ||
| 15 | namespace MapProjection { | ||
| 16 | |||
| 17 | inline constexpr double MaxLatitude = 85.05112877980659; | ||
| 18 | inline constexpr double TileSize = 256.0; | ||
| 19 | inline constexpr double MinZoom = 0.0; | ||
| 20 | inline constexpr double MaxZoom = 12.0; // city level offline (≈ 1:150,000) | ||
| 21 | inline constexpr double MaxOnlineZoom = 19.0; // street level with online tiles (S103.4.10) | ||
| 22 | |||
| 23 | // lat/lon (degrees) → world [0, 1]²; latitude clipped. | ||
| 24 | QPointF project(double latitude, double longitude); | ||
| 25 | // world → lat/lon (QPointF(longitude, latitude)) — the inverse of project(). | ||
| 26 | QPointF unproject(const QPointF &world); | ||
| 27 | // Slippy tile x/y of a world point at an integer zoom. | ||
| 28 | QPoint tileOf(const QPointF &world, int zoom); | ||
| 29 | |||
| 30 | // What the map shows: the world point at the centre of the canvas, the zoom | ||
| 31 | // and the canvas size in logical pixels. | ||
| 32 | struct Viewport { | ||
| 33 | 112 | QPointF center{0.5, 0.5}; | |
| 34 | 84 | double zoom = 1.0; | |
| 35 | 36 | QSizeF size{800, 600}; | |
| 36 | // The deepest zoom: MaxZoom offline, MaxOnlineZoom with online tiles. | ||
| 37 | 18 | double maxZoom = MaxZoom; | |
| 38 | |||
| 39 | double worldPixels() const; // 256 · 2^zoom | ||
| 40 | QPointF toScreen(const QPointF &world) const; | ||
| 41 | QPointF toWorld(const QPointF &screen) const; | ||
| 42 | // The visible world rectangle (may extend beyond [0, 1] horizontally). | ||
| 43 | QRectF visibleWorld() const; | ||
| 44 | // Pan by a screen distance; the world wraps east–west, north–south is | ||
| 45 | // clamped so the poles never leave the canvas edge. | ||
| 46 | Viewport panned(const QPointF &screenDelta) const; | ||
| 47 | // Zoom by `steps` (fractional) keeping the world point under `anchor` | ||
| 48 | // (screen) in place; clamped to [minZoom, maxZoom]. | ||
| 49 | Viewport zoomed(double steps, const QPointF &anchor) const; | ||
| 50 |
7/8✓ Branch 3 → 4 taken 28 times.
✓ Branch 3 → 5 taken 84 times.
✓ Branch 5 → 6 taken 48 times.
✓ Branch 5 → 7 taken 36 times.
✓ Branch 8 → 9 taken 18 times.
✓ Branch 8 → 10 taken 18 times.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 18 times.
|
112 | bool operator==(const Viewport &) const = default; |
| 51 | }; | ||
| 52 | |||
| 53 | // The smallest zoom so that the whole world is at least as wide as the | ||
| 54 | // canvas (no empty bands at world zoom). | ||
| 55 | double minZoomFor(const QSizeF &size); | ||
| 56 | // A viewport showing every world point of `points` with `margin` logical | ||
| 57 | // pixels; a single point gets `singleZoom`; empty input shows the world. | ||
| 58 | Viewport fit(const QList<QPointF> &worldPoints, const QSizeF &size, double margin = 48, double singleZoom = 9); | ||
| 59 | |||
| 60 | } // namespace MapProjection | ||
| 61 |