visualproof 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +99 -2
- package/dist/assets/fonts/JuliaMono-Regular.ttf +0 -0
- package/dist/assets/fonts/JuliaMono-RegularItalic.ttf +0 -0
- package/dist/assets/fonts/JuliaMono-SemiBold.ttf +0 -0
- package/dist/assets/fonts/LICENSE-JuliaMono.txt +93 -0
- package/dist/assets/latex/visualproof.sty +308 -0
- package/dist/assets/webfonts/LICENSE-Jost.txt +93 -0
- package/dist/assets/webfonts/LICENSE-SourceSans3.txt +93 -0
- package/dist/assets/webfonts/LICENSE-SourceSerif4.txt +93 -0
- package/dist/assets/webfonts/jost-latin-ext-wght-normal.woff2 +0 -0
- package/dist/assets/webfonts/jost-latin-wght-normal.woff2 +0 -0
- package/dist/assets/webfonts/source-sans-3-greek-wght-italic.woff2 +0 -0
- package/dist/assets/webfonts/source-sans-3-greek-wght-normal.woff2 +0 -0
- package/dist/assets/webfonts/source-sans-3-latin-ext-wght-italic.woff2 +0 -0
- package/dist/assets/webfonts/source-sans-3-latin-ext-wght-normal.woff2 +0 -0
- package/dist/assets/webfonts/source-sans-3-latin-wght-italic.woff2 +0 -0
- package/dist/assets/webfonts/source-sans-3-latin-wght-normal.woff2 +0 -0
- package/dist/assets/webfonts/source-serif-4-greek-wght-italic.woff2 +0 -0
- package/dist/assets/webfonts/source-serif-4-greek-wght-normal.woff2 +0 -0
- package/dist/assets/webfonts/source-serif-4-latin-ext-wght-italic.woff2 +0 -0
- package/dist/assets/webfonts/source-serif-4-latin-ext-wght-normal.woff2 +0 -0
- package/dist/assets/webfonts/source-serif-4-latin-wght-italic.woff2 +0 -0
- package/dist/assets/webfonts/source-serif-4-latin-wght-normal.woff2 +0 -0
- package/dist/extractor/Extract.lean +1180 -0
- package/dist/extractor/Usage.lean +900 -0
- package/dist/mcp/visualproof-mcp.mjs +476 -0
- package/dist/server/access.js +95 -0
- package/dist/server/agent.js +3270 -0
- package/dist/server/agentdocs.js +35 -0
- package/dist/server/agentlibrary.js +202 -0
- package/dist/server/agentnotes.js +701 -0
- package/dist/server/agentviews.js +703 -0
- package/dist/server/askfollow.js +286 -0
- package/dist/server/boardspots.js +159 -0
- package/dist/server/dirs.js +175 -0
- package/dist/server/doctor.js +186 -0
- package/dist/server/events.js +198 -0
- package/dist/server/export.js +420 -0
- package/dist/server/extract.js +204 -0
- package/dist/server/fetchurl.js +321 -0
- package/dist/server/figures.js +158 -0
- package/dist/server/history.js +780 -0
- package/dist/server/historyapi.js +304 -0
- package/dist/server/hover.js +595 -0
- package/dist/server/identity.js +114 -0
- package/dist/server/invites.js +241 -0
- package/dist/server/layoutthread.js +51 -0
- package/dist/server/library.js +600 -0
- package/dist/server/libraryroute.js +211 -0
- package/dist/server/live.js +1101 -0
- package/dist/server/lostfound.js +199 -0
- package/dist/server/main.js +1406 -0
- package/dist/server/mcptools.js +496 -0
- package/dist/server/pastdoc.js +73 -0
- package/dist/server/pipeline.js +159 -0
- package/dist/server/poppler.js +251 -0
- package/dist/server/presence.js +252 -0
- package/dist/server/project.js +222 -0
- package/dist/server/prompt.js +53 -0
- package/dist/server/readonly.js +152 -0
- package/dist/server/readonlygate.js +123 -0
- package/dist/server/renames.js +268 -0
- package/dist/server/review.js +334 -0
- package/dist/server/reviewapi.js +188 -0
- package/dist/server/snapshot.js +50 -0
- package/dist/server/sourcestore.js +473 -0
- package/dist/server/status.js +360 -0
- package/dist/server/talk.js +476 -0
- package/dist/server/tokens.js +221 -0
- package/dist/server/usage.js +501 -0
- package/dist/server/versions.js +82 -0
- package/dist/server/view.js +164 -0
- package/dist/server/views.js +1167 -0
- package/dist/shared/askfollow.js +46 -0
- package/dist/shared/board.js +332 -0
- package/dist/shared/build.js +2 -0
- package/dist/shared/collab.js +241 -0
- package/dist/shared/comment.js +285 -0
- package/dist/shared/context.js +157 -0
- package/dist/shared/doc/authors.js +98 -0
- package/dist/shared/doc/build.js +358 -0
- package/dist/shared/doc/latex.js +455 -0
- package/dist/shared/doc/markdown.js +159 -0
- package/dist/shared/doc/model.js +37 -0
- package/dist/shared/doc/order.js +124 -0
- package/dist/shared/doc/outline.js +45 -0
- package/dist/shared/doc/proof.js +272 -0
- package/dist/shared/doc/sections.js +93 -0
- package/dist/shared/doc/settings.js +75 -0
- package/dist/shared/edgecodec.js +102 -0
- package/dist/shared/editor.js +64 -0
- package/dist/shared/excerpt.js +87 -0
- package/dist/shared/graph.js +16 -0
- package/dist/shared/items.js +92 -0
- package/dist/shared/keys.js +203 -0
- package/dist/shared/layout.js +926 -0
- package/dist/shared/lexer.js +130 -0
- package/dist/shared/library.js +711 -0
- package/dist/shared/lostfound.js +150 -0
- package/dist/shared/moves.js +244 -0
- package/dist/shared/notecard.js +295 -0
- package/dist/shared/noteplace.js +505 -0
- package/dist/shared/palette.js +46 -0
- package/dist/shared/pastgraph.js +103 -0
- package/dist/shared/places.js +80 -0
- package/dist/shared/projectnotes.js +244 -0
- package/dist/shared/query.js +818 -0
- package/dist/shared/review.js +642 -0
- package/dist/shared/reviewqueue.js +333 -0
- package/dist/shared/ring.js +366 -0
- package/dist/shared/scope.js +255 -0
- package/dist/shared/scopeedit.js +81 -0
- package/dist/shared/search.js +191 -0
- package/dist/shared/separate.js +178 -0
- package/dist/shared/sharesnap.js +281 -0
- package/dist/shared/sticky.js +501 -0
- package/dist/shared/timeline.js +73 -0
- package/dist/shared/titles.js +300 -0
- package/dist/shared/viewgraph.js +157 -0
- package/dist/shared/views.js +859 -0
- package/dist/web/bundle/app.js +52671 -0
- package/dist/web/bundle/edges.js +407 -0
- package/dist/web/bundle/layout.js +1010 -0
- package/dist/web/bundle/pdfworker.js +48322 -0
- package/dist/web/index.html +257 -0
- package/dist/web/src/motion.js +430 -0
- package/dist/web/src/past.js +224 -0
- package/dist/web/src/scene.js +804 -0
- package/dist/web/style.css +2548 -0
- package/docs/agent-api/README.md +91 -0
- package/docs/agent-api/advice.md +108 -0
- package/docs/agent-api/export.md +120 -0
- package/docs/agent-api/following.md +140 -0
- package/docs/agent-api/history.md +142 -0
- package/docs/agent-api/library.md +65 -0
- package/docs/agent-api/mcp.md +104 -0
- package/docs/agent-api/notes.md +93 -0
- package/docs/agent-api/reading.md +166 -0
- package/docs/agent-api/requests.md +94 -0
- package/docs/agent-api/talking.md +100 -0
- package/docs/agent-api/tcb.md +135 -0
- package/docs/agent-api/views.md +125 -0
- package/docs/agent-api/words.md +56 -0
- package/package.json +39 -4
- package/test/toolchains.json +5 -0
|
@@ -0,0 +1,1010 @@
|
|
|
1
|
+
// node_modules/d3-hierarchy/src/lcg.js
|
|
2
|
+
var a = 1664525;
|
|
3
|
+
var c = 1013904223;
|
|
4
|
+
var m = 4294967296;
|
|
5
|
+
function lcg_default() {
|
|
6
|
+
let s = 1;
|
|
7
|
+
return () => (s = (a * s + c) % m) / m;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// node_modules/d3-hierarchy/src/array.js
|
|
11
|
+
function array_default(x) {
|
|
12
|
+
return typeof x === "object" && "length" in x ? x : Array.from(x);
|
|
13
|
+
}
|
|
14
|
+
function shuffle(array, random) {
|
|
15
|
+
let m2 = array.length, t, i;
|
|
16
|
+
while (m2) {
|
|
17
|
+
i = random() * m2-- | 0;
|
|
18
|
+
t = array[m2];
|
|
19
|
+
array[m2] = array[i];
|
|
20
|
+
array[i] = t;
|
|
21
|
+
}
|
|
22
|
+
return array;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// node_modules/d3-hierarchy/src/pack/enclose.js
|
|
26
|
+
function enclose_default(circles) {
|
|
27
|
+
return packEncloseRandom(circles, lcg_default());
|
|
28
|
+
}
|
|
29
|
+
function packEncloseRandom(circles, random) {
|
|
30
|
+
var i = 0, n = (circles = shuffle(Array.from(circles), random)).length, B = [], p, e;
|
|
31
|
+
while (i < n) {
|
|
32
|
+
p = circles[i];
|
|
33
|
+
if (e && enclosesWeak(e, p)) ++i;
|
|
34
|
+
else e = encloseBasis(B = extendBasis(B, p)), i = 0;
|
|
35
|
+
}
|
|
36
|
+
return e;
|
|
37
|
+
}
|
|
38
|
+
function extendBasis(B, p) {
|
|
39
|
+
var i, j;
|
|
40
|
+
if (enclosesWeakAll(p, B)) return [p];
|
|
41
|
+
for (i = 0; i < B.length; ++i) {
|
|
42
|
+
if (enclosesNot(p, B[i]) && enclosesWeakAll(encloseBasis2(B[i], p), B)) {
|
|
43
|
+
return [B[i], p];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
for (i = 0; i < B.length - 1; ++i) {
|
|
47
|
+
for (j = i + 1; j < B.length; ++j) {
|
|
48
|
+
if (enclosesNot(encloseBasis2(B[i], B[j]), p) && enclosesNot(encloseBasis2(B[i], p), B[j]) && enclosesNot(encloseBasis2(B[j], p), B[i]) && enclosesWeakAll(encloseBasis3(B[i], B[j], p), B)) {
|
|
49
|
+
return [B[i], B[j], p];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
throw new Error();
|
|
54
|
+
}
|
|
55
|
+
function enclosesNot(a2, b) {
|
|
56
|
+
var dr = a2.r - b.r, dx = b.x - a2.x, dy = b.y - a2.y;
|
|
57
|
+
return dr < 0 || dr * dr < dx * dx + dy * dy;
|
|
58
|
+
}
|
|
59
|
+
function enclosesWeak(a2, b) {
|
|
60
|
+
var dr = a2.r - b.r + Math.max(a2.r, b.r, 1) * 1e-9, dx = b.x - a2.x, dy = b.y - a2.y;
|
|
61
|
+
return dr > 0 && dr * dr > dx * dx + dy * dy;
|
|
62
|
+
}
|
|
63
|
+
function enclosesWeakAll(a2, B) {
|
|
64
|
+
for (var i = 0; i < B.length; ++i) {
|
|
65
|
+
if (!enclosesWeak(a2, B[i])) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
function encloseBasis(B) {
|
|
72
|
+
switch (B.length) {
|
|
73
|
+
case 1:
|
|
74
|
+
return encloseBasis1(B[0]);
|
|
75
|
+
case 2:
|
|
76
|
+
return encloseBasis2(B[0], B[1]);
|
|
77
|
+
case 3:
|
|
78
|
+
return encloseBasis3(B[0], B[1], B[2]);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function encloseBasis1(a2) {
|
|
82
|
+
return {
|
|
83
|
+
x: a2.x,
|
|
84
|
+
y: a2.y,
|
|
85
|
+
r: a2.r
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function encloseBasis2(a2, b) {
|
|
89
|
+
var x1 = a2.x, y1 = a2.y, r1 = a2.r, x2 = b.x, y2 = b.y, r2 = b.r, x21 = x2 - x1, y21 = y2 - y1, r21 = r2 - r1, l = Math.sqrt(x21 * x21 + y21 * y21);
|
|
90
|
+
return {
|
|
91
|
+
x: (x1 + x2 + x21 / l * r21) / 2,
|
|
92
|
+
y: (y1 + y2 + y21 / l * r21) / 2,
|
|
93
|
+
r: (l + r1 + r2) / 2
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function encloseBasis3(a2, b, c2) {
|
|
97
|
+
var x1 = a2.x, y1 = a2.y, r1 = a2.r, x2 = b.x, y2 = b.y, r2 = b.r, x3 = c2.x, y3 = c2.y, r3 = c2.r, a22 = x1 - x2, a3 = x1 - x3, b2 = y1 - y2, b3 = y1 - y3, c22 = r2 - r1, c3 = r3 - r1, d1 = x1 * x1 + y1 * y1 - r1 * r1, d2 = d1 - x2 * x2 - y2 * y2 + r2 * r2, d3 = d1 - x3 * x3 - y3 * y3 + r3 * r3, ab = a3 * b2 - a22 * b3, xa = (b2 * d3 - b3 * d2) / (ab * 2) - x1, xb = (b3 * c22 - b2 * c3) / ab, ya = (a3 * d2 - a22 * d3) / (ab * 2) - y1, yb = (a22 * c3 - a3 * c22) / ab, A = xb * xb + yb * yb - 1, B = 2 * (r1 + xa * xb + ya * yb), C = xa * xa + ya * ya - r1 * r1, r = -(Math.abs(A) > 1e-6 ? (B + Math.sqrt(B * B - 4 * A * C)) / (2 * A) : C / B);
|
|
98
|
+
return {
|
|
99
|
+
x: x1 + xa + xb * r,
|
|
100
|
+
y: y1 + ya + yb * r,
|
|
101
|
+
r
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// node_modules/d3-hierarchy/src/pack/siblings.js
|
|
106
|
+
function place(b, a2, c2) {
|
|
107
|
+
var dx = b.x - a2.x, x, a22, dy = b.y - a2.y, y, b2, d2 = dx * dx + dy * dy;
|
|
108
|
+
if (d2) {
|
|
109
|
+
a22 = a2.r + c2.r, a22 *= a22;
|
|
110
|
+
b2 = b.r + c2.r, b2 *= b2;
|
|
111
|
+
if (a22 > b2) {
|
|
112
|
+
x = (d2 + b2 - a22) / (2 * d2);
|
|
113
|
+
y = Math.sqrt(Math.max(0, b2 / d2 - x * x));
|
|
114
|
+
c2.x = b.x - x * dx - y * dy;
|
|
115
|
+
c2.y = b.y - x * dy + y * dx;
|
|
116
|
+
} else {
|
|
117
|
+
x = (d2 + a22 - b2) / (2 * d2);
|
|
118
|
+
y = Math.sqrt(Math.max(0, a22 / d2 - x * x));
|
|
119
|
+
c2.x = a2.x + x * dx - y * dy;
|
|
120
|
+
c2.y = a2.y + x * dy + y * dx;
|
|
121
|
+
}
|
|
122
|
+
} else {
|
|
123
|
+
c2.x = a2.x + c2.r;
|
|
124
|
+
c2.y = a2.y;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function intersects(a2, b) {
|
|
128
|
+
var dr = a2.r + b.r - 1e-6, dx = b.x - a2.x, dy = b.y - a2.y;
|
|
129
|
+
return dr > 0 && dr * dr > dx * dx + dy * dy;
|
|
130
|
+
}
|
|
131
|
+
function score(node) {
|
|
132
|
+
var a2 = node._, b = node.next._, ab = a2.r + b.r, dx = (a2.x * b.r + b.x * a2.r) / ab, dy = (a2.y * b.r + b.y * a2.r) / ab;
|
|
133
|
+
return dx * dx + dy * dy;
|
|
134
|
+
}
|
|
135
|
+
function Node(circle) {
|
|
136
|
+
this._ = circle;
|
|
137
|
+
this.next = null;
|
|
138
|
+
this.previous = null;
|
|
139
|
+
}
|
|
140
|
+
function packSiblingsRandom(circles, random) {
|
|
141
|
+
if (!(n = (circles = array_default(circles)).length)) return 0;
|
|
142
|
+
var a2, b, c2, n, aa, ca, i, j, k, sj, sk;
|
|
143
|
+
a2 = circles[0], a2.x = 0, a2.y = 0;
|
|
144
|
+
if (!(n > 1)) return a2.r;
|
|
145
|
+
b = circles[1], a2.x = -b.r, b.x = a2.r, b.y = 0;
|
|
146
|
+
if (!(n > 2)) return a2.r + b.r;
|
|
147
|
+
place(b, a2, c2 = circles[2]);
|
|
148
|
+
a2 = new Node(a2), b = new Node(b), c2 = new Node(c2);
|
|
149
|
+
a2.next = c2.previous = b;
|
|
150
|
+
b.next = a2.previous = c2;
|
|
151
|
+
c2.next = b.previous = a2;
|
|
152
|
+
pack: for (i = 3; i < n; ++i) {
|
|
153
|
+
place(a2._, b._, c2 = circles[i]), c2 = new Node(c2);
|
|
154
|
+
j = b.next, k = a2.previous, sj = b._.r, sk = a2._.r;
|
|
155
|
+
do {
|
|
156
|
+
if (sj <= sk) {
|
|
157
|
+
if (intersects(j._, c2._)) {
|
|
158
|
+
b = j, a2.next = b, b.previous = a2, --i;
|
|
159
|
+
continue pack;
|
|
160
|
+
}
|
|
161
|
+
sj += j._.r, j = j.next;
|
|
162
|
+
} else {
|
|
163
|
+
if (intersects(k._, c2._)) {
|
|
164
|
+
a2 = k, a2.next = b, b.previous = a2, --i;
|
|
165
|
+
continue pack;
|
|
166
|
+
}
|
|
167
|
+
sk += k._.r, k = k.previous;
|
|
168
|
+
}
|
|
169
|
+
} while (j !== k.next);
|
|
170
|
+
c2.previous = a2, c2.next = b, a2.next = b.previous = b = c2;
|
|
171
|
+
aa = score(a2);
|
|
172
|
+
while ((c2 = c2.next) !== b) {
|
|
173
|
+
if ((ca = score(c2)) < aa) {
|
|
174
|
+
a2 = c2, aa = ca;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
b = a2.next;
|
|
178
|
+
}
|
|
179
|
+
a2 = [b._], c2 = b;
|
|
180
|
+
while ((c2 = c2.next) !== b) a2.push(c2._);
|
|
181
|
+
c2 = packEncloseRandom(a2, random);
|
|
182
|
+
for (i = 0; i < n; ++i) a2 = circles[i], a2.x -= c2.x, a2.y -= c2.y;
|
|
183
|
+
return c2.r;
|
|
184
|
+
}
|
|
185
|
+
function siblings_default(circles) {
|
|
186
|
+
packSiblingsRandom(circles, lcg_default());
|
|
187
|
+
return circles;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// src/shared/separate.ts
|
|
191
|
+
var SLACK = 0.5;
|
|
192
|
+
var Separator = class {
|
|
193
|
+
head = new Int32Array(0);
|
|
194
|
+
next = new Int32Array(0);
|
|
195
|
+
mask = 0;
|
|
196
|
+
moved = new Uint8Array(0);
|
|
197
|
+
movedNext = new Uint8Array(0);
|
|
198
|
+
movedSmall = new Int32Array(0);
|
|
199
|
+
cell;
|
|
200
|
+
constructor(cell) {
|
|
201
|
+
this.cell = cell;
|
|
202
|
+
}
|
|
203
|
+
ensure(n, nSmall) {
|
|
204
|
+
if (this.next.length < n) {
|
|
205
|
+
this.next = new Int32Array(n);
|
|
206
|
+
this.moved = new Uint8Array(n);
|
|
207
|
+
this.movedNext = new Uint8Array(n);
|
|
208
|
+
this.movedSmall = new Int32Array(n);
|
|
209
|
+
}
|
|
210
|
+
let size = 64;
|
|
211
|
+
while (size < 2 * nSmall) size <<= 1;
|
|
212
|
+
if (this.head.length !== size) this.head = new Int32Array(size);
|
|
213
|
+
this.mask = size - 1;
|
|
214
|
+
}
|
|
215
|
+
key(x, y) {
|
|
216
|
+
return (Math.imul(Math.floor(x / this.cell), 73856093) ^ Math.imul(Math.floor(y / this.cell), 19349663)) & this.mask;
|
|
217
|
+
}
|
|
218
|
+
build(B) {
|
|
219
|
+
this.head.fill(-1);
|
|
220
|
+
for (let s = 0; s < B.small.length; s++) {
|
|
221
|
+
const k = B.small[s];
|
|
222
|
+
const h = this.key(B.x[k], B.y[k]);
|
|
223
|
+
this.next[k] = this.head[h];
|
|
224
|
+
this.head[h] = k;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/** Push a and b apart if they overlap; marks what moved. */
|
|
228
|
+
push(B, a2, b) {
|
|
229
|
+
const dx = B.x[b] - B.x[a2], dy = B.y[b] - B.y[a2];
|
|
230
|
+
const need = B.r[a2] + B.r[b];
|
|
231
|
+
const d2 = dx * dx + dy * dy;
|
|
232
|
+
if (d2 >= (need - SLACK) * (need - SLACK)) return false;
|
|
233
|
+
const pa = B.pinned[a2], pb = B.pinned[b];
|
|
234
|
+
const fixA = pa && (!pb || B.seq[a2] > B.seq[b]);
|
|
235
|
+
const fixB = pb && (!pa || B.seq[b] > B.seq[a2]);
|
|
236
|
+
const d = Math.sqrt(d2) || 1e-3;
|
|
237
|
+
const over = need - d;
|
|
238
|
+
const ra = B.r[a2] * B.r[a2], rb = B.r[b] * B.r[b];
|
|
239
|
+
const wa = fixA ? 0 : fixB ? 1 : rb / (ra + rb);
|
|
240
|
+
const ux = d2 ? dx / d : 1, uy = d2 ? dy / d : 0;
|
|
241
|
+
if (wa > 0) {
|
|
242
|
+
B.x[a2] -= ux * over * wa;
|
|
243
|
+
B.y[a2] -= uy * over * wa;
|
|
244
|
+
this.movedNext[a2] = 1;
|
|
245
|
+
}
|
|
246
|
+
if (wa < 1) {
|
|
247
|
+
B.x[b] += ux * over * (1 - wa);
|
|
248
|
+
B.y[b] += uy * over * (1 - wa);
|
|
249
|
+
this.movedNext[b] = 1;
|
|
250
|
+
}
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
overlap(B, a2, b) {
|
|
254
|
+
const dx = B.x[b] - B.x[a2], dy = B.y[b] - B.y[a2];
|
|
255
|
+
const need = B.r[a2] + B.r[b] - SLACK;
|
|
256
|
+
return dx * dx + dy * dy < need * need;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Up to `rounds` rounds of separation. After each round a body further from the origin than
|
|
260
|
+
* `limit[k]` is brought back to it (null: no limit). Returns whether anything still moved in
|
|
261
|
+
* the last round.
|
|
262
|
+
*/
|
|
263
|
+
separate(B, rounds, limit) {
|
|
264
|
+
const { big, small } = B;
|
|
265
|
+
this.ensure(B.n, small.length);
|
|
266
|
+
const moved = this.moved, next = this.movedNext;
|
|
267
|
+
moved.fill(1, 0, B.n);
|
|
268
|
+
let any = false;
|
|
269
|
+
for (let round2 = 0; round2 < rounds; round2++) {
|
|
270
|
+
any = false;
|
|
271
|
+
next.fill(0, 0, B.n);
|
|
272
|
+
this.build(B);
|
|
273
|
+
let nMovedSmall = 0;
|
|
274
|
+
for (let s = 0; s < small.length; s++) if (moved[small[s]]) this.movedSmall[nMovedSmall++] = small[s];
|
|
275
|
+
for (let p = 0; p < big.length; p++) {
|
|
276
|
+
const a2 = big[p];
|
|
277
|
+
for (let q = p + 1; q < big.length; q++) {
|
|
278
|
+
const b = big[q];
|
|
279
|
+
if ((moved[a2] || moved[b]) && this.push(B, a2, b)) any = true;
|
|
280
|
+
}
|
|
281
|
+
if (moved[a2]) {
|
|
282
|
+
for (let s = 0; s < small.length; s++) if (this.push(B, a2, small[s])) any = true;
|
|
283
|
+
} else {
|
|
284
|
+
for (let s = 0; s < nMovedSmall; s++) if (this.push(B, a2, this.movedSmall[s])) any = true;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
for (let s = 0; s < nMovedSmall; s++) {
|
|
288
|
+
const a2 = this.movedSmall[s];
|
|
289
|
+
const gx = Math.floor(B.x[a2] / this.cell), gy = Math.floor(B.y[a2] / this.cell);
|
|
290
|
+
for (let i = gx - 1; i <= gx + 1; i++) {
|
|
291
|
+
for (let j = gy - 1; j <= gy + 1; j++) {
|
|
292
|
+
const h = (Math.imul(i, 73856093) ^ Math.imul(j, 19349663)) & this.mask;
|
|
293
|
+
for (let b = this.head[h]; b >= 0; b = this.next[b]) {
|
|
294
|
+
if (b === a2 || moved[b] && b < a2) continue;
|
|
295
|
+
if (this.push(B, a2, b)) any = true;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
if (limit) {
|
|
301
|
+
for (let k = 0; k < B.n; k++) {
|
|
302
|
+
const d = Math.hypot(B.x[k], B.y[k]);
|
|
303
|
+
if (d > limit[k]) {
|
|
304
|
+
B.x[k] *= limit[k] / d;
|
|
305
|
+
B.y[k] *= limit[k] / d;
|
|
306
|
+
next[k] = 1;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
moved.set(next.subarray(0, B.n));
|
|
311
|
+
if (!any) break;
|
|
312
|
+
}
|
|
313
|
+
return any;
|
|
314
|
+
}
|
|
315
|
+
/** Whether any two bodies overlap (two drops on each other included). */
|
|
316
|
+
overlaps(B) {
|
|
317
|
+
const { big, small } = B;
|
|
318
|
+
this.ensure(B.n, small.length);
|
|
319
|
+
for (let p = 0; p < big.length; p++) {
|
|
320
|
+
for (let q = p + 1; q < big.length; q++) if (this.overlap(B, big[p], big[q])) return true;
|
|
321
|
+
for (let s = 0; s < small.length; s++) if (this.overlap(B, big[p], small[s])) return true;
|
|
322
|
+
}
|
|
323
|
+
this.build(B);
|
|
324
|
+
for (let s = 0; s < small.length; s++) {
|
|
325
|
+
const a2 = small[s];
|
|
326
|
+
const gx = Math.floor(B.x[a2] / this.cell), gy = Math.floor(B.y[a2] / this.cell);
|
|
327
|
+
for (let i = gx - 1; i <= gx + 1; i++) {
|
|
328
|
+
for (let j = gy - 1; j <= gy + 1; j++) {
|
|
329
|
+
const h = (Math.imul(i, 73856093) ^ Math.imul(j, 19349663)) & this.mask;
|
|
330
|
+
for (let b = this.head[h]; b >= 0; b = this.next[b]) if (b > a2 && this.overlap(B, a2, b)) return true;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
// src/shared/layout.ts
|
|
339
|
+
var LEAF_R = 5;
|
|
340
|
+
var GAP = 2.5;
|
|
341
|
+
var EXT_KEY = "\u27E8external\u27E9";
|
|
342
|
+
function splitName(name) {
|
|
343
|
+
const out = [];
|
|
344
|
+
let cur = "";
|
|
345
|
+
let depth = 0;
|
|
346
|
+
for (const ch of name) {
|
|
347
|
+
if (ch === "\xAB") depth++;
|
|
348
|
+
else if (ch === "\xBB") depth--;
|
|
349
|
+
if (ch === "." && depth === 0) {
|
|
350
|
+
out.push(cur);
|
|
351
|
+
cur = "";
|
|
352
|
+
} else cur += ch;
|
|
353
|
+
}
|
|
354
|
+
out.push(cur);
|
|
355
|
+
return out;
|
|
356
|
+
}
|
|
357
|
+
function tnode(key, label, parent, ext) {
|
|
358
|
+
const none = new Float64Array(0);
|
|
359
|
+
return { key, label, parent, kids: /* @__PURE__ */ new Map(), leaves: [], ext, count: 0, x: 0, y: 0, r: 0, id: -1, slot: 0, m: 0, flow: /* @__PURE__ */ new Map(), gOut: none, gIn: none };
|
|
360
|
+
}
|
|
361
|
+
function pathOf(mode, n, prefixes) {
|
|
362
|
+
if (n.ext) {
|
|
363
|
+
if (mode === "module") return [EXT_KEY, ...n.module.split(".").slice(0, 2)];
|
|
364
|
+
const parts2 = splitName(n.name);
|
|
365
|
+
return parts2.length > 1 ? [EXT_KEY, parts2[0]] : [EXT_KEY];
|
|
366
|
+
}
|
|
367
|
+
if (mode === "module") return n.module.split(".");
|
|
368
|
+
const parts = splitName(n.name);
|
|
369
|
+
return prefixes.has(n.name) ? parts : parts.slice(0, -1);
|
|
370
|
+
}
|
|
371
|
+
function potentials(c2) {
|
|
372
|
+
const m2 = c2.m;
|
|
373
|
+
const pa = [], pb = [], pc = [];
|
|
374
|
+
const rhs = new Float64Array(m2);
|
|
375
|
+
const diag = new Float64Array(m2);
|
|
376
|
+
const join = (a2, b, ab, ba) => {
|
|
377
|
+
const tot = ab + ba;
|
|
378
|
+
const g = Math.log1p(tot);
|
|
379
|
+
const drop = (ab - ba) / tot;
|
|
380
|
+
rhs[a2] += g * drop;
|
|
381
|
+
diag[a2] += g;
|
|
382
|
+
if (b < m2) {
|
|
383
|
+
rhs[b] -= g * drop;
|
|
384
|
+
diag[b] += g;
|
|
385
|
+
pa.push(a2);
|
|
386
|
+
pb.push(b);
|
|
387
|
+
pc.push(g);
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
for (const [key, ab] of c2.flow) {
|
|
391
|
+
const a2 = Math.floor(key / (m2 + 1)), b = key - a2 * (m2 + 1);
|
|
392
|
+
const ba = c2.flow.get(b * (m2 + 1) + a2) ?? 0;
|
|
393
|
+
if (a2 < b || ba === 0) join(a2, b, ab, ba);
|
|
394
|
+
}
|
|
395
|
+
for (let a2 = 0; a2 < m2; a2++) if (c2.gOut[a2] + c2.gIn[a2] > 0) join(a2, m2, c2.gOut[a2], c2.gIn[a2]);
|
|
396
|
+
const EPS = 1e-4;
|
|
397
|
+
const mul = (x, y) => {
|
|
398
|
+
for (let k = 0; k < m2; k++) y[k] = (diag[k] + EPS) * x[k];
|
|
399
|
+
for (let e = 0; e < pa.length; e++) {
|
|
400
|
+
const a2 = pa[e], b = pb[e], g = pc[e];
|
|
401
|
+
y[a2] -= g * x[b];
|
|
402
|
+
y[b] -= g * x[a2];
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
const phi = new Float64Array(m2);
|
|
406
|
+
const r = rhs.slice();
|
|
407
|
+
const p = r.slice();
|
|
408
|
+
const Ap = new Float64Array(m2);
|
|
409
|
+
let rr = r.reduce((s, v) => s + v * v, 0);
|
|
410
|
+
const stop = rr * 1e-12;
|
|
411
|
+
for (let it = 0; it < 1e3 && rr > stop && rr > 0; it++) {
|
|
412
|
+
mul(p, Ap);
|
|
413
|
+
let pAp = 0;
|
|
414
|
+
for (let k = 0; k < m2; k++) pAp += p[k] * Ap[k];
|
|
415
|
+
const alpha = rr / pAp;
|
|
416
|
+
let next = 0;
|
|
417
|
+
for (let k = 0; k < m2; k++) {
|
|
418
|
+
phi[k] += alpha * p[k];
|
|
419
|
+
r[k] -= alpha * Ap[k];
|
|
420
|
+
next += r[k] * r[k];
|
|
421
|
+
}
|
|
422
|
+
const beta = next / rr;
|
|
423
|
+
rr = next;
|
|
424
|
+
for (let k = 0; k < m2; k++) p[k] = r[k] + beta * p[k];
|
|
425
|
+
}
|
|
426
|
+
return phi;
|
|
427
|
+
}
|
|
428
|
+
var separator = new Separator(2 * LEAF_R + GAP);
|
|
429
|
+
var PITCH = 2 * LEAF_R + 0.3;
|
|
430
|
+
function settle(items, phi) {
|
|
431
|
+
const n = items.length;
|
|
432
|
+
const order = [...items.keys()].sort((p, q) => phi[q] - phi[p] || p - q);
|
|
433
|
+
let total = 0;
|
|
434
|
+
for (const it of items) total += Math.PI * (it.r + 0.3) ** 2;
|
|
435
|
+
const R = Math.sqrt(total / (Math.PI * 0.78));
|
|
436
|
+
const above = (t) => (Math.acos(t) - t * Math.sqrt(1 - t * t)) / Math.PI;
|
|
437
|
+
const heightOf = (f) => {
|
|
438
|
+
let lo = -1, hi = 1;
|
|
439
|
+
for (let k = 0; k < 40; k++) {
|
|
440
|
+
const mid = (lo + hi) / 2;
|
|
441
|
+
if (above(mid) > f) lo = mid;
|
|
442
|
+
else hi = mid;
|
|
443
|
+
}
|
|
444
|
+
return (lo + hi) / 2;
|
|
445
|
+
};
|
|
446
|
+
const share = new Float64Array(n);
|
|
447
|
+
let acc = 0;
|
|
448
|
+
for (const k of order) {
|
|
449
|
+
const a2 = Math.PI * (items[k].r + 0.3) ** 2;
|
|
450
|
+
share[k] = heightOf((acc + a2 / 2) / total);
|
|
451
|
+
acc += a2;
|
|
452
|
+
}
|
|
453
|
+
const big = [...items.keys()].filter((k) => items[k].sub).sort((p, q) => items[q].r - items[p].r || p - q);
|
|
454
|
+
const leaves = order.filter((k) => !items[k].sub);
|
|
455
|
+
if (big.length === 0) {
|
|
456
|
+
const spots = siblings_default(leaves.map(() => ({ x: 0, y: 0, r: LEAF_R + 0.15 })));
|
|
457
|
+
spots.sort((a2, b) => a2.y - b.y || a2.x - b.x);
|
|
458
|
+
leaves.forEach((k, j) => {
|
|
459
|
+
items[k].x = spots[j].x;
|
|
460
|
+
items[k].y = spots[j].y;
|
|
461
|
+
});
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
let scale = R;
|
|
465
|
+
for (let pass = 0; pass < 3; pass++) {
|
|
466
|
+
place2(share.map((t) => -t * scale));
|
|
467
|
+
let x0 = Infinity, x1 = -Infinity, y0 = Infinity, y1 = -Infinity;
|
|
468
|
+
for (const it of items) {
|
|
469
|
+
x0 = Math.min(x0, it.x - it.r);
|
|
470
|
+
x1 = Math.max(x1, it.x + it.r);
|
|
471
|
+
y0 = Math.min(y0, it.y - it.r);
|
|
472
|
+
y1 = Math.max(y1, it.y + it.r);
|
|
473
|
+
}
|
|
474
|
+
const aspect = (x1 - x0) / Math.max(1e-6, y1 - y0);
|
|
475
|
+
if (Math.abs(aspect - 1) < 0.06 || big.length === 0) break;
|
|
476
|
+
scale *= Math.sqrt(aspect);
|
|
477
|
+
}
|
|
478
|
+
finish();
|
|
479
|
+
function place2(ty) {
|
|
480
|
+
const px = [], py = [], pr = [];
|
|
481
|
+
const free = (x, y, r) => {
|
|
482
|
+
for (let j = 0; j < px.length; j++) {
|
|
483
|
+
const need = r + pr[j] + 0.3;
|
|
484
|
+
if ((x - px[j]) ** 2 + (y - py[j]) ** 2 < need * need) return false;
|
|
485
|
+
}
|
|
486
|
+
return true;
|
|
487
|
+
};
|
|
488
|
+
const cost = (x, y, t) => (y - t) ** 2 + 0.3 * x * x;
|
|
489
|
+
const ANGLES = 24;
|
|
490
|
+
for (const k of big) {
|
|
491
|
+
const r = items[k].r;
|
|
492
|
+
const t = ty[k];
|
|
493
|
+
let bx = 0, by = t, best = free(0, t, r) ? 0 : Infinity;
|
|
494
|
+
if (best > 0) {
|
|
495
|
+
const near = px.map((_, j) => j).sort((a2, b) => Math.hypot(px[a2], py[a2] - t) - pr[a2] - (Math.hypot(px[b], py[b] - t) - pr[b])).slice(0, 12);
|
|
496
|
+
for (const j of near) {
|
|
497
|
+
const d = r + pr[j] + 0.3;
|
|
498
|
+
for (let s = 0; s < ANGLES; s++) {
|
|
499
|
+
const a2 = 2 * Math.PI * s / ANGLES;
|
|
500
|
+
const x = px[j] + d * Math.cos(a2), y = py[j] + d * Math.sin(a2);
|
|
501
|
+
const c2 = cost(x, y, t);
|
|
502
|
+
if (c2 < best && free(x, y, r)) {
|
|
503
|
+
best = c2;
|
|
504
|
+
bx = x;
|
|
505
|
+
by = y;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
for (let step = 1; best === Infinity; step++) {
|
|
510
|
+
for (const x of [step * r, -step * r]) if (best === Infinity && free(x, t, r)) [best, bx, by] = [0, x, t];
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
items[k].x = bx;
|
|
514
|
+
items[k].y = by;
|
|
515
|
+
px.push(bx);
|
|
516
|
+
py.push(by);
|
|
517
|
+
pr.push(r);
|
|
518
|
+
}
|
|
519
|
+
if (big.length > 1) {
|
|
520
|
+
const D = {
|
|
521
|
+
n: big.length,
|
|
522
|
+
x: Float64Array.from(px),
|
|
523
|
+
y: Float64Array.from(py),
|
|
524
|
+
r: Float64Array.from(pr, (r) => r + 0.3),
|
|
525
|
+
pinned: new Uint8Array(big.length),
|
|
526
|
+
seq: new Float64Array(big.length),
|
|
527
|
+
big: Int32Array.from(big.keys()),
|
|
528
|
+
small: new Int32Array(0)
|
|
529
|
+
};
|
|
530
|
+
for (let it = 0; it < 80; it++) {
|
|
531
|
+
for (let j = 0; j < big.length; j++) {
|
|
532
|
+
D.x[j] *= 0.93;
|
|
533
|
+
D.y[j] += (ty[big[j]] - D.y[j]) * 0.1;
|
|
534
|
+
D.y[j] *= 0.985;
|
|
535
|
+
}
|
|
536
|
+
separator.separate(D, 4, null);
|
|
537
|
+
}
|
|
538
|
+
for (let guard = 0; guard < 20 && separator.overlaps(D); guard++) separator.separate(D, 50, null);
|
|
539
|
+
big.forEach((k, j) => {
|
|
540
|
+
items[k].x = px[j] = D.x[j];
|
|
541
|
+
items[k].y = py[j] = D.y[j];
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
if (leaves.length) {
|
|
545
|
+
const rowH = PITCH * Math.sqrt(3) / 2;
|
|
546
|
+
let Rl = Math.sqrt(leaves.length) * PITCH * 0.55 + 2 * PITCH;
|
|
547
|
+
let cells = [];
|
|
548
|
+
for (let attempt = 0; attempt < 60; attempt++) {
|
|
549
|
+
cells = [];
|
|
550
|
+
const rows = Math.ceil(Rl / rowH);
|
|
551
|
+
for (let j = -rows; j <= rows; j++) {
|
|
552
|
+
const y = j * rowH;
|
|
553
|
+
const off = j & 1 ? PITCH / 2 : 0;
|
|
554
|
+
const cols = Math.ceil(Rl / PITCH) + 1;
|
|
555
|
+
for (let i = -cols; i <= cols; i++) {
|
|
556
|
+
const x = i * PITCH + off;
|
|
557
|
+
const d2 = x * x + y * y;
|
|
558
|
+
if (d2 > Rl * Rl) continue;
|
|
559
|
+
let ok = true;
|
|
560
|
+
for (let q = 0; q < px.length && ok; q++) {
|
|
561
|
+
const need = pr[q] + LEAF_R + 0.3;
|
|
562
|
+
if ((x - px[q]) ** 2 + (y - py[q]) ** 2 < need * need) ok = false;
|
|
563
|
+
}
|
|
564
|
+
if (ok) cells.push([x, y, d2]);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
if (cells.length >= leaves.length) break;
|
|
568
|
+
Rl *= 1.08;
|
|
569
|
+
}
|
|
570
|
+
cells.sort((a2, b) => a2[2] - b[2] || a2[1] - b[1] || a2[0] - b[0]);
|
|
571
|
+
const chosen = cells.slice(0, leaves.length).sort((a2, b) => a2[1] - b[1] || a2[0] - b[0]);
|
|
572
|
+
leaves.forEach((k, j) => {
|
|
573
|
+
items[k].x = chosen[j][0];
|
|
574
|
+
items[k].y = chosen[j][1];
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
function finish() {
|
|
579
|
+
const B = {
|
|
580
|
+
n,
|
|
581
|
+
x: Float64Array.from(items, (it) => it.x),
|
|
582
|
+
y: Float64Array.from(items, (it) => it.y),
|
|
583
|
+
r: Float64Array.from(items, (it) => it.r + 0.3),
|
|
584
|
+
pinned: new Uint8Array(n),
|
|
585
|
+
seq: new Float64Array(n),
|
|
586
|
+
big: Int32Array.from(big),
|
|
587
|
+
small: Int32Array.from(leaves)
|
|
588
|
+
};
|
|
589
|
+
if (separator.overlaps(B)) {
|
|
590
|
+
for (let guard = 0; guard < 20 && separator.overlaps(B); guard++) separator.separate(B, 50, null);
|
|
591
|
+
items.forEach((it, k) => {
|
|
592
|
+
it.x = B.x[k];
|
|
593
|
+
it.y = B.y[k];
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
function layoutCluster(c2, pos) {
|
|
599
|
+
for (const k of c2.kids.values()) layoutCluster(k, pos);
|
|
600
|
+
const items = [];
|
|
601
|
+
for (const k of c2.kids.values()) items.push({ key: "c:" + k.key, r: k.r, x: 0, y: 0, sub: k });
|
|
602
|
+
for (const n of c2.leaves) items.push({ key: "n:" + n, r: LEAF_R, x: 0, y: 0, leaf: n });
|
|
603
|
+
c2.count = c2.leaves.length + [...c2.kids.values()].reduce((a2, k) => a2 + k.count, 0);
|
|
604
|
+
if (items.length === 1) {
|
|
605
|
+
items[0].x = 0;
|
|
606
|
+
items[0].y = 0;
|
|
607
|
+
} else if (items.length > 1) {
|
|
608
|
+
settle(items, potentials(c2));
|
|
609
|
+
}
|
|
610
|
+
const enc = items.length ? enclose_default(items.map((i) => ({ x: i.x, y: i.y, r: i.r }))) : { x: 0, y: 0, r: 0 };
|
|
611
|
+
const pad = c2.parent ? 10 + Math.min(14, Math.sqrt(c2.count)) : 0;
|
|
612
|
+
c2.r = (enc?.r ?? 0) + pad;
|
|
613
|
+
for (const it of items) {
|
|
614
|
+
const x = it.x - (enc?.x ?? 0);
|
|
615
|
+
const y = it.y - (enc?.y ?? 0);
|
|
616
|
+
if (it.sub) {
|
|
617
|
+
it.sub.x = x;
|
|
618
|
+
it.sub.y = y;
|
|
619
|
+
} else {
|
|
620
|
+
pos[2 * it.leaf] = x;
|
|
621
|
+
pos[2 * it.leaf + 1] = y;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
function buildTree(mode, nodes, hidden) {
|
|
626
|
+
const prefixes = /* @__PURE__ */ new Set();
|
|
627
|
+
if (mode === "namespace") {
|
|
628
|
+
for (const n of nodes) {
|
|
629
|
+
if (n.ext) continue;
|
|
630
|
+
const parts = splitName(n.name);
|
|
631
|
+
for (let i = 1; i < parts.length; i++) prefixes.add(parts.slice(0, i).join("."));
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
const root = tnode("", "", null, false);
|
|
635
|
+
const home = new Array(nodes.length);
|
|
636
|
+
nodes.forEach((n, i) => {
|
|
637
|
+
let cur = root;
|
|
638
|
+
for (const part of pathOf(mode, n, prefixes)) {
|
|
639
|
+
const key = cur.key ? `${cur.key}.${part}` : part;
|
|
640
|
+
let next = cur.kids.get(part);
|
|
641
|
+
if (!next) {
|
|
642
|
+
next = tnode(key, part === EXT_KEY ? "External" : part, cur, cur.ext || part === EXT_KEY);
|
|
643
|
+
cur.kids.set(part, next);
|
|
644
|
+
}
|
|
645
|
+
cur = next;
|
|
646
|
+
}
|
|
647
|
+
cur.leaves.push(i);
|
|
648
|
+
});
|
|
649
|
+
const collapse = (c2) => {
|
|
650
|
+
for (const [part, k] of [...c2.kids]) {
|
|
651
|
+
let kid = k;
|
|
652
|
+
while (kid.leaves.length === 0 && kid.kids.size === 1 && kid.key !== EXT_KEY) {
|
|
653
|
+
const only = [...kid.kids.values()][0];
|
|
654
|
+
only.label = `${kid.label}.${only.label}`;
|
|
655
|
+
only.parent = c2;
|
|
656
|
+
kid = only;
|
|
657
|
+
}
|
|
658
|
+
c2.kids.set(part, kid);
|
|
659
|
+
collapse(kid);
|
|
660
|
+
}
|
|
661
|
+
};
|
|
662
|
+
collapse(root);
|
|
663
|
+
const via = /* @__PURE__ */ new Map();
|
|
664
|
+
const lift = (c2) => {
|
|
665
|
+
const kids = /* @__PURE__ */ new Map();
|
|
666
|
+
for (const k of c2.kids.values()) {
|
|
667
|
+
lift(k);
|
|
668
|
+
if (!hidden.has(k.key)) {
|
|
669
|
+
kids.set(k.key, k);
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
for (const kk of k.kids.values()) {
|
|
673
|
+
kk.parent = c2;
|
|
674
|
+
via.set(kk, [k.label, ...via.get(kk) ?? []]);
|
|
675
|
+
kids.set(kk.key, kk);
|
|
676
|
+
}
|
|
677
|
+
c2.leaves.push(...k.leaves);
|
|
678
|
+
}
|
|
679
|
+
c2.kids = kids;
|
|
680
|
+
if (hidden.has(c2.key)) return;
|
|
681
|
+
const seen = /* @__PURE__ */ new Map();
|
|
682
|
+
for (const k of kids.values()) seen.set(k.label, (seen.get(k.label) ?? 0) + 1);
|
|
683
|
+
for (const k of kids.values()) if (seen.get(k.label) > 1 && via.has(k)) k.label = [...via.get(k), k.label].join(".");
|
|
684
|
+
};
|
|
685
|
+
if (hidden.size) lift(root);
|
|
686
|
+
const reindex = (c2) => {
|
|
687
|
+
for (const n of c2.leaves) home[n] = c2;
|
|
688
|
+
for (const k of c2.kids.values()) reindex(k);
|
|
689
|
+
};
|
|
690
|
+
reindex(root);
|
|
691
|
+
return { root, home };
|
|
692
|
+
}
|
|
693
|
+
function flatten(root, n, rel) {
|
|
694
|
+
const clusters = [];
|
|
695
|
+
const x = new Array(n).fill(0);
|
|
696
|
+
const y = new Array(n).fill(0);
|
|
697
|
+
const cluster = new Array(n).fill(-1);
|
|
698
|
+
const place2 = (c2, ox, oy, parentId, depth) => {
|
|
699
|
+
const cx = ox + c2.x;
|
|
700
|
+
const cy = oy + c2.y;
|
|
701
|
+
let id = parentId;
|
|
702
|
+
if (c2.parent) {
|
|
703
|
+
id = clusters.length;
|
|
704
|
+
c2.id = id;
|
|
705
|
+
clusters.push({
|
|
706
|
+
key: c2.key,
|
|
707
|
+
label: c2.label,
|
|
708
|
+
parent: parentId,
|
|
709
|
+
depth,
|
|
710
|
+
x: round(cx),
|
|
711
|
+
y: round(cy),
|
|
712
|
+
lx: 0,
|
|
713
|
+
ly: 0,
|
|
714
|
+
r: round(c2.r),
|
|
715
|
+
count: c2.count,
|
|
716
|
+
ext: c2.ext
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
for (const i of c2.leaves) {
|
|
720
|
+
if (rel) {
|
|
721
|
+
x[i] = round(cx + rel[2 * i]);
|
|
722
|
+
y[i] = round(cy + rel[2 * i + 1]);
|
|
723
|
+
}
|
|
724
|
+
cluster[i] = id;
|
|
725
|
+
}
|
|
726
|
+
for (const k of c2.kids.values()) place2(k, cx, cy, id, c2.parent ? depth + 1 : 0);
|
|
727
|
+
};
|
|
728
|
+
place2(root, 0, 0, -1, 0);
|
|
729
|
+
return withLocal({ x, y, lx: [], ly: [], cluster, clusters });
|
|
730
|
+
}
|
|
731
|
+
function computeLayout(mode, nodes, edges, hidden = []) {
|
|
732
|
+
const { root, home } = buildTree(mode, nodes, new Set(hidden));
|
|
733
|
+
const leafSlot = new Int32Array(nodes.length);
|
|
734
|
+
const number = (c2) => {
|
|
735
|
+
let s = 0;
|
|
736
|
+
for (const k of c2.kids.values()) {
|
|
737
|
+
k.slot = s++;
|
|
738
|
+
number(k);
|
|
739
|
+
}
|
|
740
|
+
for (const n of c2.leaves) leafSlot[n] = s++;
|
|
741
|
+
c2.m = s;
|
|
742
|
+
c2.gOut = new Float64Array(s);
|
|
743
|
+
c2.gIn = new Float64Array(s);
|
|
744
|
+
};
|
|
745
|
+
number(root);
|
|
746
|
+
const chain = (c2) => {
|
|
747
|
+
const out = [];
|
|
748
|
+
for (let x = c2; x; x = x.parent) out.push(x);
|
|
749
|
+
return out.reverse();
|
|
750
|
+
};
|
|
751
|
+
const chains = /* @__PURE__ */ new Map();
|
|
752
|
+
const chainOf = (c2) => {
|
|
753
|
+
let ch = chains.get(c2);
|
|
754
|
+
if (!ch) chains.set(c2, ch = chain(c2));
|
|
755
|
+
return ch;
|
|
756
|
+
};
|
|
757
|
+
for (let e = 0; e < edges.length; e += 3) {
|
|
758
|
+
const u = edges[e];
|
|
759
|
+
const v = edges[e + 1];
|
|
760
|
+
if (u === v) continue;
|
|
761
|
+
const cu = chainOf(home[u]);
|
|
762
|
+
const cv = chainOf(home[v]);
|
|
763
|
+
let i = 0;
|
|
764
|
+
while (i < cu.length && i < cv.length && cu[i] === cv[i]) i++;
|
|
765
|
+
const meet = cu[i - 1];
|
|
766
|
+
const a2 = i < cu.length ? cu[i].slot : leafSlot[u];
|
|
767
|
+
const b = i < cv.length ? cv[i].slot : leafSlot[v];
|
|
768
|
+
if (a2 !== b) {
|
|
769
|
+
const key = a2 * (meet.m + 1) + b;
|
|
770
|
+
meet.flow.set(key, (meet.flow.get(key) ?? 0) + 1);
|
|
771
|
+
}
|
|
772
|
+
for (let j = i; j < cu.length; j++) cu[j].gOut[j + 1 < cu.length ? cu[j + 1].slot : leafSlot[u]]++;
|
|
773
|
+
for (let j = i; j < cv.length; j++) cv[j].gIn[j + 1 < cv.length ? cv[j + 1].slot : leafSlot[v]]++;
|
|
774
|
+
}
|
|
775
|
+
const rel = new Float64Array(nodes.length * 2);
|
|
776
|
+
layoutCluster(root, rel);
|
|
777
|
+
return flatten(root, nodes.length, rel);
|
|
778
|
+
}
|
|
779
|
+
function withLocal(L) {
|
|
780
|
+
for (const c2 of L.clusters) {
|
|
781
|
+
const p = c2.parent >= 0 ? L.clusters[c2.parent] : null;
|
|
782
|
+
c2.lx = round(c2.x - (p ? p.x : 0));
|
|
783
|
+
c2.ly = round(c2.y - (p ? p.y : 0));
|
|
784
|
+
}
|
|
785
|
+
L.lx = L.x.map((x, i) => round(x - (L.cluster[i] >= 0 ? L.clusters[L.cluster[i]].x : 0)));
|
|
786
|
+
L.ly = L.y.map((y, i) => round(y - (L.cluster[i] >= 0 ? L.clusters[L.cluster[i]].y : 0)));
|
|
787
|
+
return L;
|
|
788
|
+
}
|
|
789
|
+
function round(v) {
|
|
790
|
+
return Math.round(v * 10) / 10;
|
|
791
|
+
}
|
|
792
|
+
var SPACING = 2 * LEAF_R;
|
|
793
|
+
var Occupancy = class {
|
|
794
|
+
cells = /* @__PURE__ */ new Map();
|
|
795
|
+
key(x, y) {
|
|
796
|
+
return `${Math.floor(x / SPACING)},${Math.floor(y / SPACING)}`;
|
|
797
|
+
}
|
|
798
|
+
add(x, y) {
|
|
799
|
+
const k = this.key(x, y);
|
|
800
|
+
const c2 = this.cells.get(k);
|
|
801
|
+
if (c2) c2.push([x, y]);
|
|
802
|
+
else this.cells.set(k, [[x, y]]);
|
|
803
|
+
}
|
|
804
|
+
free(x, y) {
|
|
805
|
+
const gx = Math.floor(x / SPACING);
|
|
806
|
+
const gy = Math.floor(y / SPACING);
|
|
807
|
+
for (let i = gx - 1; i <= gx + 1; i++) {
|
|
808
|
+
for (let j = gy - 1; j <= gy + 1; j++) {
|
|
809
|
+
for (const [px, py] of this.cells.get(`${i},${j}`) ?? []) {
|
|
810
|
+
if ((px - x) ** 2 + (py - y) ** 2 < SPACING * SPACING) return false;
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
return true;
|
|
815
|
+
}
|
|
816
|
+
};
|
|
817
|
+
function nearestFree(occ, x, y, discs = []) {
|
|
818
|
+
const ok = (px, py) => occ.free(px, py) && discs.every((d) => (d.x - px) ** 2 + (d.y - py) ** 2 >= (d.r + LEAF_R) ** 2);
|
|
819
|
+
if (ok(x, y)) return [x, y];
|
|
820
|
+
for (let ring = 1; ring < 400; ring++) {
|
|
821
|
+
const n = 6 * ring;
|
|
822
|
+
for (let k = 0; k < n; k++) {
|
|
823
|
+
const a2 = 2 * Math.PI * k / n;
|
|
824
|
+
const px = x + Math.cos(a2) * ring * SPACING;
|
|
825
|
+
const py = y + Math.sin(a2) * ring * SPACING;
|
|
826
|
+
if (ok(px, py)) return [px, py];
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
return [x, y];
|
|
830
|
+
}
|
|
831
|
+
function stabilize(fresh, nodes, mem) {
|
|
832
|
+
if (!mem) return fresh;
|
|
833
|
+
const survivors = nodes.filter((n) => mem.nodes[n.name]).length;
|
|
834
|
+
if (survivors < nodes.length * 0.5) return fresh;
|
|
835
|
+
const MOVE = 0.1;
|
|
836
|
+
const extent = (xs) => Math.max(1, ...xs.map(([x2, y2, r]) => Math.hypot(x2, y2) + r));
|
|
837
|
+
const freshTop = extent(fresh.clusters.filter((c2) => c2.parent < 0).map((c2) => [c2.x, c2.y, c2.r]));
|
|
838
|
+
const oldTop = extent(Object.values(mem.clusters));
|
|
839
|
+
const keeps = (fy, fr, oy, or) => Math.abs(fy / fr - oy / or) <= MOVE;
|
|
840
|
+
const cs = fresh.clusters.map((c2) => ({ ...c2 }));
|
|
841
|
+
for (let i = 0; i < cs.length; i++) {
|
|
842
|
+
const c2 = cs[i];
|
|
843
|
+
const p = c2.parent;
|
|
844
|
+
const fp = p >= 0 ? fresh.clusters[p] : null;
|
|
845
|
+
const old = mem.clusters[c2.key];
|
|
846
|
+
const oldP = p >= 0 ? mem.clusters[cs[p].key] : null;
|
|
847
|
+
const px = p >= 0 ? cs[p].x : 0, py = p >= 0 ? cs[p].y : 0;
|
|
848
|
+
const fx = fresh.clusters[i].x - (fp ? fp.x : 0), fy = fresh.clusters[i].y - (fp ? fp.y : 0);
|
|
849
|
+
if (old && (p < 0 || oldP)) {
|
|
850
|
+
const ox = old[0] - (oldP ? oldP[0] : 0), oy = old[1] - (oldP ? oldP[1] : 0);
|
|
851
|
+
if (keeps(fy, fp ? fp.r : freshTop, oy, oldP ? oldP[2] : oldTop)) {
|
|
852
|
+
c2.x = round(px + ox);
|
|
853
|
+
c2.y = round(py + oy);
|
|
854
|
+
c2.r = old[2];
|
|
855
|
+
continue;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
c2.x = round(px + fx);
|
|
859
|
+
c2.y = round(py + fy);
|
|
860
|
+
}
|
|
861
|
+
const x = [...fresh.x];
|
|
862
|
+
const y = [...fresh.y];
|
|
863
|
+
const occ = new Occupancy();
|
|
864
|
+
const placed = new Uint8Array(nodes.length);
|
|
865
|
+
nodes.forEach((n, i) => {
|
|
866
|
+
const old = mem.nodes[n.name];
|
|
867
|
+
const c2 = fresh.cluster[i];
|
|
868
|
+
const key = c2 >= 0 ? cs[c2].key : "";
|
|
869
|
+
if (!old || old[2] !== key) return;
|
|
870
|
+
const oldC = c2 >= 0 ? mem.clusters[key] : null;
|
|
871
|
+
if (c2 >= 0 && !oldC) return;
|
|
872
|
+
const ox = old[0] - (oldC ? oldC[0] : 0), oy = old[1] - (oldC ? oldC[1] : 0);
|
|
873
|
+
const fc = c2 >= 0 ? fresh.clusters[c2] : null;
|
|
874
|
+
const fy = fresh.y[i] - (fc ? fc.y : 0);
|
|
875
|
+
if (!keeps(fy, fc ? fc.r : freshTop, oy, oldC ? oldC[2] : oldTop)) return;
|
|
876
|
+
x[i] = round((c2 >= 0 ? cs[c2].x : 0) + ox);
|
|
877
|
+
y[i] = round((c2 >= 0 ? cs[c2].y : 0) + oy);
|
|
878
|
+
occ.add(x[i], y[i]);
|
|
879
|
+
placed[i] = 1;
|
|
880
|
+
});
|
|
881
|
+
nodes.forEach((_, i) => {
|
|
882
|
+
if (placed[i]) return;
|
|
883
|
+
const c2 = fresh.cluster[i];
|
|
884
|
+
let tx = fresh.x[i];
|
|
885
|
+
let ty = fresh.y[i];
|
|
886
|
+
if (c2 >= 0) {
|
|
887
|
+
tx = cs[c2].x + (fresh.x[i] - fresh.clusters[c2].x);
|
|
888
|
+
ty = cs[c2].y + (fresh.y[i] - fresh.clusters[c2].y);
|
|
889
|
+
}
|
|
890
|
+
const discs = cs.filter((k) => k.parent === c2).map((k) => ({ x: k.x, y: k.y, r: k.r }));
|
|
891
|
+
[x[i], y[i]] = nearestFree(occ, tx, ty, discs).map(round);
|
|
892
|
+
occ.add(x[i], y[i]);
|
|
893
|
+
for (let k = c2; k >= 0; k = cs[k].parent) {
|
|
894
|
+
const d = Math.hypot(x[i] - cs[k].x, y[i] - cs[k].y) + LEAF_R + 4;
|
|
895
|
+
if (d > cs[k].r) cs[k].r = round(d);
|
|
896
|
+
}
|
|
897
|
+
});
|
|
898
|
+
return relax(withLocal({ x, y, lx: [], ly: [], cluster: fresh.cluster, clusters: cs }));
|
|
899
|
+
}
|
|
900
|
+
function relax(L, only) {
|
|
901
|
+
const cs = L.clusters;
|
|
902
|
+
const kidsC = cs.map(() => []);
|
|
903
|
+
const kidsN = cs.map(() => []);
|
|
904
|
+
const rootC = [];
|
|
905
|
+
const rootN = [];
|
|
906
|
+
cs.forEach((c2, i) => (c2.parent >= 0 ? kidsC[c2.parent] : rootC).push(i));
|
|
907
|
+
L.cluster.forEach((c2, i) => (c2 >= 0 ? kidsN[c2] : rootN).push(i));
|
|
908
|
+
const dcx = new Float64Array(cs.length), dcy = new Float64Array(cs.length);
|
|
909
|
+
const dnx = new Float64Array(L.x.length), dny = new Float64Array(L.x.length);
|
|
910
|
+
const separate = (kc, kn) => {
|
|
911
|
+
if (!kc.length) return 0;
|
|
912
|
+
const items = [...kc.map((c2) => ({ c: c2, i: -1, r: cs[c2].r })), ...kn.map((i) => ({ c: -1, i, r: LEAF_R }))];
|
|
913
|
+
const pos = (it) => it.c >= 0 ? [cs[it.c].lx, cs[it.c].ly] : [L.lx[it.i], L.ly[it.i]];
|
|
914
|
+
const shift = (it, dx, dy) => {
|
|
915
|
+
if (it.c >= 0) {
|
|
916
|
+
cs[it.c].lx += dx;
|
|
917
|
+
cs[it.c].ly += dy;
|
|
918
|
+
dcx[it.c] += dx;
|
|
919
|
+
dcy[it.c] += dy;
|
|
920
|
+
} else {
|
|
921
|
+
L.lx[it.i] += dx;
|
|
922
|
+
L.ly[it.i] += dy;
|
|
923
|
+
dnx[it.i] += dx;
|
|
924
|
+
dny[it.i] += dy;
|
|
925
|
+
}
|
|
926
|
+
};
|
|
927
|
+
let moved = 0;
|
|
928
|
+
for (let iter = 0; iter < 40; iter++) {
|
|
929
|
+
let any = false;
|
|
930
|
+
for (let a2 = 0; a2 < kc.length; a2++) {
|
|
931
|
+
for (let b = a2 + 1; b < items.length; b++) {
|
|
932
|
+
const A = items[a2], B = items[b];
|
|
933
|
+
const [ax, ay] = pos(A), [bx, by] = pos(B);
|
|
934
|
+
let dx = bx - ax, dy = by - ay;
|
|
935
|
+
let d = Math.hypot(dx, dy);
|
|
936
|
+
const need = A.r + B.r;
|
|
937
|
+
if (d >= need - 0.5) continue;
|
|
938
|
+
if (d < 1e-6) {
|
|
939
|
+
dx = 1;
|
|
940
|
+
dy = 0;
|
|
941
|
+
d = 1;
|
|
942
|
+
}
|
|
943
|
+
const push = need - d;
|
|
944
|
+
const wa = B.r * B.r / (A.r * A.r + B.r * B.r);
|
|
945
|
+
shift(A, -dx / d * push * wa, -dy / d * push * wa);
|
|
946
|
+
shift(B, dx / d * push * (1 - wa), dy / d * push * (1 - wa));
|
|
947
|
+
any = true;
|
|
948
|
+
moved++;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
if (!any) break;
|
|
952
|
+
}
|
|
953
|
+
return moved;
|
|
954
|
+
};
|
|
955
|
+
const look = only ? new Set(only) : null;
|
|
956
|
+
for (let c2 = cs.length - 1; c2 >= 0; c2--) {
|
|
957
|
+
if (look && !look.has(c2)) continue;
|
|
958
|
+
if (separate(kidsC[c2], kidsN[c2]) === 0) continue;
|
|
959
|
+
let reach = 0;
|
|
960
|
+
for (const k of kidsC[c2]) reach = Math.max(reach, Math.hypot(cs[k].lx, cs[k].ly) + cs[k].r);
|
|
961
|
+
for (const i of kidsN[c2]) reach = Math.max(reach, Math.hypot(L.lx[i], L.ly[i]) + LEAF_R);
|
|
962
|
+
const was = cs[c2].r;
|
|
963
|
+
cs[c2].r = round(Math.max(cs[c2].r, reach + 6));
|
|
964
|
+
if (look && cs[c2].r !== was) look.add(cs[c2].parent);
|
|
965
|
+
}
|
|
966
|
+
if (!look || look.has(-1)) separate(rootC, rootN);
|
|
967
|
+
const wdx = new Float64Array(cs.length), wdy = new Float64Array(cs.length);
|
|
968
|
+
cs.forEach((c2, i) => {
|
|
969
|
+
wdx[i] = (c2.parent >= 0 ? wdx[c2.parent] : 0) + dcx[i];
|
|
970
|
+
wdy[i] = (c2.parent >= 0 ? wdy[c2.parent] : 0) + dcy[i];
|
|
971
|
+
if (wdx[i] || wdy[i]) {
|
|
972
|
+
c2.x = round(c2.x + wdx[i]);
|
|
973
|
+
c2.y = round(c2.y + wdy[i]);
|
|
974
|
+
c2.lx = round(c2.lx);
|
|
975
|
+
c2.ly = round(c2.ly);
|
|
976
|
+
}
|
|
977
|
+
});
|
|
978
|
+
for (let i = 0; i < L.x.length; i++) {
|
|
979
|
+
const c2 = L.cluster[i];
|
|
980
|
+
const dx = (c2 >= 0 ? wdx[c2] : 0) + dnx[i];
|
|
981
|
+
const dy = (c2 >= 0 ? wdy[c2] : 0) + dny[i];
|
|
982
|
+
if (dx || dy) {
|
|
983
|
+
L.x[i] = round(L.x[i] + dx);
|
|
984
|
+
L.y[i] = round(L.y[i] + dy);
|
|
985
|
+
L.lx[i] = round(L.lx[i]);
|
|
986
|
+
L.ly[i] = round(L.ly[i]);
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
return L;
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
// src/web/src/layoutworker.ts
|
|
993
|
+
function layOut(a2) {
|
|
994
|
+
const nodes = a2.nodes;
|
|
995
|
+
return stabilize(computeLayout(a2.mode, nodes, a2.edges, a2.hidden), nodes, a2.mem);
|
|
996
|
+
}
|
|
997
|
+
var scope = globalThis;
|
|
998
|
+
if (typeof scope.document === "undefined" && typeof globalThis.WorkerGlobalScope !== "undefined") {
|
|
999
|
+
scope.onmessage = (e) => {
|
|
1000
|
+
const { id, ...ask } = e.data;
|
|
1001
|
+
try {
|
|
1002
|
+
scope.postMessage({ id, layout: layOut(ask) });
|
|
1003
|
+
} catch (err) {
|
|
1004
|
+
scope.postMessage({ id, error: err instanceof Error ? err.message : String(err) });
|
|
1005
|
+
}
|
|
1006
|
+
};
|
|
1007
|
+
}
|
|
1008
|
+
export {
|
|
1009
|
+
layOut
|
|
1010
|
+
};
|