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: 97.1% 202 / 0 / 208
Functions: 100.0% 12 / 0 / 12
Branches: 92.0% 240 / 0 / 261

data/RelationGraphClusters.cpp
Line Branch Exec Source
1 #include "RelationGraphClusters.h"
2
3 #include "RelationGraphBlocks.h"
4 #include "RelationGraphForce.h"
5 #include "RelationGraphLayout.h"
6 #include "RelationGraphRows.h"
7
8 #include <QMap>
9 #include <QSet>
10 #include <algorithm>
11 #include <cmath>
12 #include <functional>
13
14 namespace RelationGraphLayout {
15
16 namespace {
17
18 // Relationships that join people into one cluster (not memberships, layers or suggestions).
19 2996 bool joins(const RelationGraph::Edge &edge) {
20
6/6
✓ Branch 4 → 5 taken 206 times.
✓ Branch 4 → 11 taken 2790 times.
✓ Branch 7 → 8 taken 56 times.
✓ Branch 7 → 11 taken 150 times.
✓ Branch 10 → 11 taken 24 times.
✓ Branch 10 → 12 taken 32 times.
3052 return edge.kind == QLatin1String("relation") || edge.kind == QLatin1String("inferred") ||
21 3052 edge.kind == QLatin1String("via");
22 }
23
24 22 QHash<int, QList<int>> neighboursOf(const RelationGraph::Graph &graph) {
25 22 QHash<int, QList<int>> out;
26 22 const int n = int(graph.nodes.size());
27
2/2
✓ Branch 29 → 5 taken 2986 times.
✓ Branch 29 → 30 taken 22 times.
3008 for (const RelationGraph::Edge &e : graph.edges) {
28
5/10
✓ Branch 8 → 9 taken 2954 times.
✗ Branch 8 → 19 not taken.
✓ Branch 9 → 10 taken 2954 times.
✗ Branch 9 → 19 not taken.
✓ Branch 10 → 11 taken 2954 times.
✗ Branch 10 → 19 not taken.
✓ Branch 11 → 12 taken 2954 times.
✗ Branch 11 → 19 not taken.
✓ Branch 12 → 13 taken 2954 times.
✗ Branch 12 → 19 not taken.
5940 if (!joins(e) || e.from < 0 || e.to < 0 || e.from >= n || e.to >= n || e.from == e.to ||
29
6/8
✓ Branch 7 → 8 taken 2954 times.
✓ Branch 7 → 19 taken 32 times.
✓ Branch 15 → 16 taken 2954 times.
✗ Branch 15 → 19 not taken.
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 20 taken 2954 times.
✓ Branch 21 → 22 taken 32 times.
✓ Branch 21 → 23 taken 2954 times.
5940 !isShown(graph.nodes.at(e.from)) || !isShown(graph.nodes.at(e.to)))
30 32 continue;
31
2/2
✓ Branch 23 → 24 taken 2954 times.
✓ Branch 24 → 25 taken 2954 times.
2954 out[e.from].append(e.to);
32
2/2
✓ Branch 25 → 26 taken 2954 times.
✓ Branch 26 → 27 taken 2954 times.
2954 out[e.to].append(e.from);
33 }
34
3/3
✓ Branch 30 → 31 taken 22 times.
✓ Branch 45 → 32 taken 2118 times.
✓ Branch 45 → 46 taken 22 times.
2140 for (QList<int> &list : out) {
35
3/3
✓ Branch 33 → 34 taken 2118 times.
✓ Branch 34 → 35 taken 2118 times.
✓ Branch 35 → 36 taken 2118 times.
2118 std::sort(list.begin(), list.end());
36
5/5
✓ Branch 36 → 37 taken 2118 times.
✓ Branch 38 → 39 taken 2118 times.
✓ Branch 39 → 40 taken 2118 times.
✓ Branch 40 → 41 taken 2118 times.
✓ Branch 42 → 43 taken 2118 times.
2118 list.erase(std::unique(list.begin(), list.end()), list.end());
37 }
38 22 return out;
39 ✗ }
40
41 202 bool byName(const RelationGraph::Graph &graph, int a, int b) {
42 202 const int c = graph.nodes.at(a).name.localeAwareCompare(graph.nodes.at(b).name);
43
1/2
✓ Branch 5 → 6 taken 202 times.
✗ Branch 5 → 7 not taken.
202 return c != 0 ? c < 0 : graph.nodes.at(a).key < graph.nodes.at(b).key;
44 }
45
46 // The satellites of a family cluster in columns beside its tree: each on
47 // the side of the family member it is joined to and as near that member's
48 // height as the column allows, those joined through it right below it.
49 336 void placeSatellites(const RelationGraph::Graph &graph, const Cluster &cluster, QHash<int, QPointF> *placed) {
50 336 double minX = 0, maxX = 0, minY = 0, maxY = 0;
51 336 bool first = true;
52
2/2
✓ Branch 28 → 4 taken 1492 times.
✓ Branch 28 → 29 taken 336 times.
1828 for (int i : cluster.tree) {
53 1492 const QPointF p = placed->value(i);
54
2/2
✓ Branch 6 → 7 taken 336 times.
✓ Branch 6 → 8 taken 1156 times.
1492 minX = first ? p.x() : std::min(minX, p.x());
55
2/2
✓ Branch 11 → 12 taken 336 times.
✓ Branch 11 → 13 taken 1156 times.
1492 maxX = first ? p.x() : std::max(maxX, p.x());
56
2/2
✓ Branch 16 → 17 taken 336 times.
✓ Branch 16 → 18 taken 1156 times.
1492 minY = first ? p.y() : std::min(minY, p.y());
57
2/2
✓ Branch 21 → 22 taken 336 times.
✓ Branch 21 → 23 taken 1156 times.
1492 maxY = first ? p.y() : std::max(maxY, p.y());
58 1492 first = false;
59 }
60
1/1
✓ Branch 31 → 32 taken 336 times.
336 const QSet<int> inTree(cluster.tree.cbegin(), cluster.tree.cend());
61 336 QHash<int, QList<int>> children;
62 336 QList<int> top;
63
2/2
✓ Branch 44 → 34 taken 615 times.
✓ Branch 44 → 45 taken 336 times.
951 for (int s : cluster.satellites) {
64 615 const int up = cluster.parent.value(s, -1);
65
4/4
✓ Branch 37 → 38 taken 538 times.
✓ Branch 37 → 39 taken 77 times.
✓ Branch 39 → 40 taken 77 times.
✓ Branch 41 → 42 taken 615 times.
615 (inTree.contains(up) ? top : children[up]).append(s);
66 }
67 336 const double middle = (minX + maxX) / 2;
68 336 QList<int> left, right;
69
2/2
✓ Branch 62 → 48 taken 538 times.
✓ Branch 62 → 63 taken 336 times.
874 for (int s : std::as_const(top)) {
70 538 const double x = placed->value(cluster.parent.value(s)).x();
71
7/7
✓ Branch 52 → 53 taken 292 times.
✓ Branch 52 → 57 taken 246 times.
✓ Branch 53 → 54 taken 53 times.
✓ Branch 53 → 58 taken 239 times.
✓ Branch 56 → 57 taken 34 times.
✓ Branch 56 → 58 taken 19 times.
✓ Branch 59 → 60 taken 538 times.
538 (x < middle || (x == middle && left.size() <= right.size()) ? left : right).append(s);
72 }
73 601 const auto byAnchor = [&](int a, int b) {
74 601 const QPointF pa = placed->value(cluster.parent.value(a)), pb = placed->value(cluster.parent.value(b));
75
2/2
✓ Branch 8 → 9 taken 249 times.
✓ Branch 8 → 12 taken 352 times.
601 if (pa.y() != pb.y())
76 249 return pa.y() < pb.y();
77
2/2
✓ Branch 14 → 15 taken 150 times.
✓ Branch 14 → 18 taken 202 times.
352 if (pa.x() != pb.x())
78 150 return pa.x() < pb.x();
79
1/1
✓ Branch 18 → 19 taken 202 times.
202 return byName(graph, a, b);
80 336 };
81
2/2
✓ Branch 123 → 65 taken 672 times.
✓ Branch 123 → 124 taken 336 times.
1008 for (const int side : {-1, 1}) {
82
2/2
✓ Branch 65 → 66 taken 336 times.
✓ Branch 65 → 67 taken 336 times.
672 QList<int> &tops = side < 0 ? left : right;
83
3/3
✓ Branch 68 → 69 taken 672 times.
✓ Branch 69 → 70 taken 672 times.
✓ Branch 70 → 71 taken 672 times.
672 std::sort(tops.begin(), tops.end(), byAnchor);
84 672 QList<int> column;
85 ✗ const std::function<void(int)> visit = [&](int s) {
86 615 column.append(s);
87
4/4
✓ Branch 4 → 5 taken 615 times.
✓ Branch 5 → 6 taken 615 times.
✓ Branch 11 → 7 taken 77 times.
✓ Branch 11 → 12 taken 615 times.
692 for (int child : children.value(s))
88
1/1
✓ Branch 8 → 9 taken 77 times.
692 visit(child);
89
1/1
✓ Branch 71 → 72 taken 672 times.
1287 };
90
2/2
✓ Branch 79 → 75 taken 538 times.
✓ Branch 79 → 80 taken 672 times.
1210 for (int s : std::as_const(tops))
91
1/1
✓ Branch 76 → 77 taken 538 times.
538 visit(s);
92 // Each sub-column of ColumnHeight people stands as near the height of
93 // the people they are joined to as ColumnStep allows (isotonic regression).
94
2/2
✓ Branch 119 → 81 taken 296 times.
✓ Branch 119 → 120 taken 672 times.
968 for (int from = 0; from < column.size(); from += ColumnHeight) {
95 296 const int sub = from / ColumnHeight;
96
1/1
✓ Branch 81 → 82 taken 296 times.
296 const QList<int> part = column.mid(from, ColumnHeight);
97 // The aim is the height of the family member the chain starts at; in
98 // the column's order (by that height, a chain together) the aims ascend.
99 296 QList<double> targets;
100
2/2
✓ Branch 101 → 84 taken 615 times.
✓ Branch 101 → 102 taken 296 times.
911 for (int s : part) {
101 615 int anchor = cluster.parent.value(s, -1);
102
5/6
✓ Branch 90 → 91 taken 83 times.
✓ Branch 90 → 94 taken 615 times.
✓ Branch 92 → 93 taken 83 times.
✗ Branch 92 → 94 not taken.
✓ Branch 95 → 87 taken 83 times.
✓ Branch 95 → 96 taken 615 times.
698 while (!inTree.contains(anchor) && cluster.parent.contains(anchor))
103 83 anchor = cluster.parent.value(anchor);
104
1/1
✓ Branch 98 → 99 taken 615 times.
615 targets.append(placed->value(anchor).y());
105 }
106
1/1
✓ Branch 102 → 103 taken 296 times.
296 const QList<double> ys = place(targets, ColumnStep);
107
2/2
✓ Branch 103 → 104 taken 163 times.
✓ Branch 103 → 105 taken 133 times.
296 const double x = side < 0 ? minX - ColumnGap - sub * ColumnGap : maxX + ColumnGap + sub * ColumnGap;
108
2/2
✓ Branch 113 → 107 taken 615 times.
✓ Branch 113 → 114 taken 296 times.
911 for (int k = 0; k < part.size(); ++k)
109
1/1
✓ Branch 110 → 111 taken 615 times.
615 placed->insert(part.at(k), QPointF(x, ys.at(k) + (sub % 2) * ColumnStep / 2));
110 296 }
111 672 }
112 336 }
113
114 // A cluster without a family: a small force layout of its people, pushed apart until no two overlap.
115 1 void placeGroup(const RelationGraph::Graph &graph, const Cluster &cluster, QHash<int, QPointF> *placed) {
116 1 const QList<int> &people = cluster.satellites;
117
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 8 taken 1 time.
1 if (people.size() == 1) {
118 ✗ placed->insert(people.first(), QPointF());
119 ✗ return;
120 }
121 1 QHash<int, int> local;
122
2/2
✓ Branch 13 → 9 taken 2 times.
✓ Branch 13 → 14 taken 1 time.
3 for (int k = 0; k < people.size(); ++k)
123
1/1
✓ Branch 10 → 11 taken 2 times.
2 local.insert(people.at(k), k);
124 1 const double spread = 130 * std::sqrt(double(people.size()));
125 1 QList<QPointF> positions;
126
2/2
✓ Branch 23 → 17 taken 2 times.
✓ Branch 23 → 24 taken 1 time.
3 for (int i : people)
127
2/2
✓ Branch 19 → 20 taken 2 times.
✓ Branch 20 → 21 taken 2 times.
2 positions.append(RelationGraphForce::seeded(graph.nodes.at(i).key, spread));
128 1 QList<QPair<int, int>> links;
129
2/2
✓ Branch 44 → 26 taken 10 times.
✓ Branch 44 → 45 taken 1 time.
11 for (const RelationGraph::Edge &e : graph.edges)
130
7/10
✓ Branch 28 → 29 taken 10 times.
✗ Branch 28 → 35 not taken.
✓ Branch 30 → 31 taken 1 time.
✓ Branch 30 → 35 taken 9 times.
✓ Branch 32 → 33 taken 1 time.
✗ Branch 32 → 35 not taken.
✓ Branch 33 → 34 taken 1 time.
✗ Branch 33 → 35 not taken.
✓ Branch 36 → 37 taken 1 time.
✓ Branch 36 → 42 taken 9 times.
10 if (joins(e) && local.contains(e.from) && local.contains(e.to) && e.from != e.to)
131
1/1
✓ Branch 40 → 41 taken 1 time.
1 links.append({local.value(e.from), local.value(e.to)});
132
2/2
✓ Branch 47 → 48 taken 1 time.
✓ Branch 48 → 49 taken 1 time.
1 RelationGraphForce::layout(&positions, links, QList<bool>(people.size(), false), 130, 200, spread / 10);
133
2/2
✓ Branch 55 → 56 taken 1 time.
✓ Branch 56 → 57 taken 1 time.
1 RelationGraphForce::separate(&positions, QList<QSizeF>(people.size(), QSizeF(TreeGap, 110)),
134
1/1
✓ Branch 52 → 53 taken 1 time.
2 QList<bool>(people.size(), false));
135
2/2
✓ Branch 65 → 60 taken 2 times.
✓ Branch 65 → 66 taken 1 time.
3 for (int k = 0; k < people.size(); ++k)
136
1/1
✓ Branch 62 → 63 taken 2 times.
2 placed->insert(people.at(k), positions.at(k));
137 1 }
138
139 // Where a line from a cluster's middle towards `towards` leaves its rectangle.
140 214 QPointF rimPoint(QPointF centre, QSizeF size, QPointF towards) {
141 214 const QPointF d = towards - centre;
142
2/2
✓ Branch 5 → 6 taken 206 times.
✓ Branch 5 → 10 taken 8 times.
214 const double tx = std::abs(d.x()) > 1e-6 ? size.width() / 2 / std::abs(d.x()) : 1e9;
143
2/2
✓ Branch 13 → 14 taken 180 times.
✓ Branch 13 → 18 taken 34 times.
214 const double ty = std::abs(d.y()) > 1e-6 ? size.height() / 2 / std::abs(d.y()) : 1e9;
144
1/1
✓ Branch 19 → 20 taken 214 times.
214 return centre + d * std::min({tx, ty, 1.0});
145 }
146
147 } // namespace
148
149 22 QList<Cluster> overviewClusters(const RelationGraph::Graph &graph, QList<int> *clusterOf) {
150 22 const int n = int(graph.nodes.size());
151
1/1
✓ Branch 3 → 4 taken 22 times.
22 *clusterOf = QList<int>(n, -1);
152 22 QSet<int> inArea;
153 22 QList<Cluster> clusters;
154 22 QList<int> singles;
155
5/5
✓ Branch 7 → 8 taken 22 times.
✓ Branch 8 → 9 taken 22 times.
✓ Branch 9 → 10 taken 22 times.
✓ Branch 38 → 11 taken 960 times.
✓ Branch 38 → 39 taken 22 times.
982 for (const QList<int> &block : overviewBlocks(graph, &inArea)) {
156
1/1
✓ Branch 14 → 15 taken 960 times.
3010 const bool area = std::any_of(block.cbegin(), block.cend(), [&](int i) { return inArea.contains(i); });
157
5/6
✓ Branch 16 → 17 taken 622 times.
✓ Branch 16 → 19 taken 338 times.
✓ Branch 17 → 18 taken 622 times.
✗ Branch 17 → 19 not taken.
✓ Branch 20 → 21 taken 622 times.
✓ Branch 20 → 24 taken 338 times.
960 if (block.size() == 1 && !area) {
158
1/1
✓ Branch 22 → 23 taken 622 times.
622 singles.append(block.first());
159 622 continue;
160 }
161 338 Cluster cluster;
162 338 cluster.tree = block;
163 338 cluster.family = area;
164
2/2
✓ Branch 32 → 27 taken 1497 times.
✓ Branch 32 → 33 taken 338 times.
1835 for (int i : block)
165
1/1
✓ Branch 29 → 30 taken 1497 times.
1497 (*clusterOf)[i] = int(clusters.size());
166
1/1
✓ Branch 33 → 34 taken 338 times.
338 clusters.append(cluster);
167 360 }
168
1/1
✓ Branch 40 → 41 taken 22 times.
22 const QHash<int, QList<int>> neighbours = neighboursOf(graph);
169 // Breadth first from every family at once: each other person joins the family it reaches first.
170 22 QList<int> queue;
171
2/2
✓ Branch 48 → 44 taken 338 times.
✓ Branch 48 → 49 taken 22 times.
360 for (const Cluster &cluster : std::as_const(clusters))
172
1/1
✓ Branch 45 → 46 taken 338 times.
338 queue += cluster.tree;
173
2/2
✓ Branch 71 → 50 taken 2115 times.
✓ Branch 71 → 72 taken 22 times.
2137 for (int head = 0; head < queue.size(); ++head) {
174 2115 const int u = queue.at(head);
175
4/4
✓ Branch 52 → 53 taken 2115 times.
✓ Branch 53 → 54 taken 2115 times.
✓ Branch 67 → 55 taken 5876 times.
✓ Branch 67 → 68 taken 2115 times.
7991 for (int v : neighbours.value(u))
176
2/2
✓ Branch 57 → 58 taken 618 times.
✓ Branch 57 → 65 taken 5258 times.
5876 if (clusterOf->at(v) < 0) {
177 618 const int c = clusterOf->at(u);
178
1/1
✓ Branch 59 → 60 taken 618 times.
618 (*clusterOf)[v] = c;
179
2/2
✓ Branch 60 → 61 taken 618 times.
✓ Branch 61 → 62 taken 618 times.
618 clusters[c].satellites.append(v);
180
2/2
✓ Branch 62 → 63 taken 618 times.
✓ Branch 63 → 64 taken 618 times.
618 clusters[c].parent.insert(v, u);
181
1/1
✓ Branch 64 → 65 taken 618 times.
618 queue.append(v);
182 2115 }
183 }
184 // Everyone else: one cluster per group joined by relationships.
185
2/2
✓ Branch 106 → 75 taken 622 times.
✓ Branch 106 → 107 taken 22 times.
644 for (int start : std::as_const(singles)) {
186
2/2
✓ Branch 77 → 78 taken 620 times.
✓ Branch 77 → 79 taken 2 times.
622 if (clusterOf->at(start) >= 0)
187 620 continue;
188 2 Cluster cluster;
189 2 const int c = int(clusters.size());
190
1/1
✓ Branch 80 → 81 taken 2 times.
2 (*clusterOf)[start] = c;
191
1/1
✓ Branch 81 → 82 taken 2 times.
2 cluster.satellites.append(start);
192
2/2
✓ Branch 100 → 83 taken 4 times.
✓ Branch 100 → 101 taken 2 times.
6 for (int head = 0; head < cluster.satellites.size(); ++head) {
193 4 const int u = cluster.satellites.at(head);
194
4/4
✓ Branch 85 → 86 taken 4 times.
✓ Branch 86 → 87 taken 4 times.
✓ Branch 96 → 88 taken 4 times.
✓ Branch 96 → 97 taken 4 times.
8 for (int v : neighbours.value(u))
195
2/2
✓ Branch 90 → 91 taken 2 times.
✓ Branch 90 → 94 taken 2 times.
4 if (clusterOf->at(v) < 0) {
196
1/1
✓ Branch 91 → 92 taken 2 times.
2 (*clusterOf)[v] = c;
197
1/1
✓ Branch 92 → 93 taken 2 times.
2 cluster.satellites.append(v);
198
1/1
✓ Branch 93 → 94 taken 2 times.
2 cluster.parent.insert(v, u);
199 4 }
200 }
201
1/1
✓ Branch 101 → 102 taken 2 times.
2 clusters.append(cluster);
202 2 }
203 22 return clusters;
204 22 }
205
206 337 QHash<int, QPointF> clusterLayout(const RelationGraph::Graph &graph, const Cluster &cluster, QSizeF *size) {
207 337 QHash<int, QPointF> placed;
208
2/2
✓ Branch 3 → 4 taken 336 times.
✓ Branch 3 → 10 taken 1 time.
337 if (!cluster.tree.isEmpty()) {
209
2/2
✓ Branch 4 → 5 taken 336 times.
✓ Branch 5 → 6 taken 336 times.
336 placed = rows(graph, cluster.tree, allGenerations(graph, cluster.tree));
210
1/1
✓ Branch 9 → 11 taken 336 times.
336 placeSatellites(graph, cluster, &placed);
211 } else {
212
1/1
✓ Branch 10 → 11 taken 1 time.
1 placeGroup(graph, cluster, &placed);
213 }
214 337 double minX = 0, maxX = 0, minY = 0, maxY = 0;
215 337 bool first = true;
216
2/2
✓ Branch 37 → 14 taken 2109 times.
✓ Branch 37 → 38 taken 337 times.
2446 for (const QPointF &p : std::as_const(placed)) {
217
2/2
✓ Branch 15 → 16 taken 337 times.
✓ Branch 15 → 17 taken 1772 times.
2109 minX = first ? p.x() : std::min(minX, p.x());
218
2/2
✓ Branch 20 → 21 taken 337 times.
✓ Branch 20 → 22 taken 1772 times.
2109 maxX = first ? p.x() : std::max(maxX, p.x());
219
2/2
✓ Branch 25 → 26 taken 337 times.
✓ Branch 25 → 27 taken 1772 times.
2109 minY = first ? p.y() : std::min(minY, p.y());
220
2/2
✓ Branch 30 → 31 taken 337 times.
✓ Branch 30 → 32 taken 1772 times.
2109 maxY = first ? p.y() : std::max(maxY, p.y());
221 2109 first = false;
222 }
223 // A person is an avatar with a name and a role below: TreeGap × 110 px
224 // with room around. A family's area reaches AreaRoom beyond its people,
225 // with the family name on its rim: the cluster keeps that room free.
226
2/2
✓ Branch 38 → 39 taken 10 times.
✓ Branch 38 → 40 taken 327 times.
337 const double room = cluster.family ? AreaRoom : 0;
227 337 const QPointF middle((minX + maxX) / 2, (minY + maxY) / 2 + 13);
228
3/3
✓ Branch 42 → 43 taken 337 times.
✓ Branch 49 → 44 taken 2109 times.
✓ Branch 49 → 50 taken 337 times.
2446 for (auto it = placed.begin(); it != placed.end(); ++it)
229 2109 it.value() -= middle;
230 337 *size = QSizeF(maxX - minX + TreeGap + 2 * room, maxY - minY + 110 + 2 * room);
231 337 return placed;
232 ✗ }
233
234 21 void bundleRoutes(const RelationGraph::Graph &graph, const QList<QPointF> &positions, const QList<int> &clusterOf,
235 const QList<QPointF> &centres, const QList<QSizeF> &sizes, QList<Route> *routes) {
236 21 QMap<QPair<int, int>, QList<int>> between;
237
5/6
✓ Branch 30 → 31 taken 2976 times.
✓ Branch 30 → 34 taken 21 times.
✓ Branch 32 → 33 taken 2976 times.
✗ Branch 32 → 34 not taken.
✓ Branch 35 → 3 taken 2976 times.
✓ Branch 35 → 36 taken 21 times.
2997 for (int e = 0; e < graph.edges.size() && e < routes->size(); ++e) {
238 2976 const RelationGraph::Edge &edge = graph.edges.at(e);
239
6/6
✓ Branch 6 → 7 taken 2944 times.
✓ Branch 6 → 11 taken 32 times.
✓ Branch 10 → 11 taken 156 times.
✓ Branch 10 → 12 taken 2788 times.
✓ Branch 13 → 14 taken 188 times.
✓ Branch 13 → 15 taken 2788 times.
2976 if (edge.kind == QLatin1String("member") || routes->at(e).shape == QLatin1String("none"))
240 2023 continue;
241 2788 const int a = clusterOf.value(edge.from, -1), b = clusterOf.value(edge.to, -1);
242
4/6
✓ Branch 17 → 18 taken 2788 times.
✗ Branch 17 → 20 not taken.
✓ Branch 18 → 19 taken 2788 times.
✗ Branch 18 → 20 not taken.
✓ Branch 19 → 20 taken 1835 times.
✓ Branch 19 → 21 taken 953 times.
2788 if (a < 0 || b < 0 || a == b)
243 1835 continue;
244
2/2
✓ Branch 24 → 25 taken 953 times.
✓ Branch 25 → 26 taken 953 times.
953 between[{std::min(a, b), std::max(a, b)}].append(e);
245 }
246
4/4
✓ Branch 36 → 37 taken 21 times.
✓ Branch 103 → 104 taken 817 times.
✓ Branch 105 → 38 taken 796 times.
✓ Branch 105 → 106 taken 21 times.
817 for (auto it = between.cbegin(); it != between.cend(); ++it) {
247
2/2
✓ Branch 40 → 41 taken 689 times.
✓ Branch 40 → 42 taken 107 times.
796 if (it.value().size() < 2)
248 689 continue;
249 107 const int a = it.key().first, b = it.key().second;
250 107 const QPointF ca = centres.at(a), cb = centres.at(b);
251 107 const double length = std::hypot(cb.x() - ca.x(), cb.y() - ca.y());
252
1/2
✗ Branch 50 → 51 not taken.
✓ Branch 50 → 52 taken 107 times.
107 if (length < 1)
253 ✗ continue;
254 107 const QPointF d = (cb - ca) / length;
255
2/2
✓ Branch 55 → 56 taken 107 times.
✓ Branch 57 → 58 taken 107 times.
107 const QPointF hubA = rimPoint(ca, sizes.at(a), cb), hubB = rimPoint(cb, sizes.at(b), ca);
256
2/2
✓ Branch 99 → 61 taken 264 times.
✓ Branch 99 → 100 taken 107 times.
371 for (int e : it.value()) {
257 264 const RelationGraph::Edge &edge = graph.edges.at(e);
258 264 const bool fromA = clusterOf.at(edge.from) == a;
259 264 const QPointF start = positions.at(edge.from), end = positions.at(edge.to);
260
4/4
✓ Branch 66 → 67 taken 108 times.
✓ Branch 66 → 68 taken 156 times.
✓ Branch 69 → 70 taken 108 times.
✓ Branch 69 → 71 taken 156 times.
264 const QPointF first = fromA ? hubA : hubB, second = fromA ? hubB : hubA;
261
2/2
✓ Branch 72 → 73 taken 108 times.
✓ Branch 72 → 74 taken 156 times.
264 const QPointF along = fromA ? d : -d; // the trunk's direction from the start's side
262 // Into the first hub heading along the trunk, out of the second the same way.
263 264 const double in = std::hypot(first.x() - start.x(), first.y() - start.y()) / 2;
264 264 const double out = std::hypot(end.x() - second.x(), end.y() - second.y()) / 2;
265
1/3
✓ Branch 90 → 91 taken 264 times.
✗ Branch 113 → 114 not taken.
✗ Branch 113 → 115 not taken.
528 Route route{QStringLiteral("bundle"), {start, first - along * in, first, second, second + along * out, end}};
266 264 route.bundle = int(it.value().size());
267
1/1
✓ Branch 94 → 95 taken 264 times.
264 (*routes)[e] = route;
268 264 }
269 }
270 21 }
271
272 } // namespace RelationGraphLayout
273