data/RelationGraphLayout.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "RelationGraphLayout.h" | ||
| 2 | |||
| 3 | #include "RelationGraphBlocks.h" | ||
| 4 | #include "RelationGraphClusters.h" | ||
| 5 | #include "RelationGraphForce.h" | ||
| 6 | |||
| 7 | #include <algorithm> | ||
| 8 | #include <cmath> | ||
| 9 | |||
| 10 | namespace RelationGraphLayout { | ||
| 11 | |||
| 12 | 21 | Layout overviewLayout(const RelationGraph::Graph &graph, const QHash<QString, QPointF> &previous, | |
| 13 | const QSet<QString> &changed, const Options &options) { | ||
| 14 | 21 | Layout layout; | |
| 15 | 21 | const int n = int(graph.nodes.size()); | |
| 16 |
1/1✓ Branch 3 → 4 taken 21 times.
|
21 | layout.positions = QList<QPointF>(n); |
| 17 |
1/2✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 21 times.
|
21 | if (n <= 0) |
| 18 | ✗ | return layout; | |
| 19 | 21 | QList<int> clusterOf; | |
| 20 |
1/1✓ Branch 8 → 9 taken 21 times.
|
21 | const QList<Cluster> clusters = overviewClusters(graph, &clusterOf); |
| 21 | 21 | const int count = int(clusters.size()); | |
| 22 |
1/1✓ Branch 10 → 11 taken 21 times.
|
21 | QList<QHash<int, QPointF>> local(count); |
| 23 |
1/1✓ Branch 11 → 12 taken 21 times.
|
21 | QList<QSizeF> sizes(count); |
| 24 |
2/2✓ Branch 20 → 13 taken 337 times.
✓ Branch 20 → 21 taken 21 times.
|
358 | for (int c = 0; c < count; ++c) |
| 25 |
3/3✓ Branch 13 → 14 taken 337 times.
✓ Branch 15 → 16 taken 337 times.
✓ Branch 16 → 17 taken 337 times.
|
337 | local[c] = clusterLayout(graph, clusters.at(c), &sizes[c]); |
| 26 | // Where each cluster was: the offset that keeps its known people where they were. | ||
| 27 |
1/1✓ Branch 21 → 22 taken 21 times.
|
21 | QList<QPointF> offset(count); |
| 28 |
2/2✓ Branch 22 → 23 taken 21 times.
✓ Branch 23 → 24 taken 21 times.
|
21 | QList<bool> known(count, false), pinned(count, false); |
| 29 |
2/2✓ Branch 77 → 25 taken 337 times.
✓ Branch 77 → 78 taken 21 times.
|
358 | for (int c = 0; c < count; ++c) { |
| 30 | 337 | QPointF sum; | |
| 31 | 337 | int seen = 0; | |
| 32 | 337 | bool unchanged = true; | |
| 33 |
2/2✓ Branch 49 → 27 taken 2109 times.
✓ Branch 49 → 50 taken 337 times.
|
2446 | for (auto it = local.at(c).cbegin(); it != local.at(c).cend(); ++it) { |
| 34 | 2109 | const QString key = graph.nodes.at(it.key()).key; | |
| 35 |
2/2✓ Branch 31 → 32 taken 223 times.
✓ Branch 31 → 37 taken 1886 times.
|
2109 | if (previous.contains(key)) { |
| 36 | 223 | sum += previous.value(key) - it.value(); | |
| 37 | 223 | ++seen; | |
| 38 | } | ||
| 39 |
6/6✓ Branch 37 → 38 taken 524 times.
✓ Branch 37 → 43 taken 1585 times.
✓ Branch 39 → 40 taken 220 times.
✓ Branch 39 → 43 taken 304 times.
✓ Branch 41 → 42 taken 218 times.
✓ Branch 41 → 43 taken 2 times.
|
2109 | unchanged = unchanged && previous.contains(key) && !changed.contains(key); |
| 40 | 2109 | } | |
| 41 |
2/2✓ Branch 50 → 51 taken 304 times.
✓ Branch 50 → 52 taken 33 times.
|
337 | if (seen == 0) |
| 42 | 304 | continue; | |
| 43 |
1/1✓ Branch 52 → 53 taken 33 times.
|
33 | known[c] = true; |
| 44 |
1/1✓ Branch 54 → 55 taken 33 times.
|
33 | offset[c] = sum / seen; |
| 45 |
1/1✓ Branch 55 → 56 taken 33 times.
|
33 | pinned[c] = unchanged; |
| 46 |
2/2✓ Branch 74 → 58 taken 223 times.
✓ Branch 74 → 75 taken 33 times.
|
256 | for (auto it = local.at(c).cbegin(); it != local.at(c).cend(); ++it) // arranged as before? |
| 47 | 223 | if (const QPointF d = previous.value(graph.nodes.at(it.key()).key) - it.value() - offset.at(c); | |
| 48 |
1/2✗ Branch 67 → 68 not taken.
✓ Branch 67 → 70 taken 223 times.
|
223 | std::hypot(d.x(), d.y()) >= 1) |
| 49 | ✗ | pinned[c] = false; | |
| 50 | } | ||
| 51 | 21 | QList<QPair<int, int>> links; | |
| 52 |
2/2✓ Branch 103 → 80 taken 2976 times.
✓ Branch 103 → 104 taken 21 times.
|
2997 | for (const RelationGraph::Edge &e : graph.edges) |
| 53 |
5/7✓ Branch 82 → 83 taken 2976 times.
✗ Branch 82 → 94 not taken.
✓ Branch 85 → 86 taken 2944 times.
✓ Branch 85 → 94 taken 32 times.
✓ Branch 86 → 87 taken 2944 times.
✓ Branch 87 → 88 taken 2944 times.
✗ Branch 87 → 94 not taken.
|
2976 | if (e.from >= 0 && e.to >= 0 && e.kind != QLatin1String("member") && clusterOf.value(e.from) >= 0 && |
| 54 |
7/9✓ Branch 81 → 82 taken 2976 times.
✗ Branch 81 → 94 not taken.
✓ Branch 88 → 89 taken 2944 times.
✓ Branch 89 → 90 taken 2944 times.
✗ Branch 89 → 94 not taken.
✓ Branch 92 → 93 taken 953 times.
✓ Branch 92 → 94 taken 1991 times.
✓ Branch 95 → 96 taken 953 times.
✓ Branch 95 → 101 taken 2023 times.
|
5952 | clusterOf.value(e.to) >= 0 && clusterOf.at(e.from) != clusterOf.at(e.to)) |
| 55 |
1/1✓ Branch 99 → 100 taken 953 times.
|
953 | links.append({clusterOf.at(e.from), clusterOf.at(e.to)}); |
| 56 | 21 | const double gap = options.idealDistance * 0.6; // between two clusters' rims | |
| 57 |
3/3✓ Branch 107 → 108 taken 21 times.
✓ Branch 109 → 110 taken 15 times.
✓ Branch 109 → 114 taken 6 times.
|
21 | if (std::find(known.cbegin(), known.cend(), true) == known.cend()) { |
| 58 |
1/1✓ Branch 110 → 111 taken 15 times.
|
15 | offset = pack(sizes, options.aspect, gap); |
| 59 | } else { | ||
| 60 | // Incremental (G15): known clusters stay; a new one starts beside a known | ||
| 61 | // cluster it is joined to, else in a row of its own below everything. | ||
| 62 | 6 | double bottom = 0; | |
| 63 |
2/2✓ Branch 124 → 115 taken 33 times.
✓ Branch 124 → 125 taken 6 times.
|
39 | for (int c = 0; c < count; ++c) |
| 64 |
1/2✓ Branch 116 → 117 taken 33 times.
✗ Branch 116 → 123 not taken.
|
33 | if (known.at(c)) |
| 65 | 33 | bottom = std::max(bottom, offset.at(c).y() + sizes.at(c).height() / 2); | |
| 66 | 6 | QList<int> loose; | |
| 67 |
2/2✓ Branch 166 → 126 taken 33 times.
✓ Branch 166 → 167 taken 6 times.
|
39 | for (int c = 0; c < count; ++c) { |
| 68 |
1/2✓ Branch 127 → 128 taken 33 times.
✗ Branch 127 → 129 not taken.
|
33 | if (known.at(c)) |
| 69 | 33 | continue; | |
| 70 | ✗ | const QString key = graph.nodes.at(clusters.at(c).members().first()).key; | |
| 71 | ✗ | bool placed = false; | |
| 72 | ✗ | for (const auto &[x, y] : std::as_const(links)) | |
| 73 | ✗ | if ((x == c && known.at(y)) || (y == c && known.at(x))) { | |
| 74 | ✗ | offset[c] = offset.at(x == c ? y : x) + RelationGraphForce::seeded(key, gap); | |
| 75 | ✗ | placed = true; | |
| 76 | ✗ | break; | |
| 77 | } | ||
| 78 | ✗ | if (!placed) | |
| 79 | ✗ | loose.append(c); | |
| 80 | ✗ | } | |
| 81 | 6 | QList<QSizeF> looseSizes; | |
| 82 |
1/2✗ Branch 175 → 170 not taken.
✓ Branch 175 → 176 taken 6 times.
|
6 | for (int c : std::as_const(loose)) |
| 83 | ✗ | looseSizes.append(sizes.at(c)); | |
| 84 |
1/1✓ Branch 176 → 177 taken 6 times.
|
6 | const QList<QPointF> packed = pack(looseSizes, options.aspect, gap); |
| 85 | 6 | double looseTop = 0; | |
| 86 |
1/2✗ Branch 185 → 178 not taken.
✓ Branch 185 → 186 taken 6 times.
|
6 | for (int k = 0; k < loose.size(); ++k) |
| 87 | ✗ | looseTop = std::min(looseTop, packed.at(k).y() - looseSizes.at(k).height() / 2); | |
| 88 |
1/2✗ Branch 194 → 187 not taken.
✓ Branch 194 → 195 taken 6 times.
|
6 | for (int k = 0; k < loose.size(); ++k) |
| 89 | ✗ | offset[loose.at(k)] = packed.at(k) + QPointF(0, bottom + gap - looseTop); | |
| 90 |
1/1✓ Branch 195 → 196 taken 6 times.
|
6 | RelationGraphForce::separate(&offset, sizes, pinned); |
| 91 |
1/1✓ Branch 196 → 197 taken 6 times.
|
6 | RelationGraphForce::compact(&offset, sizes, pinned, gap * 0.5, links); |
| 92 | 6 | } | |
| 93 |
2/2✓ Branch 215 → 202 taken 337 times.
✓ Branch 215 → 216 taken 21 times.
|
358 | for (int c = 0; c < count; ++c) |
| 94 |
2/2✓ Branch 213 → 204 taken 2109 times.
✓ Branch 213 → 214 taken 337 times.
|
2446 | for (auto it = local.at(c).cbegin(); it != local.at(c).cend(); ++it) |
| 95 |
1/1✓ Branch 208 → 209 taken 2109 times.
|
2109 | layout.positions[it.key()] = offset.at(c) + it.value(); |
| 96 | // A family card (hidden, F103-13) in the middle of its members. | ||
| 97 |
2/2✓ Branch 252 → 217 taken 2121 times.
✓ Branch 252 → 253 taken 21 times.
|
2142 | for (int i = 0; i < n; ++i) { |
| 98 |
2/2✓ Branch 219 → 220 taken 2109 times.
✓ Branch 219 → 221 taken 12 times.
|
2121 | if (isShown(graph.nodes.at(i))) |
| 99 | 2109 | continue; | |
| 100 | 12 | QPointF sum; | |
| 101 | 12 | int members = 0; | |
| 102 |
2/2✓ Branch 245 → 223 taken 707 times.
✓ Branch 245 → 246 taken 12 times.
|
719 | for (const RelationGraph::Edge &e : graph.edges) |
| 103 |
10/13✓ Branch 226 → 227 taken 69 times.
✓ Branch 226 → 235 taken 638 times.
✓ Branch 227 → 228 taken 37 times.
✓ Branch 227 → 229 taken 32 times.
✗ Branch 228 → 229 not taken.
✓ Branch 228 → 235 taken 37 times.
✓ Branch 229 → 230 taken 32 times.
✗ Branch 229 → 231 not taken.
✓ Branch 232 → 233 taken 32 times.
✓ Branch 233 → 234 taken 32 times.
✗ Branch 233 → 235 not taken.
✓ Branch 236 → 237 taken 32 times.
✓ Branch 236 → 243 taken 675 times.
|
707 | if (e.kind == QLatin1String("member") && (e.from == i || e.to == i) && clusterOf.value(e.from == i ? e.to : e.from) >= 0) { |
| 104 |
1/2✓ Branch 237 → 238 taken 32 times.
✗ Branch 237 → 239 not taken.
|
32 | sum += layout.positions.at(e.from == i ? e.to : e.from); |
| 105 | 32 | ++members; | |
| 106 | } | ||
| 107 |
2/3✓ Branch 246 → 247 taken 12 times.
✗ Branch 246 → 248 not taken.
✓ Branch 249 → 250 taken 12 times.
|
12 | layout.positions[i] = members > 0 ? sum / members : QPointF(); |
| 108 | } | ||
| 109 |
1/1✓ Branch 253 → 254 taken 21 times.
|
21 | layout.routes = routes(graph, layout.positions); |
| 110 |
1/1✓ Branch 256 → 257 taken 21 times.
|
21 | bundleRoutes(graph, layout.positions, clusterOf, offset, sizes, &layout.routes); |
| 111 | 21 | return layout; | |
| 112 | 21 | } | |
| 113 | |||
| 114 | 12 | QList<QPointF> overview(const RelationGraph::Graph &graph, const QHash<QString, QPointF> &previous, | |
| 115 | const QSet<QString> &changed, const Options &options) { | ||
| 116 |
1/1✓ Branch 2 → 3 taken 12 times.
|
12 | return overviewLayout(graph, previous, changed, options).positions; |
| 117 | } | ||
| 118 | |||
| 119 | } // namespace RelationGraphLayout | ||
| 120 |