@knowvah/dot-engine 1.6.0 → 1.6.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/dist/api/geometry.d.ts +5 -2
- package/dist/api/geometry.d.ts.map +1 -1
- package/dist/api.js +2 -4
- package/dist/api.js.map +2 -2
- package/dist/cdt/splay.d.ts.map +1 -1
- package/dist/common/htmltable-emit-rules.d.ts.map +1 -1
- package/dist/common/shape-clip.d.ts +17 -0
- package/dist/common/shape-clip.d.ts.map +1 -0
- package/dist/index.js +599 -578
- package/dist/index.js.map +4 -4
- package/dist/layout/dot/edge-route.d.ts.map +1 -1
- package/dist/layout/dot/pack-components.d.ts.map +1 -1
- package/dist/layout/dot/sameport.d.ts +1 -13
- package/dist/layout/dot/sameport.d.ts.map +1 -1
- package/dist/layout/dot/self-loop.d.ts.map +1 -1
- package/dist/layout/dot/splines-groups.d.ts.map +1 -1
- package/dist/layout/neato/index.d.ts.map +1 -1
- package/dist/layout/neato/init.d.ts.map +1 -1
- package/dist/ortho/ortho-route.d.ts.map +1 -1
- package/dist/render/dot.d.ts.map +1 -1
- package/dist/render.js +1209 -1186
- package/dist/render.js.map +4 -4
- package/package.json +14 -5
- package/src/api/geometry.ts +8 -7
- package/src/cdt/splay.ts +0 -2
- package/src/common/arm-pow.ts +3 -3
- package/src/common/htmltable-emit-rules.ts +0 -10
- package/src/common/random.ts +2 -2
- package/src/common/shape-clip.ts +48 -0
- package/src/common/spline-midpoint.ts +1 -1
- package/src/layout/circo/circular.ts +1 -1
- package/src/layout/dot/edge-route.ts +18 -6
- package/src/layout/dot/ns.ts +1 -1
- package/src/layout/dot/pack-components.ts +0 -1
- package/src/layout/dot/sameport.ts +1 -25
- package/src/layout/dot/self-loop.ts +4 -2
- package/src/layout/dot/splines-flat-labeled.ts +1 -1
- package/src/layout/dot/splines-groups.ts +8 -1
- package/src/layout/neato/cdt-surface.ts +1 -1
- package/src/layout/neato/index.ts +0 -3
- package/src/layout/neato/init.ts +0 -1
- package/src/ortho/ortho-route.ts +1 -3
- package/src/ortho/trap-query.ts +1 -1
- package/src/render/dot.ts +3 -10
- package/src/vpsc/Solver.ts +1 -1
package/dist/render.js
CHANGED
|
@@ -21470,7 +21470,7 @@ function leaveEdge(ctx) {
|
|
|
21470
21470
|
}
|
|
21471
21471
|
if (j > 0) {
|
|
21472
21472
|
ctx.sI = 0;
|
|
21473
|
-
[rv
|
|
21473
|
+
[rv] = leaveEdgeScan(ctx, j, cnt, rv);
|
|
21474
21474
|
}
|
|
21475
21475
|
return rv;
|
|
21476
21476
|
}
|
|
@@ -24494,204 +24494,591 @@ function dotPosition(g) {
|
|
|
24494
24494
|
return 0;
|
|
24495
24495
|
}
|
|
24496
24496
|
|
|
24497
|
-
// src/
|
|
24498
|
-
|
|
24499
|
-
|
|
24500
|
-
|
|
24501
|
-
|
|
24497
|
+
// src/common/shape-clip.ts
|
|
24498
|
+
function shapeClip0(ctx, insidefn, n, curve, leftInside) {
|
|
24499
|
+
const saveRealSize = n.info.rw;
|
|
24500
|
+
const c = curve.map((p) => ({ x: p.x - n.info.coord.x, y: p.y - n.info.coord.y }));
|
|
24501
|
+
bezierClip(ctx, insidefn, c, leftInside);
|
|
24502
|
+
for (let i = 0; i < 4; i++) {
|
|
24503
|
+
curve[i] = { x: c[i].x + n.info.coord.x, y: c[i].y + n.info.coord.y };
|
|
24502
24504
|
}
|
|
24503
|
-
|
|
24504
|
-
|
|
24505
|
-
|
|
24506
|
-
|
|
24505
|
+
n.info.rw = saveRealSize;
|
|
24506
|
+
}
|
|
24507
|
+
function shapeClip(n, curve) {
|
|
24508
|
+
const insidefn = n.info.shape?.fns?.insidefn ?? null;
|
|
24509
|
+
if (insidefn === null) return;
|
|
24510
|
+
const ctx = { nodeCoord: n.info.coord, rw: n.info.rw, bp: null, node: n };
|
|
24511
|
+
const saveRealSize = n.info.rw;
|
|
24512
|
+
const leftInside = insidefn(ctx, { x: curve[0].x - n.info.coord.x, y: curve[0].y - n.info.coord.y });
|
|
24513
|
+
n.info.rw = saveRealSize;
|
|
24514
|
+
shapeClip0(ctx, insidefn, n, curve, leftInside);
|
|
24515
|
+
}
|
|
24516
|
+
|
|
24517
|
+
// src/layout/dot/sameport.ts
|
|
24518
|
+
function sameedge(same, e, id) {
|
|
24519
|
+
for (const grp of same) {
|
|
24520
|
+
if (grp.id === id) {
|
|
24521
|
+
grp.edges.push(e);
|
|
24522
|
+
return;
|
|
24523
|
+
}
|
|
24507
24524
|
}
|
|
24508
|
-
|
|
24509
|
-
|
|
24510
|
-
|
|
24511
|
-
|
|
24512
|
-
|
|
24513
|
-
|
|
24514
|
-
|
|
24515
|
-
|
|
24516
|
-
|
|
24525
|
+
same.push({ id, edges: [e] });
|
|
24526
|
+
}
|
|
24527
|
+
function computeBoundaryOffset(u, x, y, ranksep) {
|
|
24528
|
+
const r = Math.max(
|
|
24529
|
+
(u.info.lw ?? 0) + (u.info.rw ?? 0),
|
|
24530
|
+
(u.info.ht ?? 0) + ranksep
|
|
24531
|
+
);
|
|
24532
|
+
const x2 = x * r + u.info.coord.x;
|
|
24533
|
+
const y2 = y * r + u.info.coord.y;
|
|
24534
|
+
const curve = [
|
|
24535
|
+
{ x: u.info.coord.x, y: u.info.coord.y },
|
|
24536
|
+
{ x: (2 * u.info.coord.x + x2) / 3, y: (2 * u.info.coord.y + y2) / 3 },
|
|
24537
|
+
{ x: (2 * x2 + u.info.coord.x) / 3, y: (2 * y2 + u.info.coord.y) / 3 },
|
|
24538
|
+
{ x: x2, y: y2 }
|
|
24539
|
+
];
|
|
24540
|
+
shapeClip(u, curve);
|
|
24541
|
+
return {
|
|
24542
|
+
x1: curve[0].x - u.info.coord.x,
|
|
24543
|
+
y1: curve[0].y - u.info.coord.y
|
|
24544
|
+
};
|
|
24545
|
+
}
|
|
24546
|
+
function averageDirection(u, edges) {
|
|
24547
|
+
let sx = 0, sy = 0;
|
|
24548
|
+
for (const e of edges) {
|
|
24549
|
+
const v = e.head === u ? e.tail : e.head;
|
|
24550
|
+
const dx = v.info.coord.x - u.info.coord.x;
|
|
24551
|
+
const dy = v.info.coord.y - u.info.coord.y;
|
|
24552
|
+
const r2 = Math.hypot(dx, dy);
|
|
24553
|
+
if (r2 !== 0) {
|
|
24554
|
+
sx += dx / r2;
|
|
24555
|
+
sy += dy / r2;
|
|
24517
24556
|
}
|
|
24518
|
-
r[0] = -b2a;
|
|
24519
|
-
return 1;
|
|
24520
24557
|
}
|
|
24521
|
-
|
|
24522
|
-
|
|
24523
|
-
|
|
24524
|
-
|
|
24525
|
-
|
|
24526
|
-
|
|
24527
|
-
|
|
24528
|
-
|
|
24558
|
+
const r = Math.hypot(sx, sy);
|
|
24559
|
+
return r !== 0 ? { x: sx / r, y: sy / r } : { x: 0, y: 0 };
|
|
24560
|
+
}
|
|
24561
|
+
function buildSharedPort(u, edges, ranksep) {
|
|
24562
|
+
const dir = averageDirection(u, edges);
|
|
24563
|
+
const { x1, y1 } = computeBoundaryOffset(u, dir.x, dir.y, ranksep);
|
|
24564
|
+
const px = cround(x1);
|
|
24565
|
+
const py = cround(y1);
|
|
24566
|
+
const lw = u.info.lw ?? 0;
|
|
24567
|
+
const rw = u.info.rw ?? 0;
|
|
24568
|
+
const order = lw + rw !== 0 ? MC_SCALE * (lw + px) / (lw + rw) : 0;
|
|
24569
|
+
return {
|
|
24570
|
+
p: { x: px, y: py },
|
|
24571
|
+
theta: 0,
|
|
24572
|
+
bp: null,
|
|
24573
|
+
defined: true,
|
|
24574
|
+
constrained: false,
|
|
24575
|
+
clip: false,
|
|
24576
|
+
dyna: false,
|
|
24577
|
+
order,
|
|
24578
|
+
side: 0,
|
|
24579
|
+
name: null
|
|
24580
|
+
};
|
|
24581
|
+
}
|
|
24582
|
+
function assignHeadIfMatch(f, u, prt) {
|
|
24583
|
+
if (f.head === u) f.info.head_port = prt;
|
|
24584
|
+
if (f.tail === u) f.info.tail_port = prt;
|
|
24585
|
+
}
|
|
24586
|
+
function assignPortForwardChain(e, u, prt) {
|
|
24587
|
+
for (let f = e; f !== void 0; f = (f.info.edge_type ?? 0) === VIRTUAL && (f.head.info.node_type ?? 0) === VIRTUAL && (f.head.info.out?.size ?? 0) === 1 ? f.head.info.out.list[0] : void 0) {
|
|
24588
|
+
assignHeadIfMatch(f, u, prt);
|
|
24529
24589
|
}
|
|
24530
|
-
|
|
24531
|
-
|
|
24532
|
-
|
|
24533
|
-
|
|
24534
|
-
r[1] = r[2] = -0.5 * (r[0] + b3a) - b3a;
|
|
24535
|
-
return 3;
|
|
24590
|
+
}
|
|
24591
|
+
function assignPortBackwardChain(e, u, prt) {
|
|
24592
|
+
for (let f = e; f !== void 0; f = (f.info.edge_type ?? 0) === VIRTUAL && (f.tail.info.node_type ?? 0) === VIRTUAL && (f.tail.info.in?.size ?? 0) === 1 ? f.tail.info.in.list[0] : void 0) {
|
|
24593
|
+
assignHeadIfMatch(f, u, prt);
|
|
24536
24594
|
}
|
|
24537
|
-
|
|
24538
|
-
|
|
24539
|
-
|
|
24540
|
-
|
|
24541
|
-
|
|
24542
|
-
const p = cv / (3 * a) - p0;
|
|
24543
|
-
const disc = q * q + 4 * p * p * p;
|
|
24544
|
-
return disc < 0 ? _Solver.solve3neg(disc, q, b3a, r) : _Solver.solve3pos(disc, q, b3a, r);
|
|
24595
|
+
}
|
|
24596
|
+
function assignPortToAllVirts(e, u, prt) {
|
|
24597
|
+
for (let virt = e; virt !== void 0; virt = virt.info.to_virt) {
|
|
24598
|
+
assignPortForwardChain(virt, u, prt);
|
|
24599
|
+
assignPortBackwardChain(virt, u, prt);
|
|
24545
24600
|
}
|
|
24546
|
-
};
|
|
24547
|
-
function solve3(coeff, roots) {
|
|
24548
|
-
return Solver.solve3(coeff, roots);
|
|
24549
24601
|
}
|
|
24550
|
-
|
|
24551
|
-
|
|
24552
|
-
|
|
24553
|
-
|
|
24554
|
-
|
|
24555
|
-
|
|
24556
|
-
|
|
24557
|
-
|
|
24602
|
+
function sameport(u, edges, ranksep) {
|
|
24603
|
+
if (edges.length < 2) return;
|
|
24604
|
+
const prt = buildSharedPort(u, edges, ranksep);
|
|
24605
|
+
for (const e of edges) assignPortToAllVirts(e, u, prt);
|
|
24606
|
+
u.info.has_port = true;
|
|
24607
|
+
}
|
|
24608
|
+
function graphHasSamehead(g) {
|
|
24609
|
+
for (const e of g.edges) {
|
|
24610
|
+
if (e.info.samehead !== void 0) return true;
|
|
24558
24611
|
}
|
|
24559
|
-
|
|
24560
|
-
|
|
24561
|
-
|
|
24612
|
+
return false;
|
|
24613
|
+
}
|
|
24614
|
+
function graphHasSametail(g) {
|
|
24615
|
+
for (const e of g.edges) {
|
|
24616
|
+
if (e.info.sametail !== void 0) return true;
|
|
24562
24617
|
}
|
|
24563
|
-
|
|
24564
|
-
|
|
24565
|
-
|
|
24618
|
+
return false;
|
|
24619
|
+
}
|
|
24620
|
+
function collectSamehead(n) {
|
|
24621
|
+
const same = [];
|
|
24622
|
+
for (const e of n.root.edges) {
|
|
24623
|
+
if (e.head === n && e.tail === n) continue;
|
|
24624
|
+
const id = e.head === n ? e.info.samehead : void 0;
|
|
24625
|
+
if (id && id !== "") sameedge(same, e, id);
|
|
24566
24626
|
}
|
|
24567
|
-
|
|
24568
|
-
|
|
24627
|
+
return same;
|
|
24628
|
+
}
|
|
24629
|
+
function collectSametail(n) {
|
|
24630
|
+
const same = [];
|
|
24631
|
+
for (const e of n.root.edges) {
|
|
24632
|
+
if (e.head === n && e.tail === n) continue;
|
|
24633
|
+
const id = e.tail === n ? e.info.sametail : void 0;
|
|
24634
|
+
if (id && id !== "") sameedge(same, e, id);
|
|
24569
24635
|
}
|
|
24570
|
-
|
|
24571
|
-
|
|
24572
|
-
|
|
24636
|
+
return same;
|
|
24637
|
+
}
|
|
24638
|
+
function applyGroupsToNode(n, groups, ranksep) {
|
|
24639
|
+
for (const grp of groups) {
|
|
24640
|
+
if (grp.edges.length > 1) sameport(n, grp.edges, ranksep);
|
|
24573
24641
|
}
|
|
24574
|
-
|
|
24575
|
-
|
|
24576
|
-
|
|
24642
|
+
}
|
|
24643
|
+
function dotSameports(g) {
|
|
24644
|
+
const hasSH = graphHasSamehead(g);
|
|
24645
|
+
const hasST = graphHasSametail(g);
|
|
24646
|
+
if (!hasSH && !hasST) return;
|
|
24647
|
+
const ranksep = g.info.ranksep ?? 0;
|
|
24648
|
+
for (const n of nodesInSeq(g)) {
|
|
24649
|
+
if (hasSH) applyGroupsToNode(n, collectSamehead(n), ranksep);
|
|
24650
|
+
if (hasST) applyGroupsToNode(n, collectSametail(n), ranksep);
|
|
24577
24651
|
}
|
|
24578
|
-
|
|
24579
|
-
|
|
24580
|
-
|
|
24581
|
-
|
|
24582
|
-
|
|
24652
|
+
}
|
|
24653
|
+
|
|
24654
|
+
// src/common/spline-midpoint.ts
|
|
24655
|
+
function dist2(p, q) {
|
|
24656
|
+
const dx = p.x - q.x;
|
|
24657
|
+
const dy = p.y - q.y;
|
|
24658
|
+
return dx * dx + dy * dy;
|
|
24659
|
+
}
|
|
24660
|
+
function distPt(p, q) {
|
|
24661
|
+
return Math.sqrt(dist2(p, q));
|
|
24662
|
+
}
|
|
24663
|
+
function evalBez4(pts, t) {
|
|
24664
|
+
const u = 1 - t;
|
|
24665
|
+
const [p0, p1, p2, p3] = pts;
|
|
24666
|
+
return {
|
|
24667
|
+
x: u * u * u * p0.x + 3 * u * u * t * p1.x + 3 * u * t * t * p2.x + t * t * t * p3.x,
|
|
24668
|
+
y: u * u * u * p0.y + 3 * u * u * t * p1.y + 3 * u * t * t * p2.y + t * t * t * p3.y
|
|
24669
|
+
};
|
|
24670
|
+
}
|
|
24671
|
+
function dotneatoClosest(spl, pt) {
|
|
24672
|
+
let besti = 0;
|
|
24673
|
+
let bestj = -1;
|
|
24674
|
+
let bestd2 = Number.MAX_VALUE;
|
|
24675
|
+
for (let i = 0; i < spl.list.length; i++) {
|
|
24676
|
+
const bz2 = spl.list[i];
|
|
24677
|
+
const n = bz2.size ?? bz2.list.length;
|
|
24678
|
+
for (let j2 = 0; j2 < n; j2++) {
|
|
24679
|
+
const d2 = dist2(bz2.list[j2], pt);
|
|
24680
|
+
if (bestj === -1 || d2 < bestd2) {
|
|
24681
|
+
besti = i;
|
|
24682
|
+
bestj = j2;
|
|
24683
|
+
bestd2 = d2;
|
|
24684
|
+
}
|
|
24583
24685
|
}
|
|
24584
|
-
return v;
|
|
24585
24686
|
}
|
|
24586
|
-
|
|
24587
|
-
|
|
24687
|
+
const bz = spl.list[besti];
|
|
24688
|
+
const bzn = bz.size ?? bz.list.length;
|
|
24689
|
+
let j = bestj === bzn - 1 ? bestj - 1 : bestj;
|
|
24690
|
+
j = 3 * Math.floor(j / 3);
|
|
24691
|
+
const c = [bz.list[j], bz.list[j + 1], bz.list[j + 2], bz.list[j + 3]];
|
|
24692
|
+
let lo = 0;
|
|
24693
|
+
let hi = 1;
|
|
24694
|
+
let dlo2 = dist2(c[0], pt);
|
|
24695
|
+
let dhi2 = dist2(c[3], pt);
|
|
24696
|
+
let pt2;
|
|
24697
|
+
for (; ; ) {
|
|
24698
|
+
const t = (lo + hi) / 2;
|
|
24699
|
+
pt2 = evalBez4(c, t);
|
|
24700
|
+
if (Math.abs(dlo2 - dhi2) < 1 || Math.abs(hi - lo) < 1e-5) break;
|
|
24701
|
+
if (dlo2 < dhi2) {
|
|
24702
|
+
hi = t;
|
|
24703
|
+
dhi2 = dist2(pt2, pt);
|
|
24704
|
+
} else {
|
|
24705
|
+
lo = t;
|
|
24706
|
+
dlo2 = dist2(pt2, pt);
|
|
24707
|
+
}
|
|
24588
24708
|
}
|
|
24589
|
-
|
|
24590
|
-
|
|
24709
|
+
return pt2;
|
|
24710
|
+
}
|
|
24711
|
+
function polylineMidpoint(spl) {
|
|
24712
|
+
let total = 0;
|
|
24713
|
+
for (const bz of spl.list) {
|
|
24714
|
+
for (let j = 0, k = 3; k < bz.list.length; j += 3, k += 3)
|
|
24715
|
+
total += distPt(bz.list[j], bz.list[k]);
|
|
24591
24716
|
}
|
|
24592
|
-
|
|
24593
|
-
|
|
24717
|
+
total /= 2;
|
|
24718
|
+
for (const bz of spl.list) {
|
|
24719
|
+
for (let j = 0, k = 3; k < bz.list.length; j += 3, k += 3) {
|
|
24720
|
+
const pf = bz.list[j];
|
|
24721
|
+
const qf = bz.list[k];
|
|
24722
|
+
const d = distPt(pf, qf);
|
|
24723
|
+
if (d >= total) {
|
|
24724
|
+
return {
|
|
24725
|
+
x: fma(qf.x, total, pf.x * (d - total)) / d,
|
|
24726
|
+
y: fma(qf.y, total, pf.y * (d - total)) / d
|
|
24727
|
+
};
|
|
24728
|
+
}
|
|
24729
|
+
total -= d;
|
|
24730
|
+
}
|
|
24594
24731
|
}
|
|
24595
|
-
|
|
24596
|
-
|
|
24732
|
+
const first = spl.list[0];
|
|
24733
|
+
return first.sflag ? first.sp : first.list[0];
|
|
24734
|
+
}
|
|
24735
|
+
function splEndPoints(spl) {
|
|
24736
|
+
const first = spl.list[0];
|
|
24737
|
+
const p = first.sflag ? first.sp : first.list[0];
|
|
24738
|
+
const last = spl.list[spl.list.length - 1];
|
|
24739
|
+
const q = last.eflag ? last.ep : last.list[last.list.length - 1];
|
|
24740
|
+
return { p, q };
|
|
24741
|
+
}
|
|
24742
|
+
|
|
24743
|
+
// src/common/splines-path-shared.ts
|
|
24744
|
+
function addBox(P, b) {
|
|
24745
|
+
if (b.ll.x < b.ur.x && b.ll.y < b.ur.y) {
|
|
24746
|
+
P.boxes[P.nbox++] = b;
|
|
24597
24747
|
}
|
|
24598
|
-
|
|
24599
|
-
|
|
24748
|
+
}
|
|
24749
|
+
function concSlope(n) {
|
|
24750
|
+
const inE = n.info.in;
|
|
24751
|
+
const outE = n.info.out;
|
|
24752
|
+
const cntIn = inE?.size ?? 0;
|
|
24753
|
+
const cntOut = outE?.size ?? 0;
|
|
24754
|
+
let sIn = 0;
|
|
24755
|
+
let sOut = 0;
|
|
24756
|
+
for (let i = 0; i < cntIn; i++) sIn += inE.list[i].tail.info.coord.x;
|
|
24757
|
+
for (let i = 0; i < cntOut; i++) sOut += outE.list[i].head.info.coord.x;
|
|
24758
|
+
const x1 = n.info.coord.x - sIn / cntIn;
|
|
24759
|
+
const y1 = n.info.coord.y - inE.list[0].tail.info.coord.y;
|
|
24760
|
+
const x2 = sOut / cntOut - n.info.coord.x;
|
|
24761
|
+
const y2 = outE.list[0].head.info.coord.y - n.info.coord.y;
|
|
24762
|
+
return (Math.atan2(y1, x1) + Math.atan2(y2, x2)) / 2;
|
|
24763
|
+
}
|
|
24764
|
+
var SIDE_PORT = ["s", "e", "n", "w"];
|
|
24765
|
+
var ALL_SIDES2 = TOP | BOTTOM | LEFT | RIGHT;
|
|
24766
|
+
function cvtPt(p, rankdir) {
|
|
24767
|
+
switch (rankdir) {
|
|
24768
|
+
case RANKDIR_BT:
|
|
24769
|
+
return { x: p.x, y: -p.y };
|
|
24770
|
+
case RANKDIR_LR:
|
|
24771
|
+
return { x: -p.y, y: p.x };
|
|
24772
|
+
case RANKDIR_RL:
|
|
24773
|
+
return { x: p.y, y: p.x };
|
|
24774
|
+
default:
|
|
24775
|
+
return { x: p.x, y: p.y };
|
|
24600
24776
|
}
|
|
24601
|
-
|
|
24602
|
-
|
|
24603
|
-
|
|
24604
|
-
|
|
24777
|
+
}
|
|
24778
|
+
function nodeBoxLocal(n, flip) {
|
|
24779
|
+
const lw = n.info.lw, ht22 = n.info.ht / 2;
|
|
24780
|
+
return flip ? { ll: { x: -ht22, y: -lw }, ur: { x: ht22, y: lw } } : { ll: { x: -lw, y: -ht22 }, ur: { x: lw, y: ht22 } };
|
|
24781
|
+
}
|
|
24782
|
+
function faceMidpoint(b, ix) {
|
|
24783
|
+
const cx = (b.ll.x + b.ur.x) / 2, cy = (b.ll.y + b.ur.y) / 2;
|
|
24784
|
+
if (ix === BOTTOM_IX) return { x: cx, y: b.ll.y };
|
|
24785
|
+
if (ix === RIGHT_IX) return { x: b.ur.x, y: cy };
|
|
24786
|
+
if (ix === TOP_IX) return { x: cx, y: b.ur.y };
|
|
24787
|
+
return { x: b.ll.x, y: cy };
|
|
24788
|
+
}
|
|
24789
|
+
function closestSide(n, other, port) {
|
|
24790
|
+
const sides = port.side;
|
|
24791
|
+
if (sides === 0 || sides === ALL_SIDES2) return null;
|
|
24792
|
+
const rkd = (n.root.info.rankdir ?? 0) & 3;
|
|
24793
|
+
const pt = cvtPt(n.info.coord, rkd);
|
|
24794
|
+
const opt = cvtPt(other.info.coord, rkd);
|
|
24795
|
+
const b = port.bp ?? nodeBoxLocal(n, rkd === RANKDIR_LR || rkd === RANKDIR_RL);
|
|
24796
|
+
let rv = null;
|
|
24797
|
+
let mind = 0;
|
|
24798
|
+
for (let i = 0; i < 4; i++) {
|
|
24799
|
+
if ((sides & 1 << i) === 0) continue;
|
|
24800
|
+
const m = faceMidpoint(b, i);
|
|
24801
|
+
const d = dist2({ x: m.x + pt.x, y: m.y + pt.y }, opt);
|
|
24802
|
+
if (rv === null || d < mind) {
|
|
24803
|
+
mind = d;
|
|
24804
|
+
rv = SIDE_PORT[i];
|
|
24805
|
+
}
|
|
24605
24806
|
}
|
|
24606
|
-
|
|
24607
|
-
|
|
24608
|
-
|
|
24609
|
-
|
|
24610
|
-
|
|
24807
|
+
return rv;
|
|
24808
|
+
}
|
|
24809
|
+
function resolvePort(n, other, port) {
|
|
24810
|
+
if (!port.dyna) return port;
|
|
24811
|
+
const compass = closestSide(n, other, port);
|
|
24812
|
+
const rv = makePort();
|
|
24813
|
+
rv.name = port.name;
|
|
24814
|
+
compassPort(n, { bp: port.bp, compass: compass ?? "", sides: port.side }, rv);
|
|
24815
|
+
return rv;
|
|
24816
|
+
}
|
|
24817
|
+
function walkToOrig(e) {
|
|
24818
|
+
let cur = e;
|
|
24819
|
+
while (cur.info.to_orig != null && cur.info.edge_type !== 0) {
|
|
24820
|
+
cur = cur.info.to_orig;
|
|
24611
24821
|
}
|
|
24612
|
-
|
|
24613
|
-
|
|
24614
|
-
|
|
24615
|
-
|
|
24616
|
-
|
|
24822
|
+
return cur;
|
|
24823
|
+
}
|
|
24824
|
+
function clearClipForOrig(e, n, isTail) {
|
|
24825
|
+
const orig = walkToOrig(e);
|
|
24826
|
+
if (isTail) {
|
|
24827
|
+
if (n === orig.tail) orig.info.tail_port.clip = false;
|
|
24828
|
+
else orig.info.head_port.clip = false;
|
|
24829
|
+
} else {
|
|
24830
|
+
if (n === orig.head) orig.info.head_port.clip = false;
|
|
24831
|
+
else orig.info.tail_port.clip = false;
|
|
24617
24832
|
}
|
|
24618
|
-
|
|
24619
|
-
|
|
24620
|
-
|
|
24621
|
-
|
|
24622
|
-
|
|
24623
|
-
|
|
24624
|
-
|
|
24625
|
-
|
|
24626
|
-
|
|
24627
|
-
if (yn === 4) return 4;
|
|
24628
|
-
for (let j = 0; j < yn; j++) _RouteHelper.addRoot(yr[j], acc);
|
|
24629
|
-
} else if (yn === 4) {
|
|
24630
|
-
for (let i = 0; i < xn; i++) _RouteHelper.addRoot(xr[i], acc);
|
|
24631
|
-
} else {
|
|
24632
|
-
for (let i = 0; i < xn; i++)
|
|
24633
|
-
for (let j = 0; j < yn; j++)
|
|
24634
|
-
if (xr[i] === yr[j]) _RouteHelper.addRoot(xr[i], acc);
|
|
24635
|
-
}
|
|
24636
|
-
return acc.n;
|
|
24833
|
+
}
|
|
24834
|
+
function applyDefaultBoxes(P, et, endp) {
|
|
24835
|
+
if (et === FLATEDGE) {
|
|
24836
|
+
if (endp.sidemask === TOP) endp.boxes[0].ll.y = P.start.p.y;
|
|
24837
|
+
else endp.boxes[0].ur.y = P.start.p.y;
|
|
24838
|
+
} else {
|
|
24839
|
+
endp.boxes[0].ur.y = P.start.p.y;
|
|
24840
|
+
endp.sidemask = BOTTOM;
|
|
24841
|
+
P.start.p.y -= 1;
|
|
24637
24842
|
}
|
|
24638
|
-
|
|
24639
|
-
|
|
24640
|
-
|
|
24641
|
-
|
|
24642
|
-
|
|
24643
|
-
|
|
24644
|
-
|
|
24645
|
-
|
|
24646
|
-
|
|
24647
|
-
_RouteHelper.points2coeff(sps[0].y, sps[1].y, sps[2].y, sps[3].y, sc);
|
|
24648
|
-
const sv = (sc[0] + tv * (sc[1] + tv * (sc[2] + tv * sc[3])) - lc.yc0) / lc.yc1;
|
|
24649
|
-
if (sv >= 0 && sv <= 1) _RouteHelper.addRoot(tv, acc);
|
|
24650
|
-
}
|
|
24651
|
-
}
|
|
24652
|
-
return acc.n;
|
|
24843
|
+
}
|
|
24844
|
+
function applyEndDefaultBoxes(P, et, endp) {
|
|
24845
|
+
if (et === FLATEDGE) {
|
|
24846
|
+
if (endp.sidemask === TOP) endp.boxes[0].ll.y = P.end.p.y;
|
|
24847
|
+
else endp.boxes[0].ur.y = P.end.p.y;
|
|
24848
|
+
} else {
|
|
24849
|
+
endp.boxes[0].ll.y = P.end.p.y;
|
|
24850
|
+
endp.sidemask = TOP;
|
|
24851
|
+
P.end.p.y += 1;
|
|
24653
24852
|
}
|
|
24654
|
-
|
|
24655
|
-
|
|
24656
|
-
|
|
24657
|
-
|
|
24658
|
-
|
|
24659
|
-
|
|
24660
|
-
|
|
24661
|
-
|
|
24662
|
-
|
|
24663
|
-
|
|
24664
|
-
|
|
24665
|
-
|
|
24666
|
-
|
|
24667
|
-
|
|
24668
|
-
|
|
24669
|
-
|
|
24670
|
-
|
|
24671
|
-
const sv = (sc[0] + tv * (sc[1] + tv * (sc[2] + tv * sc[3])) - lc.xc0) / lc.xc1;
|
|
24672
|
-
if (sv >= 0 && sv <= 1) _RouteHelper.addRoot(tv, acc);
|
|
24673
|
-
}
|
|
24674
|
-
}
|
|
24675
|
-
return acc.n;
|
|
24853
|
+
}
|
|
24854
|
+
function invokePboxfn(fns, n, port, side, endp) {
|
|
24855
|
+
if (!fns?.pboxfn) return 0;
|
|
24856
|
+
const kptr = [endp.boxn];
|
|
24857
|
+
const mask = fns.pboxfn(n, port, side, endp.boxes, kptr);
|
|
24858
|
+
endp.boxn = kptr[0];
|
|
24859
|
+
return mask;
|
|
24860
|
+
}
|
|
24861
|
+
function setStartTheta(P, e, merge) {
|
|
24862
|
+
if (merge) {
|
|
24863
|
+
P.start.theta = concSlope(e.tail);
|
|
24864
|
+
P.start.constrained = true;
|
|
24865
|
+
} else if (e.info.tail_port.constrained) {
|
|
24866
|
+
P.start.theta = e.info.tail_port.theta;
|
|
24867
|
+
P.start.constrained = true;
|
|
24868
|
+
} else {
|
|
24869
|
+
P.start.constrained = false;
|
|
24676
24870
|
}
|
|
24677
|
-
|
|
24678
|
-
|
|
24679
|
-
|
|
24680
|
-
|
|
24681
|
-
|
|
24682
|
-
|
|
24683
|
-
|
|
24684
|
-
|
|
24685
|
-
|
|
24686
|
-
|
|
24687
|
-
return _RouteHelper.silXzeroYnonzero(sps, lc, acc);
|
|
24688
|
-
}
|
|
24689
|
-
return _RouteHelper.silGeneral(sps, lc, acc);
|
|
24871
|
+
}
|
|
24872
|
+
function setEndTheta(P, e, merge) {
|
|
24873
|
+
if (merge) {
|
|
24874
|
+
P.end.theta = concSlope(e.head) + Math.PI;
|
|
24875
|
+
P.end.constrained = true;
|
|
24876
|
+
} else if (e.info.head_port.constrained) {
|
|
24877
|
+
P.end.theta = e.info.head_port.theta;
|
|
24878
|
+
P.end.constrained = true;
|
|
24879
|
+
} else {
|
|
24880
|
+
P.end.constrained = false;
|
|
24690
24881
|
}
|
|
24691
|
-
|
|
24692
|
-
|
|
24693
|
-
|
|
24694
|
-
|
|
24882
|
+
}
|
|
24883
|
+
|
|
24884
|
+
// src/pathplan/solvers.ts
|
|
24885
|
+
var EPS2 = 1e-7;
|
|
24886
|
+
var Solver = class _Solver {
|
|
24887
|
+
static aeq0(x) {
|
|
24888
|
+
return x < EPS2 && x > -EPS2;
|
|
24889
|
+
}
|
|
24890
|
+
static solve1(c, r) {
|
|
24891
|
+
if (_Solver.aeq0(c[1])) return _Solver.aeq0(c[0]) ? 4 : 0;
|
|
24892
|
+
r[0] = -c[0] / c[1];
|
|
24893
|
+
return 1;
|
|
24894
|
+
}
|
|
24895
|
+
static solve2(c, r) {
|
|
24896
|
+
if (_Solver.aeq0(c[2])) return _Solver.solve1(c, r);
|
|
24897
|
+
const b2a = c[1] / (2 * c[2]);
|
|
24898
|
+
const disc = b2a * b2a - c[0] / c[2];
|
|
24899
|
+
if (disc < 0) return 0;
|
|
24900
|
+
if (disc > 0) {
|
|
24901
|
+
r[0] = -b2a + Math.sqrt(disc);
|
|
24902
|
+
r[1] = -2 * b2a - r[0];
|
|
24903
|
+
return 2;
|
|
24904
|
+
}
|
|
24905
|
+
r[0] = -b2a;
|
|
24906
|
+
return 1;
|
|
24907
|
+
}
|
|
24908
|
+
static solve3neg(disc, q, b3a, r) {
|
|
24909
|
+
const rr = 0.5 * Math.sqrt(-disc + q * q);
|
|
24910
|
+
const theta = Math.atan2(Math.sqrt(-disc), -q);
|
|
24911
|
+
const temp = 2 * Math.cbrt(rr);
|
|
24912
|
+
r[0] = temp * Math.cos(theta / 3) - b3a;
|
|
24913
|
+
r[1] = temp * Math.cos((theta + 2 * Math.PI) / 3) - b3a;
|
|
24914
|
+
r[2] = temp * Math.cos((theta - 2 * Math.PI) / 3) - b3a;
|
|
24915
|
+
return 3;
|
|
24916
|
+
}
|
|
24917
|
+
static solve3pos(disc, q, b3a, r) {
|
|
24918
|
+
const al = 0.5 * (Math.sqrt(disc) - q);
|
|
24919
|
+
r[0] = Math.cbrt(al) + Math.cbrt(-q - al) - b3a;
|
|
24920
|
+
if (disc > 0) return 1;
|
|
24921
|
+
r[1] = r[2] = -0.5 * (r[0] + b3a) - b3a;
|
|
24922
|
+
return 3;
|
|
24923
|
+
}
|
|
24924
|
+
static solve3(c, r) {
|
|
24925
|
+
const a = c[3], b = c[2], cv = c[1], d = c[0];
|
|
24926
|
+
if (_Solver.aeq0(a)) return _Solver.solve2(c, r);
|
|
24927
|
+
const b3a = b / (3 * a), p0 = b3a * b3a;
|
|
24928
|
+
const q = 2 * b3a * p0 - b3a * cv / a + d / a;
|
|
24929
|
+
const p = cv / (3 * a) - p0;
|
|
24930
|
+
const disc = q * q + 4 * p * p * p;
|
|
24931
|
+
return disc < 0 ? _Solver.solve3neg(disc, q, b3a, r) : _Solver.solve3pos(disc, q, b3a, r);
|
|
24932
|
+
}
|
|
24933
|
+
};
|
|
24934
|
+
function solve3(coeff, roots) {
|
|
24935
|
+
return Solver.solve3(coeff, roots);
|
|
24936
|
+
}
|
|
24937
|
+
|
|
24938
|
+
// src/pathplan/route.ts
|
|
24939
|
+
var EPSILON1 = 1e-3;
|
|
24940
|
+
var EPSILON2 = 1e-6;
|
|
24941
|
+
var RouteHelper = class _RouteHelper {
|
|
24942
|
+
static B0(t) {
|
|
24943
|
+
const u = 1 - t;
|
|
24944
|
+
return u * u * u;
|
|
24945
|
+
}
|
|
24946
|
+
static B1(t) {
|
|
24947
|
+
const u = 1 - t;
|
|
24948
|
+
return 3 * t * u * u;
|
|
24949
|
+
}
|
|
24950
|
+
static B2(t) {
|
|
24951
|
+
const u = 1 - t;
|
|
24952
|
+
return 3 * t * t * u;
|
|
24953
|
+
}
|
|
24954
|
+
static B3(t) {
|
|
24955
|
+
return t * t * t;
|
|
24956
|
+
}
|
|
24957
|
+
static B01(t) {
|
|
24958
|
+
const u = 1 - t;
|
|
24959
|
+
return u * u * (u + 3 * t);
|
|
24960
|
+
}
|
|
24961
|
+
static B23(t) {
|
|
24962
|
+
const u = 1 - t;
|
|
24963
|
+
return t * t * (3 * u + t);
|
|
24964
|
+
}
|
|
24965
|
+
static normv(v) {
|
|
24966
|
+
const d = v.x * v.x + v.y * v.y;
|
|
24967
|
+
if (d > 1e-6) {
|
|
24968
|
+
const s = Math.sqrt(d);
|
|
24969
|
+
return { x: v.x / s, y: v.y / s };
|
|
24970
|
+
}
|
|
24971
|
+
return v;
|
|
24972
|
+
}
|
|
24973
|
+
static ptAdd(a, b) {
|
|
24974
|
+
return { x: a.x + b.x, y: a.y + b.y };
|
|
24975
|
+
}
|
|
24976
|
+
static ptSub(a, b) {
|
|
24977
|
+
return { x: a.x - b.x, y: a.y - b.y };
|
|
24978
|
+
}
|
|
24979
|
+
static ptScale(p, c) {
|
|
24980
|
+
return { x: p.x * c, y: p.y * c };
|
|
24981
|
+
}
|
|
24982
|
+
static ptDot(a, b) {
|
|
24983
|
+
return a.x * b.x + a.y * b.y;
|
|
24984
|
+
}
|
|
24985
|
+
static ptDist(a, b) {
|
|
24986
|
+
return Math.hypot(a.x - b.x, a.y - b.y);
|
|
24987
|
+
}
|
|
24988
|
+
static distN(pts) {
|
|
24989
|
+
let rv = 0;
|
|
24990
|
+
for (let i = 1; i < pts.length; i++) rv += _RouteHelper.ptDist(pts[i], pts[i - 1]);
|
|
24991
|
+
return rv;
|
|
24992
|
+
}
|
|
24993
|
+
static points2coeff(v0, v1, v2, v3, c) {
|
|
24994
|
+
c[3] = v3 + 3 * v1 - (v0 + 3 * v2);
|
|
24995
|
+
c[2] = 3 * v0 + 3 * v2 - 6 * v1;
|
|
24996
|
+
c[1] = 3 * (v1 - v0);
|
|
24997
|
+
c[0] = v0;
|
|
24998
|
+
}
|
|
24999
|
+
static addRoot(root, acc) {
|
|
25000
|
+
if (root >= 0 && root <= 1) {
|
|
25001
|
+
acc.roots[acc.n] = root;
|
|
25002
|
+
acc.n++;
|
|
25003
|
+
}
|
|
25004
|
+
}
|
|
25005
|
+
static silBothZero(sps, lc, acc) {
|
|
25006
|
+
const sc = [0, 0, 0, 0], xr = [0, 0, 0], yr = [0, 0, 0];
|
|
25007
|
+
_RouteHelper.points2coeff(sps[0].x, sps[1].x, sps[2].x, sps[3].x, sc);
|
|
25008
|
+
sc[0] -= lc.xc0;
|
|
25009
|
+
const xn = solve3(sc, xr);
|
|
25010
|
+
_RouteHelper.points2coeff(sps[0].y, sps[1].y, sps[2].y, sps[3].y, sc);
|
|
25011
|
+
sc[0] -= lc.yc0;
|
|
25012
|
+
const yn = solve3(sc, yr);
|
|
25013
|
+
if (xn === 4) {
|
|
25014
|
+
if (yn === 4) return 4;
|
|
25015
|
+
for (let j = 0; j < yn; j++) _RouteHelper.addRoot(yr[j], acc);
|
|
25016
|
+
} else if (yn === 4) {
|
|
25017
|
+
for (let i = 0; i < xn; i++) _RouteHelper.addRoot(xr[i], acc);
|
|
25018
|
+
} else {
|
|
25019
|
+
for (let i = 0; i < xn; i++)
|
|
25020
|
+
for (let j = 0; j < yn; j++)
|
|
25021
|
+
if (xr[i] === yr[j]) _RouteHelper.addRoot(xr[i], acc);
|
|
25022
|
+
}
|
|
25023
|
+
return acc.n;
|
|
25024
|
+
}
|
|
25025
|
+
static silXzeroYnonzero(sps, lc, acc) {
|
|
25026
|
+
const sc = [0, 0, 0, 0], xr = [0, 0, 0];
|
|
25027
|
+
_RouteHelper.points2coeff(sps[0].x, sps[1].x, sps[2].x, sps[3].x, sc);
|
|
25028
|
+
sc[0] -= lc.xc0;
|
|
25029
|
+
const xn = solve3(sc, xr);
|
|
25030
|
+
if (xn === 4) return 4;
|
|
25031
|
+
for (let i = 0; i < xn; i++) {
|
|
25032
|
+
const tv = xr[i];
|
|
25033
|
+
if (tv >= 0 && tv <= 1) {
|
|
25034
|
+
_RouteHelper.points2coeff(sps[0].y, sps[1].y, sps[2].y, sps[3].y, sc);
|
|
25035
|
+
const sv = (sc[0] + tv * (sc[1] + tv * (sc[2] + tv * sc[3])) - lc.yc0) / lc.yc1;
|
|
25036
|
+
if (sv >= 0 && sv <= 1) _RouteHelper.addRoot(tv, acc);
|
|
25037
|
+
}
|
|
25038
|
+
}
|
|
25039
|
+
return acc.n;
|
|
25040
|
+
}
|
|
25041
|
+
static silGeneral(sps, lc, acc) {
|
|
25042
|
+
const sc = [0, 0, 0, 0], xr = [0, 0, 0];
|
|
25043
|
+
const rat = lc.yc1 / lc.xc1;
|
|
25044
|
+
_RouteHelper.points2coeff(
|
|
25045
|
+
sps[0].y - rat * sps[0].x,
|
|
25046
|
+
sps[1].y - rat * sps[1].x,
|
|
25047
|
+
sps[2].y - rat * sps[2].x,
|
|
25048
|
+
sps[3].y - rat * sps[3].x,
|
|
25049
|
+
sc
|
|
25050
|
+
);
|
|
25051
|
+
sc[0] += rat * lc.xc0 - lc.yc0;
|
|
25052
|
+
const xn = solve3(sc, xr);
|
|
25053
|
+
if (xn === 4) return 4;
|
|
25054
|
+
for (let i = 0; i < xn; i++) {
|
|
25055
|
+
const tv = xr[i];
|
|
25056
|
+
if (tv >= 0 && tv <= 1) {
|
|
25057
|
+
_RouteHelper.points2coeff(sps[0].x, sps[1].x, sps[2].x, sps[3].x, sc);
|
|
25058
|
+
const sv = (sc[0] + tv * (sc[1] + tv * (sc[2] + tv * sc[3])) - lc.xc0) / lc.xc1;
|
|
25059
|
+
if (sv >= 0 && sv <= 1) _RouteHelper.addRoot(tv, acc);
|
|
25060
|
+
}
|
|
25061
|
+
}
|
|
25062
|
+
return acc.n;
|
|
25063
|
+
}
|
|
25064
|
+
static splineIntersectsLine(sps, lps, roots) {
|
|
25065
|
+
const lc = {
|
|
25066
|
+
xc0: lps[0].x,
|
|
25067
|
+
xc1: lps[1].x - lps[0].x,
|
|
25068
|
+
yc0: lps[0].y,
|
|
25069
|
+
yc1: lps[1].y - lps[0].y
|
|
25070
|
+
};
|
|
25071
|
+
const acc = { roots, n: 0 };
|
|
25072
|
+
if (lc.xc1 === 0) {
|
|
25073
|
+
if (lc.yc1 === 0) return _RouteHelper.silBothZero(sps, lc, acc);
|
|
25074
|
+
return _RouteHelper.silXzeroYnonzero(sps, lc, acc);
|
|
25075
|
+
}
|
|
25076
|
+
return _RouteHelper.silGeneral(sps, lc, acc);
|
|
25077
|
+
}
|
|
25078
|
+
static splineIsInside(barriers, sps) {
|
|
25079
|
+
const roots = [0, 0, 0, 0];
|
|
25080
|
+
for (let ei = 0; ei < barriers.length; ei++) {
|
|
25081
|
+
const lps = [barriers[ei].a, barriers[ei].b];
|
|
24695
25082
|
const rootn = _RouteHelper.splineIntersectsLine(sps, lps, roots);
|
|
24696
25083
|
if (rootn === 4) continue;
|
|
24697
25084
|
for (let ri = 0; ri < rootn; ri++) {
|
|
@@ -24792,1057 +25179,496 @@ var RouteHelper = class _RouteHelper {
|
|
|
24792
25179
|
}
|
|
24793
25180
|
a = a > 0.01 ? a / 2 : 0;
|
|
24794
25181
|
}
|
|
24795
|
-
return 0;
|
|
24796
|
-
}
|
|
24797
|
-
static reallyRoute(state3, inps, ev0, ev1) {
|
|
24798
|
-
const tnas = _RouteHelper.initTnas(inps, ev0, ev1);
|
|
24799
|
-
const ends = _RouteHelper.mkspline(inps, tnas, ev0, ev1);
|
|
24800
|
-
if (_RouteHelper.splineFits(state3, ends, inps)) return true;
|
|
24801
|
-
const maxi = _RouteHelper.findMaxDev(inps, tnas, ends);
|
|
24802
|
-
const sv1 = _RouteHelper.normv(_RouteHelper.ptSub(inps[maxi], inps[maxi - 1]));
|
|
24803
|
-
const sv2 = _RouteHelper.normv(_RouteHelper.ptSub(inps[maxi + 1], inps[maxi]));
|
|
24804
|
-
const splitv = _RouteHelper.normv(_RouteHelper.ptAdd(sv1, sv2));
|
|
24805
|
-
if (!_RouteHelper.reallyRoute(state3, inps.slice(0, maxi + 1), ev0, splitv)) return false;
|
|
24806
|
-
if (!_RouteHelper.reallyRoute(state3, inps.slice(maxi), splitv, ev1)) return false;
|
|
24807
|
-
return true;
|
|
24808
|
-
}
|
|
24809
|
-
static run(barriers, route, slopes) {
|
|
24810
|
-
const state3 = { ops: [], barriers };
|
|
24811
|
-
const ev0 = _RouteHelper.normv(slopes[0]);
|
|
24812
|
-
const ev1 = _RouteHelper.normv(slopes[1]);
|
|
24813
|
-
state3.ops.push(route[0]);
|
|
24814
|
-
_RouteHelper.reallyRoute(state3, route, ev0, ev1);
|
|
24815
|
-
return state3.ops;
|
|
24816
|
-
}
|
|
24817
|
-
};
|
|
24818
|
-
function routeSpline(barriers, route, slopes) {
|
|
24819
|
-
return RouteHelper.run(barriers, route, slopes);
|
|
24820
|
-
}
|
|
24821
|
-
function polyBarriers(polys) {
|
|
24822
|
-
const out = [];
|
|
24823
|
-
for (const poly of polys) {
|
|
24824
|
-
const n = poly.ps.length;
|
|
24825
|
-
for (let j = 0; j < n; j++) out.push({ a: poly.ps[j], b: poly.ps[(j + 1) % n] });
|
|
24826
|
-
}
|
|
24827
|
-
return out;
|
|
24828
|
-
}
|
|
24829
|
-
function makePolyline(pts) {
|
|
24830
|
-
const out = [];
|
|
24831
|
-
out.push(pts[0], pts[0]);
|
|
24832
|
-
for (let i = 1; i + 1 < pts.length; i++) out.push(pts[i], pts[i], pts[i]);
|
|
24833
|
-
out.push(pts[pts.length - 1], pts[pts.length - 1]);
|
|
24834
|
-
return out;
|
|
24835
|
-
}
|
|
24836
|
-
|
|
24837
|
-
// src/pathplan/triang.ts
|
|
24838
|
-
var ISCCW = 1;
|
|
24839
|
-
var ISCW = 2;
|
|
24840
|
-
var ISON = 3;
|
|
24841
|
-
var SPLIT2 = 134217729;
|
|
24842
|
-
function twoProductErr(a, b, P) {
|
|
24843
|
-
const ac = SPLIT2 * a;
|
|
24844
|
-
const ahi = ac - (ac - a);
|
|
24845
|
-
const alo = a - ahi;
|
|
24846
|
-
const bc = SPLIT2 * b;
|
|
24847
|
-
const bhi = bc - (bc - b);
|
|
24848
|
-
const blo = b - bhi;
|
|
24849
|
-
return ahi * bhi - P + ahi * blo + alo * bhi + alo * blo;
|
|
24850
|
-
}
|
|
24851
|
-
function twoDiffTail(P, D, s) {
|
|
24852
|
-
const bvirt = P - s;
|
|
24853
|
-
const avirt = s + bvirt;
|
|
24854
|
-
const bround = bvirt - D;
|
|
24855
|
-
const around = P - avirt;
|
|
24856
|
-
return around + bround;
|
|
24857
|
-
}
|
|
24858
|
-
var dyadicView = new DataView(new ArrayBuffer(8));
|
|
24859
|
-
function dyadic(x) {
|
|
24860
|
-
if (x === 0) return { m: 0n, e: 0 };
|
|
24861
|
-
dyadicView.setFloat64(0, x);
|
|
24862
|
-
const hi = dyadicView.getUint32(0);
|
|
24863
|
-
const lo = dyadicView.getUint32(4);
|
|
24864
|
-
const sign2 = hi >>> 31 ? -1n : 1n;
|
|
24865
|
-
const biasedExp = hi >>> 20 & 2047;
|
|
24866
|
-
let mant = BigInt(hi & 1048575) << 32n | BigInt(lo);
|
|
24867
|
-
let e;
|
|
24868
|
-
if (biasedExp === 0) {
|
|
24869
|
-
e = -1074;
|
|
24870
|
-
} else {
|
|
24871
|
-
mant |= 1n << 52n;
|
|
24872
|
-
e = biasedExp - 1075;
|
|
24873
|
-
}
|
|
24874
|
-
return { m: sign2 * mant, e };
|
|
24875
|
-
}
|
|
24876
|
-
function signOfSum3(a, b, c) {
|
|
24877
|
-
const da = dyadic(a);
|
|
24878
|
-
const db = dyadic(b);
|
|
24879
|
-
const dc = dyadic(c);
|
|
24880
|
-
const e = Math.min(da.e, db.e, dc.e);
|
|
24881
|
-
const sum = (da.m << BigInt(da.e - e)) + (db.m << BigInt(db.e - e)) + (dc.m << BigInt(dc.e - e));
|
|
24882
|
-
return sum > 0n ? 1 : sum < 0n ? -1 : 0;
|
|
24883
|
-
}
|
|
24884
|
-
var TriangHelper = class _TriangHelper {
|
|
24885
|
-
static ccw(p1, p2, p3) {
|
|
24886
|
-
const a = p1.y - p2.y;
|
|
24887
|
-
const b = p3.x - p2.x;
|
|
24888
|
-
const c = p3.y - p2.y;
|
|
24889
|
-
const e = p1.x - p2.x;
|
|
24890
|
-
const P = a * b;
|
|
24891
|
-
const D = c * e;
|
|
24892
|
-
const d = P - D;
|
|
24893
|
-
const bound = 23e-17 * (Math.abs(P) + Math.abs(D));
|
|
24894
|
-
if (d > bound) return ISCW;
|
|
24895
|
-
if (d < -bound) return ISCCW;
|
|
24896
|
-
const err = twoProductErr(a, b, P);
|
|
24897
|
-
const s = P - D;
|
|
24898
|
-
const tail = twoDiffTail(P, D, s);
|
|
24899
|
-
const sign2 = signOfSum3(s, tail, err);
|
|
24900
|
-
return sign2 > 0 ? ISCW : sign2 < 0 ? ISCCW : ISON;
|
|
24901
|
-
}
|
|
24902
|
-
/** Is pc on segment [pa, pb]? */
|
|
24903
|
-
static between(pa, pb, pc) {
|
|
24904
|
-
if (_TriangHelper.ccw(pa, pb, pc) !== ISON) return false;
|
|
24905
|
-
const pba = { x: pb.x - pa.x, y: pb.y - pa.y };
|
|
24906
|
-
const pca = { x: pc.x - pa.x, y: pc.y - pa.y };
|
|
24907
|
-
return pca.x * pba.x + pca.y * pba.y >= 0 && pca.x * pca.x + pca.y * pca.y <= pba.x * pba.x + pba.y * pba.y;
|
|
24908
|
-
}
|
|
24909
|
-
static anyCollinear(pa, pb, pc, pd) {
|
|
24910
|
-
const c = _TriangHelper.ccw;
|
|
24911
|
-
return c(pa, pb, pc) === ISON || c(pa, pb, pd) === ISON || c(pc, pd, pa) === ISON || c(pc, pd, pb) === ISON;
|
|
24912
|
-
}
|
|
24913
|
-
static collinearIntersects(pa, pb, pc, pd) {
|
|
24914
|
-
const b = _TriangHelper.between;
|
|
24915
|
-
return b(pa, pb, pc) || b(pa, pb, pd) || b(pc, pd, pa) || b(pc, pd, pb);
|
|
24916
|
-
}
|
|
24917
|
-
static crossIntersects(pa, pb, pc, pd) {
|
|
24918
|
-
const c = _TriangHelper.ccw;
|
|
24919
|
-
const c1 = c(pa, pb, pc) === ISCCW ? 1 : 0;
|
|
24920
|
-
const c2 = c(pa, pb, pd) === ISCCW ? 1 : 0;
|
|
24921
|
-
const c3 = c(pc, pd, pa) === ISCCW ? 1 : 0;
|
|
24922
|
-
const c4 = c(pc, pd, pb) === ISCCW ? 1 : 0;
|
|
24923
|
-
return (c1 ^ c2) !== 0 && (c3 ^ c4) !== 0;
|
|
24924
|
-
}
|
|
24925
|
-
static intersects(pa, pb, pc, pd) {
|
|
24926
|
-
if (_TriangHelper.anyCollinear(pa, pb, pc, pd))
|
|
24927
|
-
return _TriangHelper.collinearIntersects(pa, pb, pc, pd);
|
|
24928
|
-
return _TriangHelper.crossIntersects(pa, pb, pc, pd);
|
|
24929
|
-
}
|
|
24930
|
-
static isdiagNeighborhood(i, ip2, get, pointn) {
|
|
24931
|
-
const ip1 = (i + 1) % pointn;
|
|
24932
|
-
const im1 = (i + pointn - 1) % pointn;
|
|
24933
|
-
const c = _TriangHelper.ccw;
|
|
24934
|
-
if (c(get(im1), get(i), get(ip1)) === ISCCW) {
|
|
24935
|
-
return c(get(i), get(ip2), get(im1)) === ISCCW && c(get(ip2), get(i), get(ip1)) === ISCCW;
|
|
24936
|
-
}
|
|
24937
|
-
return c(get(i), get(ip2), get(ip1)) === ISCW;
|
|
24938
|
-
}
|
|
24939
|
-
static isdiagonal(i, ip2, get, pointn) {
|
|
24940
|
-
if (!_TriangHelper.isdiagNeighborhood(i, ip2, get, pointn)) return false;
|
|
24941
|
-
for (let j = 0; j < pointn; j++) {
|
|
24942
|
-
const jp1 = (j + 1) % pointn;
|
|
24943
|
-
if (j !== i && jp1 !== i && j !== ip2 && jp1 !== ip2) {
|
|
24944
|
-
if (_TriangHelper.intersects(get(i), get(ip2), get(j), get(jp1)))
|
|
24945
|
-
return false;
|
|
24946
|
-
}
|
|
24947
|
-
}
|
|
24948
|
-
return true;
|
|
24949
|
-
}
|
|
24950
|
-
static triangulateInner(pts, fn) {
|
|
24951
|
-
let cur = pts;
|
|
24952
|
-
while (cur.length > 3) {
|
|
24953
|
-
const n = cur.length;
|
|
24954
|
-
let cut = -1;
|
|
24955
|
-
for (let i = 0; i < n; i++) {
|
|
24956
|
-
const ip2 = (i + 2) % n;
|
|
24957
|
-
if (_TriangHelper.isdiagonal(i, ip2, (k) => cur[k], n)) {
|
|
24958
|
-
fn([cur[i], cur[(i + 1) % n], cur[ip2]]);
|
|
24959
|
-
cut = (i + 1) % n;
|
|
24960
|
-
break;
|
|
24961
|
-
}
|
|
24962
|
-
}
|
|
24963
|
-
if (cut === -1) return false;
|
|
24964
|
-
cur = cur.filter((_, idx) => idx !== cut);
|
|
24965
|
-
}
|
|
24966
|
-
fn([cur[0], cur[1], cur[2]]);
|
|
24967
|
-
return true;
|
|
24968
|
-
}
|
|
24969
|
-
};
|
|
24970
|
-
function ccw(p1, p2, p3) {
|
|
24971
|
-
return TriangHelper.ccw(p1, p2, p3);
|
|
24972
|
-
}
|
|
24973
|
-
function isdiagonal(i, ip2, get, pointn) {
|
|
24974
|
-
return TriangHelper.isdiagonal(i, ip2, get, pointn);
|
|
24975
|
-
}
|
|
24976
|
-
|
|
24977
|
-
// src/pathplan/shortest.ts
|
|
24978
|
-
var NO_TRI = -1;
|
|
24979
|
-
var DQ_FRONT = 1;
|
|
24980
|
-
var DQ_BACK = 2;
|
|
24981
|
-
var ShortestHelper = class _ShortestHelper {
|
|
24982
|
-
static buildTri(a, b, c) {
|
|
24983
|
-
const mk = (p0, p1) => ({ pnl0: p0, pnl1: p1, rightIndex: NO_TRI });
|
|
24984
|
-
return { mark: 0, e: [mk(a, b), mk(b, c), mk(c, a)] };
|
|
24985
|
-
}
|
|
24986
|
-
static triInner(pnlps, tris) {
|
|
24987
|
-
let pts = pnlps;
|
|
24988
|
-
while (pts.length > 3) {
|
|
24989
|
-
const n = pts.length;
|
|
24990
|
-
let cut = -1;
|
|
24991
|
-
for (let i = 0; i < n; i++) {
|
|
24992
|
-
const ip2 = (i + 2) % n;
|
|
24993
|
-
if (isdiagonal(i, ip2, (k) => pts[k].pp, n)) {
|
|
24994
|
-
tris.push(_ShortestHelper.buildTri(pts[i], pts[(i + 1) % n], pts[ip2]));
|
|
24995
|
-
cut = (i + 1) % n;
|
|
24996
|
-
break;
|
|
24997
|
-
}
|
|
24998
|
-
}
|
|
24999
|
-
if (cut === -1) return false;
|
|
25000
|
-
pts = pts.filter((_, j) => j !== cut);
|
|
25001
|
-
}
|
|
25002
|
-
tris.push(_ShortestHelper.buildTri(pts[0], pts[1], pts[2]));
|
|
25003
|
-
return true;
|
|
25004
|
-
}
|
|
25005
|
-
static connectTri(i, j, tris) {
|
|
25006
|
-
const t1 = tris[i], t2 = tris[j];
|
|
25007
|
-
for (let ei = 0; ei < 3; ei++) {
|
|
25008
|
-
for (let ej = 0; ej < 3; ej++) {
|
|
25009
|
-
const e1 = t1.e[ei], e2 = t2.e[ej];
|
|
25010
|
-
if (e1.pnl0 === e2.pnl0 && e1.pnl1 === e2.pnl1 || e1.pnl0 === e2.pnl1 && e1.pnl1 === e2.pnl0)
|
|
25011
|
-
e1.rightIndex = j, e2.rightIndex = i;
|
|
25012
|
-
}
|
|
25013
|
-
}
|
|
25014
|
-
}
|
|
25015
|
-
static connectAll(tris) {
|
|
25016
|
-
for (let i = 0; i < tris.length; i++)
|
|
25017
|
-
for (let j = i + 1; j < tris.length; j++)
|
|
25018
|
-
_ShortestHelper.connectTri(i, j, tris);
|
|
25019
|
-
}
|
|
25020
|
-
static pointInTri(tri, p) {
|
|
25021
|
-
let sum = 0;
|
|
25022
|
-
for (let ei = 0; ei < 3; ei++)
|
|
25023
|
-
if (ccw(tri.e[ei].pnl0.pp, tri.e[ei].pnl1.pp, p) !== ISCW) sum++;
|
|
25024
|
-
return sum === 3 || sum === 0;
|
|
25025
|
-
}
|
|
25026
|
-
static markPath(tris, trii, trij) {
|
|
25027
|
-
if (tris[trii].mark) return false;
|
|
25028
|
-
tris[trii].mark = 1;
|
|
25029
|
-
if (trii === trij) return true;
|
|
25030
|
-
for (let ei = 0; ei < 3; ei++) {
|
|
25031
|
-
const ri = tris[trii].e[ei].rightIndex;
|
|
25032
|
-
if (ri !== NO_TRI && _ShortestHelper.markPath(tris, ri, trij)) return true;
|
|
25033
|
-
}
|
|
25034
|
-
tris[trii].mark = 0;
|
|
25035
|
-
return false;
|
|
25036
|
-
}
|
|
25037
|
-
static findTri(tris, p) {
|
|
25038
|
-
for (let i = 0; i < tris.length; i++)
|
|
25039
|
-
if (_ShortestHelper.pointInTri(tris[i], p)) return i;
|
|
25040
|
-
return NO_TRI;
|
|
25041
|
-
}
|
|
25042
|
-
static findMinX(ps) {
|
|
25043
|
-
let minx = Infinity, minpi = 0;
|
|
25044
|
-
for (let i = 0; i < ps.length; i++)
|
|
25045
|
-
if (ps[i].x < minx) {
|
|
25046
|
-
minx = ps[i].x;
|
|
25047
|
-
minpi = i;
|
|
25048
|
-
}
|
|
25049
|
-
return minpi;
|
|
25050
|
-
}
|
|
25051
|
-
static isPolyCW(ps, minpi) {
|
|
25052
|
-
const pn = ps.length;
|
|
25053
|
-
const p2 = ps[minpi];
|
|
25054
|
-
const p1 = ps[minpi === 0 ? pn - 1 : minpi - 1];
|
|
25055
|
-
const p3 = ps[(minpi + 1) % pn];
|
|
25056
|
-
if (p1.x === p2.x && p2.x === p3.x && p3.y > p2.y) return true;
|
|
25057
|
-
return ccw(p1, p2, p3) !== ISCCW;
|
|
25058
|
-
}
|
|
25059
|
-
static loadForward(ps) {
|
|
25060
|
-
const r = [];
|
|
25061
|
-
for (let i = 0; i < ps.length; i++) {
|
|
25062
|
-
if (i > 0 && ps[i].x === ps[i - 1].x && ps[i].y === ps[i - 1].y) continue;
|
|
25063
|
-
r.push({ pp: ps[i], link: null });
|
|
25064
|
-
}
|
|
25065
|
-
return r;
|
|
25066
|
-
}
|
|
25067
|
-
static loadReverse(ps) {
|
|
25068
|
-
const r = [];
|
|
25069
|
-
for (let i = ps.length - 1; i >= 0; i--) {
|
|
25070
|
-
if (i < ps.length - 1 && ps[i].x === ps[i + 1].x && ps[i].y === ps[i + 1].y) continue;
|
|
25071
|
-
r.push({ pp: ps[i], link: null });
|
|
25072
|
-
}
|
|
25073
|
-
return r;
|
|
25074
|
-
}
|
|
25075
|
-
static loadPoints(poly) {
|
|
25076
|
-
const ps = poly.ps;
|
|
25077
|
-
return _ShortestHelper.isPolyCW(ps, _ShortestHelper.findMinX(ps)) ? _ShortestHelper.loadReverse(ps) : _ShortestHelper.loadForward(ps);
|
|
25078
|
-
}
|
|
25079
|
-
static initDeque(pnll) {
|
|
25080
|
-
const pnlpn = pnll * 2;
|
|
25081
|
-
const pnlps = new Array(pnlpn).fill(null);
|
|
25082
|
-
const fpnlpi = Math.floor(pnlpn / 2);
|
|
25083
|
-
return { pnlps, pnlpn, fpnlpi, lpnlpi: fpnlpi - 1, apex: 0 };
|
|
25084
|
-
}
|
|
25085
|
-
static add2dq(dq, side, pnl) {
|
|
25086
|
-
if (side === DQ_FRONT) {
|
|
25087
|
-
if (dq.lpnlpi >= dq.fpnlpi) pnl.link = dq.pnlps[dq.fpnlpi];
|
|
25088
|
-
dq.fpnlpi--;
|
|
25089
|
-
dq.pnlps[dq.fpnlpi] = pnl;
|
|
25090
|
-
} else {
|
|
25091
|
-
if (dq.lpnlpi >= dq.fpnlpi) pnl.link = dq.pnlps[dq.lpnlpi];
|
|
25092
|
-
dq.lpnlpi++;
|
|
25093
|
-
dq.pnlps[dq.lpnlpi] = pnl;
|
|
25094
|
-
}
|
|
25095
|
-
}
|
|
25096
|
-
static splitdq(dq, side, index) {
|
|
25097
|
-
if (side === DQ_FRONT) dq.lpnlpi = index;
|
|
25098
|
-
else dq.fpnlpi = index;
|
|
25099
|
-
}
|
|
25100
|
-
static finddqsplit(dq, pnl) {
|
|
25101
|
-
for (let idx = dq.fpnlpi; idx < dq.apex; idx++)
|
|
25102
|
-
if (ccw(dq.pnlps[idx + 1].pp, dq.pnlps[idx].pp, pnl.pp) === ISCCW) return idx;
|
|
25103
|
-
for (let idx = dq.lpnlpi; idx > dq.apex; idx--)
|
|
25104
|
-
if (ccw(dq.pnlps[idx - 1].pp, dq.pnlps[idx].pp, pnl.pp) === ISCW) return idx;
|
|
25105
|
-
return dq.apex;
|
|
25106
|
-
}
|
|
25107
|
-
static fuFindEi(trip, tris) {
|
|
25108
|
-
for (let ei = 0; ei < 3; ei++) {
|
|
25109
|
-
const ri = trip.e[ei].rightIndex;
|
|
25110
|
-
if (ri !== NO_TRI && tris[ri].mark === 1) return ei;
|
|
25111
|
-
}
|
|
25112
|
-
return 3;
|
|
25113
|
-
}
|
|
25114
|
-
static fuNextTri(trip, tris) {
|
|
25115
|
-
for (let ei = 0; ei < 3; ei++) {
|
|
25116
|
-
const ri = trip.e[ei].rightIndex;
|
|
25117
|
-
if (ri !== NO_TRI && tris[ri].mark === 1) return ri;
|
|
25118
|
-
}
|
|
25119
|
-
return NO_TRI;
|
|
25120
|
-
}
|
|
25121
|
-
static fuGetPairLast(epnl1, dq) {
|
|
25122
|
-
if (ccw(epnl1.pp, dq.pnlps[dq.fpnlpi].pp, dq.pnlps[dq.lpnlpi].pp) === ISCCW)
|
|
25123
|
-
return [dq.pnlps[dq.lpnlpi], epnl1];
|
|
25124
|
-
return [epnl1, dq.pnlps[dq.lpnlpi]];
|
|
25125
|
-
}
|
|
25126
|
-
static fuGetPairNormal(trip, ei) {
|
|
25127
|
-
const e = trip.e[ei];
|
|
25128
|
-
const pnl = trip.e[(ei + 1) % 3].pnl1;
|
|
25129
|
-
if (ccw(e.pnl0.pp, pnl.pp, e.pnl1.pp) === ISCCW) return [e.pnl1, e.pnl0];
|
|
25130
|
-
return [e.pnl0, e.pnl1];
|
|
25131
|
-
}
|
|
25132
|
-
static fuUpdateRight(dq, r) {
|
|
25133
|
-
const si = _ShortestHelper.finddqsplit(dq, r);
|
|
25134
|
-
_ShortestHelper.splitdq(dq, DQ_BACK, si);
|
|
25135
|
-
_ShortestHelper.add2dq(dq, DQ_FRONT, r);
|
|
25136
|
-
if (si > dq.apex) dq.apex = si;
|
|
25137
|
-
}
|
|
25138
|
-
static fuUpdateLeft(dq, l) {
|
|
25139
|
-
const si = _ShortestHelper.finddqsplit(dq, l);
|
|
25140
|
-
_ShortestHelper.splitdq(dq, DQ_FRONT, si);
|
|
25141
|
-
_ShortestHelper.add2dq(dq, DQ_BACK, l);
|
|
25142
|
-
if (si < dq.apex) dq.apex = si;
|
|
25143
|
-
}
|
|
25144
|
-
static fuUpdate(dq, l, r, isFirst) {
|
|
25145
|
-
if (isFirst) {
|
|
25146
|
-
_ShortestHelper.add2dq(dq, DQ_BACK, l);
|
|
25147
|
-
_ShortestHelper.add2dq(dq, DQ_FRONT, r);
|
|
25148
|
-
return;
|
|
25149
|
-
}
|
|
25150
|
-
if (dq.pnlps[dq.fpnlpi] !== r && dq.pnlps[dq.lpnlpi] !== r)
|
|
25151
|
-
_ShortestHelper.fuUpdateRight(dq, r);
|
|
25152
|
-
else
|
|
25153
|
-
_ShortestHelper.fuUpdateLeft(dq, l);
|
|
25154
|
-
}
|
|
25155
|
-
static fuLoop(tris, dq, epnls, ftrii) {
|
|
25156
|
-
let trii = ftrii;
|
|
25157
|
-
while (trii !== NO_TRI) {
|
|
25158
|
-
const trip = tris[trii];
|
|
25159
|
-
trip.mark = 2;
|
|
25160
|
-
const ei = _ShortestHelper.fuFindEi(trip, tris);
|
|
25161
|
-
const [l, r] = ei === 3 ? _ShortestHelper.fuGetPairLast(epnls[1], dq) : _ShortestHelper.fuGetPairNormal(trip, ei);
|
|
25162
|
-
_ShortestHelper.fuUpdate(dq, l, r, trii === ftrii);
|
|
25163
|
-
trii = _ShortestHelper.fuNextTri(trip, tris);
|
|
25164
|
-
}
|
|
25165
|
-
}
|
|
25166
|
-
static extractPath(epnl1) {
|
|
25167
|
-
const pts = [];
|
|
25168
|
-
for (let p = epnl1; p !== null; p = p.link) pts.push(p.pp);
|
|
25169
|
-
pts.reverse();
|
|
25170
|
-
return pts;
|
|
25171
|
-
}
|
|
25172
|
-
static run(poly, eps) {
|
|
25173
|
-
const pnlps = _ShortestHelper.loadPoints(poly);
|
|
25174
|
-
const tris = [];
|
|
25175
|
-
if (!_ShortestHelper.triInner(pnlps.slice(), tris)) {
|
|
25176
|
-
console.warn("triangulation failed");
|
|
25177
|
-
}
|
|
25178
|
-
_ShortestHelper.connectAll(tris);
|
|
25179
|
-
const ftrii = _ShortestHelper.findTri(tris, eps[0]);
|
|
25180
|
-
const ltrii = _ShortestHelper.findTri(tris, eps[1]);
|
|
25181
|
-
if (ftrii === NO_TRI || ltrii === NO_TRI) return null;
|
|
25182
|
-
if (ftrii === ltrii) return [eps[0], eps[1]];
|
|
25183
|
-
if (!_ShortestHelper.markPath(tris, ftrii, ltrii)) return [eps[0], eps[1]];
|
|
25184
|
-
const epnls = [{ pp: eps[0], link: null }, { pp: eps[1], link: null }];
|
|
25185
|
-
const dq = _ShortestHelper.initDeque(pnlps.length);
|
|
25186
|
-
_ShortestHelper.add2dq(dq, DQ_FRONT, epnls[0]);
|
|
25187
|
-
dq.apex = dq.fpnlpi;
|
|
25188
|
-
_ShortestHelper.fuLoop(tris, dq, epnls, ftrii);
|
|
25189
|
-
return _ShortestHelper.extractPath(epnls[1]);
|
|
25190
|
-
}
|
|
25191
|
-
};
|
|
25192
|
-
function shortestPath(poly, eps) {
|
|
25193
|
-
return ShortestHelper.run(poly, eps);
|
|
25194
|
-
}
|
|
25195
|
-
|
|
25196
|
-
// src/layout/dot/edge-route-poly.ts
|
|
25197
|
-
function fwdDirs(boxes, bi) {
|
|
25198
|
-
const n = boxes.length;
|
|
25199
|
-
const prev = bi > 0 ? boxes[bi].ll.y > boxes[bi - 1].ll.y ? -1 : 1 : 0;
|
|
25200
|
-
const next = bi + 1 < n ? boxes[bi + 1].ll.y > boxes[bi].ll.y ? 1 : -1 : 0;
|
|
25201
|
-
return { prev, next };
|
|
25202
|
-
}
|
|
25203
|
-
function emitFwdBox(b, prev, next, pts) {
|
|
25204
|
-
if (prev !== next) {
|
|
25205
|
-
if (next === -1 || prev === 1) {
|
|
25206
|
-
pts.push({ x: b.ll.x, y: b.ur.y }, { x: b.ll.x, y: b.ll.y });
|
|
25207
|
-
} else {
|
|
25208
|
-
pts.push({ x: b.ur.x, y: b.ll.y }, { x: b.ur.x, y: b.ur.y });
|
|
25209
|
-
}
|
|
25210
|
-
} else if (prev === 0) {
|
|
25211
|
-
pts.push({ x: b.ll.x, y: b.ur.y }, { x: b.ll.x, y: b.ll.y });
|
|
25212
|
-
}
|
|
25213
|
-
}
|
|
25214
|
-
function addForwardPolyPts(boxes, pts) {
|
|
25215
|
-
for (let bi = 0; bi < boxes.length; bi++) {
|
|
25216
|
-
const { prev, next } = fwdDirs(boxes, bi);
|
|
25217
|
-
emitFwdBox(boxes[bi], prev, next, pts);
|
|
25218
|
-
}
|
|
25219
|
-
}
|
|
25220
|
-
function revDirs(boxes, bi) {
|
|
25221
|
-
const n = boxes.length;
|
|
25222
|
-
const prev = bi + 1 < n ? boxes[bi].ll.y > boxes[bi + 1].ll.y ? -1 : 1 : 0;
|
|
25223
|
-
const next = bi > 0 ? boxes[bi - 1].ll.y > boxes[bi].ll.y ? 1 : -1 : 0;
|
|
25224
|
-
return { prev, next };
|
|
25225
|
-
}
|
|
25226
|
-
function emitAllCorners(b, pts) {
|
|
25227
|
-
pts.push(
|
|
25228
|
-
{ x: b.ur.x, y: b.ll.y },
|
|
25229
|
-
{ x: b.ur.x, y: b.ur.y },
|
|
25230
|
-
{ x: b.ll.x, y: b.ur.y },
|
|
25231
|
-
{ x: b.ll.x, y: b.ll.y }
|
|
25232
|
-
);
|
|
25233
|
-
}
|
|
25234
|
-
function emitRevBox(b, prev, next, pts) {
|
|
25235
|
-
if (prev !== next) {
|
|
25236
|
-
if (next === -1 || prev === 1) {
|
|
25237
|
-
pts.push({ x: b.ll.x, y: b.ur.y }, { x: b.ll.x, y: b.ll.y });
|
|
25238
|
-
} else {
|
|
25239
|
-
pts.push({ x: b.ur.x, y: b.ll.y }, { x: b.ur.x, y: b.ur.y });
|
|
25240
|
-
}
|
|
25241
|
-
} else if (prev === 0) {
|
|
25242
|
-
pts.push({ x: b.ur.x, y: b.ll.y }, { x: b.ur.x, y: b.ur.y });
|
|
25243
|
-
} else {
|
|
25244
|
-
emitAllCorners(b, pts);
|
|
25245
|
-
}
|
|
25246
|
-
}
|
|
25247
|
-
function addReversePolyPts(boxes, pts) {
|
|
25248
|
-
for (let bi = boxes.length - 1; bi >= 0; bi--) {
|
|
25249
|
-
const { prev, next } = revDirs(boxes, bi);
|
|
25250
|
-
emitRevBox(boxes[bi], prev, next, pts);
|
|
25251
|
-
}
|
|
25252
|
-
}
|
|
25253
|
-
function boxesToPolygon(boxes) {
|
|
25254
|
-
if (boxes.length === 0) return [];
|
|
25255
|
-
const pts = [];
|
|
25256
|
-
addForwardPolyPts(boxes, pts);
|
|
25257
|
-
addReversePolyPts(boxes, pts);
|
|
25258
|
-
return pts;
|
|
25259
|
-
}
|
|
25260
|
-
function polyEdgesFromPts(polygon) {
|
|
25261
|
-
const n = polygon.length;
|
|
25262
|
-
return polygon.map((a, i) => ({ a, b: polygon[(i + 1) % n] }));
|
|
25263
|
-
}
|
|
25264
|
-
function linearBezier(p0, p3) {
|
|
25265
|
-
return [
|
|
25266
|
-
p0,
|
|
25267
|
-
{ x: p0.x + (p3.x - p0.x) / 3, y: p0.y + (p3.y - p0.y) / 3 },
|
|
25268
|
-
{ x: p0.x + 2 * (p3.x - p0.x) / 3, y: p0.y + 2 * (p3.y - p0.y) / 3 },
|
|
25269
|
-
p3
|
|
25270
|
-
];
|
|
25271
|
-
}
|
|
25272
|
-
function tryRouteSpline(barriers, wpts) {
|
|
25273
|
-
const zero = { x: 0, y: 0 };
|
|
25274
|
-
const raw = routeSpline(barriers, wpts, [zero, zero]);
|
|
25275
|
-
if (raw.length < 4) return null;
|
|
25276
|
-
return [raw[0], raw[1], raw[2], raw[3]];
|
|
25277
|
-
}
|
|
25278
|
-
function computeSpline(boxes, startPt, endPt) {
|
|
25279
|
-
const polygon = boxesToPolygon(boxes);
|
|
25280
|
-
if (polygon.length < 3) return linearBezier(startPt, endPt);
|
|
25281
|
-
const wpts = shortestPath({ ps: polygon }, [startPt, endPt]);
|
|
25282
|
-
if (wpts === null || wpts.length < 2) return linearBezier(startPt, endPt);
|
|
25283
|
-
return tryRouteSpline(polyEdgesFromPts(polygon), wpts) ?? linearBezier(startPt, endPt);
|
|
25284
|
-
}
|
|
25285
|
-
|
|
25286
|
-
// src/layout/dot/edge-route-boxes.ts
|
|
25287
|
-
var FUDGE2 = 2;
|
|
25288
|
-
function makeTailBox(nb, startPy) {
|
|
25289
|
-
return { ll: nb.ll, ur: { x: nb.ur.x, y: startPy } };
|
|
25290
|
-
}
|
|
25291
|
-
function makeHeadBox(nb, endPy) {
|
|
25292
|
-
return { ll: { x: nb.ll.x, y: endPy }, ur: nb.ur };
|
|
25293
|
-
}
|
|
25294
|
-
function makeRankBox(p) {
|
|
25295
|
-
return {
|
|
25296
|
-
ll: { x: p.llx, y: p.headCy + p.headHt2 },
|
|
25297
|
-
ur: { x: p.urx, y: p.tailCy - p.tailHt1 }
|
|
25298
|
-
};
|
|
25299
|
-
}
|
|
25300
|
-
function makeMaximalBbox(box, ht1, ht22) {
|
|
25301
|
-
return {
|
|
25302
|
-
ll: { x: box.center.x - box.lw - FUDGE2, y: box.center.y - ht1 },
|
|
25303
|
-
ur: { x: box.center.x + box.rw + FUDGE2, y: box.center.y + ht22 }
|
|
25304
|
-
};
|
|
25305
|
-
}
|
|
25306
|
-
|
|
25307
|
-
// src/layout/dot/edge-route-routing.ts
|
|
25308
|
-
var ARROW_LENGTH2 = 10;
|
|
25309
|
-
var CLIP_BOTH = { tail: true, head: true };
|
|
25310
|
-
function buildRankCorridor(tailBox, headBox, rank3, ports) {
|
|
25311
|
-
const startPy = tailBox.center.y;
|
|
25312
|
-
const endPy = headBox.center.y;
|
|
25313
|
-
const tailNb = makeMaximalBbox(tailBox, rank3.tailHt1, rank3.tailHt2);
|
|
25314
|
-
const headNb = makeMaximalBbox(headBox, rank3.headHt1, rank3.headHt2);
|
|
25315
|
-
const rp = {
|
|
25316
|
-
llx: rank3.leftBound,
|
|
25317
|
-
urx: rank3.rightBound,
|
|
25318
|
-
tailCy: tailBox.center.y,
|
|
25319
|
-
tailHt1: rank3.tailHt1,
|
|
25320
|
-
headCy: headBox.center.y,
|
|
25321
|
-
headHt2: rank3.headHt2
|
|
25322
|
-
};
|
|
25323
|
-
return {
|
|
25324
|
-
startPt: ports?.tailP ?? { x: tailBox.center.x, y: startPy - 1 },
|
|
25325
|
-
endPt: ports?.headP ?? { x: headBox.center.x, y: endPy + 1 },
|
|
25326
|
-
boxes: [makeTailBox(tailNb, startPy), makeRankBox(rp), makeHeadBox(headNb, endPy)]
|
|
25327
|
-
};
|
|
25328
|
-
}
|
|
25329
|
-
function normalArrowLen(penwidth = DEFAULT_NODEPENWIDTH) {
|
|
25330
|
-
const ARROWWIDTH = 0.35;
|
|
25331
|
-
return ARROW_LENGTH2 + penwidth * Math.sqrt(1 + ARROWWIDTH * ARROWWIDTH) / (2 * ARROWWIDTH);
|
|
25332
|
-
}
|
|
25333
|
-
function nodeInsideFn2(box) {
|
|
25334
|
-
const halfW = (box.lw + box.rw) / 2;
|
|
25335
|
-
const halfH = box.ht / 2;
|
|
25336
|
-
const pw = box.penwidth ?? DEFAULT_NODEPENWIDTH;
|
|
25337
|
-
return box.isEllipse ? makeEllipseInsideFn(halfW, halfH, pw) : makeBoxInsideFn(halfW, halfH, pw);
|
|
25338
|
-
}
|
|
25339
|
-
function clipToNodes(bezier, tailBox, headBox, penwidth = DEFAULT_NODEPENWIDTH, clip = CLIP_BOTH) {
|
|
25340
|
-
const step1 = clip.tail ? bezierClipNode(bezier, tailBox.center.x, tailBox.center.y, nodeInsideFn2(tailBox), true) : bezier;
|
|
25341
|
-
const step2 = clip.head ? bezierClipNode(step1, headBox.center.x, headBox.center.y, nodeInsideFn2(headBox), false) : step1;
|
|
25342
|
-
const arrowTip = step2[3];
|
|
25343
|
-
const elen = normalArrowLen(penwidth);
|
|
25344
|
-
const clipped = arrowEndClip(step2, arrowTip, elen);
|
|
25345
|
-
const arrowDir = normalizeVec({
|
|
25346
|
-
x: clipped[3].x - arrowTip.x,
|
|
25347
|
-
y: clipped[3].y - arrowTip.y
|
|
25348
|
-
});
|
|
25349
|
-
return { clipped, arrowTip, arrowDir };
|
|
25350
|
-
}
|
|
25351
|
-
function routeWithRank(tailBox, headBox, rank3, penwidth = DEFAULT_NODEPENWIDTH, port) {
|
|
25352
|
-
const corridor = port ? { tailP: port.tailP, headP: port.headP } : void 0;
|
|
25353
|
-
const { startPt, endPt, boxes } = buildRankCorridor(tailBox, headBox, rank3, corridor);
|
|
25354
|
-
const bezier = computeSpline(boxes, startPt, endPt);
|
|
25355
|
-
const clip = port ? { tail: port.clipTail, head: port.clipHead } : CLIP_BOTH;
|
|
25356
|
-
const { clipped, arrowTip, arrowDir } = clipToNodes(bezier, tailBox, headBox, penwidth, clip);
|
|
25357
|
-
return { bezierPts: clipped, arrowTip, arrowDir };
|
|
25358
|
-
}
|
|
25359
|
-
function routeSimple(tailBox, headBox, routeBezierFn) {
|
|
25360
|
-
const dir = normalizeVec({
|
|
25361
|
-
x: headBox.center.x - tailBox.center.x,
|
|
25362
|
-
y: headBox.center.y - tailBox.center.y
|
|
25363
|
-
});
|
|
25364
|
-
const headToTail = negateVec(dir);
|
|
25365
|
-
const tailClip = clipToNodeBox(tailBox, dir);
|
|
25366
|
-
const arrowTip = clipToNodeBox(headBox, headToTail);
|
|
25367
|
-
return {
|
|
25368
|
-
bezierPts: routeBezierFn(tailClip, offsetPoint(arrowTip, headToTail, ARROW_LENGTH2)),
|
|
25369
|
-
arrowTip,
|
|
25370
|
-
arrowDir: headToTail
|
|
25371
|
-
};
|
|
25372
|
-
}
|
|
25373
|
-
|
|
25374
|
-
// src/layout/dot/edge-route-helpers.ts
|
|
25375
|
-
function defaultEdgeDir(g) {
|
|
25376
|
-
return g.kind === "directed" || g.kind === "strict-directed" ? "forward" : "none";
|
|
25377
|
-
}
|
|
25378
|
-
var ELLIPSE_SHAPES = /* @__PURE__ */ new Set([
|
|
25379
|
-
"ellipse",
|
|
25380
|
-
"oval",
|
|
25381
|
-
"circle",
|
|
25382
|
-
"egg",
|
|
25383
|
-
"doublecircle",
|
|
25384
|
-
"Mcircle",
|
|
25385
|
-
"point"
|
|
25386
|
-
]);
|
|
25387
|
-
function recordClipBox(n) {
|
|
25388
|
-
const f = n.info.shape_info;
|
|
25389
|
-
if (!f?.b) return void 0;
|
|
25390
|
-
const halfW = (f.b.ur.x - f.b.ll.x) / 2;
|
|
25391
|
-
return { lw: halfW, rw: halfW, ht: f.b.ur.y - f.b.ll.y };
|
|
25392
|
-
}
|
|
25393
|
-
function nodePenwidthOf(n, g) {
|
|
25394
|
-
const v = nodeAttr(n, g, "penwidth");
|
|
25395
|
-
const pw = v !== void 0 ? parseFloat(v) : NaN;
|
|
25396
|
-
return Number.isFinite(pw) && pw >= 0 ? pw : DEFAULT_NODEPENWIDTH;
|
|
25397
|
-
}
|
|
25398
|
-
function nodeBoxOf(n, g) {
|
|
25399
|
-
const shapeName = nodeAttr(n, g, "shape") ?? "ellipse";
|
|
25400
|
-
const penwidth = nodePenwidthOf(n, g);
|
|
25401
|
-
if (shapeName === "record" || shapeName === "Mrecord") {
|
|
25402
|
-
const rb = recordClipBox(n);
|
|
25403
|
-
if (rb) return { center: n.info.coord, ...rb, isEllipse: false, penwidth };
|
|
25182
|
+
return 0;
|
|
25404
25183
|
}
|
|
25405
|
-
|
|
25406
|
-
|
|
25407
|
-
const
|
|
25408
|
-
|
|
25409
|
-
const
|
|
25410
|
-
const
|
|
25411
|
-
|
|
25412
|
-
|
|
25413
|
-
|
|
25414
|
-
|
|
25415
|
-
|
|
25416
|
-
isEllipse: ELLIPSE_SHAPES.has(shapeName),
|
|
25417
|
-
penwidth: 0
|
|
25418
|
-
};
|
|
25184
|
+
static reallyRoute(state3, inps, ev0, ev1) {
|
|
25185
|
+
const tnas = _RouteHelper.initTnas(inps, ev0, ev1);
|
|
25186
|
+
const ends = _RouteHelper.mkspline(inps, tnas, ev0, ev1);
|
|
25187
|
+
if (_RouteHelper.splineFits(state3, ends, inps)) return true;
|
|
25188
|
+
const maxi = _RouteHelper.findMaxDev(inps, tnas, ends);
|
|
25189
|
+
const sv1 = _RouteHelper.normv(_RouteHelper.ptSub(inps[maxi], inps[maxi - 1]));
|
|
25190
|
+
const sv2 = _RouteHelper.normv(_RouteHelper.ptSub(inps[maxi + 1], inps[maxi]));
|
|
25191
|
+
const splitv = _RouteHelper.normv(_RouteHelper.ptAdd(sv1, sv2));
|
|
25192
|
+
if (!_RouteHelper.reallyRoute(state3, inps.slice(0, maxi + 1), ev0, splitv)) return false;
|
|
25193
|
+
if (!_RouteHelper.reallyRoute(state3, inps.slice(maxi), splitv, ev1)) return false;
|
|
25194
|
+
return true;
|
|
25419
25195
|
}
|
|
25420
|
-
|
|
25421
|
-
|
|
25422
|
-
|
|
25423
|
-
|
|
25424
|
-
|
|
25425
|
-
|
|
25426
|
-
|
|
25427
|
-
}
|
|
25196
|
+
static run(barriers, route, slopes) {
|
|
25197
|
+
const state3 = { ops: [], barriers };
|
|
25198
|
+
const ev0 = _RouteHelper.normv(slopes[0]);
|
|
25199
|
+
const ev1 = _RouteHelper.normv(slopes[1]);
|
|
25200
|
+
state3.ops.push(route[0]);
|
|
25201
|
+
_RouteHelper.reallyRoute(state3, route, ev0, ev1);
|
|
25202
|
+
return state3.ops;
|
|
25203
|
+
}
|
|
25204
|
+
};
|
|
25205
|
+
function routeSpline(barriers, route, slopes) {
|
|
25206
|
+
return RouteHelper.run(barriers, route, slopes);
|
|
25428
25207
|
}
|
|
25429
|
-
function
|
|
25430
|
-
|
|
25208
|
+
function polyBarriers(polys) {
|
|
25209
|
+
const out = [];
|
|
25210
|
+
for (const poly of polys) {
|
|
25211
|
+
const n = poly.ps.length;
|
|
25212
|
+
for (let j = 0; j < n; j++) out.push({ a: poly.ps[j], b: poly.ps[(j + 1) % n] });
|
|
25213
|
+
}
|
|
25214
|
+
return out;
|
|
25431
25215
|
}
|
|
25432
|
-
function
|
|
25433
|
-
const
|
|
25434
|
-
|
|
25216
|
+
function makePolyline(pts) {
|
|
25217
|
+
const out = [];
|
|
25218
|
+
out.push(pts[0], pts[0]);
|
|
25219
|
+
for (let i = 1; i + 1 < pts.length; i++) out.push(pts[i], pts[i], pts[i]);
|
|
25220
|
+
out.push(pts[pts.length - 1], pts[pts.length - 1]);
|
|
25221
|
+
return out;
|
|
25435
25222
|
}
|
|
25436
|
-
|
|
25437
|
-
|
|
25438
|
-
|
|
25439
|
-
|
|
25440
|
-
|
|
25441
|
-
|
|
25442
|
-
|
|
25443
|
-
|
|
25444
|
-
|
|
25223
|
+
|
|
25224
|
+
// src/pathplan/triang.ts
|
|
25225
|
+
var ISCCW = 1;
|
|
25226
|
+
var ISCW = 2;
|
|
25227
|
+
var ISON = 3;
|
|
25228
|
+
var SPLIT2 = 134217729;
|
|
25229
|
+
function twoProductErr(a, b, P) {
|
|
25230
|
+
const ac = SPLIT2 * a;
|
|
25231
|
+
const ahi = ac - (ac - a);
|
|
25232
|
+
const alo = a - ahi;
|
|
25233
|
+
const bc = SPLIT2 * b;
|
|
25234
|
+
const bhi = bc - (bc - b);
|
|
25235
|
+
const blo = b - bhi;
|
|
25236
|
+
return ahi * bhi - P + ahi * blo + alo * bhi + alo * blo;
|
|
25445
25237
|
}
|
|
25446
|
-
function
|
|
25447
|
-
|
|
25238
|
+
function twoDiffTail(P, D, s) {
|
|
25239
|
+
const bvirt = P - s;
|
|
25240
|
+
const avirt = s + bvirt;
|
|
25241
|
+
const bround = bvirt - D;
|
|
25242
|
+
const around = P - avirt;
|
|
25243
|
+
return around + bround;
|
|
25448
25244
|
}
|
|
25449
|
-
|
|
25450
|
-
|
|
25451
|
-
|
|
25452
|
-
|
|
25453
|
-
|
|
25454
|
-
|
|
25455
|
-
|
|
25245
|
+
var dyadicView = new DataView(new ArrayBuffer(8));
|
|
25246
|
+
function dyadic(x) {
|
|
25247
|
+
if (x === 0) return { m: 0n, e: 0 };
|
|
25248
|
+
dyadicView.setFloat64(0, x);
|
|
25249
|
+
const hi = dyadicView.getUint32(0);
|
|
25250
|
+
const lo = dyadicView.getUint32(4);
|
|
25251
|
+
const sign2 = hi >>> 31 ? -1n : 1n;
|
|
25252
|
+
const biasedExp = hi >>> 20 & 2047;
|
|
25253
|
+
let mant = BigInt(hi & 1048575) << 32n | BigInt(lo);
|
|
25254
|
+
let e;
|
|
25255
|
+
if (biasedExp === 0) {
|
|
25256
|
+
e = -1074;
|
|
25257
|
+
} else {
|
|
25258
|
+
mant |= 1n << 52n;
|
|
25259
|
+
e = biasedExp - 1075;
|
|
25456
25260
|
}
|
|
25261
|
+
return { m: sign2 * mant, e };
|
|
25457
25262
|
}
|
|
25458
|
-
function
|
|
25459
|
-
|
|
25460
|
-
const
|
|
25461
|
-
const
|
|
25462
|
-
|
|
25463
|
-
|
|
25464
|
-
|
|
25465
|
-
const noBarriers = [];
|
|
25466
|
-
const zero = { x: 0, y: 0 };
|
|
25467
|
-
const raw = routeSpline(noBarriers, [from, to], [zero, zero]);
|
|
25468
|
-
if (!isUsableSpline(raw)) return linearBezier(from, to);
|
|
25469
|
-
return [raw[0], raw[1], raw[2], raw[3]];
|
|
25470
|
-
}
|
|
25471
|
-
function straightEdgeSplineWithRank(tailBox, headBox, rankInfo, penwidth = 1, port) {
|
|
25472
|
-
return rankInfo !== void 0 ? routeWithRank(tailBox, headBox, rankInfo, penwidth, port) : routeSimple(tailBox, headBox, routeBezier);
|
|
25263
|
+
function signOfSum3(a, b, c) {
|
|
25264
|
+
const da = dyadic(a);
|
|
25265
|
+
const db = dyadic(b);
|
|
25266
|
+
const dc = dyadic(c);
|
|
25267
|
+
const e = Math.min(da.e, db.e, dc.e);
|
|
25268
|
+
const sum = (da.m << BigInt(da.e - e)) + (db.m << BigInt(db.e - e)) + (dc.m << BigInt(dc.e - e));
|
|
25269
|
+
return sum > 0n ? 1 : sum < 0n ? -1 : 0;
|
|
25473
25270
|
}
|
|
25474
|
-
|
|
25475
|
-
|
|
25476
|
-
|
|
25477
|
-
|
|
25478
|
-
|
|
25479
|
-
|
|
25480
|
-
|
|
25271
|
+
var TriangHelper = class _TriangHelper {
|
|
25272
|
+
static ccw(p1, p2, p3) {
|
|
25273
|
+
const a = p1.y - p2.y;
|
|
25274
|
+
const b = p3.x - p2.x;
|
|
25275
|
+
const c = p3.y - p2.y;
|
|
25276
|
+
const e = p1.x - p2.x;
|
|
25277
|
+
const P = a * b;
|
|
25278
|
+
const D = c * e;
|
|
25279
|
+
const d = P - D;
|
|
25280
|
+
const bound = 23e-17 * (Math.abs(P) + Math.abs(D));
|
|
25281
|
+
if (d > bound) return ISCW;
|
|
25282
|
+
if (d < -bound) return ISCCW;
|
|
25283
|
+
const err = twoProductErr(a, b, P);
|
|
25284
|
+
const s = P - D;
|
|
25285
|
+
const tail = twoDiffTail(P, D, s);
|
|
25286
|
+
const sign2 = signOfSum3(s, tail, err);
|
|
25287
|
+
return sign2 > 0 ? ISCW : sign2 < 0 ? ISCCW : ISON;
|
|
25288
|
+
}
|
|
25289
|
+
/** Is pc on segment [pa, pb]? */
|
|
25290
|
+
static between(pa, pb, pc) {
|
|
25291
|
+
if (_TriangHelper.ccw(pa, pb, pc) !== ISON) return false;
|
|
25292
|
+
const pba = { x: pb.x - pa.x, y: pb.y - pa.y };
|
|
25293
|
+
const pca = { x: pc.x - pa.x, y: pc.y - pa.y };
|
|
25294
|
+
return pca.x * pba.x + pca.y * pba.y >= 0 && pca.x * pca.x + pca.y * pca.y <= pba.x * pba.x + pba.y * pba.y;
|
|
25295
|
+
}
|
|
25296
|
+
static anyCollinear(pa, pb, pc, pd) {
|
|
25297
|
+
const c = _TriangHelper.ccw;
|
|
25298
|
+
return c(pa, pb, pc) === ISON || c(pa, pb, pd) === ISON || c(pc, pd, pa) === ISON || c(pc, pd, pb) === ISON;
|
|
25299
|
+
}
|
|
25300
|
+
static collinearIntersects(pa, pb, pc, pd) {
|
|
25301
|
+
const b = _TriangHelper.between;
|
|
25302
|
+
return b(pa, pb, pc) || b(pa, pb, pd) || b(pc, pd, pa) || b(pc, pd, pb);
|
|
25303
|
+
}
|
|
25304
|
+
static crossIntersects(pa, pb, pc, pd) {
|
|
25305
|
+
const c = _TriangHelper.ccw;
|
|
25306
|
+
const c1 = c(pa, pb, pc) === ISCCW ? 1 : 0;
|
|
25307
|
+
const c2 = c(pa, pb, pd) === ISCCW ? 1 : 0;
|
|
25308
|
+
const c3 = c(pc, pd, pa) === ISCCW ? 1 : 0;
|
|
25309
|
+
const c4 = c(pc, pd, pb) === ISCCW ? 1 : 0;
|
|
25310
|
+
return (c1 ^ c2) !== 0 && (c3 ^ c4) !== 0;
|
|
25311
|
+
}
|
|
25312
|
+
static intersects(pa, pb, pc, pd) {
|
|
25313
|
+
if (_TriangHelper.anyCollinear(pa, pb, pc, pd))
|
|
25314
|
+
return _TriangHelper.collinearIntersects(pa, pb, pc, pd);
|
|
25315
|
+
return _TriangHelper.crossIntersects(pa, pb, pc, pd);
|
|
25316
|
+
}
|
|
25317
|
+
static isdiagNeighborhood(i, ip2, get, pointn) {
|
|
25318
|
+
const ip1 = (i + 1) % pointn;
|
|
25319
|
+
const im1 = (i + pointn - 1) % pointn;
|
|
25320
|
+
const c = _TriangHelper.ccw;
|
|
25321
|
+
if (c(get(im1), get(i), get(ip1)) === ISCCW) {
|
|
25322
|
+
return c(get(i), get(ip2), get(im1)) === ISCCW && c(get(ip2), get(i), get(ip1)) === ISCCW;
|
|
25481
25323
|
}
|
|
25324
|
+
return c(get(i), get(ip2), get(ip1)) === ISCW;
|
|
25482
25325
|
}
|
|
25483
|
-
|
|
25484
|
-
|
|
25485
|
-
|
|
25486
|
-
|
|
25487
|
-
|
|
25488
|
-
|
|
25489
|
-
|
|
25490
|
-
|
|
25491
|
-
|
|
25492
|
-
|
|
25493
|
-
|
|
25494
|
-
)
|
|
25495
|
-
|
|
25496
|
-
|
|
25497
|
-
|
|
25498
|
-
|
|
25499
|
-
|
|
25500
|
-
|
|
25501
|
-
|
|
25502
|
-
|
|
25503
|
-
|
|
25504
|
-
|
|
25505
|
-
|
|
25506
|
-
|
|
25507
|
-
|
|
25508
|
-
|
|
25509
|
-
function averageDirection(u, edges) {
|
|
25510
|
-
let sx = 0, sy = 0;
|
|
25511
|
-
for (const e of edges) {
|
|
25512
|
-
const v = e.head === u ? e.tail : e.head;
|
|
25513
|
-
const dx = v.info.coord.x - u.info.coord.x;
|
|
25514
|
-
const dy = v.info.coord.y - u.info.coord.y;
|
|
25515
|
-
const r2 = Math.hypot(dx, dy);
|
|
25516
|
-
if (r2 !== 0) {
|
|
25517
|
-
sx += dx / r2;
|
|
25518
|
-
sy += dy / r2;
|
|
25326
|
+
static isdiagonal(i, ip2, get, pointn) {
|
|
25327
|
+
if (!_TriangHelper.isdiagNeighborhood(i, ip2, get, pointn)) return false;
|
|
25328
|
+
for (let j = 0; j < pointn; j++) {
|
|
25329
|
+
const jp1 = (j + 1) % pointn;
|
|
25330
|
+
if (j !== i && jp1 !== i && j !== ip2 && jp1 !== ip2) {
|
|
25331
|
+
if (_TriangHelper.intersects(get(i), get(ip2), get(j), get(jp1)))
|
|
25332
|
+
return false;
|
|
25333
|
+
}
|
|
25334
|
+
}
|
|
25335
|
+
return true;
|
|
25336
|
+
}
|
|
25337
|
+
static triangulateInner(pts, fn) {
|
|
25338
|
+
let cur = pts;
|
|
25339
|
+
while (cur.length > 3) {
|
|
25340
|
+
const n = cur.length;
|
|
25341
|
+
let cut = -1;
|
|
25342
|
+
for (let i = 0; i < n; i++) {
|
|
25343
|
+
const ip2 = (i + 2) % n;
|
|
25344
|
+
if (_TriangHelper.isdiagonal(i, ip2, (k) => cur[k], n)) {
|
|
25345
|
+
fn([cur[i], cur[(i + 1) % n], cur[ip2]]);
|
|
25346
|
+
cut = (i + 1) % n;
|
|
25347
|
+
break;
|
|
25348
|
+
}
|
|
25349
|
+
}
|
|
25350
|
+
if (cut === -1) return false;
|
|
25351
|
+
cur = cur.filter((_, idx) => idx !== cut);
|
|
25519
25352
|
}
|
|
25353
|
+
fn([cur[0], cur[1], cur[2]]);
|
|
25354
|
+
return true;
|
|
25520
25355
|
}
|
|
25521
|
-
|
|
25522
|
-
|
|
25523
|
-
|
|
25524
|
-
function buildSharedPort(u, edges, ranksep) {
|
|
25525
|
-
const dir = averageDirection(u, edges);
|
|
25526
|
-
const { x1, y1 } = computeBoundaryOffset(u, dir.x, dir.y, ranksep);
|
|
25527
|
-
const px = cround(x1);
|
|
25528
|
-
const py = cround(y1);
|
|
25529
|
-
const lw = u.info.lw ?? 0;
|
|
25530
|
-
const rw = u.info.rw ?? 0;
|
|
25531
|
-
const order = lw + rw !== 0 ? MC_SCALE * (lw + px) / (lw + rw) : 0;
|
|
25532
|
-
return {
|
|
25533
|
-
p: { x: px, y: py },
|
|
25534
|
-
theta: 0,
|
|
25535
|
-
bp: null,
|
|
25536
|
-
defined: true,
|
|
25537
|
-
constrained: false,
|
|
25538
|
-
clip: false,
|
|
25539
|
-
dyna: false,
|
|
25540
|
-
order,
|
|
25541
|
-
side: 0,
|
|
25542
|
-
name: null
|
|
25543
|
-
};
|
|
25356
|
+
};
|
|
25357
|
+
function ccw(p1, p2, p3) {
|
|
25358
|
+
return TriangHelper.ccw(p1, p2, p3);
|
|
25544
25359
|
}
|
|
25545
|
-
function
|
|
25546
|
-
|
|
25547
|
-
if (f.tail === u) f.info.tail_port = prt;
|
|
25360
|
+
function isdiagonal(i, ip2, get, pointn) {
|
|
25361
|
+
return TriangHelper.isdiagonal(i, ip2, get, pointn);
|
|
25548
25362
|
}
|
|
25549
|
-
|
|
25550
|
-
|
|
25551
|
-
|
|
25363
|
+
|
|
25364
|
+
// src/pathplan/shortest.ts
|
|
25365
|
+
var NO_TRI = -1;
|
|
25366
|
+
var DQ_FRONT = 1;
|
|
25367
|
+
var DQ_BACK = 2;
|
|
25368
|
+
var ShortestHelper = class _ShortestHelper {
|
|
25369
|
+
static buildTri(a, b, c) {
|
|
25370
|
+
const mk = (p0, p1) => ({ pnl0: p0, pnl1: p1, rightIndex: NO_TRI });
|
|
25371
|
+
return { mark: 0, e: [mk(a, b), mk(b, c), mk(c, a)] };
|
|
25552
25372
|
}
|
|
25553
|
-
|
|
25554
|
-
|
|
25555
|
-
|
|
25556
|
-
|
|
25373
|
+
static triInner(pnlps, tris) {
|
|
25374
|
+
let pts = pnlps;
|
|
25375
|
+
while (pts.length > 3) {
|
|
25376
|
+
const n = pts.length;
|
|
25377
|
+
let cut = -1;
|
|
25378
|
+
for (let i = 0; i < n; i++) {
|
|
25379
|
+
const ip2 = (i + 2) % n;
|
|
25380
|
+
if (isdiagonal(i, ip2, (k) => pts[k].pp, n)) {
|
|
25381
|
+
tris.push(_ShortestHelper.buildTri(pts[i], pts[(i + 1) % n], pts[ip2]));
|
|
25382
|
+
cut = (i + 1) % n;
|
|
25383
|
+
break;
|
|
25384
|
+
}
|
|
25385
|
+
}
|
|
25386
|
+
if (cut === -1) return false;
|
|
25387
|
+
pts = pts.filter((_, j) => j !== cut);
|
|
25388
|
+
}
|
|
25389
|
+
tris.push(_ShortestHelper.buildTri(pts[0], pts[1], pts[2]));
|
|
25390
|
+
return true;
|
|
25557
25391
|
}
|
|
25558
|
-
|
|
25559
|
-
|
|
25560
|
-
|
|
25561
|
-
|
|
25562
|
-
|
|
25392
|
+
static connectTri(i, j, tris) {
|
|
25393
|
+
const t1 = tris[i], t2 = tris[j];
|
|
25394
|
+
for (let ei = 0; ei < 3; ei++) {
|
|
25395
|
+
for (let ej = 0; ej < 3; ej++) {
|
|
25396
|
+
const e1 = t1.e[ei], e2 = t2.e[ej];
|
|
25397
|
+
if (e1.pnl0 === e2.pnl0 && e1.pnl1 === e2.pnl1 || e1.pnl0 === e2.pnl1 && e1.pnl1 === e2.pnl0)
|
|
25398
|
+
e1.rightIndex = j, e2.rightIndex = i;
|
|
25399
|
+
}
|
|
25400
|
+
}
|
|
25563
25401
|
}
|
|
25564
|
-
|
|
25565
|
-
|
|
25566
|
-
|
|
25567
|
-
|
|
25568
|
-
for (const e of edges) assignPortToAllVirts(e, u, prt);
|
|
25569
|
-
u.info.has_port = true;
|
|
25570
|
-
}
|
|
25571
|
-
function graphHasSamehead(g) {
|
|
25572
|
-
for (const e of g.edges) {
|
|
25573
|
-
if (e.info.samehead !== void 0) return true;
|
|
25402
|
+
static connectAll(tris) {
|
|
25403
|
+
for (let i = 0; i < tris.length; i++)
|
|
25404
|
+
for (let j = i + 1; j < tris.length; j++)
|
|
25405
|
+
_ShortestHelper.connectTri(i, j, tris);
|
|
25574
25406
|
}
|
|
25575
|
-
|
|
25576
|
-
|
|
25577
|
-
|
|
25578
|
-
|
|
25579
|
-
|
|
25407
|
+
static pointInTri(tri, p) {
|
|
25408
|
+
let sum = 0;
|
|
25409
|
+
for (let ei = 0; ei < 3; ei++)
|
|
25410
|
+
if (ccw(tri.e[ei].pnl0.pp, tri.e[ei].pnl1.pp, p) !== ISCW) sum++;
|
|
25411
|
+
return sum === 3 || sum === 0;
|
|
25580
25412
|
}
|
|
25581
|
-
|
|
25582
|
-
|
|
25583
|
-
|
|
25584
|
-
|
|
25585
|
-
|
|
25586
|
-
|
|
25587
|
-
|
|
25588
|
-
|
|
25413
|
+
static markPath(tris, trii, trij) {
|
|
25414
|
+
if (tris[trii].mark) return false;
|
|
25415
|
+
tris[trii].mark = 1;
|
|
25416
|
+
if (trii === trij) return true;
|
|
25417
|
+
for (let ei = 0; ei < 3; ei++) {
|
|
25418
|
+
const ri = tris[trii].e[ei].rightIndex;
|
|
25419
|
+
if (ri !== NO_TRI && _ShortestHelper.markPath(tris, ri, trij)) return true;
|
|
25420
|
+
}
|
|
25421
|
+
tris[trii].mark = 0;
|
|
25422
|
+
return false;
|
|
25589
25423
|
}
|
|
25590
|
-
|
|
25591
|
-
|
|
25592
|
-
|
|
25593
|
-
|
|
25594
|
-
for (const e of n.root.edges) {
|
|
25595
|
-
if (e.head === n && e.tail === n) continue;
|
|
25596
|
-
const id = e.tail === n ? e.info.sametail : void 0;
|
|
25597
|
-
if (id && id !== "") sameedge(same, e, id);
|
|
25424
|
+
static findTri(tris, p) {
|
|
25425
|
+
for (let i = 0; i < tris.length; i++)
|
|
25426
|
+
if (_ShortestHelper.pointInTri(tris[i], p)) return i;
|
|
25427
|
+
return NO_TRI;
|
|
25598
25428
|
}
|
|
25599
|
-
|
|
25600
|
-
|
|
25601
|
-
|
|
25602
|
-
|
|
25603
|
-
|
|
25429
|
+
static findMinX(ps) {
|
|
25430
|
+
let minx = Infinity, minpi = 0;
|
|
25431
|
+
for (let i = 0; i < ps.length; i++)
|
|
25432
|
+
if (ps[i].x < minx) {
|
|
25433
|
+
minx = ps[i].x;
|
|
25434
|
+
minpi = i;
|
|
25435
|
+
}
|
|
25436
|
+
return minpi;
|
|
25604
25437
|
}
|
|
25605
|
-
|
|
25606
|
-
|
|
25607
|
-
|
|
25608
|
-
|
|
25609
|
-
|
|
25610
|
-
|
|
25611
|
-
|
|
25612
|
-
if (hasSH) applyGroupsToNode(n, collectSamehead(n), ranksep);
|
|
25613
|
-
if (hasST) applyGroupsToNode(n, collectSametail(n), ranksep);
|
|
25438
|
+
static isPolyCW(ps, minpi) {
|
|
25439
|
+
const pn = ps.length;
|
|
25440
|
+
const p2 = ps[minpi];
|
|
25441
|
+
const p1 = ps[minpi === 0 ? pn - 1 : minpi - 1];
|
|
25442
|
+
const p3 = ps[(minpi + 1) % pn];
|
|
25443
|
+
if (p1.x === p2.x && p2.x === p3.x && p3.y > p2.y) return true;
|
|
25444
|
+
return ccw(p1, p2, p3) !== ISCCW;
|
|
25614
25445
|
}
|
|
25615
|
-
|
|
25616
|
-
|
|
25617
|
-
|
|
25618
|
-
|
|
25619
|
-
|
|
25620
|
-
|
|
25621
|
-
|
|
25622
|
-
}
|
|
25623
|
-
|
|
25624
|
-
|
|
25625
|
-
|
|
25626
|
-
|
|
25627
|
-
|
|
25628
|
-
|
|
25629
|
-
|
|
25630
|
-
|
|
25631
|
-
|
|
25632
|
-
|
|
25633
|
-
|
|
25634
|
-
|
|
25635
|
-
|
|
25636
|
-
|
|
25637
|
-
|
|
25638
|
-
|
|
25639
|
-
|
|
25640
|
-
|
|
25641
|
-
|
|
25642
|
-
|
|
25643
|
-
if (
|
|
25644
|
-
|
|
25645
|
-
|
|
25646
|
-
|
|
25647
|
-
|
|
25446
|
+
static loadForward(ps) {
|
|
25447
|
+
const r = [];
|
|
25448
|
+
for (let i = 0; i < ps.length; i++) {
|
|
25449
|
+
if (i > 0 && ps[i].x === ps[i - 1].x && ps[i].y === ps[i - 1].y) continue;
|
|
25450
|
+
r.push({ pp: ps[i], link: null });
|
|
25451
|
+
}
|
|
25452
|
+
return r;
|
|
25453
|
+
}
|
|
25454
|
+
static loadReverse(ps) {
|
|
25455
|
+
const r = [];
|
|
25456
|
+
for (let i = ps.length - 1; i >= 0; i--) {
|
|
25457
|
+
if (i < ps.length - 1 && ps[i].x === ps[i + 1].x && ps[i].y === ps[i + 1].y) continue;
|
|
25458
|
+
r.push({ pp: ps[i], link: null });
|
|
25459
|
+
}
|
|
25460
|
+
return r;
|
|
25461
|
+
}
|
|
25462
|
+
static loadPoints(poly) {
|
|
25463
|
+
const ps = poly.ps;
|
|
25464
|
+
return _ShortestHelper.isPolyCW(ps, _ShortestHelper.findMinX(ps)) ? _ShortestHelper.loadReverse(ps) : _ShortestHelper.loadForward(ps);
|
|
25465
|
+
}
|
|
25466
|
+
static initDeque(pnll) {
|
|
25467
|
+
const pnlpn = pnll * 2;
|
|
25468
|
+
const pnlps = new Array(pnlpn).fill(null);
|
|
25469
|
+
const fpnlpi = Math.floor(pnlpn / 2);
|
|
25470
|
+
return { pnlps, pnlpn, fpnlpi, lpnlpi: fpnlpi - 1, apex: 0 };
|
|
25471
|
+
}
|
|
25472
|
+
static add2dq(dq, side, pnl) {
|
|
25473
|
+
if (side === DQ_FRONT) {
|
|
25474
|
+
if (dq.lpnlpi >= dq.fpnlpi) pnl.link = dq.pnlps[dq.fpnlpi];
|
|
25475
|
+
dq.fpnlpi--;
|
|
25476
|
+
dq.pnlps[dq.fpnlpi] = pnl;
|
|
25477
|
+
} else {
|
|
25478
|
+
if (dq.lpnlpi >= dq.fpnlpi) pnl.link = dq.pnlps[dq.lpnlpi];
|
|
25479
|
+
dq.lpnlpi++;
|
|
25480
|
+
dq.pnlps[dq.lpnlpi] = pnl;
|
|
25481
|
+
}
|
|
25482
|
+
}
|
|
25483
|
+
static splitdq(dq, side, index) {
|
|
25484
|
+
if (side === DQ_FRONT) dq.lpnlpi = index;
|
|
25485
|
+
else dq.fpnlpi = index;
|
|
25486
|
+
}
|
|
25487
|
+
static finddqsplit(dq, pnl) {
|
|
25488
|
+
for (let idx = dq.fpnlpi; idx < dq.apex; idx++)
|
|
25489
|
+
if (ccw(dq.pnlps[idx + 1].pp, dq.pnlps[idx].pp, pnl.pp) === ISCCW) return idx;
|
|
25490
|
+
for (let idx = dq.lpnlpi; idx > dq.apex; idx--)
|
|
25491
|
+
if (ccw(dq.pnlps[idx - 1].pp, dq.pnlps[idx].pp, pnl.pp) === ISCW) return idx;
|
|
25492
|
+
return dq.apex;
|
|
25493
|
+
}
|
|
25494
|
+
static fuFindEi(trip, tris) {
|
|
25495
|
+
for (let ei = 0; ei < 3; ei++) {
|
|
25496
|
+
const ri = trip.e[ei].rightIndex;
|
|
25497
|
+
if (ri !== NO_TRI && tris[ri].mark === 1) return ei;
|
|
25498
|
+
}
|
|
25499
|
+
return 3;
|
|
25500
|
+
}
|
|
25501
|
+
static fuNextTri(trip, tris) {
|
|
25502
|
+
for (let ei = 0; ei < 3; ei++) {
|
|
25503
|
+
const ri = trip.e[ei].rightIndex;
|
|
25504
|
+
if (ri !== NO_TRI && tris[ri].mark === 1) return ri;
|
|
25648
25505
|
}
|
|
25506
|
+
return NO_TRI;
|
|
25649
25507
|
}
|
|
25650
|
-
|
|
25651
|
-
|
|
25652
|
-
|
|
25653
|
-
|
|
25654
|
-
const c = [bz.list[j], bz.list[j + 1], bz.list[j + 2], bz.list[j + 3]];
|
|
25655
|
-
let lo = 0;
|
|
25656
|
-
let hi = 1;
|
|
25657
|
-
let dlo2 = dist2(c[0], pt);
|
|
25658
|
-
let dhi2 = dist2(c[3], pt);
|
|
25659
|
-
let pt2 = c[0];
|
|
25660
|
-
for (; ; ) {
|
|
25661
|
-
const t = (lo + hi) / 2;
|
|
25662
|
-
pt2 = evalBez4(c, t);
|
|
25663
|
-
if (Math.abs(dlo2 - dhi2) < 1 || Math.abs(hi - lo) < 1e-5) break;
|
|
25664
|
-
if (dlo2 < dhi2) {
|
|
25665
|
-
hi = t;
|
|
25666
|
-
dhi2 = dist2(pt2, pt);
|
|
25667
|
-
} else {
|
|
25668
|
-
lo = t;
|
|
25669
|
-
dlo2 = dist2(pt2, pt);
|
|
25670
|
-
}
|
|
25508
|
+
static fuGetPairLast(epnl1, dq) {
|
|
25509
|
+
if (ccw(epnl1.pp, dq.pnlps[dq.fpnlpi].pp, dq.pnlps[dq.lpnlpi].pp) === ISCCW)
|
|
25510
|
+
return [dq.pnlps[dq.lpnlpi], epnl1];
|
|
25511
|
+
return [epnl1, dq.pnlps[dq.lpnlpi]];
|
|
25671
25512
|
}
|
|
25672
|
-
|
|
25673
|
-
|
|
25674
|
-
|
|
25675
|
-
|
|
25676
|
-
|
|
25677
|
-
for (let j = 0, k = 3; k < bz.list.length; j += 3, k += 3)
|
|
25678
|
-
total += distPt(bz.list[j], bz.list[k]);
|
|
25513
|
+
static fuGetPairNormal(trip, ei) {
|
|
25514
|
+
const e = trip.e[ei];
|
|
25515
|
+
const pnl = trip.e[(ei + 1) % 3].pnl1;
|
|
25516
|
+
if (ccw(e.pnl0.pp, pnl.pp, e.pnl1.pp) === ISCCW) return [e.pnl1, e.pnl0];
|
|
25517
|
+
return [e.pnl0, e.pnl1];
|
|
25679
25518
|
}
|
|
25680
|
-
|
|
25681
|
-
|
|
25682
|
-
|
|
25683
|
-
|
|
25684
|
-
|
|
25685
|
-
|
|
25686
|
-
|
|
25687
|
-
|
|
25688
|
-
|
|
25689
|
-
|
|
25690
|
-
|
|
25691
|
-
|
|
25692
|
-
|
|
25519
|
+
static fuUpdateRight(dq, r) {
|
|
25520
|
+
const si = _ShortestHelper.finddqsplit(dq, r);
|
|
25521
|
+
_ShortestHelper.splitdq(dq, DQ_BACK, si);
|
|
25522
|
+
_ShortestHelper.add2dq(dq, DQ_FRONT, r);
|
|
25523
|
+
if (si > dq.apex) dq.apex = si;
|
|
25524
|
+
}
|
|
25525
|
+
static fuUpdateLeft(dq, l) {
|
|
25526
|
+
const si = _ShortestHelper.finddqsplit(dq, l);
|
|
25527
|
+
_ShortestHelper.splitdq(dq, DQ_FRONT, si);
|
|
25528
|
+
_ShortestHelper.add2dq(dq, DQ_BACK, l);
|
|
25529
|
+
if (si < dq.apex) dq.apex = si;
|
|
25530
|
+
}
|
|
25531
|
+
static fuUpdate(dq, l, r, isFirst) {
|
|
25532
|
+
if (isFirst) {
|
|
25533
|
+
_ShortestHelper.add2dq(dq, DQ_BACK, l);
|
|
25534
|
+
_ShortestHelper.add2dq(dq, DQ_FRONT, r);
|
|
25535
|
+
return;
|
|
25693
25536
|
}
|
|
25537
|
+
if (dq.pnlps[dq.fpnlpi] !== r && dq.pnlps[dq.lpnlpi] !== r)
|
|
25538
|
+
_ShortestHelper.fuUpdateRight(dq, r);
|
|
25539
|
+
else
|
|
25540
|
+
_ShortestHelper.fuUpdateLeft(dq, l);
|
|
25694
25541
|
}
|
|
25695
|
-
|
|
25696
|
-
|
|
25697
|
-
|
|
25698
|
-
|
|
25699
|
-
|
|
25700
|
-
|
|
25701
|
-
|
|
25702
|
-
|
|
25703
|
-
|
|
25704
|
-
}
|
|
25705
|
-
|
|
25706
|
-
// src/common/splines-path-shared.ts
|
|
25707
|
-
function addBox(P, b) {
|
|
25708
|
-
if (b.ll.x < b.ur.x && b.ll.y < b.ur.y) {
|
|
25709
|
-
P.boxes[P.nbox++] = b;
|
|
25542
|
+
static fuLoop(tris, dq, epnls, ftrii) {
|
|
25543
|
+
let trii = ftrii;
|
|
25544
|
+
while (trii !== NO_TRI) {
|
|
25545
|
+
const trip = tris[trii];
|
|
25546
|
+
trip.mark = 2;
|
|
25547
|
+
const ei = _ShortestHelper.fuFindEi(trip, tris);
|
|
25548
|
+
const [l, r] = ei === 3 ? _ShortestHelper.fuGetPairLast(epnls[1], dq) : _ShortestHelper.fuGetPairNormal(trip, ei);
|
|
25549
|
+
_ShortestHelper.fuUpdate(dq, l, r, trii === ftrii);
|
|
25550
|
+
trii = _ShortestHelper.fuNextTri(trip, tris);
|
|
25551
|
+
}
|
|
25710
25552
|
}
|
|
25711
|
-
|
|
25712
|
-
|
|
25713
|
-
|
|
25714
|
-
|
|
25715
|
-
|
|
25716
|
-
const cntOut = outE?.size ?? 0;
|
|
25717
|
-
let sIn = 0;
|
|
25718
|
-
let sOut = 0;
|
|
25719
|
-
for (let i = 0; i < cntIn; i++) sIn += inE.list[i].tail.info.coord.x;
|
|
25720
|
-
for (let i = 0; i < cntOut; i++) sOut += outE.list[i].head.info.coord.x;
|
|
25721
|
-
const x1 = n.info.coord.x - sIn / cntIn;
|
|
25722
|
-
const y1 = n.info.coord.y - inE.list[0].tail.info.coord.y;
|
|
25723
|
-
const x2 = sOut / cntOut - n.info.coord.x;
|
|
25724
|
-
const y2 = outE.list[0].head.info.coord.y - n.info.coord.y;
|
|
25725
|
-
return (Math.atan2(y1, x1) + Math.atan2(y2, x2)) / 2;
|
|
25726
|
-
}
|
|
25727
|
-
var SIDE_PORT = ["s", "e", "n", "w"];
|
|
25728
|
-
var ALL_SIDES2 = TOP | BOTTOM | LEFT | RIGHT;
|
|
25729
|
-
function cvtPt(p, rankdir) {
|
|
25730
|
-
switch (rankdir) {
|
|
25731
|
-
case RANKDIR_BT:
|
|
25732
|
-
return { x: p.x, y: -p.y };
|
|
25733
|
-
case RANKDIR_LR:
|
|
25734
|
-
return { x: -p.y, y: p.x };
|
|
25735
|
-
case RANKDIR_RL:
|
|
25736
|
-
return { x: p.y, y: p.x };
|
|
25737
|
-
default:
|
|
25738
|
-
return { x: p.x, y: p.y };
|
|
25553
|
+
static extractPath(epnl1) {
|
|
25554
|
+
const pts = [];
|
|
25555
|
+
for (let p = epnl1; p !== null; p = p.link) pts.push(p.pp);
|
|
25556
|
+
pts.reverse();
|
|
25557
|
+
return pts;
|
|
25739
25558
|
}
|
|
25740
|
-
|
|
25741
|
-
|
|
25742
|
-
|
|
25743
|
-
|
|
25744
|
-
|
|
25745
|
-
function faceMidpoint(b, ix) {
|
|
25746
|
-
const cx = (b.ll.x + b.ur.x) / 2, cy = (b.ll.y + b.ur.y) / 2;
|
|
25747
|
-
if (ix === BOTTOM_IX) return { x: cx, y: b.ll.y };
|
|
25748
|
-
if (ix === RIGHT_IX) return { x: b.ur.x, y: cy };
|
|
25749
|
-
if (ix === TOP_IX) return { x: cx, y: b.ur.y };
|
|
25750
|
-
return { x: b.ll.x, y: cy };
|
|
25751
|
-
}
|
|
25752
|
-
function closestSide(n, other, port) {
|
|
25753
|
-
const sides = port.side;
|
|
25754
|
-
if (sides === 0 || sides === ALL_SIDES2) return null;
|
|
25755
|
-
const rkd = (n.root.info.rankdir ?? 0) & 3;
|
|
25756
|
-
const pt = cvtPt(n.info.coord, rkd);
|
|
25757
|
-
const opt = cvtPt(other.info.coord, rkd);
|
|
25758
|
-
const b = port.bp ?? nodeBoxLocal(n, rkd === RANKDIR_LR || rkd === RANKDIR_RL);
|
|
25759
|
-
let rv = null;
|
|
25760
|
-
let mind = 0;
|
|
25761
|
-
for (let i = 0; i < 4; i++) {
|
|
25762
|
-
if ((sides & 1 << i) === 0) continue;
|
|
25763
|
-
const m = faceMidpoint(b, i);
|
|
25764
|
-
const d = dist2({ x: m.x + pt.x, y: m.y + pt.y }, opt);
|
|
25765
|
-
if (rv === null || d < mind) {
|
|
25766
|
-
mind = d;
|
|
25767
|
-
rv = SIDE_PORT[i];
|
|
25559
|
+
static run(poly, eps) {
|
|
25560
|
+
const pnlps = _ShortestHelper.loadPoints(poly);
|
|
25561
|
+
const tris = [];
|
|
25562
|
+
if (!_ShortestHelper.triInner(pnlps.slice(), tris)) {
|
|
25563
|
+
console.warn("triangulation failed");
|
|
25768
25564
|
}
|
|
25565
|
+
_ShortestHelper.connectAll(tris);
|
|
25566
|
+
const ftrii = _ShortestHelper.findTri(tris, eps[0]);
|
|
25567
|
+
const ltrii = _ShortestHelper.findTri(tris, eps[1]);
|
|
25568
|
+
if (ftrii === NO_TRI || ltrii === NO_TRI) return null;
|
|
25569
|
+
if (ftrii === ltrii) return [eps[0], eps[1]];
|
|
25570
|
+
if (!_ShortestHelper.markPath(tris, ftrii, ltrii)) return [eps[0], eps[1]];
|
|
25571
|
+
const epnls = [{ pp: eps[0], link: null }, { pp: eps[1], link: null }];
|
|
25572
|
+
const dq = _ShortestHelper.initDeque(pnlps.length);
|
|
25573
|
+
_ShortestHelper.add2dq(dq, DQ_FRONT, epnls[0]);
|
|
25574
|
+
dq.apex = dq.fpnlpi;
|
|
25575
|
+
_ShortestHelper.fuLoop(tris, dq, epnls, ftrii);
|
|
25576
|
+
return _ShortestHelper.extractPath(epnls[1]);
|
|
25769
25577
|
}
|
|
25770
|
-
|
|
25771
|
-
|
|
25772
|
-
|
|
25773
|
-
if (!port.dyna) return port;
|
|
25774
|
-
const compass = closestSide(n, other, port);
|
|
25775
|
-
const rv = makePort();
|
|
25776
|
-
rv.name = port.name;
|
|
25777
|
-
compassPort(n, { bp: port.bp, compass: compass ?? "", sides: port.side }, rv);
|
|
25778
|
-
return rv;
|
|
25578
|
+
};
|
|
25579
|
+
function shortestPath(poly, eps) {
|
|
25580
|
+
return ShortestHelper.run(poly, eps);
|
|
25779
25581
|
}
|
|
25780
|
-
|
|
25781
|
-
|
|
25782
|
-
|
|
25783
|
-
|
|
25784
|
-
|
|
25785
|
-
|
|
25582
|
+
|
|
25583
|
+
// src/layout/dot/edge-route-poly.ts
|
|
25584
|
+
function fwdDirs(boxes, bi) {
|
|
25585
|
+
const n = boxes.length;
|
|
25586
|
+
const prev = bi > 0 ? boxes[bi].ll.y > boxes[bi - 1].ll.y ? -1 : 1 : 0;
|
|
25587
|
+
const next = bi + 1 < n ? boxes[bi + 1].ll.y > boxes[bi].ll.y ? 1 : -1 : 0;
|
|
25588
|
+
return { prev, next };
|
|
25786
25589
|
}
|
|
25787
|
-
function
|
|
25788
|
-
|
|
25789
|
-
|
|
25790
|
-
|
|
25791
|
-
else
|
|
25792
|
-
|
|
25793
|
-
|
|
25794
|
-
|
|
25590
|
+
function emitFwdBox(b, prev, next, pts) {
|
|
25591
|
+
if (prev !== next) {
|
|
25592
|
+
if (next === -1 || prev === 1) {
|
|
25593
|
+
pts.push({ x: b.ll.x, y: b.ur.y }, { x: b.ll.x, y: b.ll.y });
|
|
25594
|
+
} else {
|
|
25595
|
+
pts.push({ x: b.ur.x, y: b.ll.y }, { x: b.ur.x, y: b.ur.y });
|
|
25596
|
+
}
|
|
25597
|
+
} else if (prev === 0) {
|
|
25598
|
+
pts.push({ x: b.ll.x, y: b.ur.y }, { x: b.ll.x, y: b.ll.y });
|
|
25795
25599
|
}
|
|
25796
25600
|
}
|
|
25797
|
-
function
|
|
25798
|
-
|
|
25799
|
-
|
|
25800
|
-
|
|
25801
|
-
} else {
|
|
25802
|
-
endp.boxes[0].ur.y = P.start.p.y;
|
|
25803
|
-
endp.sidemask = BOTTOM;
|
|
25804
|
-
P.start.p.y -= 1;
|
|
25601
|
+
function addForwardPolyPts(boxes, pts) {
|
|
25602
|
+
for (let bi = 0; bi < boxes.length; bi++) {
|
|
25603
|
+
const { prev, next } = fwdDirs(boxes, bi);
|
|
25604
|
+
emitFwdBox(boxes[bi], prev, next, pts);
|
|
25805
25605
|
}
|
|
25806
25606
|
}
|
|
25807
|
-
function
|
|
25808
|
-
|
|
25809
|
-
|
|
25810
|
-
|
|
25811
|
-
|
|
25812
|
-
endp.boxes[0].ll.y = P.end.p.y;
|
|
25813
|
-
endp.sidemask = TOP;
|
|
25814
|
-
P.end.p.y += 1;
|
|
25815
|
-
}
|
|
25607
|
+
function revDirs(boxes, bi) {
|
|
25608
|
+
const n = boxes.length;
|
|
25609
|
+
const prev = bi + 1 < n ? boxes[bi].ll.y > boxes[bi + 1].ll.y ? -1 : 1 : 0;
|
|
25610
|
+
const next = bi > 0 ? boxes[bi - 1].ll.y > boxes[bi].ll.y ? 1 : -1 : 0;
|
|
25611
|
+
return { prev, next };
|
|
25816
25612
|
}
|
|
25817
|
-
function
|
|
25818
|
-
|
|
25819
|
-
|
|
25820
|
-
|
|
25821
|
-
|
|
25822
|
-
|
|
25613
|
+
function emitAllCorners(b, pts) {
|
|
25614
|
+
pts.push(
|
|
25615
|
+
{ x: b.ur.x, y: b.ll.y },
|
|
25616
|
+
{ x: b.ur.x, y: b.ur.y },
|
|
25617
|
+
{ x: b.ll.x, y: b.ur.y },
|
|
25618
|
+
{ x: b.ll.x, y: b.ll.y }
|
|
25619
|
+
);
|
|
25823
25620
|
}
|
|
25824
|
-
function
|
|
25825
|
-
if (
|
|
25826
|
-
|
|
25827
|
-
|
|
25828
|
-
|
|
25829
|
-
|
|
25830
|
-
|
|
25621
|
+
function emitRevBox(b, prev, next, pts) {
|
|
25622
|
+
if (prev !== next) {
|
|
25623
|
+
if (next === -1 || prev === 1) {
|
|
25624
|
+
pts.push({ x: b.ll.x, y: b.ur.y }, { x: b.ll.x, y: b.ll.y });
|
|
25625
|
+
} else {
|
|
25626
|
+
pts.push({ x: b.ur.x, y: b.ll.y }, { x: b.ur.x, y: b.ur.y });
|
|
25627
|
+
}
|
|
25628
|
+
} else if (prev === 0) {
|
|
25629
|
+
pts.push({ x: b.ur.x, y: b.ll.y }, { x: b.ur.x, y: b.ur.y });
|
|
25831
25630
|
} else {
|
|
25832
|
-
|
|
25631
|
+
emitAllCorners(b, pts);
|
|
25833
25632
|
}
|
|
25834
25633
|
}
|
|
25835
|
-
function
|
|
25836
|
-
|
|
25837
|
-
|
|
25838
|
-
|
|
25839
|
-
} else if (e.info.head_port.constrained) {
|
|
25840
|
-
P.end.theta = e.info.head_port.theta;
|
|
25841
|
-
P.end.constrained = true;
|
|
25842
|
-
} else {
|
|
25843
|
-
P.end.constrained = false;
|
|
25634
|
+
function addReversePolyPts(boxes, pts) {
|
|
25635
|
+
for (let bi = boxes.length - 1; bi >= 0; bi--) {
|
|
25636
|
+
const { prev, next } = revDirs(boxes, bi);
|
|
25637
|
+
emitRevBox(boxes[bi], prev, next, pts);
|
|
25844
25638
|
}
|
|
25845
25639
|
}
|
|
25640
|
+
function boxesToPolygon(boxes) {
|
|
25641
|
+
if (boxes.length === 0) return [];
|
|
25642
|
+
const pts = [];
|
|
25643
|
+
addForwardPolyPts(boxes, pts);
|
|
25644
|
+
addReversePolyPts(boxes, pts);
|
|
25645
|
+
return pts;
|
|
25646
|
+
}
|
|
25647
|
+
function polyEdgesFromPts(polygon) {
|
|
25648
|
+
const n = polygon.length;
|
|
25649
|
+
return polygon.map((a, i) => ({ a, b: polygon[(i + 1) % n] }));
|
|
25650
|
+
}
|
|
25651
|
+
function linearBezier(p0, p3) {
|
|
25652
|
+
return [
|
|
25653
|
+
p0,
|
|
25654
|
+
{ x: p0.x + (p3.x - p0.x) / 3, y: p0.y + (p3.y - p0.y) / 3 },
|
|
25655
|
+
{ x: p0.x + 2 * (p3.x - p0.x) / 3, y: p0.y + 2 * (p3.y - p0.y) / 3 },
|
|
25656
|
+
p3
|
|
25657
|
+
];
|
|
25658
|
+
}
|
|
25659
|
+
function tryRouteSpline(barriers, wpts) {
|
|
25660
|
+
const zero = { x: 0, y: 0 };
|
|
25661
|
+
const raw = routeSpline(barriers, wpts, [zero, zero]);
|
|
25662
|
+
if (raw.length < 4) return null;
|
|
25663
|
+
return [raw[0], raw[1], raw[2], raw[3]];
|
|
25664
|
+
}
|
|
25665
|
+
function computeSpline(boxes, startPt, endPt) {
|
|
25666
|
+
const polygon = boxesToPolygon(boxes);
|
|
25667
|
+
if (polygon.length < 3) return linearBezier(startPt, endPt);
|
|
25668
|
+
const wpts = shortestPath({ ps: polygon }, [startPt, endPt]);
|
|
25669
|
+
if (wpts === null || wpts.length < 2) return linearBezier(startPt, endPt);
|
|
25670
|
+
return tryRouteSpline(polyEdgesFromPts(polygon), wpts) ?? linearBezier(startPt, endPt);
|
|
25671
|
+
}
|
|
25846
25672
|
|
|
25847
25673
|
// src/layout/dot/edge-route-rank.ts
|
|
25848
25674
|
var MINW = 16;
|
|
@@ -26898,7 +26724,7 @@ function rankY(g, r) {
|
|
|
26898
26724
|
return g.info.rank[r].v[0].info.coord?.y ?? 0;
|
|
26899
26725
|
}
|
|
26900
26726
|
function sizeyAtMaxrank(g, n, r) {
|
|
26901
|
-
if (r > 0) return rankY(g, r - 1) - (n.info.coord?.y ?? 0);
|
|
26727
|
+
if (r - (g.info.abomShift ?? 0) > 0) return rankY(g, r - 1) - (n.info.coord?.y ?? 0);
|
|
26902
26728
|
return n.info.ht ?? 0;
|
|
26903
26729
|
}
|
|
26904
26730
|
function sizeyAtMinrank(g, n, r) {
|
|
@@ -29735,7 +29561,7 @@ function makeFlatLabeledEdge(g, e) {
|
|
|
29735
29561
|
const et = edgeType(g);
|
|
29736
29562
|
if (et === EDGETYPE_LINE) {
|
|
29737
29563
|
const ps2 = flatLabeledLinePoints(e.tail, e.head, e);
|
|
29738
|
-
|
|
29564
|
+
clipAndInstall(e, e.head, ps2, ps2.length, buildDotSinfo());
|
|
29739
29565
|
return true;
|
|
29740
29566
|
}
|
|
29741
29567
|
const tailIsLeft = (e.tail.info.order ?? 0) <= (e.head.info.order ?? 0);
|
|
@@ -29919,6 +29745,195 @@ function makeAdjFlatNoPortEdge(g, e) {
|
|
|
29919
29745
|
return true;
|
|
29920
29746
|
}
|
|
29921
29747
|
|
|
29748
|
+
// src/layout/dot/edge-route-boxes.ts
|
|
29749
|
+
var FUDGE2 = 2;
|
|
29750
|
+
function makeTailBox(nb, startPy) {
|
|
29751
|
+
return { ll: nb.ll, ur: { x: nb.ur.x, y: startPy } };
|
|
29752
|
+
}
|
|
29753
|
+
function makeHeadBox(nb, endPy) {
|
|
29754
|
+
return { ll: { x: nb.ll.x, y: endPy }, ur: nb.ur };
|
|
29755
|
+
}
|
|
29756
|
+
function makeRankBox(p) {
|
|
29757
|
+
return {
|
|
29758
|
+
ll: { x: p.llx, y: p.headCy + p.headHt2 },
|
|
29759
|
+
ur: { x: p.urx, y: p.tailCy - p.tailHt1 }
|
|
29760
|
+
};
|
|
29761
|
+
}
|
|
29762
|
+
function makeMaximalBbox(box, ht1, ht22) {
|
|
29763
|
+
return {
|
|
29764
|
+
ll: { x: box.center.x - box.lw - FUDGE2, y: box.center.y - ht1 },
|
|
29765
|
+
ur: { x: box.center.x + box.rw + FUDGE2, y: box.center.y + ht22 }
|
|
29766
|
+
};
|
|
29767
|
+
}
|
|
29768
|
+
|
|
29769
|
+
// src/layout/dot/edge-route-routing.ts
|
|
29770
|
+
var ARROW_LENGTH2 = 10;
|
|
29771
|
+
var CLIP_BOTH = { tail: true, head: true };
|
|
29772
|
+
function buildRankCorridor(tailBox, headBox, rank3, ports) {
|
|
29773
|
+
const startPy = tailBox.center.y;
|
|
29774
|
+
const endPy = headBox.center.y;
|
|
29775
|
+
const tailNb = makeMaximalBbox(tailBox, rank3.tailHt1, rank3.tailHt2);
|
|
29776
|
+
const headNb = makeMaximalBbox(headBox, rank3.headHt1, rank3.headHt2);
|
|
29777
|
+
const rp = {
|
|
29778
|
+
llx: rank3.leftBound,
|
|
29779
|
+
urx: rank3.rightBound,
|
|
29780
|
+
tailCy: tailBox.center.y,
|
|
29781
|
+
tailHt1: rank3.tailHt1,
|
|
29782
|
+
headCy: headBox.center.y,
|
|
29783
|
+
headHt2: rank3.headHt2
|
|
29784
|
+
};
|
|
29785
|
+
return {
|
|
29786
|
+
startPt: ports?.tailP ?? { x: tailBox.center.x, y: startPy - 1 },
|
|
29787
|
+
endPt: ports?.headP ?? { x: headBox.center.x, y: endPy + 1 },
|
|
29788
|
+
boxes: [makeTailBox(tailNb, startPy), makeRankBox(rp), makeHeadBox(headNb, endPy)]
|
|
29789
|
+
};
|
|
29790
|
+
}
|
|
29791
|
+
function normalArrowLen(penwidth = DEFAULT_NODEPENWIDTH) {
|
|
29792
|
+
const ARROWWIDTH = 0.35;
|
|
29793
|
+
return ARROW_LENGTH2 + penwidth * Math.sqrt(1 + ARROWWIDTH * ARROWWIDTH) / (2 * ARROWWIDTH);
|
|
29794
|
+
}
|
|
29795
|
+
function nodeInsideFn2(box) {
|
|
29796
|
+
const halfW = (box.lw + box.rw) / 2;
|
|
29797
|
+
const halfH = box.ht / 2;
|
|
29798
|
+
const pw = box.penwidth ?? DEFAULT_NODEPENWIDTH;
|
|
29799
|
+
return box.isEllipse ? makeEllipseInsideFn(halfW, halfH, pw) : makeBoxInsideFn(halfW, halfH, pw);
|
|
29800
|
+
}
|
|
29801
|
+
function clipToNodes(bezier, tailBox, headBox, penwidth = DEFAULT_NODEPENWIDTH, clip = CLIP_BOTH) {
|
|
29802
|
+
const step1 = clip.tail ? bezierClipNode(bezier, tailBox.center.x, tailBox.center.y, nodeInsideFn2(tailBox), true) : bezier;
|
|
29803
|
+
const step2 = clip.head ? bezierClipNode(step1, headBox.center.x, headBox.center.y, nodeInsideFn2(headBox), false) : step1;
|
|
29804
|
+
const arrowTip = step2[3];
|
|
29805
|
+
const elen = normalArrowLen(penwidth);
|
|
29806
|
+
const clipped = arrowEndClip(step2, arrowTip, elen);
|
|
29807
|
+
const arrowDir = normalizeVec({
|
|
29808
|
+
x: clipped[3].x - arrowTip.x,
|
|
29809
|
+
y: clipped[3].y - arrowTip.y
|
|
29810
|
+
});
|
|
29811
|
+
return { clipped, arrowTip, arrowDir };
|
|
29812
|
+
}
|
|
29813
|
+
function routeWithRank(tailBox, headBox, rank3, penwidth = DEFAULT_NODEPENWIDTH, port) {
|
|
29814
|
+
const corridor = port ? { tailP: port.tailP, headP: port.headP } : void 0;
|
|
29815
|
+
const { startPt, endPt, boxes } = buildRankCorridor(tailBox, headBox, rank3, corridor);
|
|
29816
|
+
const bezier = computeSpline(boxes, startPt, endPt);
|
|
29817
|
+
const clip = port ? { tail: port.clipTail, head: port.clipHead } : CLIP_BOTH;
|
|
29818
|
+
const { clipped, arrowTip, arrowDir } = clipToNodes(bezier, tailBox, headBox, penwidth, clip);
|
|
29819
|
+
return { bezierPts: clipped, arrowTip, arrowDir };
|
|
29820
|
+
}
|
|
29821
|
+
function routeSimple(tailBox, headBox, routeBezierFn) {
|
|
29822
|
+
const dir = normalizeVec({
|
|
29823
|
+
x: headBox.center.x - tailBox.center.x,
|
|
29824
|
+
y: headBox.center.y - tailBox.center.y
|
|
29825
|
+
});
|
|
29826
|
+
const headToTail = negateVec(dir);
|
|
29827
|
+
const tailClip = clipToNodeBox(tailBox, dir);
|
|
29828
|
+
const arrowTip = clipToNodeBox(headBox, headToTail);
|
|
29829
|
+
return {
|
|
29830
|
+
bezierPts: routeBezierFn(tailClip, offsetPoint(arrowTip, headToTail, ARROW_LENGTH2)),
|
|
29831
|
+
arrowTip,
|
|
29832
|
+
arrowDir: headToTail
|
|
29833
|
+
};
|
|
29834
|
+
}
|
|
29835
|
+
|
|
29836
|
+
// src/layout/dot/edge-route-helpers.ts
|
|
29837
|
+
function defaultEdgeDir(g) {
|
|
29838
|
+
return g.kind === "directed" || g.kind === "strict-directed" ? "forward" : "none";
|
|
29839
|
+
}
|
|
29840
|
+
var ELLIPSE_SHAPES = /* @__PURE__ */ new Set([
|
|
29841
|
+
"ellipse",
|
|
29842
|
+
"oval",
|
|
29843
|
+
"circle",
|
|
29844
|
+
"egg",
|
|
29845
|
+
"doublecircle",
|
|
29846
|
+
"Mcircle",
|
|
29847
|
+
"point"
|
|
29848
|
+
]);
|
|
29849
|
+
function recordClipBox(n) {
|
|
29850
|
+
const f = n.info.shape_info;
|
|
29851
|
+
if (!f?.b) return void 0;
|
|
29852
|
+
const halfW = (f.b.ur.x - f.b.ll.x) / 2;
|
|
29853
|
+
return { lw: halfW, rw: halfW, ht: f.b.ur.y - f.b.ll.y };
|
|
29854
|
+
}
|
|
29855
|
+
function nodePenwidthOf(n, g) {
|
|
29856
|
+
const v = nodeAttr(n, g, "penwidth");
|
|
29857
|
+
const pw = v !== void 0 ? parseFloat(v) : NaN;
|
|
29858
|
+
return Number.isFinite(pw) && pw >= 0 ? pw : DEFAULT_NODEPENWIDTH;
|
|
29859
|
+
}
|
|
29860
|
+
function nodeBoxOf(n, g) {
|
|
29861
|
+
const shapeName = nodeAttr(n, g, "shape") ?? "ellipse";
|
|
29862
|
+
const penwidth = nodePenwidthOf(n, g);
|
|
29863
|
+
if (shapeName === "record" || shapeName === "Mrecord") {
|
|
29864
|
+
const rb = recordClipBox(n);
|
|
29865
|
+
if (rb) return { center: n.info.coord, ...rb, isEllipse: false, penwidth };
|
|
29866
|
+
}
|
|
29867
|
+
const si = n.info.shape_info;
|
|
29868
|
+
if (si?.option?.fixedshape === true && si.vertices) {
|
|
29869
|
+
const ext = fixedShapeSize(si);
|
|
29870
|
+
const flip = g.root.info.flip === true;
|
|
29871
|
+
const w = flip ? ext.h : ext.w;
|
|
29872
|
+
const h = flip ? ext.w : ext.h;
|
|
29873
|
+
return {
|
|
29874
|
+
center: n.info.coord,
|
|
29875
|
+
lw: w / 2,
|
|
29876
|
+
rw: w / 2,
|
|
29877
|
+
ht: h,
|
|
29878
|
+
isEllipse: ELLIPSE_SHAPES.has(shapeName),
|
|
29879
|
+
penwidth: 0
|
|
29880
|
+
};
|
|
29881
|
+
}
|
|
29882
|
+
return {
|
|
29883
|
+
center: n.info.coord,
|
|
29884
|
+
lw: n.info.lw > 0 ? n.info.lw : 27,
|
|
29885
|
+
rw: n.info.rw > 0 ? n.info.rw : 27,
|
|
29886
|
+
ht: n.info.ht > 0 ? n.info.ht : 36,
|
|
29887
|
+
isEllipse: ELLIPSE_SHAPES.has(shapeName),
|
|
29888
|
+
penwidth
|
|
29889
|
+
};
|
|
29890
|
+
}
|
|
29891
|
+
function edgeRenderPenwidth(e) {
|
|
29892
|
+
return resolvePenWidth(parseStyleFlags(e.attrs.get("style")), e.attrs.get("penwidth"));
|
|
29893
|
+
}
|
|
29894
|
+
function edgePenwidthAttr(e) {
|
|
29895
|
+
const pw = parseFloat(e.attrs.get("penwidth") ?? "");
|
|
29896
|
+
return isNaN(pw) ? 1 : pw;
|
|
29897
|
+
}
|
|
29898
|
+
function makeBezierRecord(bezierPts, arrowTip) {
|
|
29899
|
+
return {
|
|
29900
|
+
list: bezierPts,
|
|
29901
|
+
size: bezierPts.length,
|
|
29902
|
+
sflag: 0,
|
|
29903
|
+
eflag: 1,
|
|
29904
|
+
sp: bezierPts[0] ?? { x: 0, y: 0 },
|
|
29905
|
+
ep: arrowTip
|
|
29906
|
+
};
|
|
29907
|
+
}
|
|
29908
|
+
function makeSplineRecord(bz) {
|
|
29909
|
+
return { list: [bz], size: 1, bb: { ll: { x: 0, y: 0 }, ur: { x: 0, y: 0 } } };
|
|
29910
|
+
}
|
|
29911
|
+
function installEdgeSpline(e, bezierPts, arrowTip) {
|
|
29912
|
+
e.info.spl = makeSplineRecord(makeBezierRecord(bezierPts, arrowTip));
|
|
29913
|
+
const bb = e.tail.root.info.bb;
|
|
29914
|
+
if (bb != null) {
|
|
29915
|
+
for (let i = 0; i + 3 < bezierPts.length; i += 3) {
|
|
29916
|
+
updateBbBz(bb, [bezierPts[i], bezierPts[i + 1], bezierPts[i + 2], bezierPts[i + 3]]);
|
|
29917
|
+
}
|
|
29918
|
+
}
|
|
29919
|
+
}
|
|
29920
|
+
function isUsableSpline(raw) {
|
|
29921
|
+
if (raw.length < 4) return false;
|
|
29922
|
+
const p0 = raw[0];
|
|
29923
|
+
const p1 = raw[1];
|
|
29924
|
+
return p0.x !== p1.x || p0.y !== p1.y;
|
|
29925
|
+
}
|
|
29926
|
+
function routeBezier(from, to) {
|
|
29927
|
+
const noBarriers = [];
|
|
29928
|
+
const zero = { x: 0, y: 0 };
|
|
29929
|
+
const raw = routeSpline(noBarriers, [from, to], [zero, zero]);
|
|
29930
|
+
if (!isUsableSpline(raw)) return linearBezier(from, to);
|
|
29931
|
+
return [raw[0], raw[1], raw[2], raw[3]];
|
|
29932
|
+
}
|
|
29933
|
+
function straightEdgeSplineWithRank(tailBox, headBox, rankInfo, penwidth = 1, port) {
|
|
29934
|
+
return rankInfo !== void 0 ? routeWithRank(tailBox, headBox, rankInfo, penwidth, port) : routeSimple(tailBox, headBox, routeBezier);
|
|
29935
|
+
}
|
|
29936
|
+
|
|
29922
29937
|
// src/layout/dot/edge-route.ts
|
|
29923
29938
|
function coordsDefined(e) {
|
|
29924
29939
|
return e.tail.info.coord !== void 0 && e.head.info.coord !== void 0;
|
|
@@ -30022,8 +30037,14 @@ function hasSidePort(e) {
|
|
|
30022
30037
|
const hp = resolvePort(e.head, e.tail, e.info.head_port);
|
|
30023
30038
|
return (tp.side ?? 0) !== 0 || (hp.side ?? 0) !== 0;
|
|
30024
30039
|
}
|
|
30040
|
+
function hasDefinedPort(e) {
|
|
30041
|
+
return e.info.tail_port.defined || e.info.head_port.defined;
|
|
30042
|
+
}
|
|
30043
|
+
function isAdjacentPortFlat(e, g) {
|
|
30044
|
+
return e.tail.info.rank !== void 0 && e.tail.info.rank === e.head.info.rank && isFlatAdjacent(g, e) && hasDefinedPort(e);
|
|
30045
|
+
}
|
|
30025
30046
|
function isGroupableFlat(x, g) {
|
|
30026
|
-
return x.info.spl === void 0 && x
|
|
30047
|
+
return x.info.spl === void 0 && isAdjacentPortFlat(x, g);
|
|
30027
30048
|
}
|
|
30028
30049
|
function collectAdjacentFlatGroup(e, g) {
|
|
30029
30050
|
const u = e.tail, v = e.head;
|
|
@@ -30064,7 +30085,7 @@ function routeFlatEdge(e, g) {
|
|
|
30064
30085
|
if (isLostFlatAdjRecordEdge(g, e)) return true;
|
|
30065
30086
|
if (makeFlatLabeledEdge(g, e)) return true;
|
|
30066
30087
|
if (makeAdjFlatNoPortEdge(g, e)) return true;
|
|
30067
|
-
if (hasSidePort(e) && routeFaithfulSidePort(e, g)) return true;
|
|
30088
|
+
if ((hasSidePort(e) || isAdjacentPortFlat(e, g)) && routeFaithfulSidePort(e, g)) return true;
|
|
30068
30089
|
if (e.tail.info.rank !== void 0 && e.tail.info.rank === e.head.info.rank && e.info.label === void 0 && !isFlatAdjacent(g, e)) {
|
|
30069
30090
|
const group = collectNonAdjacentFlatGroup(e, g);
|
|
30070
30091
|
if (group.length > 0 && routeFlatEdgeGroupFaithful(g, group, group.length) && e.info.spl !== void 0) return true;
|
|
@@ -30118,8 +30139,8 @@ var M_LEFT = 2;
|
|
|
30118
30139
|
var M_BOTTOM = 3;
|
|
30119
30140
|
|
|
30120
30141
|
// src/common/random.ts
|
|
30121
|
-
var A =
|
|
30122
|
-
var C =
|
|
30142
|
+
var A = BigInt("0x5deece66d");
|
|
30143
|
+
var C = BigInt("0xb");
|
|
30123
30144
|
var MASK48 = (1n << 48n) - 1n;
|
|
30124
30145
|
var TWO48 = 2 ** 48;
|
|
30125
30146
|
var state = 0x330en;
|
|
@@ -32661,8 +32682,11 @@ function dispatchEdgeGroup(g, group, ctx) {
|
|
|
32661
32682
|
}
|
|
32662
32683
|
return;
|
|
32663
32684
|
}
|
|
32664
|
-
if (nodeRankOf(e0.tail) === nodeRankOf(e0.head)) return;
|
|
32665
32685
|
const uniq = dedupByOrig(group);
|
|
32686
|
+
if (nodeRankOf(e0.tail) === nodeRankOf(e0.head)) {
|
|
32687
|
+
for (const e of uniq) routeLoneEdge(e, g);
|
|
32688
|
+
return;
|
|
32689
|
+
}
|
|
32666
32690
|
if (uniq.length <= 1) {
|
|
32667
32691
|
const runOrig = routeEntryRun(g, e0);
|
|
32668
32692
|
if (runOrig !== null) {
|
|
@@ -36974,7 +36998,6 @@ var Cdt = class {
|
|
|
36974
36998
|
v1 = r.v1;
|
|
36975
36999
|
v2 = r.v2;
|
|
36976
37000
|
v3 = r.v3;
|
|
36977
|
-
prev = r.e1;
|
|
36978
37001
|
e2 = r.e2;
|
|
36979
37002
|
e3 = r.e3;
|
|
36980
37003
|
}
|
|
@@ -40315,9 +40338,9 @@ var POW_LOG_TABLE_BITS = 7;
|
|
|
40315
40338
|
var N_LOG = 1 << POW_LOG_TABLE_BITS;
|
|
40316
40339
|
var EXP_TABLE_BITS = 7;
|
|
40317
40340
|
var N_EXP = 1 << EXP_TABLE_BITS;
|
|
40318
|
-
var OFF =
|
|
40319
|
-
var INF_BITS =
|
|
40320
|
-
var ONE_BITS =
|
|
40341
|
+
var OFF = BigInt("0x3fe6955500000000");
|
|
40342
|
+
var INF_BITS = BigInt("0x7ff0000000000000");
|
|
40343
|
+
var ONE_BITS = BigInt("0x3ff0000000000000");
|
|
40321
40344
|
var SIGN_BIAS = 2048 << EXP_TABLE_BITS;
|
|
40322
40345
|
var C22 = EC[0];
|
|
40323
40346
|
var C3 = EC[1];
|
|
@@ -45396,7 +45419,7 @@ function circoLayout(g) {
|
|
|
45396
45419
|
dg.components = comps;
|
|
45397
45420
|
let blockCount = 0;
|
|
45398
45421
|
if (comps.length === 1) {
|
|
45399
|
-
|
|
45422
|
+
circularLayout(comps[0], g, blockCount, allEdges3);
|
|
45400
45423
|
copyPositions(comps[0]);
|
|
45401
45424
|
adjustNodesFull(g);
|
|
45402
45425
|
} else {
|