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: 88.9% 8 / 0 / 9
Functions: 100.0% 8 / 0 / 8
Branches: -% 0 / 0 / 0

presentation/GraphGeometry.h
Line Branch Exec Source
1 #pragma once
2
3 #include <QColor>
4 #include <QHash>
5 #include <QPainter>
6 #include <QList>
7 #include <QPointF>
8 #include <QRectF>
9
10 #include <vector>
11
12 // Sprint 105 S105.4.2 (D-6): the relationship graph's lines and family areas
13 // as triangles for the scene graph, in screen pixels — widths, dashes,
14 // arrowheads and rings keep their pixel size at every zoom, and a zoom or a
15 // pan only rebuilds these vertices (GraphLinesItem, GraphAreasItem). Every
16 // edge is feathered over one pixel (alpha), which is the antialiasing. Pure.
17 namespace GraphGeometry {
18
19 // The layout of QSGGeometry::defaultAttributes_ColoredPoint2D (premultiplied).
20 struct Vertex {
21 float x = 0;
22 float y = 0;
23 unsigned char r = 0;
24 unsigned char g = 0;
25 unsigned char b = 0;
26 unsigned char a = 0;
27 };
28
29 // Where no line is drawn: the names on the canvas and the signs of couples.
30 // A line is gone within Clear px of a box and fades back in up to Fade px
31 // (the Canvas version erased the boxes in three growing steps).
32 class Cutouts {
33 public:
34 static constexpr double Clear = 2;
35 static constexpr double Fade = 9;
36 void clear();
37 void add(const QRectF &box);
38 7141 bool isEmpty() const { return m_boxes.isEmpty(); }
39 2716165 const QList<QRectF> &boxes() const { return m_boxes; }
40 // 0 inside a box or within Clear, 1 from Fade px away, smooth between.
41 double alphaAt(QPointF point) const;
42 // Whether a segment passes within Fade of a box (it then needs vertices
43 // close enough to carry the fade).
44 bool near(QPointF a, QPointF b) const;
45 // The boxes registered in the cells the segment a→b crosses (each once):
46 // every box a point of the segment can be near.
47 QList<int> candidates(QPointF a, QPointF b) const;
48 void candidates(QPointF a, QPointF b, QList<int> *found) const;
49 // The parts of the segment a→b (t in 0…1, merged, in order) that pass
50 // within Fade of a box: only there are extra vertices needed.
51 QList<QPair<double, double>> nearParts(QPointF a, QPointF b) const;
52 // The same for boxes already known to be the segment's candidates.
53 QList<QPair<double, double>> nearParts(QPointF a, QPointF b, const QList<int> &boxes) const;
54 // alphaAt() asking only these boxes (a segment's candidates).
55 double alphaAmong(QPointF point, const QList<int> &boxes) const;
56
57 private:
58 // Boxes by grid cell (Cell px, the boxes grown by Fade): a point asks only
59 // the boxes of its own cell. Built on the first question after a change.
60 static constexpr double Cell = 48;
61 void index() const;
62
63 141213 static quint64 keyOf(int column, int row) { return (quint64(quint32(column)) << 32) | quint32(row); }
64 QList<QRectF> m_boxes;
65 mutable QHash<quint64, QList<int>> m_cells;
66 mutable bool m_indexed = false;
67 };
68
69 // What the graph items draw with: the scene graph's triangles (Mesh) or,
70 // on Qt Quick's software renderer, which draws no custom geometry, a
71 // QPainter into an image (PainterSink).
72 class Sink {
73 public:
74 141 virtual ~Sink() = default;
75 // Only what reaches into `viewport` is drawn (empty = everything).
76 136 void setViewport(const QRectF &viewport) { m_viewport = viewport; }
77 // A polyline `width` px wide; `dash` alternates on/off lengths in px
78 // (empty: solid); `cuts` may be null. A closed outline repeats no point.
79 virtual void stroke(const QList<QPointF> &points, double width, const QList<double> &dash, const QColor &colour,
80 double alpha, const Cutouts *cuts, bool closed = false) = 0;
81 // Triangles (three points each): fills of large areas.
82 virtual void fill(const QList<QPointF> &triangles, const QColor &colour, double alpha) = 0;
83 // A filled triangle (an arrowhead); `cuts` as for a stroke.
84 virtual void triangle(QPointF a, QPointF b, QPointF c, const QColor &colour, double alpha,
85 const Cutouts *cuts = nullptr) = 0;
86 // A band between two polylines of equal length (outer[i] ↔ inner[i]) with
87 // alpha from `outerAlpha` to `innerAlpha`: the glow inside a border.
88 virtual void band(const QList<QPointF> &outer, const QList<QPointF> &inner, const QColor &colour, double outerAlpha,
89 double innerAlpha, bool closed) = 0;
90
91 protected:
92 QRectF m_viewport;
93 };
94
95 // Indexed triangles: the cross-sections of a line are shared by its
96 // consecutive segments (four vertices per point, 18 indices per segment).
97 class Mesh : public Sink {
98 public:
99 void clear() {
100 m_vertices.clear();
101 m_indices.clear();
102 }
103 14 const std::vector<Vertex> &vertices() const { return m_vertices; }
104 2 const std::vector<quint32> &indices() const { return m_indices; }
105 void stroke(const QList<QPointF> &points, double width, const QList<double> &dash, const QColor &colour,
106 double alpha, const Cutouts *cuts, bool closed = false) override;
107 // Not feathered.
108 void fill(const QList<QPointF> &triangles, const QColor &colour, double alpha) override;
109 // Feathered over one pixel.
110 void triangle(QPointF a, QPointF b, QPointF c, const QColor &colour, double alpha,
111 const Cutouts *cuts = nullptr) override;
112 void band(const QList<QPointF> &outer, const QList<QPointF> &inner, const QColor &colour, double outerAlpha,
113 double innerAlpha, bool closed) override;
114
115 private:
116 void emitStrip(const QPointF *points, const double *cutAlpha, int n, double width, const QColor &colour, double alpha,
117 bool closed);
118 // A vertex; its index is returned (not yet used by a triangle).
119 quint32 vertex(QPointF point, const QColor &colour, double alpha);
120 // A vertex used once, in the order of the triangles.
121 void push(QPointF point, const QColor &colour, double alpha);
122 std::vector<Vertex> m_vertices;
123 std::vector<quint32> m_indices;
124 // Scratch buffers of stroke()/emitStrip(), kept between lines.
125 std::vector<QPointF> m_line, m_dense, m_dash, m_normals, m_miters;
126 std::vector<double> m_denseAlpha, m_dashAlpha, m_stretch;
127 std::vector<qint64> m_first;
128 QList<int> m_boxes, m_local;
129 QRgb m_colourKey = 0;
130 bool m_colourValid = false;
131 float m_red = 0, m_green = 0, m_blue = 0, m_alpha = 0;
132 };
133
134 // The same drawing with a QPainter (antialiased strokes, dashes by the pen;
135 // the cut-outs are clipped out without the fade).
136 class PainterSink : public Sink {
137 public:
138 129 explicit PainterSink(QPainter *painter) : m_painter(painter) {}
139 void stroke(const QList<QPointF> &points, double width, const QList<double> &dash, const QColor &colour,
140 double alpha, const Cutouts *cuts, bool closed = false) override;
141 void fill(const QList<QPointF> &triangles, const QColor &colour, double alpha) override;
142 void triangle(QPointF a, QPointF b, QPointF c, const QColor &colour, double alpha,
143 const Cutouts *cuts = nullptr) override;
144 void band(const QList<QPointF> &outer, const QList<QPointF> &inner, const QColor &colour, double outerAlpha,
145 double innerAlpha, bool closed) override;
146
147 private:
148 void clipFor(const Cutouts *cuts);
149 QPainter *m_painter;
150 bool m_clipSet = false;
151 const Cutouts *m_clipped = nullptr;
152 qsizetype m_clippedBoxes = -1;
153 };
154
155 // A quadratic curve a → (control c) → b as points, at most `tolerance` px
156 // off the true curve (a included, b included).
157 QList<QPointF> quadratic(QPointF a, QPointF c, QPointF b, double tolerance = 0.5);
158 // A polyline with its corners rounded (radius px, at most half of either
159 // segment), as the Canvas's arcTo drew the family tree's elbows.
160 QList<QPointF> rounded(const QList<QPointF> &points, double radius);
161 // Inserts points so no segment is longer than `step` (for fades along it).
162 QList<QPointF> densified(const QList<QPointF> &points, double step, bool closed = false);
163 // The point halfway along a polyline and the polyline's length.
164 QPointF middle(const QList<QPointF> &points, double *length = nullptr);
165 // A closed loop with fewer points, none further than `tolerance` from the
166 // original outline (Douglas–Peucker on the two halves of the loop).
167 QList<QPointF> simplified(const QList<QPointF> &loop, double tolerance);
168 // The even-odd region of `loops` (outlines and holes in any orientation,
169 // not crossing each other) as triangles, three points each.
170 QList<QPointF> triangulate(const QList<QList<QPointF>> &loops);
171 // Signed area (positive: counter-clockwise in a y-up frame).
172 double signedArea(const QList<QPointF> &loop);
173 bool contains(const QList<QPointF> &loop, QPointF point);
174
175 } // namespace GraphGeometry
176