MailJDTourDownloadDocsQualityTestsCoverage

Which source lines and branches the tests execute. Lines 91.5 %, branches 75.0 % (minimum 85 % and 72 %). main @ 399ffe3d · 21 October 2026 · pipeline 7238.

GCC Code Coverage Report


Directory: src/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 98.6% 70 / 0 / 71
Functions: 100.0% 12 / 0 / 12
Branches: 85.2% 23 / 0 / 27

data/MapProjection.cpp
Line Branch Exec Source
1 #include "MapProjection.h"
2
3 #include <QList>
4 #include <QPoint>
5 #include <QtMath>
6 #include <algorithm>
7 #include <cmath>
8
9 namespace MapProjection {
10
11 123101 QPointF project(double latitude, double longitude) {
12
1/1
✓ Branch 2 → 3 taken 123101 times.
123101 const double lat = std::clamp(latitude, -MaxLatitude, MaxLatitude);
13 123101 const double x = (longitude + 180.0) / 360.0;
14 123101 const double sinLat = std::sin(qDegreesToRadians(lat));
15 123101 const double y = 0.5 - std::log((1.0 + sinLat) / (1.0 - sinLat)) / (4.0 * M_PI);
16 123101 return {x, y};
17 }
18
19 13 QPointF unproject(const QPointF &world) {
20 13 const double longitude = world.x() * 360.0 - 180.0;
21 13 const double n = M_PI - 2.0 * M_PI * world.y();
22 13 const double latitude = qRadiansToDegrees(std::atan(std::sinh(n)));
23 13 return {longitude, latitude};
24 }
25
26 13 QPoint tileOf(const QPointF &world, int zoom) {
27 13 const double tiles = std::ldexp(1.0, zoom);
28 13 const int max = int(tiles) - 1;
29
2/2
✓ Branch 3 → 4 taken 13 times.
✓ Branch 5 → 6 taken 13 times.
13 return {std::clamp(int(std::floor(world.x() * tiles)), 0, max), std::clamp(int(std::floor(world.y() * tiles)), 0, max)};
30 }
31
32 5576 double Viewport::worldPixels() const { return TileSize * std::exp2(zoom); }
33
34 4940 QPointF Viewport::toScreen(const QPointF &world) const {
35 4940 const double scale = worldPixels();
36 4940 return {(world.x() - center.x()) * scale + size.width() / 2.0, (world.y() - center.y()) * scale + size.height() / 2.0};
37 }
38
39 35 QPointF Viewport::toWorld(const QPointF &screen) const {
40 35 const double scale = worldPixels();
41 35 return {center.x() + (screen.x() - size.width() / 2.0) / scale,
42 35 center.y() + (screen.y() - size.height() / 2.0) / scale};
43 }
44
45 326 QRectF Viewport::visibleWorld() const {
46 326 const double scale = worldPixels();
47 326 const double w = size.width() / scale;
48 326 const double h = size.height() / scale;
49 326 return {center.x() - w / 2.0, center.y() - h / 2.0, w, h};
50 }
51
52 namespace {
53
54 // Keeps the world filling the canvas vertically and wraps east–west.
55 48 Viewport normalised(Viewport v) {
56 48 v.center.setX(v.center.x() - std::floor(v.center.x()));
57 48 const double half = v.size.height() / 2.0 / v.worldPixels();
58
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 48 times.
48 if (half >= 0.5)
59 ✗ v.center.setY(0.5);
60 else
61
1/1
✓ Branch 10 → 11 taken 48 times.
48 v.center.setY(std::clamp(v.center.y(), half, 1.0 - half));
62 48 return v;
63 }
64
65 } // namespace
66
67 7 Viewport Viewport::panned(const QPointF &screenDelta) const {
68 7 Viewport v = *this;
69 7 const double scale = worldPixels();
70 7 v.center -= QPointF(screenDelta.x() / scale, screenDelta.y() / scale);
71
1/1
✓ Branch 7 → 8 taken 7 times.
14 return normalised(v);
72 }
73
74 24 Viewport Viewport::zoomed(double steps, const QPointF &anchor) const {
75 24 Viewport v = *this;
76 24 const QPointF anchorWorld = toWorld(anchor);
77
3/3
✓ Branch 3 → 4 taken 24 times.
✓ Branch 5 → 6 taken 24 times.
✓ Branch 6 → 7 taken 24 times.
24 v.zoom = std::clamp(zoom + steps, minZoomFor(size), std::max(maxZoom, minZoomFor(size)));
78 // Keep anchorWorld under the anchor: centre = anchorWorld - offset/scale.
79 24 const double scale = v.worldPixels();
80 24 v.center = anchorWorld - QPointF((anchor.x() - size.width() / 2.0) / scale, (anchor.y() - size.height() / 2.0) / scale);
81
1/1
✓ Branch 14 → 15 taken 24 times.
48 return normalised(v);
82 }
83
84 168 double minZoomFor(const QSizeF &size) {
85 168 const double longest = std::max(size.width(), 1.0);
86
1/1
✓ Branch 4 → 5 taken 168 times.
168 return std::clamp(std::log2(longest / TileSize), MinZoom, MaxZoom);
87 }
88
89 17 Viewport fit(const QList<QPointF> &worldPoints, const QSizeF &size, double margin, double singleZoom) {
90 17 Viewport v;
91 17 v.size = size;
92
1/1
✓ Branch 2 → 3 taken 17 times.
17 v.zoom = minZoomFor(size);
93
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 7 taken 16 times.
17 if (worldPoints.isEmpty())
94
1/1
✓ Branch 5 → 6 taken 1 time.
1 return normalised(v);
95 16 double minX = 1, minY = 1, maxX = 0, maxY = 0;
96
2/2
✓ Branch 20 → 9 taken 892 times.
✓ Branch 20 → 21 taken 16 times.
908 for (const QPointF &p : worldPoints) {
97 892 minX = std::min(minX, p.x());
98 892 maxX = std::max(maxX, p.x());
99 892 minY = std::min(minY, p.y());
100 892 maxY = std::max(maxY, p.y());
101 }
102 16 v.center = {(minX + maxX) / 2.0, (minY + maxY) / 2.0};
103 16 const double w = std::max(maxX - minX, 1e-9);
104 16 const double h = std::max(maxY - minY, 1e-9);
105 16 const double usableW = std::max(size.width() - 2 * margin, 1.0);
106 16 const double usableH = std::max(size.height() - 2 * margin, 1.0);
107 16 const double scale = std::min(usableW / w, usableH / h);
108
3/6
✓ Branch 30 → 31 taken 15 times.
✓ Branch 30 → 34 taken 1 time.
✗ Branch 31 → 32 not taken.
✓ Branch 31 → 33 taken 15 times.
✗ Branch 32 → 33 not taken.
✗ Branch 32 → 34 not taken.
16 v.zoom = worldPoints.size() == 1 || (w < 1e-6 && h < 1e-6) ? singleZoom : std::log2(scale / TileSize);
109
2/2
✓ Branch 35 → 36 taken 16 times.
✓ Branch 36 → 37 taken 16 times.
16 v.zoom = std::clamp(v.zoom, minZoomFor(size), MaxZoom);
110
1/1
✓ Branch 37 → 38 taken 16 times.
16 return normalised(v);
111 }
112
113 } // namespace MapProjection
114