@jbrowse/bandage-core 10.0.0 → 10.0.1
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/README.md +20 -0
- package/dist/chunks/{chunk-3APK25GI.js → chunk-3XE3OUEN.js} +1 -1
- package/dist/chunks/chunk-A647OH7N.js +284 -0
- package/dist/chunks/{chunk-Q6IOQP4J.js → chunk-AZJF2PZE.js} +5 -5
- package/dist/chunks/{chunk-33T67FPZ.js → chunk-CFNFT4RA.js} +1 -1
- package/dist/chunks/{chunk-RJXPPYA7.js → chunk-FFFYXMOP.js} +7 -7
- package/dist/chunks/{chunk-VK6XMP6B.js → chunk-FLUQODT2.js} +1 -3
- package/dist/chunks/{chunk-ICXMWYOA.js → chunk-IFOZFVZK.js} +4 -4
- package/dist/chunks/{chunk-CDPYXHVR.js → chunk-KY4LV2Z6.js} +1 -1
- package/dist/chunks/{chunk-W4GZCVUK.js → chunk-MSX3BDO4.js} +5 -5
- package/dist/chunks/{chunk-OOLNLCIO.js → chunk-QORSYW7J.js} +1 -1
- package/dist/chunks/{chunk-JVLURPFW.js → chunk-VPE4AYP7.js} +1 -2
- package/dist/chunks/{chunk-E5UEYZWK.js → chunk-ZR7A7DKQ.js} +1 -1
- package/dist/cli/figure.js +12 -14
- package/dist/cli/fold.js +2 -2
- package/dist/figure.js +8 -8
- package/dist/figureData.js +10 -12
- package/dist/figureSettings.js +3 -3
- package/dist/index.js +36 -37
- package/dist/layout/deletionRoutes.js +1 -3
- package/dist/layout/forceCache.js +3 -3
- package/dist/layout/walkRowLayout.js +2 -2
- package/dist/layout/walkRows.js +1 -1
- package/dist/layoutEngines.js +1 -5
- package/dist/layoutModes.js +4 -4
- package/dist/pipeline.js +2 -2
- package/dist/tubeMap/draw.js +2 -2
- package/dist/types/index.d.ts +1 -1
- package/dist/types/layout/deletionRoutes.d.ts +0 -1
- package/dist/types/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/viewport.js +3 -3
- package/package.json +2 -1
- package/dist/chunks/chunk-KAN2WTG5.js +0 -226
- package/dist/chunks/chunk-LYJ4US66.js +0 -664
- package/dist/chunks/chunk-Q6FRNVDU.js +0 -531
- package/dist/layout/stressEngine.js +0 -11
- package/dist/layout/stressPlacement.js +0 -7
- package/dist/types/layout/stressEngine.d.ts +0 -27
- package/dist/types/layout/stressPlacement.d.ts +0 -5
- package/dist/chunks/{chunk-EU6FBTQF.js → chunk-HQ2AHRMH.js} +3 -3
|
@@ -1,531 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
stressPlacement
|
|
3
|
-
} from "./chunk-LYJ4US66.js";
|
|
4
|
-
import {
|
|
5
|
-
isBackbone
|
|
6
|
-
} from "./chunk-FYQWPEEY.js";
|
|
7
|
-
|
|
8
|
-
// src/layout/stressEngine.ts
|
|
9
|
-
var QUALITY = [
|
|
10
|
-
{ walks: 2, iterations: 15 },
|
|
11
|
-
{ walks: 4, iterations: 30 },
|
|
12
|
-
{ walks: 8, iterations: 60 },
|
|
13
|
-
{ walks: 12, iterations: 90 },
|
|
14
|
-
{ walks: 16, iterations: 120 }
|
|
15
|
-
];
|
|
16
|
-
var UNTANGLE_PASSES = 20;
|
|
17
|
-
var UNTANGLE_LINKS = 3;
|
|
18
|
-
var UNTANGLE_PUSH = 0.3;
|
|
19
|
-
var SMOOTH_PASSES = 2;
|
|
20
|
-
var MAX_HOPS = 200;
|
|
21
|
-
var REFERENCE_HOPS = 20;
|
|
22
|
-
var EPS = 0.1;
|
|
23
|
-
var WARM = 0.5;
|
|
24
|
-
function flipped(strand, name) {
|
|
25
|
-
const own = name.at(-1);
|
|
26
|
-
return (strand === "+" || strand === "-") && (own === "+" || own === "-") && strand !== own;
|
|
27
|
-
}
|
|
28
|
-
function xorshift(seed) {
|
|
29
|
-
let s = Math.imul(seed, 2654435761) >>> 0 || 1;
|
|
30
|
-
return () => {
|
|
31
|
-
s ^= s << 13;
|
|
32
|
-
s >>>= 0;
|
|
33
|
-
s ^= s >>> 17;
|
|
34
|
-
s ^= s << 5;
|
|
35
|
-
s >>>= 0;
|
|
36
|
-
return s / 4294967296;
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
function num(value, fallback) {
|
|
40
|
-
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
41
|
-
}
|
|
42
|
-
function chains(request) {
|
|
43
|
-
const { nodes, edges } = request.graph;
|
|
44
|
-
const o = request.options;
|
|
45
|
-
const perMegabase = num(o.nodeLengthPerMegabase, 1e3);
|
|
46
|
-
const minimum = num(o.minimumNodeLength, 1);
|
|
47
|
-
const segment = num(o.nodeSegmentLength, 1);
|
|
48
|
-
const link = num(o.edgeLength, 1);
|
|
49
|
-
const ids = nodes.map((n2) => n2.id);
|
|
50
|
-
const first = new Int32Array(nodes.length);
|
|
51
|
-
const count = new Int32Array(nodes.length);
|
|
52
|
-
const per = new Float64Array(nodes.length);
|
|
53
|
-
let n = 0;
|
|
54
|
-
nodes.forEach((node, k) => {
|
|
55
|
-
const drawn = Math.max(perMegabase * node.length / 1e6, minimum);
|
|
56
|
-
const steps = Math.max(1, Math.ceil(drawn / segment));
|
|
57
|
-
first[k] = n;
|
|
58
|
-
count[k] = steps + 1;
|
|
59
|
-
per[k] = drawn / steps;
|
|
60
|
-
n += steps + 1;
|
|
61
|
-
});
|
|
62
|
-
const chainOf = new Int32Array(n);
|
|
63
|
-
const indexOf = new Int32Array(n);
|
|
64
|
-
const seedX = new Float64Array(n).fill(NaN);
|
|
65
|
-
const seedY = new Float64Array(n).fill(NaN);
|
|
66
|
-
const backbone = new Uint8Array(n);
|
|
67
|
-
const adjacent = Array.from({ length: n }, () => []);
|
|
68
|
-
nodes.forEach((node, k) => {
|
|
69
|
-
const seeded = typeof node.x === "number" && typeof node.y === "number";
|
|
70
|
-
const reference = isBackbone(node) ? 1 : 0;
|
|
71
|
-
for (let i = 0; i < count[k]; i++) {
|
|
72
|
-
const v = first[k] + i;
|
|
73
|
-
chainOf[v] = k;
|
|
74
|
-
indexOf[v] = i;
|
|
75
|
-
backbone[v] = reference;
|
|
76
|
-
if (seeded) {
|
|
77
|
-
seedX[v] = node.x + i * per[k];
|
|
78
|
-
seedY[v] = node.y;
|
|
79
|
-
}
|
|
80
|
-
if (i > 0) {
|
|
81
|
-
adjacent[v - 1].push([v, per[k]]);
|
|
82
|
-
adjacent[v].push([v - 1, per[k]]);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
const index = new Map(ids.map((id, k) => [id, k]));
|
|
87
|
-
const links = nodes.map(() => [[], []]);
|
|
88
|
-
for (const edge of edges) {
|
|
89
|
-
const a = index.get(edge.from);
|
|
90
|
-
const b = index.get(edge.to);
|
|
91
|
-
if (a === void 0 || b === void 0) {
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
if (a === b && count[a] <= 2) {
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
const fromSide = flipped(edge.fromStrand, edge.from) ? 0 : 1;
|
|
98
|
-
const toSide = flipped(edge.toStrand, edge.to) ? 1 : 0;
|
|
99
|
-
const u = first[a] + (fromSide ? count[a] - 1 : 0);
|
|
100
|
-
const v = first[b] + (toSide ? count[b] - 1 : 0);
|
|
101
|
-
adjacent[u].push([v, link]);
|
|
102
|
-
adjacent[v].push([u, link]);
|
|
103
|
-
links[a][fromSide].push([b, toSide]);
|
|
104
|
-
links[b][toSide].push([a, fromSide]);
|
|
105
|
-
}
|
|
106
|
-
const off = new Int32Array(n + 1);
|
|
107
|
-
for (let i = 0; i < n; i++) {
|
|
108
|
-
off[i + 1] = off[i] + adjacent[i].length;
|
|
109
|
-
}
|
|
110
|
-
const nb = new Int32Array(off[n]);
|
|
111
|
-
const wt = new Float64Array(off[n]);
|
|
112
|
-
for (let i = 0; i < n; i++) {
|
|
113
|
-
adjacent[i].forEach(([v, w], k) => {
|
|
114
|
-
nb[off[i] + k] = v;
|
|
115
|
-
wt[off[i] + k] = w;
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
return {
|
|
119
|
-
ids,
|
|
120
|
-
first,
|
|
121
|
-
count,
|
|
122
|
-
per,
|
|
123
|
-
links,
|
|
124
|
-
chainOf,
|
|
125
|
-
indexOf,
|
|
126
|
-
seedX,
|
|
127
|
-
seedY,
|
|
128
|
-
backbone,
|
|
129
|
-
off,
|
|
130
|
-
nb,
|
|
131
|
-
wt,
|
|
132
|
-
n,
|
|
133
|
-
link
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
function components(c) {
|
|
137
|
-
const { n, off, nb } = c;
|
|
138
|
-
const comp = new Int32Array(n).fill(-1);
|
|
139
|
-
const members = [];
|
|
140
|
-
for (let s = 0; s < n; s++) {
|
|
141
|
-
if (comp[s] >= 0) {
|
|
142
|
-
continue;
|
|
143
|
-
}
|
|
144
|
-
const queue = [s];
|
|
145
|
-
comp[s] = members.length;
|
|
146
|
-
for (const u of queue) {
|
|
147
|
-
for (let e = off[u]; e < off[u + 1]; e++) {
|
|
148
|
-
const v = nb[e];
|
|
149
|
-
if (comp[v] < 0) {
|
|
150
|
-
comp[v] = members.length;
|
|
151
|
-
queue.push(v);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
members.push(queue);
|
|
156
|
-
}
|
|
157
|
-
return { comp, members };
|
|
158
|
-
}
|
|
159
|
-
function stressLayout(request, opts = {}) {
|
|
160
|
-
const c = chains(request);
|
|
161
|
-
const { n, off, nb, wt, seedX, seedY, backbone, first, count, per, link } = c;
|
|
162
|
-
const o = request.options;
|
|
163
|
-
const quality = QUALITY[Math.max(0, Math.min(4, num(opts.quality ?? o.quality, 2)))];
|
|
164
|
-
const gap = num(opts.componentSeparation ?? o.componentSeparation, 15);
|
|
165
|
-
const rand = xorshift(num(opts.seed ?? o.seed, 1));
|
|
166
|
-
const X = new Float64Array(n);
|
|
167
|
-
const Y = new Float64Array(n);
|
|
168
|
-
const nodePositions = {};
|
|
169
|
-
if (n === 0) {
|
|
170
|
-
return { nodePositions };
|
|
171
|
-
}
|
|
172
|
-
const { comp, members } = components(c);
|
|
173
|
-
let dmin = Infinity;
|
|
174
|
-
let total = 0;
|
|
175
|
-
for (let e = 0; e < nb.length; e++) {
|
|
176
|
-
dmin = Math.min(dmin, wt[e]);
|
|
177
|
-
total += wt[e];
|
|
178
|
-
}
|
|
179
|
-
total /= 2;
|
|
180
|
-
let anySeed = false;
|
|
181
|
-
for (let i = 0; i < n; i++) {
|
|
182
|
-
if (!Number.isNaN(seedX[i])) {
|
|
183
|
-
anySeed = true;
|
|
184
|
-
break;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
const placed = anySeed ? stressPlacement(c) : void 0;
|
|
188
|
-
const side = Math.sqrt(n) * 20;
|
|
189
|
-
for (let i = 0; i < n; i++) {
|
|
190
|
-
if (placed && !Number.isNaN(placed.X[i])) {
|
|
191
|
-
X[i] = placed.X[i];
|
|
192
|
-
Y[i] = placed.Y[i];
|
|
193
|
-
} else if (anySeed && !Number.isNaN(seedX[i])) {
|
|
194
|
-
X[i] = seedX[i] + rand() - 0.5;
|
|
195
|
-
Y[i] = seedY[i] + rand() - 0.5;
|
|
196
|
-
} else {
|
|
197
|
-
X[i] = rand() * side;
|
|
198
|
-
Y[i] = rand() * side;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
const refIdx = members.map(
|
|
202
|
-
(points) => Int32Array.from(
|
|
203
|
-
points.filter((i) => backbone[i] && !Number.isNaN(seedX[i])).sort((a, b) => seedX[a] - seedX[b])
|
|
204
|
-
)
|
|
205
|
-
);
|
|
206
|
-
const refX = refIdx.map((idx) => Float64Array.from(idx, (i) => seedX[i]));
|
|
207
|
-
let span = 0;
|
|
208
|
-
for (const xs of refX) {
|
|
209
|
-
if (xs.length) {
|
|
210
|
-
span = Math.max(span, xs[xs.length - 1] - xs[0]);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
const dmax = Math.max(span, total / 4, dmin * 10);
|
|
214
|
-
const etaMax = dmax * dmax;
|
|
215
|
-
const etaMin = EPS * dmin * dmin;
|
|
216
|
-
const { walks, iterations } = quality;
|
|
217
|
-
const lambda = Math.log(etaMax / etaMin) / Math.max(1, iterations - 1);
|
|
218
|
-
const logMin = Math.log(dmin);
|
|
219
|
-
const logMax = Math.log(dmax);
|
|
220
|
-
const move = (i, j, d, eta) => {
|
|
221
|
-
let mu = eta / (d * d);
|
|
222
|
-
if (mu > 1) {
|
|
223
|
-
mu = 1;
|
|
224
|
-
}
|
|
225
|
-
const dx = X[i] - X[j];
|
|
226
|
-
const dy = Y[i] - Y[j];
|
|
227
|
-
const mag = Math.sqrt(dx * dx + dy * dy) || 1e-9;
|
|
228
|
-
const r = mu * (mag - d) / (2 * mag);
|
|
229
|
-
const rx = r * dx;
|
|
230
|
-
const ry = r * dy;
|
|
231
|
-
X[i] = X[i] - rx;
|
|
232
|
-
Y[i] = Y[i] - ry;
|
|
233
|
-
X[j] = X[j] + rx;
|
|
234
|
-
Y[j] = Y[j] + ry;
|
|
235
|
-
};
|
|
236
|
-
let walked = 0;
|
|
237
|
-
const walk = (i, length) => {
|
|
238
|
-
let chain = c.chainOf[i];
|
|
239
|
-
let idx = c.indexOf[i];
|
|
240
|
-
let dir = rand() < 0.5 ? -1 : 1;
|
|
241
|
-
let remaining = length;
|
|
242
|
-
const maxHops = refIdx[comp[i]].length >= 2 ? REFERENCE_HOPS : MAX_HOPS;
|
|
243
|
-
for (let hops = 0; hops < maxHops; hops++) {
|
|
244
|
-
const points = count[chain];
|
|
245
|
-
const step = per[chain];
|
|
246
|
-
const toEnd = (dir > 0 ? points - 1 - idx : idx) * step;
|
|
247
|
-
if (remaining <= toEnd) {
|
|
248
|
-
const steps = Math.round(remaining / step);
|
|
249
|
-
walked = length - remaining + steps * step;
|
|
250
|
-
return first[chain] + idx + dir * steps;
|
|
251
|
-
}
|
|
252
|
-
remaining -= toEnd;
|
|
253
|
-
const out = c.links[chain][dir > 0 ? 1 : 0];
|
|
254
|
-
if (out.length === 0) {
|
|
255
|
-
walked = length - remaining;
|
|
256
|
-
return first[chain] + (dir > 0 ? points - 1 : 0);
|
|
257
|
-
}
|
|
258
|
-
const [next, enterSide] = out[Math.floor(rand() * out.length)];
|
|
259
|
-
remaining -= link;
|
|
260
|
-
chain = next;
|
|
261
|
-
dir = enterSide === 0 ? 1 : -1;
|
|
262
|
-
idx = enterSide === 0 ? 0 : count[next] - 1;
|
|
263
|
-
if (remaining <= 0) {
|
|
264
|
-
walked = length - remaining;
|
|
265
|
-
return first[chain] + idx;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
return -1;
|
|
269
|
-
};
|
|
270
|
-
const referenceTerm = (i, eta) => {
|
|
271
|
-
const idx = refIdx[comp[i]];
|
|
272
|
-
if (!backbone[i] || idx.length < 2 || Number.isNaN(seedX[i])) {
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
const xs = refX[comp[i]];
|
|
276
|
-
const target = seedX[i] + Math.exp(logMin + rand() * (logMax - logMin)) * (rand() < 0.5 ? -1 : 1);
|
|
277
|
-
let lo = 0;
|
|
278
|
-
let hi = xs.length;
|
|
279
|
-
while (lo < hi) {
|
|
280
|
-
const mid = lo + hi >> 1;
|
|
281
|
-
if (xs[mid] < target) {
|
|
282
|
-
lo = mid + 1;
|
|
283
|
-
} else {
|
|
284
|
-
hi = mid;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
const j = idx[Math.min(lo, idx.length - 1)];
|
|
288
|
-
const d = seedX[j] - seedX[i];
|
|
289
|
-
if (j === i || d === 0) {
|
|
290
|
-
return;
|
|
291
|
-
}
|
|
292
|
-
let mu = eta / (d * d);
|
|
293
|
-
if (mu > 1) {
|
|
294
|
-
mu = 1;
|
|
295
|
-
}
|
|
296
|
-
const r = mu * (X[j] - X[i] - d) / 2;
|
|
297
|
-
X[i] = X[i] + r;
|
|
298
|
-
X[j] = X[j] - r;
|
|
299
|
-
};
|
|
300
|
-
const adjacentTerms = (i, eta) => {
|
|
301
|
-
for (let e = off[i]; e < off[i + 1]; e++) {
|
|
302
|
-
const j = nb[e];
|
|
303
|
-
if (j > i) {
|
|
304
|
-
move(i, j, wt[e], eta);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
};
|
|
308
|
-
const order = new Int32Array(n);
|
|
309
|
-
for (let i = 0; i < n; i++) {
|
|
310
|
-
order[i] = i;
|
|
311
|
-
}
|
|
312
|
-
const warm = anySeed ? Math.floor(WARM * iterations) : 0;
|
|
313
|
-
for (let t = warm; t < iterations; t++) {
|
|
314
|
-
const eta = etaMax * Math.exp(-lambda * t);
|
|
315
|
-
for (let k = n - 1; k > 0; k--) {
|
|
316
|
-
const r = Math.floor(rand() * (k + 1));
|
|
317
|
-
const tmp = order[k];
|
|
318
|
-
order[k] = order[r];
|
|
319
|
-
order[r] = tmp;
|
|
320
|
-
}
|
|
321
|
-
for (let q = 0; q < n; q++) {
|
|
322
|
-
const i = order[q];
|
|
323
|
-
adjacentTerms(i, eta);
|
|
324
|
-
for (let w = 0; w < walks; w++) {
|
|
325
|
-
const length = Math.exp(logMin + rand() * (logMax - logMin));
|
|
326
|
-
const j = walk(i, length);
|
|
327
|
-
if (j >= 0 && j !== i && walked > 0) {
|
|
328
|
-
move(i, j, walked, eta);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
referenceTerm(i, eta);
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
const radius = UNTANGLE_LINKS * link;
|
|
335
|
-
const key = (x, y) => Math.floor(x / radius) * 73856093 ^ Math.floor(y / radius) * 19349663;
|
|
336
|
-
for (let u = 0; u < UNTANGLE_PASSES; u++) {
|
|
337
|
-
const grid = /* @__PURE__ */ new Map();
|
|
338
|
-
for (let i = 0; i < n; i++) {
|
|
339
|
-
const k = key(X[i], Y[i]);
|
|
340
|
-
const list = grid.get(k);
|
|
341
|
-
if (list) {
|
|
342
|
-
list.push(i);
|
|
343
|
-
} else {
|
|
344
|
-
grid.set(k, [i]);
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
for (let i = 0; i < n; i++) {
|
|
348
|
-
const cx = Math.floor(X[i] / radius);
|
|
349
|
-
const cy = Math.floor(Y[i] / radius);
|
|
350
|
-
for (let gx = cx - 1; gx <= cx + 1; gx++) {
|
|
351
|
-
for (let gy = cy - 1; gy <= cy + 1; gy++) {
|
|
352
|
-
const list = grid.get(gx * 73856093 ^ gy * 19349663);
|
|
353
|
-
if (!list) {
|
|
354
|
-
continue;
|
|
355
|
-
}
|
|
356
|
-
for (const j of list) {
|
|
357
|
-
if (j <= i) {
|
|
358
|
-
continue;
|
|
359
|
-
}
|
|
360
|
-
let joined = false;
|
|
361
|
-
for (let e = off[i]; e < off[i + 1]; e++) {
|
|
362
|
-
if (nb[e] === j) {
|
|
363
|
-
joined = true;
|
|
364
|
-
break;
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
if (joined) {
|
|
368
|
-
continue;
|
|
369
|
-
}
|
|
370
|
-
const dx = X[i] - X[j];
|
|
371
|
-
const dy = Y[i] - Y[j];
|
|
372
|
-
const mag = Math.sqrt(dx * dx + dy * dy);
|
|
373
|
-
if (mag >= radius) {
|
|
374
|
-
continue;
|
|
375
|
-
}
|
|
376
|
-
let rx;
|
|
377
|
-
let ry;
|
|
378
|
-
if (mag > 1e-6) {
|
|
379
|
-
const r = UNTANGLE_PUSH * (radius - mag) / (2 * mag);
|
|
380
|
-
rx = r * dx;
|
|
381
|
-
ry = r * dy;
|
|
382
|
-
} else {
|
|
383
|
-
rx = UNTANGLE_PUSH * radius * (rand() - 0.5);
|
|
384
|
-
ry = UNTANGLE_PUSH * radius * (rand() - 0.5);
|
|
385
|
-
}
|
|
386
|
-
X[i] = X[i] + rx;
|
|
387
|
-
Y[i] = Y[i] + ry;
|
|
388
|
-
X[j] = X[j] - rx;
|
|
389
|
-
Y[j] = Y[j] - ry;
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
for (let i = 0; i < n; i++) {
|
|
395
|
-
adjacentTerms(i, Infinity);
|
|
396
|
-
referenceTerm(i, etaMin * 4);
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
for (let k = 0; k < count.length; k++) {
|
|
400
|
-
const a = first[k];
|
|
401
|
-
const m = count[k];
|
|
402
|
-
if (m < 3) {
|
|
403
|
-
continue;
|
|
404
|
-
}
|
|
405
|
-
for (let s = 0; s < SMOOTH_PASSES; s++) {
|
|
406
|
-
const xs = X.slice(a, a + m);
|
|
407
|
-
const ys = Y.slice(a, a + m);
|
|
408
|
-
for (let i = 1; i + 1 < m; i++) {
|
|
409
|
-
X[a + i] = 0.5 * xs[i] + 0.25 * (xs[i - 1] + xs[i + 1]);
|
|
410
|
-
Y[a + i] = 0.5 * ys[i] + 0.25 * (ys[i - 1] + ys[i + 1]);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
respace(X, Y, a, m, per[k]);
|
|
414
|
-
}
|
|
415
|
-
packComponents(comp, members, X, Y, anySeed, gap);
|
|
416
|
-
for (let k = 0; k < c.ids.length; k++) {
|
|
417
|
-
const points = [];
|
|
418
|
-
for (let i = 0; i < count[k]; i++) {
|
|
419
|
-
points.push({ x: X[first[k] + i], y: Y[first[k] + i] });
|
|
420
|
-
}
|
|
421
|
-
nodePositions[c.ids[k]] = points;
|
|
422
|
-
}
|
|
423
|
-
return { nodePositions };
|
|
424
|
-
}
|
|
425
|
-
function respace(X, Y, a, m, per) {
|
|
426
|
-
const arc = new Float64Array(m);
|
|
427
|
-
for (let i = 1; i < m; i++) {
|
|
428
|
-
arc[i] = arc[i - 1] + Math.hypot(X[a + i] - X[a + i - 1], Y[a + i] - Y[a + i - 1]);
|
|
429
|
-
}
|
|
430
|
-
if (!arc[m - 1]) {
|
|
431
|
-
return;
|
|
432
|
-
}
|
|
433
|
-
const loss = per * (m - 1) - arc[m - 1];
|
|
434
|
-
if (loss > 0) {
|
|
435
|
-
extend(X, Y, a, a + 1, loss / 2);
|
|
436
|
-
extend(X, Y, a + m - 1, a + m - 2, loss / 2);
|
|
437
|
-
for (let i = 1; i < m; i++) {
|
|
438
|
-
arc[i] = arc[i - 1] + Math.hypot(X[a + i] - X[a + i - 1], Y[a + i] - Y[a + i - 1]);
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
const total = arc[m - 1];
|
|
442
|
-
const xs = X.slice(a, a + m);
|
|
443
|
-
const ys = Y.slice(a, a + m);
|
|
444
|
-
let seg = 1;
|
|
445
|
-
for (let i = 1; i + 1 < m; i++) {
|
|
446
|
-
const s = total * i / (m - 1);
|
|
447
|
-
while (seg < m - 1 && arc[seg] < s) {
|
|
448
|
-
seg++;
|
|
449
|
-
}
|
|
450
|
-
const span = arc[seg] - arc[seg - 1];
|
|
451
|
-
const t = span > 0 ? (s - arc[seg - 1]) / span : 0;
|
|
452
|
-
X[a + i] = xs[seg - 1] + (xs[seg] - xs[seg - 1]) * t;
|
|
453
|
-
Y[a + i] = ys[seg - 1] + (ys[seg] - ys[seg - 1]) * t;
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
function extend(X, Y, end, next, by) {
|
|
457
|
-
const dx = X[end] - X[next];
|
|
458
|
-
const dy = Y[end] - Y[next];
|
|
459
|
-
const mag = Math.hypot(dx, dy);
|
|
460
|
-
if (mag > 0) {
|
|
461
|
-
X[end] = X[end] + dx / mag * by;
|
|
462
|
-
Y[end] = Y[end] + dy / mag * by;
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
function packComponents(comp, members, X, Y, anySeed, gap) {
|
|
466
|
-
if (!anySeed) {
|
|
467
|
-
for (const points of members) {
|
|
468
|
-
rotateToPrincipalAxis(X, Y, points);
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
if (members.length < 2) {
|
|
472
|
-
return;
|
|
473
|
-
}
|
|
474
|
-
const minX = new Float64Array(members.length).fill(Infinity);
|
|
475
|
-
const minY = new Float64Array(members.length).fill(Infinity);
|
|
476
|
-
const maxY = new Float64Array(members.length).fill(-Infinity);
|
|
477
|
-
for (let i = 0; i < X.length; i++) {
|
|
478
|
-
const k = comp[i];
|
|
479
|
-
minX[k] = Math.min(minX[k], X[i]);
|
|
480
|
-
minY[k] = Math.min(minY[k], Y[i]);
|
|
481
|
-
maxY[k] = Math.max(maxY[k], Y[i]);
|
|
482
|
-
}
|
|
483
|
-
const shift = new Float64Array(members.length);
|
|
484
|
-
let y = 0;
|
|
485
|
-
for (let k = 0; k < members.length; k++) {
|
|
486
|
-
shift[k] = y - minY[k];
|
|
487
|
-
y += maxY[k] - minY[k] + gap;
|
|
488
|
-
}
|
|
489
|
-
for (let i = 0; i < X.length; i++) {
|
|
490
|
-
const k = comp[i];
|
|
491
|
-
X[i] = X[i] - minX[k];
|
|
492
|
-
Y[i] = Y[i] + shift[k];
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
function rotateToPrincipalAxis(X, Y, points) {
|
|
496
|
-
if (points.length < 3) {
|
|
497
|
-
return;
|
|
498
|
-
}
|
|
499
|
-
let cx = 0;
|
|
500
|
-
let cy = 0;
|
|
501
|
-
for (const i of points) {
|
|
502
|
-
cx += X[i];
|
|
503
|
-
cy += Y[i];
|
|
504
|
-
}
|
|
505
|
-
cx /= points.length;
|
|
506
|
-
cy /= points.length;
|
|
507
|
-
let sxx = 0;
|
|
508
|
-
let syy = 0;
|
|
509
|
-
let sxy = 0;
|
|
510
|
-
for (const i of points) {
|
|
511
|
-
const dx = X[i] - cx;
|
|
512
|
-
const dy = Y[i] - cy;
|
|
513
|
-
sxx += dx * dx;
|
|
514
|
-
syy += dy * dy;
|
|
515
|
-
sxy += dx * dy;
|
|
516
|
-
}
|
|
517
|
-
const angle = -0.5 * Math.atan2(2 * sxy, sxx - syy);
|
|
518
|
-
const cos = Math.cos(angle);
|
|
519
|
-
const sin = Math.sin(angle);
|
|
520
|
-
for (const i of points) {
|
|
521
|
-
const dx = X[i] - cx;
|
|
522
|
-
const dy = Y[i] - cy;
|
|
523
|
-
X[i] = cx + cos * dx - sin * dy;
|
|
524
|
-
Y[i] = cy + sin * dx + cos * dy;
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
export {
|
|
529
|
-
chains,
|
|
530
|
-
stressLayout
|
|
531
|
-
};
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type { EngineRequest } from '../pipeline.js';
|
|
2
|
-
import type { LayoutResult } from '../types.js';
|
|
3
|
-
export type Side = 0 | 1;
|
|
4
|
-
export interface Chains {
|
|
5
|
-
ids: string[];
|
|
6
|
-
first: Int32Array;
|
|
7
|
-
count: Int32Array;
|
|
8
|
-
per: Float64Array;
|
|
9
|
-
links: [number, Side][][][];
|
|
10
|
-
chainOf: Int32Array;
|
|
11
|
-
indexOf: Int32Array;
|
|
12
|
-
seedX: Float64Array;
|
|
13
|
-
seedY: Float64Array;
|
|
14
|
-
backbone: Uint8Array;
|
|
15
|
-
off: Int32Array;
|
|
16
|
-
nb: Int32Array;
|
|
17
|
-
wt: Float64Array;
|
|
18
|
-
n: number;
|
|
19
|
-
link: number;
|
|
20
|
-
}
|
|
21
|
-
export declare function chains(request: EngineRequest): Chains;
|
|
22
|
-
export interface StressOptions {
|
|
23
|
-
quality?: number;
|
|
24
|
-
seed?: number;
|
|
25
|
-
componentSeparation?: number;
|
|
26
|
-
}
|
|
27
|
-
export declare function stressLayout(request: EngineRequest, opts?: StressOptions): LayoutResult;
|