@knowvah/dot-engine 1.2.2 → 1.2.4

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.
Files changed (42) hide show
  1. package/dist/cdt/bag.d.ts +6 -4
  2. package/dist/cdt/bag.d.ts.map +1 -1
  3. package/dist/common/arrows-shapes-poly.d.ts +1 -1
  4. package/dist/common/arrows-shapes-poly.d.ts.map +1 -1
  5. package/dist/common/arrows-shapes.d.ts +2 -2
  6. package/dist/common/arrows-shapes.d.ts.map +1 -1
  7. package/dist/common/htmltable-lex.d.ts.map +1 -1
  8. package/dist/common/record.d.ts.map +1 -1
  9. package/dist/index.js +2013 -2008
  10. package/dist/index.js.map +4 -4
  11. package/dist/layout/dot/edge-route-arrow.d.ts +8 -0
  12. package/dist/layout/dot/edge-route-arrow.d.ts.map +1 -1
  13. package/dist/model/geom.d.ts +5 -0
  14. package/dist/model/geom.d.ts.map +1 -1
  15. package/dist/render.js +95 -90
  16. package/dist/render.js.map +4 -4
  17. package/dist/xdot/parse.d.ts.map +1 -1
  18. package/package.json +2 -1
  19. package/src/cdt/bag.ts +30 -52
  20. package/src/common/arrows-shapes-poly.ts +20 -1
  21. package/src/common/arrows-shapes.ts +6 -2
  22. package/src/common/htmltable-lex.ts +17 -4
  23. package/src/common/htmltable-parse.ts +1 -1
  24. package/src/common/record.ts +3 -5
  25. package/src/layout/dot/edge-route-arrow.ts +7 -2
  26. package/src/model/geom.ts +14 -0
  27. package/src/xdot/parse.ts +3 -1
  28. package/dist/gvc/textlayout.d.ts +0 -33
  29. package/dist/gvc/textlayout.d.ts.map +0 -1
  30. package/dist/layout/osage/layout.d.ts +0 -49
  31. package/dist/layout/osage/layout.d.ts.map +0 -1
  32. package/dist/layout/pack/test-helpers.d.ts +0 -7
  33. package/dist/layout/pack/test-helpers.d.ts.map +0 -1
  34. package/dist/layout/patchwork/tree-node.d.ts +0 -46
  35. package/dist/layout/patchwork/tree-node.d.ts.map +0 -1
  36. package/dist/xdot/lex.d.ts +0 -22
  37. package/dist/xdot/lex.d.ts.map +0 -1
  38. package/src/gvc/textlayout.ts +0 -44
  39. package/src/layout/osage/layout.ts +0 -254
  40. package/src/layout/pack/test-helpers.ts +0 -46
  41. package/src/layout/patchwork/tree-node.ts +0 -120
  42. package/src/xdot/lex.ts +0 -151
package/dist/index.js CHANGED
@@ -4535,6 +4535,20 @@ function ccwrotatepf(p, ccwrot) {
4535
4535
  return p;
4536
4536
  }
4537
4537
  }
4538
+ function cwrotatepf(p, cwrot) {
4539
+ switch (cwrot) {
4540
+ case 0:
4541
+ return p;
4542
+ case 90:
4543
+ return { x: p.y, y: -p.x };
4544
+ case 180:
4545
+ return { x: p.x, y: -p.y };
4546
+ case 270:
4547
+ return { x: p.y, y: p.x };
4548
+ default:
4549
+ return p;
4550
+ }
4551
+ }
4538
4552
  function boxOverlap(b0, b1) {
4539
4553
  return b0.ur.x >= b1.ll.x && b1.ur.x >= b0.ll.x && b0.ur.y >= b1.ll.y && b1.ur.y >= b0.ll.y;
4540
4554
  }
@@ -10091,12 +10105,15 @@ function parseAttrs(raw) {
10091
10105
  }
10092
10106
  return out;
10093
10107
  }
10108
+ function normalizeTag(tag) {
10109
+ return tag === "TH" ? "TR" : tag;
10110
+ }
10094
10111
  function parseCloseToken(inner) {
10095
10112
  const body = inner.slice(1).trim();
10096
10113
  const sp = body.search(/\s/);
10097
10114
  const tag = (sp === -1 ? body : body.slice(0, sp)).toUpperCase();
10098
10115
  checkTag(tag);
10099
- return { type: "close", tag };
10116
+ return { type: "close", tag: normalizeTag(tag) };
10100
10117
  }
10101
10118
  function cleanText(raw) {
10102
10119
  const isKeep = (c) => c === " " || c === " " || c === "\n" || c === "\r";
@@ -10130,12 +10147,13 @@ function scanTag(src, start, tokens) {
10130
10147
  function parseOpenToken(inner) {
10131
10148
  const sp = inner.search(/\s/);
10132
10149
  if (sp === -1) {
10133
- checkTag(inner.toUpperCase());
10134
- return { type: "open", tag: inner.toUpperCase(), attrs: parseAttrs("") };
10150
+ const tag2 = inner.toUpperCase();
10151
+ checkTag(tag2);
10152
+ return { type: "open", tag: normalizeTag(tag2), attrs: parseAttrs("") };
10135
10153
  }
10136
10154
  const tag = inner.slice(0, sp).toUpperCase();
10137
10155
  checkTag(tag);
10138
- return { type: "open", tag, attrs: parseAttrs(inner.slice(sp + 1)) };
10156
+ return { type: "open", tag: normalizeTag(tag), attrs: parseAttrs(inner.slice(sp + 1)) };
10139
10157
  }
10140
10158
  function tokenize(src) {
10141
10159
  const tokens = [];
@@ -10360,7 +10378,7 @@ var buildCell = (content, a) => ({
10360
10378
  });
10361
10379
  var parseCell = (s, attrs, fontStack) => buildCell(parseCellContent(s, attrs, fontStack), attrs);
10362
10380
  var processRowToken = (s, t, cells, fontStack) => {
10363
- if (t.type === "open" && (t.tag === "TD" || t.tag === "TH")) {
10381
+ if (t.type === "open" && t.tag === "TD") {
10364
10382
  consume(s);
10365
10383
  cells.push(parseCell(s, t.attrs, fontStack));
10366
10384
  return;
@@ -16866,1497 +16884,234 @@ function assembleResult(p, dimen, grown, fixedshape) {
16866
16884
  };
16867
16885
  }
16868
16886
 
16869
- // src/common/record.ts
16870
- var HASTEXT = 1;
16871
- var HASPORT = 2;
16872
- var HASTABLE = 4;
16873
- var INTEXT = 8;
16874
- var INPORT = 16;
16875
- var BOTTOM2 = 1;
16876
- var RIGHT2 = 2;
16877
- var TOP2 = 4;
16878
- var LEFT2 = 8;
16879
- var PAD_X = 16;
16880
- var PAD_Y = 8;
16881
- function makeField() {
16882
- return {
16883
- size: { x: 0, y: 0 },
16884
- b: { ll: { x: 0, y: 0 }, ur: { x: 0, y: 0 } },
16885
- n_flds: 0,
16886
- lp: null,
16887
- fld: null,
16888
- id: null,
16889
- LR: 0,
16890
- sides: 0
16891
- };
16887
+ // src/layout/dot/fastgr.ts
16888
+ var VIRTUAL = 1;
16889
+ var NORMAL = 0;
16890
+ var FLATORDER = 4;
16891
+ var REVERSED = 3;
16892
+ var MC_SCALE = 256;
16893
+ function elistAppend(el, e) {
16894
+ el.list[el.size++] = e;
16892
16895
  }
16893
- function recIsEscapedDelim(s, j) {
16894
- if (s[j] !== "\\") return false;
16895
- const nx = s[j + 1];
16896
- return nx === "{" || nx === "}" || nx === "|" || nx === "\\";
16896
+ function zapinlist(el, e) {
16897
+ let i = 0;
16898
+ while (i < el.size && el.list[i] !== e) i++;
16899
+ if (i < el.size) {
16900
+ el.list[i] = el.list[--el.size];
16901
+ el.list[el.size] = void 0;
16902
+ }
16897
16903
  }
16898
- function recCountFields(p) {
16899
- let maxf = 1;
16900
- let cnt = 0;
16901
- for (let j = p.i; j < p.s.length; j++) {
16902
- if (recIsEscapedDelim(p.s, j)) {
16903
- j++;
16904
- continue;
16904
+ function deleteFastEdge(e) {
16905
+ if (e.tail.info.out) zapinlist(e.tail.info.out, e);
16906
+ if (e.head.info.in) zapinlist(e.head.info.in, e);
16907
+ }
16908
+ function fastEdge(e) {
16909
+ if (!e.tail.info.out) e.tail.info.out = { list: [], size: 0 };
16910
+ if (!e.head.info.in) e.head.info.in = { list: [], size: 0 };
16911
+ elistAppend(e.tail.info.out, e);
16912
+ elistAppend(e.head.info.in, e);
16913
+ }
16914
+ function findFastEdge(u, v) {
16915
+ const uOut = u.info.out;
16916
+ const vIn = v.info.in;
16917
+ if (uOut === void 0 || vIn === void 0) return void 0;
16918
+ if (uOut.size <= vIn.size) {
16919
+ for (let i = 0; i < uOut.size; i++) {
16920
+ if (uOut.list[i].head === v) return uOut.list[i];
16921
+ }
16922
+ } else {
16923
+ for (let i = 0; i < vIn.size; i++) {
16924
+ if (vIn.list[i].tail === u) return vIn.list[i];
16905
16925
  }
16906
- const c = p.s[j];
16907
- if (c === "{") cnt++;
16908
- else if (c === "}") cnt--;
16909
- else if (c === "|" && cnt === 0) maxf++;
16910
- if (cnt < 0) break;
16911
16926
  }
16912
- return maxf;
16927
+ return void 0;
16913
16928
  }
16914
- function recOpenPort(p, st) {
16915
- if (st.mode & (HASTABLE | HASPORT)) return -1;
16916
- st.mode |= HASPORT | INPORT;
16917
- p.i++;
16918
- st.pbuf = [];
16919
- st.hspIdx = 0;
16920
- return 0;
16929
+ function copyPort(p) {
16930
+ const bp = p.bp !== null ? { ll: { x: p.bp.ll.x, y: p.bp.ll.y }, ur: { x: p.bp.ur.x, y: p.bp.ur.y } } : null;
16931
+ return { p: { x: p.p.x, y: p.p.y }, theta: p.theta, bp, defined: p.defined, constrained: p.constrained, clip: p.clip, dyna: p.dyna, order: p.order, side: p.side, name: p.name };
16921
16932
  }
16922
- function recClosePort(p, st) {
16923
- if (!(st.mode & INPORT)) return -1;
16924
- const t = st.pbuf;
16925
- if (t.length > 1 && st.hspIdx !== t.length - 1 && t[t.length - 1] === " ") t.pop();
16926
- st.tmpport = t.join("");
16927
- st.mode &= ~INPORT;
16928
- p.i++;
16929
- return 0;
16933
+ function copyVirtualPorts(e, orig) {
16934
+ if (e.tail === orig.tail) e.info.tail_port = copyPort(orig.info.tail_port);
16935
+ else if (e.tail === orig.head) e.info.tail_port = copyPort(orig.info.head_port);
16936
+ if (e.head === orig.head) e.info.head_port = copyPort(orig.info.head_port);
16937
+ else if (e.head === orig.tail) e.info.head_port = copyPort(orig.info.tail_port);
16930
16938
  }
16931
- function recOpenTable(p, st, LR) {
16932
- p.i++;
16933
- if (st.mode !== 0 || p.i >= p.s.length) return -1;
16934
- st.mode = HASTABLE;
16935
- const sub = parseReclbl(p, LR ? 0 : 1, false);
16936
- if (sub === null) return -1;
16937
- st.rv.fld[st.fi++] = sub;
16938
- st.fp = sub;
16939
- return 0;
16939
+ function copyVirtualEdgeInfo(e, orig) {
16940
+ e.info.count = orig.info.count;
16941
+ e.info.xpenalty = orig.info.xpenalty;
16942
+ e.info.weight = orig.info.weight;
16943
+ e.info.minlen = orig.info.minlen;
16944
+ copyVirtualPorts(e, orig);
16945
+ e.info.label = orig.info.label;
16946
+ e.info.head_label = orig.info.head_label;
16947
+ e.info.tail_label = orig.info.tail_label;
16948
+ e.info.xlabel = orig.info.xlabel;
16949
+ if (orig.info.to_virt === void 0) orig.info.to_virt = e;
16950
+ e.info.to_orig = orig;
16951
+ e.seq = orig.seq;
16940
16952
  }
16941
- function recFlushText(p, st) {
16942
- if (!(st.mode & (HASTEXT | HASTABLE))) {
16943
- st.mode |= HASTEXT;
16944
- st.tbuf.push(" ");
16945
- }
16946
- if (st.mode & HASTEXT) {
16947
- const t = st.tbuf;
16948
- if (t.length > 1 && st.hstIdx !== t.length - 1 && t[t.length - 1] === " ") t.pop();
16949
- st.fp.lp = makeAnyLabel(
16950
- t.join(""),
16951
- false,
16952
- { fontname: p.lbl.fontname, fontsize: p.lbl.fontsize, fontcolor: p.lbl.fontcolor },
16953
- p.measurer,
16954
- p.obj
16955
- );
16956
- st.fp.LR = 1;
16957
- st.tbuf = [];
16958
- st.hstIdx = 0;
16953
+ function newVirtualEdge(u, v, orig) {
16954
+ const e = new Edge(u, v, "");
16955
+ e.info.edge_type = VIRTUAL;
16956
+ if (orig) {
16957
+ copyVirtualEdgeInfo(e, orig);
16958
+ } else {
16959
+ e.info.weight = 1;
16960
+ e.info.xpenalty = 1;
16961
+ e.info.count = 1;
16962
+ e.info.minlen = 1;
16959
16963
  }
16964
+ return e;
16960
16965
  }
16961
- function recEndField(p, st, flag) {
16962
- const c = p.i < p.s.length ? p.s[p.i] : "";
16963
- if (c === "" && !flag || st.mode & INPORT) return -1;
16964
- if (!(st.mode & HASTABLE)) {
16965
- st.fp = makeField();
16966
- st.rv.fld[st.fi++] = st.fp;
16967
- }
16968
- if (st.tmpport !== null) {
16969
- st.fp.id = st.tmpport;
16970
- st.tmpport = null;
16971
- }
16972
- recFlushText(p, st);
16973
- if (c !== "") {
16974
- if (c === "}") {
16975
- p.i++;
16976
- st.rv.n_flds = st.fi;
16977
- return 1;
16978
- }
16979
- st.mode = 0;
16980
- p.i++;
16981
- return 0;
16982
- }
16983
- st.rv.n_flds = st.fi;
16984
- return 1;
16966
+ function virtualEdge(u, v, orig) {
16967
+ const e = newVirtualEdge(u, v, orig);
16968
+ fastEdge(e);
16969
+ return e;
16985
16970
  }
16986
- function recBackslash(p, st) {
16987
- const nx = p.s[p.i + 1];
16988
- if (nx !== void 0) {
16989
- if (nx < " ") {
16990
- } else if (nx === " " && !p.lbl.html) {
16991
- st.ishardspace = true;
16992
- } else {
16993
- st.tbuf.push("\\");
16994
- st.mode |= INTEXT | HASTEXT;
16995
- }
16996
- p.i++;
16997
- }
16971
+ function mergeWeightsInto(f, ew, em, ex) {
16972
+ f.info.weight = (f.info.weight ?? 0) + ew;
16973
+ f.info.minlen = Math.max(f.info.minlen ?? 1, em);
16974
+ f.info.count = (f.info.count ?? 1) + 1;
16975
+ f.info.xpenalty = (f.info.xpenalty ?? 0) + ex;
16998
16976
  }
16999
- function recPushText(st, c, html) {
17000
- const afterSpace = st.tbuf[st.tbuf.length - 1] === " ";
17001
- if (!(c === " " && !st.ishardspace && afterSpace && !html)) st.tbuf.push(c);
17002
- if (st.ishardspace) st.hstIdx = st.tbuf.length - 1;
16977
+ function basicMerge(e, rep) {
16978
+ const ew = e.info.weight ?? 1;
16979
+ const em = e.info.minlen ?? 1;
16980
+ const ex = e.info.xpenalty ?? 0;
16981
+ for (let f = rep; f !== void 0; f = f.info.to_virt) {
16982
+ mergeWeightsInto(f, ew, em, ex);
16983
+ }
17003
16984
  }
17004
- function recPushPort(st, c) {
17005
- const atStartOrSpace = st.pbuf.length === 0 || st.pbuf[st.pbuf.length - 1] === " ";
17006
- if (!(c === " " && !st.ishardspace && atStartOrSpace)) st.pbuf.push(c);
17007
- if (st.ishardspace) st.hspIdx = st.pbuf.length - 1;
16985
+ function mergeOneway(e, rep) {
16986
+ if (e.info.to_virt !== void 0) return;
16987
+ e.info.to_virt = rep;
16988
+ basicMerge(e, rep);
17008
16989
  }
17009
- function recTextChar(p, st, c) {
17010
- if (st.mode & HASTABLE && c !== " ") return -1;
17011
- if (!(st.mode & (INTEXT | INPORT)) && c !== " ") st.mode |= INTEXT | HASTEXT;
17012
- if (st.mode & INTEXT) recPushText(st, c, p.lbl.html);
17013
- else if (st.mode & INPORT) recPushPort(st, c);
17014
- p.i++;
17015
- return 0;
16990
+ function deleteFlatEdge(e) {
16991
+ e.info.to_virt = void 0;
16992
+ if (e.tail.info.flat_out) zapinlist(e.tail.info.flat_out, e);
16993
+ if (e.head.info.flat_in) zapinlist(e.head.info.flat_in, e);
17016
16994
  }
17017
- function recDispatch(p, st, LR, flag) {
17018
- const c = p.s[p.i];
17019
- switch (c) {
17020
- case "<":
17021
- if (p.lbl.html) return recTextChar(p, st, c);
17022
- return recOpenPort(p, st);
17023
- case ">":
17024
- if (p.lbl.html) return recTextChar(p, st, c);
17025
- return recClosePort(p, st);
17026
- case "{":
17027
- return recOpenTable(p, st, LR);
17028
- case "}":
17029
- case "|":
17030
- case void 0:
17031
- return recEndField(p, st, flag);
17032
- case "\\":
17033
- recBackslash(p, st);
17034
- return recTextChar(p, st, p.s[p.i]);
17035
- default:
17036
- return recTextChar(p, st, c);
17037
- }
16995
+ function flatEdge(g, e) {
16996
+ if (!e.tail.info.flat_out) e.tail.info.flat_out = { list: [], size: 0 };
16997
+ if (!e.head.info.flat_in) e.head.info.flat_in = { list: [], size: 0 };
16998
+ elistAppend(e.tail.info.flat_out, e);
16999
+ elistAppend(e.head.info.flat_in, e);
17000
+ g.info.has_flat_edges = true;
17038
17001
  }
17039
- function parseReclbl(p, LR, flag) {
17040
- const rv = makeField();
17041
- rv.fld = new Array(recCountFields(p));
17042
- rv.LR = LR;
17043
- const st = {
17044
- rv,
17045
- fi: 0,
17046
- mode: 0,
17047
- tbuf: [],
17048
- hstIdx: 0,
17049
- pbuf: [],
17050
- hspIdx: 0,
17051
- tmpport: null,
17052
- ishardspace: false,
17053
- fp: null
17054
- };
17055
- for (; ; ) {
17056
- if (p.i < p.s.length && p.s[p.i] < " " && p.s[p.i] !== "") {
17057
- p.i++;
17058
- continue;
17002
+ function findFlatEdge(u, v) {
17003
+ const uOut = u.info.flat_out;
17004
+ const vIn = v.info.flat_in;
17005
+ if (uOut === void 0 || vIn === void 0) return void 0;
17006
+ if (uOut.size <= vIn.size) {
17007
+ for (let i = 0; i < uOut.size; i++) {
17008
+ if (uOut.list[i].head === v) return uOut.list[i];
17059
17009
  }
17060
- const r = recDispatch(p, st, LR, flag);
17061
- if (r === -1) return null;
17062
- if (r === 1) break;
17063
- if (p.i > p.s.length) break;
17064
- }
17065
- rv.n_flds = st.fi;
17066
- return rv;
17067
- }
17068
- function recLabelDimen(n, g, f) {
17069
- const dimen = { x: f.lp.dimen.x, y: f.lp.dimen.y };
17070
- if (dimen.x > 0 || dimen.y > 0) {
17071
- const m = nodeAttr(n, g, "margin");
17072
- const parts = m !== void 0 ? m.split(",").map(parseFloat) : [];
17073
- if (parts.length > 0 && !Number.isNaN(parts[0])) {
17074
- dimen.x += 2 * parts[0] * 72;
17075
- dimen.y += 2 * (parts.length > 1 && !Number.isNaN(parts[1]) ? parts[1] : parts[0]) * 72;
17076
- } else {
17077
- dimen.x += PAD_X;
17078
- dimen.y += PAD_Y;
17010
+ } else {
17011
+ for (let i = 0; i < vIn.size; i++) {
17012
+ if (vIn.list[i].tail === u) return vIn.list[i];
17079
17013
  }
17080
17014
  }
17081
- return dimen;
17015
+ return void 0;
17082
17016
  }
17083
- function sizeReclbl(n, g, f) {
17084
- let d;
17085
- if (f.lp) {
17086
- d = recLabelDimen(n, g, f);
17017
+ function reverseEdge(e) {
17018
+ deleteFastEdge(e);
17019
+ e.info.reversed = true;
17020
+ const f = findFastEdge(e.head, e.tail);
17021
+ if (f !== void 0) {
17022
+ mergeOneway(e, f);
17087
17023
  } else {
17088
- d = { x: 0, y: 0 };
17089
- for (let i = 0; i < f.n_flds; i++) {
17090
- const d0 = sizeReclbl(n, g, f.fld[i]);
17091
- if (f.LR) {
17092
- d.x += d0.x;
17093
- d.y = Math.max(d.y, d0.y);
17094
- } else {
17095
- d.y += d0.y;
17096
- d.x = Math.max(d.x, d0.x);
17097
- }
17098
- }
17024
+ virtualEdge(e.head, e.tail, e);
17099
17025
  }
17100
- f.size = d;
17101
- return d;
17102
17026
  }
17103
- function resizeReclbl(f, sz, nojustify) {
17104
- const d = { x: sz.x - f.size.x, y: sz.y - f.size.y };
17105
- f.size = sz;
17106
- if (f.lp && !nojustify) {
17107
- f.lp.space.x += d.x;
17108
- f.lp.space.y += d.y;
17109
- }
17110
- if (f.n_flds) {
17111
- const inc2 = f.LR ? d.x / f.n_flds : d.y / f.n_flds;
17112
- for (let i = 0; i < f.n_flds; i++) {
17113
- const sf = f.fld[i];
17114
- const amt = Math.trunc((i + 1) * inc2) - Math.trunc(i * inc2);
17115
- const newsz = f.LR ? { x: sf.size.x + amt, y: sz.y } : { x: sz.x, y: sf.size.y + amt };
17116
- resizeReclbl(sf, newsz, nojustify);
17117
- }
17118
- }
17027
+ function fastNode(g, n) {
17028
+ n.info.next = g.info.nlist;
17029
+ if (g.info.nlist !== void 0) g.info.nlist.info.prev = n;
17030
+ n.info.prev = void 0;
17031
+ g.info.nlist = n;
17119
17032
  }
17120
- function recSideMask(f, i, last) {
17121
- if (f.LR) {
17122
- if (i === 0) return i === last ? TOP2 | BOTTOM2 | RIGHT2 | LEFT2 : TOP2 | BOTTOM2 | LEFT2;
17123
- return i === last ? TOP2 | BOTTOM2 | RIGHT2 : TOP2 | BOTTOM2;
17124
- }
17125
- if (i === 0) return i === last ? TOP2 | BOTTOM2 | RIGHT2 | LEFT2 : TOP2 | RIGHT2 | LEFT2;
17126
- return i === last ? LEFT2 | BOTTOM2 | RIGHT2 : LEFT2 | RIGHT2;
17033
+ function deleteFastNode(g, n) {
17034
+ if (n.info.prev !== void 0) n.info.prev.info.next = n.info.next;
17035
+ else g.info.nlist = n.info.next;
17036
+ if (n.info.next !== void 0) n.info.next.info.prev = n.info.prev;
17127
17037
  }
17128
- function posReclbl(f, ul, sides) {
17129
- f.sides = sides;
17130
- f.b = {
17131
- ll: { x: ul.x, y: ul.y - f.size.y },
17132
- ur: { x: ul.x + f.size.x, y: ul.y }
17133
- };
17134
- const last = f.n_flds - 1;
17135
- const pos = { x: ul.x, y: ul.y };
17136
- for (let i = 0; i <= last; i++) {
17137
- const mask = sides ? recSideMask(f, i, last) : 0;
17138
- posReclbl(f.fld[i], { x: pos.x, y: pos.y }, sides & mask);
17139
- if (f.LR) pos.x += f.fld[i].size.x;
17140
- else pos.y -= f.fld[i].size.y;
17038
+ function removeFromRank(g, n) {
17039
+ const r = n.info.rank !== void 0 ? n.info.rank : 0;
17040
+ const rank3 = g.info.rank;
17041
+ if (rank3 === void 0) return;
17042
+ const rk = rank3[r];
17043
+ for (let j = 0; j < rk.n; j++) {
17044
+ const v = rk.v[j];
17045
+ if (v === n) {
17046
+ for (j++; j < rk.n; j++) {
17047
+ rk.v[j - 1] = rk.v[j];
17048
+ }
17049
+ rk.n--;
17050
+ break;
17051
+ }
17141
17052
  }
17142
17053
  }
17143
- function attrBool(n, g, key) {
17144
- const s = nodeAttr(n, g, key);
17145
- if (!s || s.toLowerCase() === "false" || s.toLowerCase() === "no") return false;
17146
- if (s.toLowerCase() === "true" || s.toLowerCase() === "yes") return true;
17147
- return parseInt(s, 10) !== 0;
17054
+ function virtualNode(g) {
17055
+ const n = new Node(0, "", g.root);
17056
+ n.info.node_type = VIRTUAL;
17057
+ n.info.lw = 1;
17058
+ n.info.rw = 1;
17059
+ n.info.ht = 1;
17060
+ n.info.UF_size = 1;
17061
+ n.info.in = { list: [], size: 0 };
17062
+ n.info.out = { list: [], size: 0 };
17063
+ fastNode(g, n);
17064
+ return n;
17148
17065
  }
17149
- function recAttrSize(n, g) {
17150
- const w = nodeAttr(n, g, "width");
17151
- const h = nodeAttr(n, g, "height");
17152
- return {
17153
- x: (w !== void 0 ? parseFloat(w) : 0.75) * 72,
17154
- y: (h !== void 0 ? parseFloat(h) : 0.5) * 72
17155
- };
17066
+ function otherEdge(e) {
17067
+ if (!e.tail.info.other) e.tail.info.other = { list: [], size: 0 };
17068
+ elistAppend(e.tail.info.other, e);
17156
17069
  }
17157
- function recParseOrFallback(lbl, measurer, flip, obj) {
17158
- const p = { s: lbl.text, i: 0, lbl, measurer, obj };
17159
- const info = parseReclbl(p, flip, true);
17160
- if (info !== null) return info;
17161
- const fb = { s: "\\N", i: 0, lbl, measurer, obj };
17162
- return parseReclbl(fb, flip, true);
17070
+
17071
+ // src/common/splines-geom.ts
17072
+ function approxEqPt(p, q, tol) {
17073
+ const dx = p.x - q.x;
17074
+ const dy = p.y - q.y;
17075
+ return dx * dx + dy * dy < tol * tol;
17163
17076
  }
17164
- function recordInit(n, g, measurer) {
17165
- const lbl = n.info.label;
17166
- const flip = ((g.root.info.rankdir ?? 0) >> 2 & 1) === 1 ? 0 : 1;
17167
- const info = recParseOrFallback(lbl, measurer, flip, n);
17168
- sizeReclbl(n, g, info);
17169
- const sz = recAttrSize(n, g);
17170
- if (!attrBool(n, g, "fixedsize")) {
17171
- sz.x = Math.max(info.size.x, sz.x);
17172
- sz.y = Math.max(info.size.y, sz.y);
17077
+ function evalBezier(sp, t, left, right) {
17078
+ const ab = { x: sp[0].x + t * (sp[1].x - sp[0].x), y: sp[0].y + t * (sp[1].y - sp[0].y) };
17079
+ const bc = { x: sp[1].x + t * (sp[2].x - sp[1].x), y: sp[1].y + t * (sp[2].y - sp[1].y) };
17080
+ const cd = { x: sp[2].x + t * (sp[3].x - sp[2].x), y: sp[2].y + t * (sp[3].y - sp[2].y) };
17081
+ const abbc = { x: ab.x + t * (bc.x - ab.x), y: ab.y + t * (bc.y - ab.y) };
17082
+ const bccd = { x: bc.x + t * (cd.x - bc.x), y: bc.y + t * (cd.y - bc.y) };
17083
+ const pt = { x: abbc.x + t * (bccd.x - abbc.x), y: abbc.y + t * (bccd.y - abbc.y) };
17084
+ if (left !== null) {
17085
+ left[0] = sp[0];
17086
+ left[1] = ab;
17087
+ left[2] = abbc;
17088
+ left[3] = pt;
17173
17089
  }
17174
- resizeReclbl(info, sz, attrBool(n, g, "nojustify"));
17175
- posReclbl(info, { x: -sz.x / 2, y: sz.y / 2 }, BOTTOM2 | RIGHT2 | TOP2 | LEFT2);
17176
- n.info.width = info.size.x / 72;
17177
- n.info.height = (info.size.y + 1) / 72;
17178
- const ns = gvNodesize(info.size.x, info.size.y + 1, g.root.info.flip === true);
17179
- n.info.lw = ns.lw;
17180
- n.info.rw = ns.rw;
17181
- n.info.ht = ns.ht;
17182
- n.info.shape_info = info;
17090
+ if (right !== null) {
17091
+ right[0] = pt;
17092
+ right[1] = bccd;
17093
+ right[2] = cd;
17094
+ right[3] = sp[3];
17095
+ }
17096
+ return pt;
17183
17097
  }
17184
- function recordMakeLabel(n, g, measurer) {
17185
- const labelText = nodeAttr(n, g, "label") ?? n.name;
17186
- const { fontname, fontsize, fontcolor } = readFontAttrs(n, g);
17187
- n.info.label = makeLabel(labelText, fontname, fontsize, fontcolor, measurer);
17098
+ var HW = 2;
17099
+ var SMALL = 1e-10;
17100
+ function ptToLine2(a, b, p) {
17101
+ const dx = b.x - a.x;
17102
+ const dy = b.y - a.y;
17103
+ let a2 = (p.y - a.y) * dx - (p.x - a.x) * dy;
17104
+ a2 *= a2;
17105
+ if (a2 < SMALL) return 0;
17106
+ return a2 / (dx * dx + dy * dy);
17188
17107
  }
17189
- function recordNodeInit(n, g, measurer) {
17190
- recordMakeLabel(n, g, measurer);
17191
- recordInit(n, g, measurer);
17108
+ function checkControlPoints(cp) {
17109
+ const dis1 = ptToLine2(cp[0], cp[3], cp[1]);
17110
+ const dis2 = ptToLine2(cp[0], cp[3], cp[2]);
17111
+ return dis1 < HW * HW && dis2 < HW * HW;
17192
17112
  }
17193
- function genFields(job, n, f) {
17194
- const renderer = job.renderer;
17195
- const coord = n.info.coord ?? { x: 0, y: 0 };
17196
- if (f.lp) {
17197
- const mid = {
17198
- x: (f.b.ll.x + f.b.ur.x) / 2 + coord.x,
17199
- y: (f.b.ll.y + f.b.ur.y) / 2 + coord.y
17200
- };
17201
- renderLabel(f.lp, mid, renderer, job);
17202
- }
17203
- for (let i = 0; i < f.n_flds; i++) {
17204
- if (i > 0) genFieldSeparator(job, coord, f, f.fld[i]);
17205
- genFields(job, n, f.fld[i]);
17206
- }
17207
- }
17208
- function genFieldSeparator(job, coord, f, child) {
17209
- const a = { x: 0, y: 0 };
17210
- const b = { x: 0, y: 0 };
17211
- if (f.LR) {
17212
- a.x = child.b.ll.x;
17213
- a.y = child.b.ll.y;
17214
- b.x = a.x;
17215
- b.y = child.b.ur.y;
17216
- } else {
17217
- b.x = child.b.ur.x;
17218
- b.y = child.b.ur.y;
17219
- a.x = child.b.ll.x;
17220
- a.y = b.y;
17221
- }
17222
- const pts = [
17223
- transformPoint({ x: a.x + coord.x, y: a.y + coord.y }, job),
17224
- transformPoint({ x: b.x + coord.x, y: b.y + coord.y }, job)
17225
- ];
17226
- job.renderer.polyline(pts, job);
17227
- }
17228
- function recordGencode(rawJob, rawNode) {
17229
- const job = rawJob;
17230
- const n = rawNode;
17231
- if (!job.renderer) return;
17232
- const f = n.info.shape_info;
17233
- if (!f) return;
17234
- const coord = n.info.coord ?? { x: 0, y: 0 };
17235
- const ll = { x: f.b.ll.x + coord.x, y: f.b.ll.y + coord.y };
17236
- const ur = { x: f.b.ur.x + coord.x, y: f.b.ur.y + coord.y };
17237
- const filled = job.obj !== null && applyNodeStyle(job.obj, n, job);
17238
- drawRecordBox(job, n, ll, ur, filled);
17239
- genFields(job, n, f);
17240
- }
17241
- function drawRecordBox(job, n, ll, ur, filled) {
17242
- const isMrecord = nodeAttr(n, n.root, "shape") === "Mrecord";
17243
- const rounded = isMrecord || parseStyleFlags(nodeAttr(n, n.root, "style")).rounded;
17244
- if (rounded) {
17245
- const af = [{ x: ll.x, y: ll.y }, { x: ur.x, y: ll.y }, { x: ur.x, y: ur.y }, { x: ll.x, y: ur.y }];
17246
- emitRoundedBezier(af, { x: 0, y: 0 }, filled, { renderer: job.renderer, job });
17247
- return;
17248
- }
17249
- const pts = [{ x: ll.x, y: ll.y }, { x: ll.x, y: ur.y }, { x: ur.x, y: ur.y }, { x: ur.x, y: ll.y }].map((q) => transformPoint(q, job));
17250
- job.renderer.polygon(pts, filled, job);
17251
- }
17252
-
17253
- // src/common/poly-init.ts
17254
- var DEFAULT_LW = 27;
17255
- var DEFAULT_RW = 27;
17256
- var DEFAULT_HT = 36;
17257
- function nodeAttr(n, g, key) {
17258
- const own = n.attrs.get(key);
17259
- if (own !== void 0) return own;
17260
- if (n.nodeDefaultsSnapshot !== void 0) return n.nodeDefaultsSnapshot.get(key);
17261
- return g.nodeDefaults.get(key) ?? (g !== g.root ? g.root.nodeDefaults.get(key) : void 0);
17262
- }
17263
- function readFontAttrs(n, g) {
17264
- return {
17265
- fontname: nodeAttr(n, g, "fontname") ?? DEFAULT_FONTNAME,
17266
- fontsize: parseFloat(nodeAttr(n, g, "fontsize") ?? String(DEFAULT_FONTSIZE2)),
17267
- fontcolor: nodeAttr(n, g, "fontcolor") ?? DEFAULT_COLOR2
17268
- };
17269
- }
17270
- function assignShapeInfo(n, polyDesc) {
17271
- const w = n.info.width !== void 0 ? n.info.width * 72 : (n.info.lw || DEFAULT_LW) + (n.info.rw || DEFAULT_RW);
17272
- const h = n.info.height !== void 0 ? n.info.height * 72 : n.info.ht || DEFAULT_HT;
17273
- const base = n.info.base_width !== void 0 && n.info.base_height !== void 0 ? { w: n.info.base_width * 72, h: n.info.base_height * 72 } : void 0;
17274
- n.info.shape_info = {
17275
- ...polyDesc,
17276
- vertices: computeVertices(polyDesc, w, h, base)
17277
- };
17278
- }
17279
- function buildNodeLabel(n, g, measurer) {
17280
- if (n.info.label !== void 0) return;
17281
- const labelAttr = nodeAttr(n, g, "label");
17282
- const font = readFontAttrs(n, g);
17283
- const isHtml = labelAttr !== void 0 && isHtmlValue(labelAttr);
17284
- const content = isHtml ? htmlValueContent(labelAttr) : labelAttr ?? n.name;
17285
- n.info.label = makeAnyLabel(content, isHtml, font, measurer, n);
17286
- }
17287
- function polyInit(n, g, measurer) {
17288
- const shapeName = nodeAttr(n, g, "shape") ?? "ellipse";
17289
- const shapefile = nodeAttr(n, g, "shapefile");
17290
- n.info.shape = bindShape(shapeName, shapefile);
17291
- if (shapefile !== void 0 && shapefile !== "" && shapeName !== "epsf") {
17292
- console.error(`Warning: No or improper shapefile="${shapefile}" for node "${n.name}"`);
17293
- }
17294
- if (n.info.shape.kind === 2 /* SH_RECORD */) {
17295
- if (n.info.shape_info === void 0) recordNodeInit(n, g, measurer);
17296
- return;
17297
- }
17298
- buildNodeLabel(n, g, measurer);
17299
- if (n.info.shape_info !== void 0) return;
17300
- const polyDesc = n.info.shape.polygon;
17301
- if (polyDesc !== null) assignShapeInfo(n, polyDesc);
17302
- }
17303
-
17304
- // src/render/svg-multicolor.ts
17305
- var THIN_LINE = 0.5;
17306
- function rationalFunction(x, c) {
17307
- return (x * (x * c[0] + c[1]) + c[2]) / (x + c[3]);
17308
- }
17309
- var COEFFS3LOW = [
17310
- [
17311
- [3.85268, -21.229, -0.330434, 0.0127842],
17312
- [-1.61486, 0.706564, 0.225945, 0.263682],
17313
- [-0.910164, 0.388383, 551445e-8, 671814e-8],
17314
- [-0.630184, 0.192402, 98871e-7, 0.0102527]
17315
- ],
17316
- [
17317
- [-0.162211, 9.94329, 0.13723, 0.0124084],
17318
- [-0.253135, 187735e-8, 0.0230286, 0.01264],
17319
- [-0.0695069, -0.0437594, 0.0120636, 0.0163087],
17320
- [-0.0328856, -926032e-8, -173573e-8, 527385e-8]
17321
- ]
17322
- ];
17323
- var COEFFS3HIGH = [
17324
- [
17325
- [0.0899116, -19.2349, -4.11711, 0.183362],
17326
- [0.138148, -1.45804, 1.32044, 1.38474],
17327
- [0.230903, -0.450262, 0.219963, 0.414038],
17328
- [0.0590565, -0.101062, 0.0430592, 0.0204699]
17329
- ],
17330
- [
17331
- [0.0164649, 9.89394, 0.0919496, 760802e-8],
17332
- [0.0191603, -0.0322058, 0.0134667, -0.0825018],
17333
- [0.0156192, -0.017535, 326508e-8, -0.228157],
17334
- [-0.0236752, 0.0405821, -0.0173086, 0.176187]
17335
- ]
17336
- ];
17337
- var SAFETY3 = [1e-3, 4.98, 0.207, 67e-4];
17338
- function estimateError(a, b, etaA, etaB) {
17339
- const eta = 0.5 * (etaA + etaB);
17340
- const x = b / a;
17341
- const dEta = etaB - etaA;
17342
- const cos2 = Math.cos(2 * eta);
17343
- const cos4 = Math.cos(4 * eta);
17344
- const cos6 = Math.cos(6 * eta);
17345
- const c = x < 0.25 ? COEFFS3LOW : COEFFS3HIGH;
17346
- const c0 = rationalFunction(x, c[0][0]) + cos2 * rationalFunction(x, c[0][1]) + cos4 * rationalFunction(x, c[0][2]) + cos6 * rationalFunction(x, c[0][3]);
17347
- const c1 = rationalFunction(x, c[1][0]) + cos2 * rationalFunction(x, c[1][1]) + cos4 * rationalFunction(x, c[1][2]) + cos6 * rationalFunction(x, c[1][3]);
17348
- return rationalFunction(x, SAFETY3) * a * Math.exp(c0 + c1 * dEta);
17349
- }
17350
- function allSubdivsBelowThreshold(a, b, eta1, n, dEta) {
17351
- let etaA = eta1;
17352
- for (let i = 0; i < n; i++) {
17353
- if (estimateError(a, b, etaA, etaA + dEta) > 1e-5) return false;
17354
- etaA += dEta;
17355
- }
17356
- return true;
17357
- }
17358
- function numSubdivisions(a, b, eta1, eta2) {
17359
- let n = 1;
17360
- while (n < 1024) {
17361
- const dEta = (eta2 - eta1) / n;
17362
- if (dEta <= 0.5 * Math.PI && allSubdivsBelowThreshold(a, b, eta1, n, dEta)) break;
17363
- n <<= 1;
17364
- }
17365
- return n;
17366
- }
17367
- function initArcPath(pts, e, eta1) {
17368
- const cosE = Math.cos(eta1);
17369
- const sinE = Math.sin(eta1);
17370
- const xB = e.cx + e.xsemi * cosE;
17371
- const yB = e.cy + e.ysemi * sinE;
17372
- pts.push(
17373
- { x: e.cx, y: e.cy },
17374
- { x: e.cx, y: e.cy },
17375
- { x: xB, y: yB },
17376
- { x: xB, y: yB }
17377
- );
17378
- return { xB, yB, xBDot: -e.xsemi * sinE, yBDot: e.ysemi * cosE };
17379
- }
17380
- function stepBezier(pts, state3, e, sp) {
17381
- const xA = state3.xB;
17382
- const yA = state3.yB;
17383
- const xADot = state3.xBDot;
17384
- const yADot = state3.yBDot;
17385
- const newEta = sp.etaB + sp.dEta;
17386
- const cosE = Math.cos(newEta);
17387
- const sinE = Math.sin(newEta);
17388
- state3.xB = e.cx + e.xsemi * cosE;
17389
- state3.yB = e.cy + e.ysemi * sinE;
17390
- state3.xBDot = -e.xsemi * sinE;
17391
- state3.yBDot = e.ysemi * cosE;
17392
- pts.push({ x: xA + sp.alpha * xADot, y: yA + sp.alpha * yADot });
17393
- pts.push({ x: state3.xB - sp.alpha * state3.xBDot, y: state3.yB - sp.alpha * state3.yBDot });
17394
- pts.push({ x: state3.xB, y: state3.yB });
17395
- return newEta;
17396
- }
17397
- function ellipticWedge(e, angle0, angle1) {
17398
- const TWOPI2 = 2 * Math.PI;
17399
- const eta1 = Math.atan2(Math.sin(angle0) / e.ysemi, Math.cos(angle0) / e.xsemi);
17400
- let eta2 = Math.atan2(Math.sin(angle1) / e.ysemi, Math.cos(angle1) / e.xsemi);
17401
- eta2 -= TWOPI2 * Math.floor((eta2 - eta1) / TWOPI2);
17402
- if (angle1 - angle0 > Math.PI && eta2 - eta1 < Math.PI) eta2 += TWOPI2;
17403
- const n = numSubdivisions(e.xsemi, e.ysemi, eta1, eta2);
17404
- const dEta = (eta2 - eta1) / n;
17405
- const t = Math.tan(0.5 * dEta);
17406
- const alpha = Math.sin(dEta) * (Math.sqrt(4 + 3 * t * t) - 1) / 3;
17407
- const pts = [];
17408
- const state3 = initArcPath(pts, e, eta1);
17409
- let sp = { etaB: eta1, dEta, alpha };
17410
- for (let i = 0; i < n; i++) sp = { ...sp, etaB: stepBezier(pts, state3, e, sp) };
17411
- pts.push({ x: state3.xB, y: state3.yB }, { x: e.cx, y: e.cy }, { x: e.cx, y: e.cy });
17412
- return pts;
17413
- }
17414
- function drawWedge(seg2, e, ctx) {
17415
- const TWOPI2 = 2 * Math.PI;
17416
- const angle1 = seg2.isLast ? TWOPI2 : seg2.angle0 + TWOPI2 * seg2.t;
17417
- const obj = ctx.job.obj;
17418
- if (obj !== null) obj.fillColor = resolveRenderColor(seg2.color);
17419
- const ptsUp = ellipticWedge(e, seg2.angle0, angle1);
17420
- ctx.renderer.bezier(ptsUp.map((p) => ({ x: p.x, y: -p.y })), true, ctx.job);
17421
- return angle1;
17422
- }
17423
- function wedgedEllipse(job, pf, clrs, renderer) {
17424
- const { segs, error } = parseSegs(clrs);
17425
- if (error === 1 || error === 2) return error;
17426
- const ctrX = (pf[0].x + pf[1].x) / 2;
17427
- const ctrY = (pf[0].y + pf[1].y) / 2;
17428
- const e = {
17429
- cx: ctrX,
17430
- cy: -ctrY,
17431
- xsemi: pf[1].x - ctrX,
17432
- ysemi: Math.abs(pf[1].y - ctrY)
17433
- };
17434
- const ctx = { job, renderer };
17435
- const obj = job.obj;
17436
- const saved = obj !== null ? obj.penWidth : 1;
17437
- if (obj !== null && saved > THIN_LINE) obj.penWidth = THIN_LINE;
17438
- let angle0 = 0;
17439
- for (let i = 0; i < segs.length; i++) {
17440
- const s = segs[i];
17441
- if (s.color === null) break;
17442
- if (s.t > 0) {
17443
- angle0 = drawWedge({ angle0, t: s.t, isLast: i + 1 === segs.length, color: s.color }, e, ctx);
17444
- }
17445
- }
17446
- if (obj !== null && saved > THIN_LINE) obj.penWidth = saved;
17447
- return error;
17448
- }
17449
- function drawBand(p, seg2, ctx) {
17450
- const obj = ctx.job.obj;
17451
- if (obj !== null) obj.fillColor = resolveRenderColor(seg2.color);
17452
- p[1].x = p[2].x = seg2.isLast ? seg2.lastx : p[0].x + seg2.segWidth;
17453
- ctx.renderer.polygon([...p], true, ctx.job);
17454
- p[0].x = p[3].x = p[1].x;
17455
- }
17456
- function stripedBox(job, pts, clrs, rotate, renderer) {
17457
- const { segs, error } = parseSegs(clrs);
17458
- if (error === 1 || error === 2) return error;
17459
- const p = rotate ? [{ ...pts[2] }, { ...pts[3] }, { ...pts[0] }, { ...pts[1] }] : [{ ...pts[0] }, { ...pts[1] }, { ...pts[2] }, { ...pts[3] }];
17460
- const lastx = p[1].x;
17461
- const xdelta = p[1].x - p[0].x;
17462
- p[1].x = p[2].x = p[0].x;
17463
- const ctx = { job, renderer };
17464
- const obj = job.obj;
17465
- const saved = obj !== null ? obj.penWidth : 1;
17466
- if (obj !== null && saved > THIN_LINE) obj.penWidth = THIN_LINE;
17467
- for (let i = 0; i < segs.length; i++) {
17468
- const s = segs[i];
17469
- if (s.color === null) break;
17470
- if (s.t > 0) {
17471
- drawBand(p, { color: s.color, isLast: i + 1 === segs.length, segWidth: xdelta * s.t, lastx }, ctx);
17472
- }
17473
- }
17474
- if (obj !== null && saved > THIN_LINE) obj.penWidth = saved;
17475
- return error;
17476
- }
17477
-
17478
- // src/render/xml-escape.ts
17479
- var RE_DQUOTE = new RegExp('"', "g");
17480
- var RE_SQUOTE = new RegExp("'", "g");
17481
- var RE_AMP_NONENTITY = /&(?![A-Za-z]+;|#[0-9]+;|#x[0-9A-Fa-f]+;)/g;
17482
- function escapeXml(s) {
17483
- let r = s.replace(RE_AMP_NONENTITY, "&amp;");
17484
- r = r.replace(/</g, "&lt;");
17485
- r = r.replace(/>/g, "&gt;");
17486
- r = r.replace(RE_DQUOTE, "&quot;");
17487
- r = r.replace(RE_SQUOTE, "&#39;");
17488
- return r;
17489
- }
17490
- function escapeXmlTitle(s) {
17491
- let r = escapeXml(s);
17492
- r = r.replace(/-/g, "&#45;");
17493
- r = r.replace(/ {2,}/g, (m) => " " + "&#160;".repeat(m.length - 1));
17494
- return r;
17495
- }
17496
- function escapeXmlText(s) {
17497
- let r = escapeXml(s);
17498
- r = r.replace(/-/g, "&#45;");
17499
- r = r.replace(/\n/g, "&#10;");
17500
- r = r.replace(/\r/g, "&#13;");
17501
- r = r.replace(/ {2,}/g, (m) => " " + "&#160;".repeat(m.length - 1));
17502
- return r;
17503
- }
17504
-
17505
- // src/gvc/device-cluster.ts
17506
- function applyClusterGradient(obj, fill) {
17507
- obj.fill = fill.kind === "radial" ? 3 /* Radial */ : 2 /* Linear */;
17508
- obj.fillColor = resolveRenderColor(fill.fillColor);
17509
- obj.stopColor = resolveRenderColor(fill.stopColor);
17510
- obj.gradientFrac = fill.frac;
17511
- obj.gradientAngle = fill.angle;
17512
- }
17513
- function clusterAttr(sg, key) {
17514
- for (let g = sg; g !== null; g = g.parent) {
17515
- const v = g.attrs.get(key);
17516
- if (v !== void 0) return v;
17517
- }
17518
- return void 0;
17519
- }
17520
- function clusterStyle(sg) {
17521
- return clusterAttr(sg, "style");
17522
- }
17523
- function clusterPeripheries(sg) {
17524
- const raw = clusterAttr(sg, "peripheries");
17525
- if (raw === void 0 || raw.length === 0) return 1;
17526
- const v = parseInt(raw, 10);
17527
- if (Number.isNaN(v)) return 1;
17528
- return v < 0 ? 0 : v;
17529
- }
17530
- function applyClusterPenState(obj, sg) {
17531
- const flags = parseStyleFlags(clusterStyle(sg));
17532
- const pen = clusterAttr(sg, "pencolor") ?? clusterAttr(sg, "color");
17533
- obj.penColor = clusterPeripheries(sg) === 0 ? resolveRenderColor("transparent") : resolveRenderColor(resolvePenColor(pen));
17534
- obj.penWidth = resolvePenWidth(flags, clusterAttr(sg, "penwidth"));
17535
- obj.pen = resolvePenType(flags);
17536
- }
17537
- function clusterAttrsOf(sg) {
17538
- return {
17539
- style: clusterStyle(sg),
17540
- color: clusterAttr(sg, "color"),
17541
- pencolor: clusterAttr(sg, "pencolor"),
17542
- fillcolor: clusterAttr(sg, "fillcolor"),
17543
- bgcolor: clusterAttr(sg, "bgcolor"),
17544
- penwidth: clusterAttr(sg, "penwidth"),
17545
- gradientangle: clusterAttr(sg, "gradientangle")
17546
- };
17547
- }
17548
- function applyClusterObjState(sg, job) {
17549
- const fillRes = resolveClusterFillEx(clusterAttrsOf(sg));
17550
- if (job.obj === null) return false;
17551
- const obj = job.obj;
17552
- return withColorScheme(clusterAttr(sg, "colorscheme"), () => {
17553
- applyClusterPenState(obj, sg);
17554
- if (fillRes.kind === "none") {
17555
- obj.fill = 0 /* None */;
17556
- return false;
17557
- }
17558
- if (fillRes.kind === "solid") {
17559
- obj.fill = 1 /* Solid */;
17560
- obj.fillColor = resolveRenderColor(fillRes.color);
17561
- return true;
17562
- }
17563
- applyClusterGradient(obj, fillRes);
17564
- return true;
17565
- });
17566
- }
17567
-
17568
- // src/render/svg-id.ts
17569
- function svgClass(kind, classAttr) {
17570
- return classAttr !== void 0 && classAttr.length > 0 ? 'class="' + kind + " " + escapeXmlTitle(classAttr) + '"' : 'class="' + kind + '"';
17571
- }
17572
- function svgNodeId(n, job) {
17573
- return job.objId(n.attrs.get("id"), "node" + (n.id + 1));
17574
- }
17575
- function svgEdgeId(e, job) {
17576
- return job.objId(e.attrs.get("id"), "edge" + e.graphSeq);
17577
- }
17578
- function svgClusterId(sg, job) {
17579
- return job.objId(sg.attrs.get("id"), "clust" + sg.seq);
17580
- }
17581
- function svgGraphId(g, job) {
17582
- return job.objId(g.attrs.get("id"), "graph0", true);
17583
- }
17584
- function svgNodeClass(n) {
17585
- return svgClass("node", nodeAttr(n, n.root, "class"));
17586
- }
17587
- function svgEdgeClass(e) {
17588
- return svgClass("edge", e.attrs.get("class"));
17589
- }
17590
- function svgClusterClass(sg) {
17591
- return svgClass("cluster", clusterAttr(sg, "class"));
17592
- }
17593
- function svgGraphClass(g) {
17594
- return svgClass("graph", g.attrs.get("class"));
17595
- }
17596
-
17597
- // src/common/poly-gencode.ts
17598
- function isMulticolor(fillcolor) {
17599
- return fillcolor.includes(":");
17600
- }
17601
- function renderEllipse(ring, coord, renderer, job, filled) {
17602
- const rx = Math.abs((ring[1].x - ring[0].x) / 2);
17603
- const ry = Math.abs((ring[1].y - ring[0].y) / 2);
17604
- const center = transformPoint(coord, job);
17605
- renderer.ellipse(center, rx, ry, filled, job);
17606
- }
17607
- function renderPolygon(ring, coord, renderer, job, filled) {
17608
- const pts = ring.map((v) => transformPoint({ x: v.x + coord.x, y: v.y + coord.y }, job));
17609
- renderer.polygon(pts, filled, job);
17610
- }
17611
- function renderEllipseRing(ring, coord, filled, j, ctx) {
17612
- if (ctx.style.wedged && j === 0 && isMulticolor(ctx.fillcolor)) {
17613
- const pf = ring.map(
17614
- (v) => transformPoint({ x: v.x + coord.x, y: v.y + coord.y }, ctx.job)
17615
- );
17616
- wedgedEllipse(ctx.job, pf, ctx.fillcolor, ctx.renderer);
17617
- renderEllipse(ring, coord, ctx.renderer, ctx.job, false);
17618
- } else {
17619
- renderEllipse(ring, coord, ctx.renderer, ctx.job, filled);
17620
- }
17621
- if (ctx.diagonals) mcircleHack(ring, coord, ctx);
17622
- }
17623
- function renderStripedRing(ring, coord, ctx) {
17624
- const af = ring.map((v) => transformPoint({ x: v.x + coord.x, y: v.y + coord.y }, ctx.job));
17625
- stripedBox(ctx.job, af, ctx.fillcolor, true, ctx.renderer);
17626
- renderPolygon(ring, coord, ctx.renderer, ctx.job, false);
17627
- }
17628
- function renderPolyRing(ring, coord, filled, j, ctx) {
17629
- if (ctx.style.striped && j === 0) renderStripedRing(ring, coord, ctx);
17630
- else if (ctx.underline) underlineDraw(ring, coord, filled, ctx);
17631
- else if (ctx.shape !== 0 && ctx.shape !== STAR || ctx.diagonals || ctx.rounded) {
17632
- drawRoundCorners(ring, coord, filled, ctx);
17633
- } else renderPolygon(ring, coord, ctx.renderer, ctx.job, filled);
17634
- }
17635
- function renderPeripheries(poly, coord, filled, ctx) {
17636
- const sides = poly.sides <= 2 ? 2 : poly.sides;
17637
- const verts = poly.vertices;
17638
- for (let j = 0; j < poly.peripheries; j++) {
17639
- const ring = verts.slice(j * sides, (j + 1) * sides);
17640
- if (ring.length < sides) break;
17641
- const ringFilled = j === 0 ? filled : false;
17642
- if (poly.sides <= 2) {
17643
- renderEllipseRing(ring, coord, ringFilled, j, ctx);
17644
- } else {
17645
- renderPolyRing(ring, coord, ringFilled, j, ctx);
17646
- }
17647
- }
17648
- }
17649
- function renderLabel(label, coord, renderer, job) {
17650
- if (label.u.kind !== "txt" || label.u.nspans < 1) return;
17651
- label.pos = coord;
17652
- label.set = true;
17653
- const VALIGN_TOP2 = "t".charCodeAt(0);
17654
- const VALIGN_BOTTOM2 = "b".charCodeAt(0);
17655
- let py = label.valign === VALIGN_TOP2 ? coord.y + label.space.y / 2 - label.fontsize : label.valign === VALIGN_BOTTOM2 ? coord.y - label.space.y / 2 + label.dimen.y - label.fontsize : coord.y + label.dimen.y / 2 - label.fontsize;
17656
- for (let i = 0; i < label.u.nspans; i++) {
17657
- const span = label.u.span[i];
17658
- const px = span.just === "l" ? coord.x - label.space.x / 2 : span.just === "r" ? coord.x + label.space.x / 2 : coord.x;
17659
- gvrenderTextspan(renderer, { x: px, y: py }, span, job);
17660
- py -= span.size.y;
17661
- }
17662
- }
17663
- function renderNodeLabel(n, coord, renderer, job) {
17664
- const label = n.info.label;
17665
- if (label === void 0) return;
17666
- if (label.html && label.u.kind === "html") {
17667
- label.pos = coord;
17668
- label.set = true;
17669
- const html = label.u.html;
17670
- withLabelEmitState(job, () => emitHtmlLabel(html, coord, renderer, job));
17671
- } else {
17672
- renderLabel(label, coord, renderer, job);
17673
- }
17674
- }
17675
- function anchorAttr2(n, key) {
17676
- const v = nodeAttr(n, n.root, key);
17677
- return v !== void 0 && v !== "" ? v : void 0;
17678
- }
17679
- function resolveTooltip(n, tooltip) {
17680
- if (tooltip !== void 0) return substObjAnchor(interpretCRNL(tooltip), n);
17681
- const label = n.info.label;
17682
- return label?.text ?? "";
17683
- }
17684
- function beginNodeAnchor(n, renderer, job) {
17685
- const url = anchorAttr2(n, "href") ?? anchorAttr2(n, "URL");
17686
- const tooltip = anchorAttr2(n, "tooltip");
17687
- if (url === void 0 && tooltip === void 0) return false;
17688
- renderer.beginAnchor?.(
17689
- url !== void 0 ? substObjAnchor(url, n) : "",
17690
- resolveTooltip(n, tooltip),
17691
- anchorAttr2(n, "target") ?? "",
17692
- svgNodeId(n, job),
17693
- job
17694
- );
17695
- return true;
17696
- }
17697
- function applyGradientFields(obj, fill) {
17698
- obj.fill = fill.kind === "radial" ? 3 /* Radial */ : 2 /* Linear */;
17699
- obj.fillColor = resolveRenderColor(fill.fillColor);
17700
- obj.stopColor = resolveRenderColor(fill.stopColor);
17701
- obj.gradientFrac = fill.frac;
17702
- obj.gradientAngle = fill.angle;
17703
- }
17704
- function isPointNode(n) {
17705
- return n.info.shape?.kind === 3 /* SH_POINT */;
17706
- }
17707
- function findFillDflt(n) {
17708
- const fillcolor = nodeAttr(n, n.root, "fillcolor");
17709
- if (fillcolor !== void 0 && fillcolor !== "") return fillcolor;
17710
- const color = nodeAttr(n, n.root, "color");
17711
- if (color !== void 0 && color !== "") return color;
17712
- return "black";
17713
- }
17714
- function applyFillState(obj, n, job) {
17715
- obj.id = svgNodeId(n, job);
17716
- if (isPointNode(n)) {
17717
- obj.fill = 1 /* Solid */;
17718
- obj.fillColor = resolveRenderColor(findFillDflt(n));
17719
- return true;
17720
- }
17721
- const fillRes = resolveNodeFillEx({
17722
- style: nodeAttr(n, n.root, "style"),
17723
- fillcolor: nodeAttr(n, n.root, "fillcolor"),
17724
- color: nodeAttr(n, n.root, "color"),
17725
- gradientangle: nodeAttr(n, n.root, "gradientangle")
17726
- });
17727
- if (fillRes.kind === "none") {
17728
- obj.fill = 0 /* None */;
17729
- return false;
17730
- }
17731
- if (fillRes.kind === "solid") {
17732
- obj.fill = 1 /* Solid */;
17733
- obj.fillColor = resolveRenderColor(fillRes.color);
17734
- return true;
17735
- }
17736
- applyGradientFields(obj, fillRes);
17737
- return true;
17738
- }
17739
- function applyPenState(obj, styleAttr, colorAttr, penwidthAttr) {
17740
- const flags = parseStyleFlags(styleAttr);
17741
- obj.penColor = resolveRenderColor(resolvePenColor(colorAttr));
17742
- obj.pen = resolvePenType(flags);
17743
- obj.penWidth = resolvePenWidth(flags, penwidthAttr);
17744
- obj.rawStyle = styleTokens(styleAttr);
17745
- }
17746
- function applyNodeStyle(obj, n, job) {
17747
- const styleAttr = nodeAttr(n, n.root, "style");
17748
- const colorAttr = nodeAttr(n, n.root, "color");
17749
- const filled = applyFillState(obj, n, job);
17750
- applyPenState(obj, styleAttr, colorAttr, nodeAttr(n, n.root, "penwidth"));
17751
- return filled;
17752
- }
17753
- function prepareDrawPoly(poly, filled, obj) {
17754
- if (poly.peripheries !== 0 || !filled) return poly;
17755
- obj.penColor = { type: "string", s: "transparent" };
17756
- return { ...poly, peripheries: 1 };
17757
- }
17758
- function vertexScale(n, poly) {
17759
- const info = n.info;
17760
- if (poly.vertices == null || info.width === void 0 || info.height === void 0) {
17761
- return poly;
17762
- }
17763
- const xsize = (info.lw + info.rw) / (info.width * 72);
17764
- const ysize = info.ht / (info.height * 72);
17765
- if (Math.abs(xsize - 1) < 1e-9 && Math.abs(ysize - 1) < 1e-9) return poly;
17766
- return {
17767
- ...poly,
17768
- vertices: poly.vertices.map((v) => ({ x: v.x * xsize, y: v.y * ysize }))
17769
- };
17770
- }
17771
- function resolveNodeDrawCtx(job, n) {
17772
- const rawPoly = n.info.shape_info;
17773
- if (rawPoly === void 0 || rawPoly.vertices === void 0) return null;
17774
- const poly = vertexScale(n, rawPoly);
17775
- const coord = n.info.coord ?? { x: 0, y: 0 };
17776
- const obj = job.obj;
17777
- const filled = obj !== null && applyNodeStyle(obj, n, job);
17778
- const drawPoly = obj !== null ? prepareDrawPoly(poly, filled, obj) : poly;
17779
- const styleFlags = parseStyleFlags(nodeAttr(n, n.root, "style"));
17780
- const ringCtx = {
17781
- renderer: job.renderer,
17782
- job,
17783
- style: styleFlags,
17784
- fillcolor: nodeAttr(n, n.root, "fillcolor") ?? "",
17785
- ...specialCornerFlags(drawPoly.option, styleFlags)
17786
- };
17787
- return { poly: drawPoly, coord, filled, ringCtx };
17788
- }
17789
- function specialCornerFlags(opt, style) {
17790
- return {
17791
- shape: opt.shape,
17792
- diagonals: opt.diagonals || style.diagonals,
17793
- rounded: opt.rounded || style.rounded,
17794
- underline: opt.underline || style.underline
17795
- };
17796
- }
17797
- function polyGencode(rawJob, rawNode) {
17798
- const job = rawJob;
17799
- const n = rawNode;
17800
- const renderer = job.renderer;
17801
- if (!renderer) return;
17802
- const ctx = resolveNodeDrawCtx(job, n);
17803
- if (ctx === null) return;
17804
- const clustersLast = (job.flags & EMIT_CLUSTERS_LAST) !== 0;
17805
- const savedShape = job.obj?.urlMapShape;
17806
- const savedPts = job.obj?.urlMapPts;
17807
- let inAnchor = clustersLast ? false : beginNodeAnchor(n, renderer, job);
17808
- renderPeripheries(ctx.poly, ctx.coord, ctx.filled, ctx.ringCtx);
17809
- if (!isPointNode(n)) renderNodeLabel(n, ctx.coord, renderer, job);
17810
- if (clustersLast) {
17811
- if (job.obj && savedPts !== void 0 && savedShape !== void 0) {
17812
- job.obj.urlMapShape = savedShape;
17813
- job.obj.urlMapPts = savedPts;
17814
- }
17815
- inAnchor = beginNodeAnchor(n, renderer, job);
17816
- }
17817
- if (inAnchor) renderer.endAnchor?.(job);
17818
- }
17819
-
17820
- // src/common/poly-inside.ts
17821
- function sameSide(p0, p1, L0, L1) {
17822
- const a = -(L1.y - L0.y);
17823
- const b = L1.x - L0.x;
17824
- const c = a * L0.x + b * L0.y;
17825
- const s0 = a * p0.x + b * p0.y - c >= 0;
17826
- const s1 = a * p1.x + b * p1.y - c >= 0;
17827
- return s0 === s1;
17828
- }
17829
- function fixedShapeSize(poly) {
17830
- let xmax = 0;
17831
- let ymax = 0;
17832
- for (const v of poly.vertices ?? []) {
17833
- xmax = Math.max(xmax, Math.abs(v.x));
17834
- ymax = Math.max(ymax, Math.abs(v.y));
17835
- }
17836
- return { w: 2 * xmax, h: 2 * ymax };
17837
- }
17838
- function insideDims(n, xsize, ysize) {
17839
- const w = 72 * (n.info.width || xsize / 72);
17840
- const h = 72 * (n.info.height || ysize / 72);
17841
- return { w, h, ow: 72 * n.info.outline_width || w, oh: 72 * n.info.outline_height || h };
17842
- }
17843
- function insideScale(n, poly) {
17844
- const flip = n.root.info.flip === true;
17845
- if (poly.option.fixedshape) {
17846
- const { w: w2, h: h2 } = fixedShapeSize(poly);
17847
- const xsize2 = flip ? h2 : w2;
17848
- const ysize2 = flip ? w2 : h2;
17849
- return {
17850
- scalex: xsize2 !== 0 ? w2 / xsize2 : w2,
17851
- scaley: ysize2 !== 0 ? h2 / ysize2 : h2,
17852
- boxURx: w2 / 2,
17853
- boxURy: h2 / 2
17854
- };
17855
- }
17856
- const lwrw = n.info.lw + n.info.rw;
17857
- const xsize = flip ? n.info.ht : lwrw;
17858
- const ysize = flip ? lwrw : n.info.ht;
17859
- const { w, h, ow, oh } = insideDims(n, xsize, ysize);
17860
- return {
17861
- scalex: xsize !== 0 ? w / xsize : w,
17862
- scaley: ysize !== 0 ? h / ysize : h,
17863
- boxURx: ow / 2,
17864
- boxURy: oh / 2
17865
- };
17866
- }
17867
- function polygonWalk(P, vertex, sides) {
17868
- const O = { x: 0, y: 0 };
17869
- let i = 0;
17870
- let i1 = 1 % sides;
17871
- const Q = vertex[i];
17872
- const R2 = vertex[i1];
17873
- if (!sameSide(P, O, Q, R2)) return false;
17874
- const s = sameSide(P, Q, R2, O);
17875
- if (s && sameSide(P, R2, O, Q)) return true;
17876
- for (let j = 1; j < sides; j++) {
17877
- if (s) {
17878
- i = i1;
17879
- i1 = (i + 1) % sides;
17880
- } else {
17881
- i1 = i;
17882
- i = (i + sides - 1) % sides;
17883
- }
17884
- if (!sameSide(P, O, vertex[i], vertex[i1])) return false;
17885
- }
17886
- return true;
17887
- }
17888
- function insideShape(n, poly, p) {
17889
- const sc = insideScale(n, poly);
17890
- const P = { x: p.x * sc.scalex, y: p.y * sc.scaley };
17891
- if (Math.abs(P.x) > sc.boxURx || Math.abs(P.y) > sc.boxURy) return false;
17892
- if (poly.sides <= 2) {
17893
- return Math.hypot(P.x / sc.boxURx, P.y / sc.boxURy) < 1;
17894
- }
17895
- const outerStart = (Math.max(poly.peripheries, 1) - 1) * poly.sides;
17896
- const outer = poly.vertices.slice(outerStart, outerStart + poly.sides);
17897
- const ring = polygonOutlineRing(outer, poly.sides, poly.penwidth ?? 1);
17898
- return polygonWalk(P, ring, poly.sides);
17899
- }
17900
- function polyInside(ctx, p) {
17901
- const n = ctx.node;
17902
- if (n === void 0) return false;
17903
- const rankdir = (n.root.info.rankdir ?? 0) & 3;
17904
- const P = rankdir === 0 ? p : ccwrotatepf(p, rankdir * 90);
17905
- if (ctx.bp) {
17906
- const b = ctx.bp;
17907
- return P.x >= b.ll.x && P.x <= b.ur.x && P.y >= b.ll.y && P.y <= b.ur.y;
17908
- }
17909
- const poly = n.info.shape_info;
17910
- if (poly === void 0 || poly.vertices === null) return false;
17911
- return insideShape(n, poly, P);
17912
- }
17913
- function starInside(ctx, p) {
17914
- const n = ctx.node;
17915
- if (n === void 0) return false;
17916
- const rankdir = (n.root.info.rankdir ?? 0) & 3;
17917
- const P = rankdir === 0 ? p : ccwrotatepf(p, rankdir * 90);
17918
- if (ctx.bp) {
17919
- const b = ctx.bp;
17920
- return P.x >= b.ll.x && P.x <= b.ur.x && P.y >= b.ll.y && P.y <= b.ur.y;
17921
- }
17922
- const poly = n.info.shape_info;
17923
- if (poly === void 0 || poly.vertices === null) return false;
17924
- const sides = poly.sides;
17925
- const outerStart = (Math.max(poly.peripheries, 1) - 1) * sides;
17926
- const outer = poly.vertices.slice(outerStart, outerStart + sides);
17927
- const ring = polygonOutlineRing(outer, sides, poly.penwidth ?? 1);
17928
- const O = { x: 0, y: 0 };
17929
- let outcnt = 0;
17930
- for (let i = 0; i < sides; i += 2) {
17931
- const Q = ring[i];
17932
- const R2 = ring[(i + 4) % sides];
17933
- if (!sameSide(P, O, Q, R2)) outcnt++;
17934
- if (outcnt === 2) return false;
17935
- }
17936
- return true;
17937
- }
17938
- function recordInside(ctx, p) {
17939
- const n = ctx.node;
17940
- if (n === void 0) return false;
17941
- const rankdir = (n.root.info.rankdir ?? 0) & 3;
17942
- const P = rankdir === 0 ? p : ccwrotatepf(p, rankdir * 90);
17943
- let bb;
17944
- if (ctx.bp) {
17945
- bb = ctx.bp;
17946
- } else {
17947
- const fld = n.info.shape_info;
17948
- if (!fld?.b) return false;
17949
- bb = fld.b;
17950
- }
17951
- const pw = 0.5;
17952
- return P.x >= bb.ll.x - pw && P.x <= bb.ur.x + pw && P.y >= bb.ll.y - pw && P.y <= bb.ur.y + pw;
17953
- }
17954
-
17955
- // src/layout/dot/fastgr.ts
17956
- var VIRTUAL = 1;
17957
- var NORMAL = 0;
17958
- var FLATORDER = 4;
17959
- var REVERSED = 3;
17960
- var MC_SCALE = 256;
17961
- function elistAppend(el, e) {
17962
- el.list[el.size++] = e;
17963
- }
17964
- function zapinlist(el, e) {
17965
- let i = 0;
17966
- while (i < el.size && el.list[i] !== e) i++;
17967
- if (i < el.size) {
17968
- el.list[i] = el.list[--el.size];
17969
- el.list[el.size] = void 0;
17970
- }
17971
- }
17972
- function deleteFastEdge(e) {
17973
- if (e.tail.info.out) zapinlist(e.tail.info.out, e);
17974
- if (e.head.info.in) zapinlist(e.head.info.in, e);
17975
- }
17976
- function fastEdge(e) {
17977
- if (!e.tail.info.out) e.tail.info.out = { list: [], size: 0 };
17978
- if (!e.head.info.in) e.head.info.in = { list: [], size: 0 };
17979
- elistAppend(e.tail.info.out, e);
17980
- elistAppend(e.head.info.in, e);
17981
- }
17982
- function findFastEdge(u, v) {
17983
- const uOut = u.info.out;
17984
- const vIn = v.info.in;
17985
- if (uOut === void 0 || vIn === void 0) return void 0;
17986
- if (uOut.size <= vIn.size) {
17987
- for (let i = 0; i < uOut.size; i++) {
17988
- if (uOut.list[i].head === v) return uOut.list[i];
17989
- }
17990
- } else {
17991
- for (let i = 0; i < vIn.size; i++) {
17992
- if (vIn.list[i].tail === u) return vIn.list[i];
17993
- }
17994
- }
17995
- return void 0;
17996
- }
17997
- function copyPort(p) {
17998
- const bp = p.bp !== null ? { ll: { x: p.bp.ll.x, y: p.bp.ll.y }, ur: { x: p.bp.ur.x, y: p.bp.ur.y } } : null;
17999
- return { p: { x: p.p.x, y: p.p.y }, theta: p.theta, bp, defined: p.defined, constrained: p.constrained, clip: p.clip, dyna: p.dyna, order: p.order, side: p.side, name: p.name };
18000
- }
18001
- function copyVirtualPorts(e, orig) {
18002
- if (e.tail === orig.tail) e.info.tail_port = copyPort(orig.info.tail_port);
18003
- else if (e.tail === orig.head) e.info.tail_port = copyPort(orig.info.head_port);
18004
- if (e.head === orig.head) e.info.head_port = copyPort(orig.info.head_port);
18005
- else if (e.head === orig.tail) e.info.head_port = copyPort(orig.info.tail_port);
18006
- }
18007
- function copyVirtualEdgeInfo(e, orig) {
18008
- e.info.count = orig.info.count;
18009
- e.info.xpenalty = orig.info.xpenalty;
18010
- e.info.weight = orig.info.weight;
18011
- e.info.minlen = orig.info.minlen;
18012
- copyVirtualPorts(e, orig);
18013
- e.info.label = orig.info.label;
18014
- e.info.head_label = orig.info.head_label;
18015
- e.info.tail_label = orig.info.tail_label;
18016
- e.info.xlabel = orig.info.xlabel;
18017
- if (orig.info.to_virt === void 0) orig.info.to_virt = e;
18018
- e.info.to_orig = orig;
18019
- e.seq = orig.seq;
18020
- }
18021
- function newVirtualEdge(u, v, orig) {
18022
- const e = new Edge(u, v, "");
18023
- e.info.edge_type = VIRTUAL;
18024
- if (orig) {
18025
- copyVirtualEdgeInfo(e, orig);
18026
- } else {
18027
- e.info.weight = 1;
18028
- e.info.xpenalty = 1;
18029
- e.info.count = 1;
18030
- e.info.minlen = 1;
18031
- }
18032
- return e;
18033
- }
18034
- function virtualEdge(u, v, orig) {
18035
- const e = newVirtualEdge(u, v, orig);
18036
- fastEdge(e);
18037
- return e;
18038
- }
18039
- function mergeWeightsInto(f, ew, em, ex) {
18040
- f.info.weight = (f.info.weight ?? 0) + ew;
18041
- f.info.minlen = Math.max(f.info.minlen ?? 1, em);
18042
- f.info.count = (f.info.count ?? 1) + 1;
18043
- f.info.xpenalty = (f.info.xpenalty ?? 0) + ex;
18044
- }
18045
- function basicMerge(e, rep) {
18046
- const ew = e.info.weight ?? 1;
18047
- const em = e.info.minlen ?? 1;
18048
- const ex = e.info.xpenalty ?? 0;
18049
- for (let f = rep; f !== void 0; f = f.info.to_virt) {
18050
- mergeWeightsInto(f, ew, em, ex);
18051
- }
18052
- }
18053
- function mergeOneway(e, rep) {
18054
- if (e.info.to_virt !== void 0) return;
18055
- e.info.to_virt = rep;
18056
- basicMerge(e, rep);
18057
- }
18058
- function deleteFlatEdge(e) {
18059
- e.info.to_virt = void 0;
18060
- if (e.tail.info.flat_out) zapinlist(e.tail.info.flat_out, e);
18061
- if (e.head.info.flat_in) zapinlist(e.head.info.flat_in, e);
18062
- }
18063
- function flatEdge(g, e) {
18064
- if (!e.tail.info.flat_out) e.tail.info.flat_out = { list: [], size: 0 };
18065
- if (!e.head.info.flat_in) e.head.info.flat_in = { list: [], size: 0 };
18066
- elistAppend(e.tail.info.flat_out, e);
18067
- elistAppend(e.head.info.flat_in, e);
18068
- g.info.has_flat_edges = true;
18069
- }
18070
- function findFlatEdge(u, v) {
18071
- const uOut = u.info.flat_out;
18072
- const vIn = v.info.flat_in;
18073
- if (uOut === void 0 || vIn === void 0) return void 0;
18074
- if (uOut.size <= vIn.size) {
18075
- for (let i = 0; i < uOut.size; i++) {
18076
- if (uOut.list[i].head === v) return uOut.list[i];
18077
- }
18078
- } else {
18079
- for (let i = 0; i < vIn.size; i++) {
18080
- if (vIn.list[i].tail === u) return vIn.list[i];
18081
- }
18082
- }
18083
- return void 0;
18084
- }
18085
- function reverseEdge(e) {
18086
- deleteFastEdge(e);
18087
- e.info.reversed = true;
18088
- const f = findFastEdge(e.head, e.tail);
18089
- if (f !== void 0) {
18090
- mergeOneway(e, f);
18091
- } else {
18092
- virtualEdge(e.head, e.tail, e);
18093
- }
18094
- }
18095
- function fastNode(g, n) {
18096
- n.info.next = g.info.nlist;
18097
- if (g.info.nlist !== void 0) g.info.nlist.info.prev = n;
18098
- n.info.prev = void 0;
18099
- g.info.nlist = n;
18100
- }
18101
- function deleteFastNode(g, n) {
18102
- if (n.info.prev !== void 0) n.info.prev.info.next = n.info.next;
18103
- else g.info.nlist = n.info.next;
18104
- if (n.info.next !== void 0) n.info.next.info.prev = n.info.prev;
18105
- }
18106
- function removeFromRank(g, n) {
18107
- const r = n.info.rank !== void 0 ? n.info.rank : 0;
18108
- const rank3 = g.info.rank;
18109
- if (rank3 === void 0) return;
18110
- const rk = rank3[r];
18111
- for (let j = 0; j < rk.n; j++) {
18112
- const v = rk.v[j];
18113
- if (v === n) {
18114
- for (j++; j < rk.n; j++) {
18115
- rk.v[j - 1] = rk.v[j];
18116
- }
18117
- rk.n--;
18118
- break;
18119
- }
18120
- }
18121
- }
18122
- function virtualNode(g) {
18123
- const n = new Node(0, "", g.root);
18124
- n.info.node_type = VIRTUAL;
18125
- n.info.lw = 1;
18126
- n.info.rw = 1;
18127
- n.info.ht = 1;
18128
- n.info.UF_size = 1;
18129
- n.info.in = { list: [], size: 0 };
18130
- n.info.out = { list: [], size: 0 };
18131
- fastNode(g, n);
18132
- return n;
18133
- }
18134
- function otherEdge(e) {
18135
- if (!e.tail.info.other) e.tail.info.other = { list: [], size: 0 };
18136
- elistAppend(e.tail.info.other, e);
18137
- }
18138
-
18139
- // src/layout/dot/decomp.ts
18140
- function nodesInSeq(g) {
18141
- return [...g.nodes.values()].sort((a, b) => a.id - b.id);
18142
- }
18143
- function ufFind(n) {
18144
- while (n.info.UF_parent !== void 0 && n.info.UF_parent !== n) {
18145
- const gp = n.info.UF_parent.info.UF_parent;
18146
- if (gp !== void 0) n.info.UF_parent = gp;
18147
- n = n.info.UF_parent;
18148
- }
18149
- return n;
18150
- }
18151
- function ufUnion(u, v) {
18152
- if (u === v) return u;
18153
- if (u.info.UF_parent === void 0) {
18154
- u.info.UF_parent = u;
18155
- u.info.UF_size = 1;
18156
- } else u = ufFind(u);
18157
- if (v.info.UF_parent === void 0) {
18158
- v.info.UF_parent = v;
18159
- v.info.UF_size = 1;
18160
- } else v = ufFind(v);
18161
- if (u === v) return u;
18162
- const us = u.info.UF_size ?? 0;
18163
- const vs = v.info.UF_size ?? 0;
18164
- v.info.UF_parent = u;
18165
- u.info.UF_size = us + vs;
18166
- return u;
18167
- }
18168
- function ufSingleton(u) {
18169
- u.info.UF_size = 1;
18170
- u.info.UF_parent = void 0;
18171
- u.info.ranktype = 0;
18172
- }
18173
- function ufSetname(u, v) {
18174
- u.info.UF_parent = v;
18175
- v.info.UF_size = (v.info.UF_size ?? 0) + (u.info.UF_size ?? 0);
18176
- }
18177
- function decompPushNeighbors(stk, el, n, cmark) {
18178
- if (!el || el.size === 0) return;
18179
- for (let i = el.size - 1; i >= 0; i--) {
18180
- const e = el.list[i];
18181
- const other = e.head === n ? e.tail : e.head;
18182
- if (other.info.mark !== cmark && other === ufFind(other)) {
18183
- other.info.mark = cmark + 1;
18184
- stk.push(other);
18185
- }
18186
- }
18187
- }
18188
- function decompSearch(g, start, cmark) {
18189
- const stk = [];
18190
- let lastNode;
18191
- start.info.mark = cmark + 1;
18192
- stk.push(start);
18193
- g.info.nlist = void 0;
18194
- let top;
18195
- while ((top = stk.pop()) !== void 0) {
18196
- if (top.info.mark === cmark) continue;
18197
- top.info.mark = cmark;
18198
- if (lastNode !== void 0) {
18199
- top.info.prev = lastNode;
18200
- lastNode.info.next = top;
18201
- } else {
18202
- top.info.prev = void 0;
18203
- g.info.nlist = top;
18204
- }
18205
- lastNode = top;
18206
- top.info.next = void 0;
18207
- decompPushNeighbors(stk, top.info.flat_in, top, cmark);
18208
- decompPushNeighbors(stk, top.info.flat_out, top, cmark);
18209
- decompPushNeighbors(stk, top.info.in, top, cmark);
18210
- decompPushNeighbors(stk, top.info.out, top, cmark);
18211
- }
18212
- }
18213
- var _dc = { cmark: 0 };
18214
- function resolveNode(n, pass) {
18215
- if (pass > 0) {
18216
- const subg = n.info.clust;
18217
- if (subg) return subg.info.rankleader?.[n.info.rank ?? 0];
18218
- }
18219
- return n === ufFind(n) ? n : void 0;
18220
- }
18221
- function decompose(g, pass) {
18222
- if (++_dc.cmark === 0) _dc.cmark = 1;
18223
- const cmark = _dc.cmark;
18224
- g.info.comp = [];
18225
- for (const n of nodesInSeq(g)) {
18226
- const v = resolveNode(n, pass);
18227
- if (v !== void 0 && v.info.mark !== cmark) {
18228
- decompSearch(g, v, cmark);
18229
- g.info.comp.push(g.info.nlist);
18230
- }
18231
- }
18232
- }
18233
-
18234
- // src/layout/dot/mincross-utils.ts
18235
- var CONVERGENCE = 0.995;
18236
- function matrixGet(m, row, col) {
18237
- if (row >= m.nrows || col >= m.ncols) return false;
18238
- const idx = row * m.ncols + col;
18239
- return (m.data[idx >> 3] >> (idx & 7) & 1) === 1;
18240
- }
18241
- function matrixSet(m, row, col) {
18242
- if (row >= m.nrows || col >= m.ncols) matrixExpand(m, row, col);
18243
- const idx = row * m.ncols + col;
18244
- m.data[idx >> 3] |= 1 << (idx & 7);
18245
- }
18246
- function matrixCopyBits(m, data, ncols) {
18247
- for (let r = 0; r < m.nrows; r++) {
18248
- for (let c = 0; c < m.ncols; c++) {
18249
- if (!matrixGet(m, r, c)) continue;
18250
- const idx = r * ncols + c;
18251
- data[idx >> 3] |= 1 << (idx & 7);
18252
- }
18253
- }
18254
- }
18255
- function matrixExpand(m, row, col) {
18256
- const nrows = Math.max(m.nrows, row + 1);
18257
- const ncols = Math.max(m.ncols, col + 1);
18258
- const bits = nrows * ncols;
18259
- const bytes = (bits >> 3) + (bits & 7 ? 1 : 0);
18260
- const data = new Uint8Array(bytes);
18261
- matrixCopyBits(m, data, ncols);
18262
- m.nrows = nrows;
18263
- m.ncols = ncols;
18264
- m.data = data;
18265
- }
18266
- function newMatrix(rows, cols) {
18267
- const bits = rows * cols;
18268
- const bytes = (bits >> 3) + (bits & 7 ? 1 : 0);
18269
- return { nrows: rows, ncols: cols, data: new Uint8Array(bytes) };
18270
- }
18271
- function dotRoot(g) {
18272
- return g.info.dotroot ?? g.root;
18273
- }
18274
- function agContainsNode(g, n) {
18275
- return g.nodes.get(n.name) === n;
18276
- }
18277
- function agContainsEdge(g, e) {
18278
- return g.edges.includes(e);
18279
- }
18280
- function rankGet(rank3, i) {
18281
- return rank3.v[(rank3.vStart ?? 0) + i];
18282
- }
18283
- function rankSet(rank3, i, n) {
18284
- rank3.v[(rank3.vStart ?? 0) + i] = n;
18285
- }
18286
- function isNormalNodeOf(g, v) {
18287
- return v.info.node_type === NORMAL && agContainsNode(g, v);
18288
- }
18289
- function isVnodeOfEdgeOf(g, v) {
18290
- if (v.info.node_type !== VIRTUAL) return false;
18291
- const inSz = v.info.in ? v.info.in.size : 0;
18292
- const outSz = v.info.out ? v.info.out.size : 0;
18293
- if (inSz !== 1 || outSz !== 1) return false;
18294
- let e = v.info.out.list[0];
18295
- while (e.info.edge_type !== NORMAL && e.info.to_orig) e = e.info.to_orig;
18296
- return agContainsEdge(g, e);
18297
- }
18298
- function insideCluster(g, v) {
18299
- return isNormalNodeOf(g, v) || isVnodeOfEdgeOf(g, v);
18300
- }
18301
- function neighborNode(ctx, v, dir) {
18302
- const rk = ctx.root.info.rank?.[v.info.rank ?? 0];
18303
- if (!rk) return void 0;
18304
- const order = v.info.order ?? 0;
18305
- return (dir < 0 ? order > 0 ? rk.v[order - 1] : void 0 : rk.v[order + 1]) ?? void 0;
18306
- }
18307
- function furthestNode(ctx, g, v, dir) {
18308
- let rv = v;
18309
- let u = v;
18310
- while ((u = neighborNode(ctx, u, dir)) !== void 0) {
18311
- if (isNormalNodeOf(g, u) || isVnodeOfEdgeOf(g, u)) rv = u;
18312
- }
18313
- return rv;
18314
- }
18315
-
18316
- // src/common/splines-geom.ts
18317
- function approxEqPt(p, q, tol) {
18318
- const dx = p.x - q.x;
18319
- const dy = p.y - q.y;
18320
- return dx * dx + dy * dy < tol * tol;
18321
- }
18322
- function evalBezier(sp, t, left, right) {
18323
- const ab = { x: sp[0].x + t * (sp[1].x - sp[0].x), y: sp[0].y + t * (sp[1].y - sp[0].y) };
18324
- const bc = { x: sp[1].x + t * (sp[2].x - sp[1].x), y: sp[1].y + t * (sp[2].y - sp[1].y) };
18325
- const cd = { x: sp[2].x + t * (sp[3].x - sp[2].x), y: sp[2].y + t * (sp[3].y - sp[2].y) };
18326
- const abbc = { x: ab.x + t * (bc.x - ab.x), y: ab.y + t * (bc.y - ab.y) };
18327
- const bccd = { x: bc.x + t * (cd.x - bc.x), y: bc.y + t * (cd.y - bc.y) };
18328
- const pt = { x: abbc.x + t * (bccd.x - abbc.x), y: abbc.y + t * (bccd.y - abbc.y) };
18329
- if (left !== null) {
18330
- left[0] = sp[0];
18331
- left[1] = ab;
18332
- left[2] = abbc;
18333
- left[3] = pt;
18334
- }
18335
- if (right !== null) {
18336
- right[0] = pt;
18337
- right[1] = bccd;
18338
- right[2] = cd;
18339
- right[3] = sp[3];
18340
- }
18341
- return pt;
18342
- }
18343
- var HW = 2;
18344
- var SMALL = 1e-10;
18345
- function ptToLine2(a, b, p) {
18346
- const dx = b.x - a.x;
18347
- const dy = b.y - a.y;
18348
- let a2 = (p.y - a.y) * dx - (p.x - a.x) * dy;
18349
- a2 *= a2;
18350
- if (a2 < SMALL) return 0;
18351
- return a2 / (dx * dx + dy * dy);
18352
- }
18353
- function checkControlPoints(cp) {
18354
- const dis1 = ptToLine2(cp[0], cp[3], cp[1]);
18355
- const dis2 = ptToLine2(cp[0], cp[3], cp[2]);
18356
- return dis1 < HW * HW && dis2 < HW * HW;
18357
- }
18358
- function anyOutside(bb, cp) {
18359
- return cp.some((p) => p.x > bb.ur.x || p.x < bb.ll.x || p.y > bb.ur.y || p.y < bb.ll.y);
17113
+ function anyOutside(bb, cp) {
17114
+ return cp.some((p) => p.x > bb.ur.x || p.x < bb.ll.x || p.y > bb.ur.y || p.y < bb.ll.y);
18360
17115
  }
18361
17116
  function expandByPoints(bb, cp) {
18362
17117
  for (const p of cp) {
@@ -18815,7 +17570,15 @@ function curveControlPoints(p, v, w, flag) {
18815
17570
  const AF2 = { x: p.x - 0.95 * v.x + w.x + s * w.x * (4 / 3), y: AF3.y + s * w.y * (4 / 3) };
18816
17571
  return [AF0, AF1, AF2, AF3];
18817
17572
  }
18818
- function genCurve(p0, u, _arrowsize, penwidth, flag) {
17573
+ function genCurve(p0, u, _arrowsize, penwidth, flag, rankdir = 0) {
17574
+ if (rankdir !== 0) {
17575
+ const rot = rankdir * 90;
17576
+ const fin = genCurve(ccwrotatepf(p0, rot), ccwrotatepf(u, rot), _arrowsize, penwidth, flag);
17577
+ return {
17578
+ ops: fin.ops.map((op) => "points" in op ? { ...op, points: op.points.map((pt) => cwrotatepf(pt, rot)) } : op),
17579
+ q: cwrotatepf(fin.q, rot)
17580
+ };
17581
+ }
18819
17582
  const arrowwidth = penwidth > 4 ? 0.5 * penwidth / 4 : 0.5;
18820
17583
  const noShift = flag & ARR_MOD_INV || u.x === 0 && u.y === 0;
18821
17584
  const p = noShift ? p0 : vsub2(p0, backwardDelta(u, penwidth));
@@ -19030,7 +17793,7 @@ function arrowLength(comps, arrowsize, penwidth) {
19030
17793
  for (let i = 0; i < n; i++) length += arrowLengthOne(comps[i], arrowsize, penwidth);
19031
17794
  return length;
19032
17795
  }
19033
- function dispatchSimple(r, tip2, dir, arrowsize, penwidth) {
17796
+ function dispatchSimple(r, tip2, dir, arrowsize, penwidth, rankdir = 0) {
19034
17797
  const flag = arrowFlag(r);
19035
17798
  const u = componentU(dir, r.lenfact, arrowsize);
19036
17799
  switch (r.type & ARR_TYPE_MASK) {
@@ -19044,8 +17807,10 @@ function dispatchSimple(r, tip2, dir, arrowsize, penwidth) {
19044
17807
  return genDiamond(tip2, u, arrowsize, penwidth, flag);
19045
17808
  case ARR_TYPE_DOT:
19046
17809
  return genDot(tip2, u, arrowsize, penwidth, flag);
17810
+ // curve is the one generator that is not rotation-equivariant; it needs
17811
+ // the rankdir to reproduce C's render-time (final-frame) generation.
19047
17812
  case ARR_TYPE_CURVE:
19048
- return genCurve(tip2, u, arrowsize, penwidth, flag);
17813
+ return genCurve(tip2, u, arrowsize, penwidth, flag, rankdir);
19049
17814
  case ARR_TYPE_GAP:
19050
17815
  return genGap(tip2, u, arrowsize, penwidth, flag);
19051
17816
  case ARR_TYPE_NORM:
@@ -19053,14 +17818,14 @@ function dispatchSimple(r, tip2, dir, arrowsize, penwidth) {
19053
17818
  return genNormal(tip2, u, arrowsize, penwidth, flag);
19054
17819
  }
19055
17820
  }
19056
- function arrowDrawOps(comps, tip2, dir, arrowsize, penwidth) {
17821
+ function arrowDrawOps(comps, tip2, dir, arrowsize, penwidth, rankdir = 0) {
19057
17822
  const ops = [];
19058
17823
  let p = tip2;
19059
17824
  const n = Math.min(comps.length, 4);
19060
17825
  for (let i = 0; i < n; i++) {
19061
17826
  const r = comps[i];
19062
17827
  if ((r.type & ARR_TYPE_MASK) === ARR_TYPE_NONE) break;
19063
- const res = dispatchSimple(r, p, dir, arrowsize, penwidth);
17828
+ const res = dispatchSimple(r, p, dir, arrowsize, penwidth, rankdir);
19064
17829
  ops.push(...res.ops);
19065
17830
  p = res.q;
19066
17831
  }
@@ -19204,7 +17969,8 @@ function edgeArrowsize(e) {
19204
17969
  }
19205
17970
  function arrowDrawOpsForEnd(e, end, tip2, dir, penwidth) {
19206
17971
  const comps = parseArrow(edgeArrowName(e, end)).map(resolveArrowType);
19207
- return arrowDrawOps(comps, tip2, dir, edgeArrowsize(e), penwidth);
17972
+ const rankdir = (e.tail?.root?.info?.rankdir ?? 0) & 3;
17973
+ return arrowDrawOps(comps, tip2, dir, edgeArrowsize(e), penwidth, rankdir);
19208
17974
  }
19209
17975
 
19210
17976
  // src/common/splines-clip.ts
@@ -20259,6 +19025,101 @@ function doGraphLabel(sg, measurer) {
20259
19025
  applyLabelBorder(sg, { x: label.dimen.x + 4 * GAP2, y: label.dimen.y + 2 * GAP2 });
20260
19026
  }
20261
19027
 
19028
+ // src/layout/dot/decomp.ts
19029
+ function nodesInSeq(g) {
19030
+ return [...g.nodes.values()].sort((a, b) => a.id - b.id);
19031
+ }
19032
+ function ufFind(n) {
19033
+ while (n.info.UF_parent !== void 0 && n.info.UF_parent !== n) {
19034
+ const gp = n.info.UF_parent.info.UF_parent;
19035
+ if (gp !== void 0) n.info.UF_parent = gp;
19036
+ n = n.info.UF_parent;
19037
+ }
19038
+ return n;
19039
+ }
19040
+ function ufUnion(u, v) {
19041
+ if (u === v) return u;
19042
+ if (u.info.UF_parent === void 0) {
19043
+ u.info.UF_parent = u;
19044
+ u.info.UF_size = 1;
19045
+ } else u = ufFind(u);
19046
+ if (v.info.UF_parent === void 0) {
19047
+ v.info.UF_parent = v;
19048
+ v.info.UF_size = 1;
19049
+ } else v = ufFind(v);
19050
+ if (u === v) return u;
19051
+ const us = u.info.UF_size ?? 0;
19052
+ const vs = v.info.UF_size ?? 0;
19053
+ v.info.UF_parent = u;
19054
+ u.info.UF_size = us + vs;
19055
+ return u;
19056
+ }
19057
+ function ufSingleton(u) {
19058
+ u.info.UF_size = 1;
19059
+ u.info.UF_parent = void 0;
19060
+ u.info.ranktype = 0;
19061
+ }
19062
+ function ufSetname(u, v) {
19063
+ u.info.UF_parent = v;
19064
+ v.info.UF_size = (v.info.UF_size ?? 0) + (u.info.UF_size ?? 0);
19065
+ }
19066
+ function decompPushNeighbors(stk, el, n, cmark) {
19067
+ if (!el || el.size === 0) return;
19068
+ for (let i = el.size - 1; i >= 0; i--) {
19069
+ const e = el.list[i];
19070
+ const other = e.head === n ? e.tail : e.head;
19071
+ if (other.info.mark !== cmark && other === ufFind(other)) {
19072
+ other.info.mark = cmark + 1;
19073
+ stk.push(other);
19074
+ }
19075
+ }
19076
+ }
19077
+ function decompSearch(g, start, cmark) {
19078
+ const stk = [];
19079
+ let lastNode;
19080
+ start.info.mark = cmark + 1;
19081
+ stk.push(start);
19082
+ g.info.nlist = void 0;
19083
+ let top;
19084
+ while ((top = stk.pop()) !== void 0) {
19085
+ if (top.info.mark === cmark) continue;
19086
+ top.info.mark = cmark;
19087
+ if (lastNode !== void 0) {
19088
+ top.info.prev = lastNode;
19089
+ lastNode.info.next = top;
19090
+ } else {
19091
+ top.info.prev = void 0;
19092
+ g.info.nlist = top;
19093
+ }
19094
+ lastNode = top;
19095
+ top.info.next = void 0;
19096
+ decompPushNeighbors(stk, top.info.flat_in, top, cmark);
19097
+ decompPushNeighbors(stk, top.info.flat_out, top, cmark);
19098
+ decompPushNeighbors(stk, top.info.in, top, cmark);
19099
+ decompPushNeighbors(stk, top.info.out, top, cmark);
19100
+ }
19101
+ }
19102
+ var _dc = { cmark: 0 };
19103
+ function resolveNode(n, pass) {
19104
+ if (pass > 0) {
19105
+ const subg = n.info.clust;
19106
+ if (subg) return subg.info.rankleader?.[n.info.rank ?? 0];
19107
+ }
19108
+ return n === ufFind(n) ? n : void 0;
19109
+ }
19110
+ function decompose(g, pass) {
19111
+ if (++_dc.cmark === 0) _dc.cmark = 1;
19112
+ const cmark = _dc.cmark;
19113
+ g.info.comp = [];
19114
+ for (const n of nodesInSeq(g)) {
19115
+ const v = resolveNode(n, pass);
19116
+ if (v !== void 0 && v.info.mark !== cmark) {
19117
+ decompSearch(g, v, cmark);
19118
+ g.info.comp.push(g.info.nlist);
19119
+ }
19120
+ }
19121
+ }
19122
+
20262
19123
  // src/layout/dot/acyclic.ts
20263
19124
  function dfsStep(stack) {
20264
19125
  const f = stack[stack.length - 1];
@@ -21801,6 +20662,216 @@ function dot2Rank(g) {
21801
20662
  readoutLevels(g, Xg, ncc);
21802
20663
  }
21803
20664
 
20665
+ // src/layout/dot/mincross-utils.ts
20666
+ var CONVERGENCE = 0.995;
20667
+ function matrixGet(m, row, col) {
20668
+ if (row >= m.nrows || col >= m.ncols) return false;
20669
+ const idx = row * m.ncols + col;
20670
+ return (m.data[idx >> 3] >> (idx & 7) & 1) === 1;
20671
+ }
20672
+ function matrixSet(m, row, col) {
20673
+ if (row >= m.nrows || col >= m.ncols) matrixExpand(m, row, col);
20674
+ const idx = row * m.ncols + col;
20675
+ m.data[idx >> 3] |= 1 << (idx & 7);
20676
+ }
20677
+ function matrixCopyBits(m, data, ncols) {
20678
+ for (let r = 0; r < m.nrows; r++) {
20679
+ for (let c = 0; c < m.ncols; c++) {
20680
+ if (!matrixGet(m, r, c)) continue;
20681
+ const idx = r * ncols + c;
20682
+ data[idx >> 3] |= 1 << (idx & 7);
20683
+ }
20684
+ }
20685
+ }
20686
+ function matrixExpand(m, row, col) {
20687
+ const nrows = Math.max(m.nrows, row + 1);
20688
+ const ncols = Math.max(m.ncols, col + 1);
20689
+ const bits = nrows * ncols;
20690
+ const bytes = (bits >> 3) + (bits & 7 ? 1 : 0);
20691
+ const data = new Uint8Array(bytes);
20692
+ matrixCopyBits(m, data, ncols);
20693
+ m.nrows = nrows;
20694
+ m.ncols = ncols;
20695
+ m.data = data;
20696
+ }
20697
+ function newMatrix(rows, cols) {
20698
+ const bits = rows * cols;
20699
+ const bytes = (bits >> 3) + (bits & 7 ? 1 : 0);
20700
+ return { nrows: rows, ncols: cols, data: new Uint8Array(bytes) };
20701
+ }
20702
+ function dotRoot(g) {
20703
+ return g.info.dotroot ?? g.root;
20704
+ }
20705
+ function agContainsNode(g, n) {
20706
+ return g.nodes.get(n.name) === n;
20707
+ }
20708
+ function agContainsEdge(g, e) {
20709
+ return g.edges.includes(e);
20710
+ }
20711
+ function rankGet(rank3, i) {
20712
+ return rank3.v[(rank3.vStart ?? 0) + i];
20713
+ }
20714
+ function rankSet(rank3, i, n) {
20715
+ rank3.v[(rank3.vStart ?? 0) + i] = n;
20716
+ }
20717
+ function isNormalNodeOf(g, v) {
20718
+ return v.info.node_type === NORMAL && agContainsNode(g, v);
20719
+ }
20720
+ function isVnodeOfEdgeOf(g, v) {
20721
+ if (v.info.node_type !== VIRTUAL) return false;
20722
+ const inSz = v.info.in ? v.info.in.size : 0;
20723
+ const outSz = v.info.out ? v.info.out.size : 0;
20724
+ if (inSz !== 1 || outSz !== 1) return false;
20725
+ let e = v.info.out.list[0];
20726
+ while (e.info.edge_type !== NORMAL && e.info.to_orig) e = e.info.to_orig;
20727
+ return agContainsEdge(g, e);
20728
+ }
20729
+ function insideCluster(g, v) {
20730
+ return isNormalNodeOf(g, v) || isVnodeOfEdgeOf(g, v);
20731
+ }
20732
+ function neighborNode(ctx, v, dir) {
20733
+ const rk = ctx.root.info.rank?.[v.info.rank ?? 0];
20734
+ if (!rk) return void 0;
20735
+ const order = v.info.order ?? 0;
20736
+ return (dir < 0 ? order > 0 ? rk.v[order - 1] : void 0 : rk.v[order + 1]) ?? void 0;
20737
+ }
20738
+ function furthestNode(ctx, g, v, dir) {
20739
+ let rv = v;
20740
+ let u = v;
20741
+ while ((u = neighborNode(ctx, u, dir)) !== void 0) {
20742
+ if (isNormalNodeOf(g, u) || isVnodeOfEdgeOf(g, u)) rv = u;
20743
+ }
20744
+ return rv;
20745
+ }
20746
+
20747
+ // src/layout/dot/cluster-path.ts
20748
+ var CLUSTER_EDGE = 5;
20749
+ function mapInterclustNode(n) {
20750
+ const clust = n.info.clust;
20751
+ if (clust === void 0 || clust.info.expanded) return n;
20752
+ return clust.info.rankleader[n.info.rank ?? 0];
20753
+ }
20754
+ function makeSlotsContract(root, r, pos, d) {
20755
+ const rk = root.info.rank[r];
20756
+ for (let i = pos - d + 1; i < rk.n; i++) {
20757
+ const v = rk.v[i];
20758
+ v.info.order = i + d - 1;
20759
+ rk.v[v.info.order] = v;
20760
+ }
20761
+ for (let i = rk.n + d - 1; i < rk.n; i++) rk.v[i] = null;
20762
+ }
20763
+ function makeSlotsExpand(root, r, pos, d) {
20764
+ const rk = root.info.rank[r];
20765
+ for (let i = rk.n - 1; i > pos; i--) {
20766
+ const v = rk.v[i];
20767
+ v.info.order = i + d - 1;
20768
+ rk.v[v.info.order] = v;
20769
+ }
20770
+ for (let i = pos + 1; i < pos + d; i++) rk.v[i] = null;
20771
+ }
20772
+ function makeSlots(root, r, pos, d) {
20773
+ if (d <= 0) makeSlotsContract(root, r, pos, d);
20774
+ else makeSlotsExpand(root, r, pos, d);
20775
+ root.info.rank[r].n += d - 1;
20776
+ }
20777
+ function cloneVn(g, vn) {
20778
+ const r = vn.info.rank ?? 0;
20779
+ makeSlots(g, r, vn.info.order, 2);
20780
+ const rv = virtualNode(g);
20781
+ rv.info.lw = vn.info.lw;
20782
+ rv.info.rw = vn.info.rw;
20783
+ rv.info.rank = r;
20784
+ rv.info.order = (vn.info.order ?? 0) + 1;
20785
+ g.info.rank[r].v[rv.info.order] = rv;
20786
+ return rv;
20787
+ }
20788
+ function safeOtherEdge(e) {
20789
+ if (!e.tail.info.other) e.tail.info.other = { list: [], size: 0 };
20790
+ const other = e.tail.info.other;
20791
+ for (let i = 0; i < other.size; i++) if (other.list[i] === e) return;
20792
+ other.list[other.size++] = e;
20793
+ }
20794
+ function portsEqSimple(orig, e) {
20795
+ const hp = orig.info.head_port;
20796
+ const tp = orig.info.tail_port;
20797
+ const ehp = e.info.head_port;
20798
+ const etp = e.info.tail_port;
20799
+ return hp.defined === ehp.defined && tp.defined === etp.defined && (!hp.defined || hp.p.x === ehp.p.x && hp.p.y === ehp.p.y) && (!tp.defined || tp.p.x === etp.p.x && tp.p.y === etp.p.y);
20800
+ }
20801
+ function mapPathAdjacentMulti(from, to, orig, ve, type) {
20802
+ const root = dotRoot(from.root);
20803
+ let u = from;
20804
+ for (let r = from.info.rank ?? 0; r < (to.info.rank ?? 0); r++) {
20805
+ const v = r < (to.info.rank ?? 0) - 1 ? cloneVn(root, ve.head) : to;
20806
+ const e = virtualEdge(u, v, orig);
20807
+ e.info.edge_type = type;
20808
+ u = v;
20809
+ ve.info.count = (ve.info.count ?? 1) - 1;
20810
+ ve = ve.head.info.out.list[0];
20811
+ }
20812
+ }
20813
+ function mapPathAdjacentSingle(from, to, orig, ve, type) {
20814
+ const existing = findFastEdge(from, to);
20815
+ if (existing !== void 0 && portsEqSimple(orig, existing)) {
20816
+ orig.info.to_virt = existing;
20817
+ existing.info.edge_type = type;
20818
+ existing.info.count = (existing.info.count ?? 1) + 1;
20819
+ if (from.info.node_type === NORMAL && to.info.node_type === NORMAL)
20820
+ safeOtherEdge(orig);
20821
+ } else {
20822
+ orig.info.to_virt = void 0;
20823
+ const e = virtualEdge(from, to, orig);
20824
+ e.info.edge_type = type;
20825
+ ve.info.count = (ve.info.count ?? 1) - 1;
20826
+ }
20827
+ }
20828
+ function mapPathLongSingle(from, to, orig, ve, type) {
20829
+ let e;
20830
+ if (ve.tail !== from) {
20831
+ orig.info.to_virt = void 0;
20832
+ e = orig.info.to_virt = virtualEdge(from, ve.head, orig);
20833
+ deleteFastEdge(ve);
20834
+ } else {
20835
+ e = ve;
20836
+ }
20837
+ while ((e.head.info.rank ?? 0) !== (to.info.rank ?? 0))
20838
+ e = e.head.info.out.list[0];
20839
+ if (e.head !== to) {
20840
+ const old = e;
20841
+ e = virtualEdge(e.tail, to, orig);
20842
+ e.info.edge_type = type;
20843
+ deleteFastEdge(old);
20844
+ }
20845
+ }
20846
+ function mapPathMultiEdge(from, to, orig, ve, type) {
20847
+ orig.info.to_virt = void 0;
20848
+ const span = (to.info.rank ?? 0) - (from.info.rank ?? 0);
20849
+ if (span === 1) {
20850
+ const ex = findFastEdge(from, to);
20851
+ if (ex !== void 0 && portsEqSimple(orig, ex)) {
20852
+ mergeOneway(orig, ex);
20853
+ if (from.info.node_type === NORMAL && to.info.node_type === NORMAL)
20854
+ safeOtherEdge(orig);
20855
+ return;
20856
+ }
20857
+ }
20858
+ mapPathAdjacentMulti(from, to, orig, ve, type);
20859
+ }
20860
+ function mapPath(from, to, orig, ve, type) {
20861
+ if (ve.tail === from && ve.head === to) return;
20862
+ const span = (to.info.rank ?? 0) - (from.info.rank ?? 0);
20863
+ const cnt = ve.info.count ?? 1;
20864
+ if (cnt > 1) mapPathMultiEdge(from, to, orig, ve, type);
20865
+ else if (span === 1) mapPathAdjacentSingle(from, to, orig, ve, type);
20866
+ else mapPathLongSingle(from, to, orig, ve, type);
20867
+ }
20868
+ function makeInterclustChain(from, to, orig) {
20869
+ const u = mapInterclustNode(from);
20870
+ const v = mapInterclustNode(to);
20871
+ const type = u === from && v === to ? VIRTUAL : CLUSTER_EDGE;
20872
+ mapPath(u, v, orig, orig.info.to_virt, type);
20873
+ }
20874
+
21804
20875
  // src/layout/dot/mincross-cross.ts
21805
20876
  var reMincross = false;
21806
20877
  function setReMincross(b) {
@@ -22451,134 +21522,6 @@ function orderedEdges(ctx, g) {
22451
21522
  doOrderingForNodes(ctx, g);
22452
21523
  }
22453
21524
 
22454
- // src/layout/dot/cluster-path.ts
22455
- var CLUSTER_EDGE = 5;
22456
- function mapInterclustNode(n) {
22457
- const clust = n.info.clust;
22458
- if (clust === void 0 || clust.info.expanded) return n;
22459
- return clust.info.rankleader[n.info.rank ?? 0];
22460
- }
22461
- function makeSlotsContract(root, r, pos, d) {
22462
- const rk = root.info.rank[r];
22463
- for (let i = pos - d + 1; i < rk.n; i++) {
22464
- const v = rk.v[i];
22465
- v.info.order = i + d - 1;
22466
- rk.v[v.info.order] = v;
22467
- }
22468
- for (let i = rk.n + d - 1; i < rk.n; i++) rk.v[i] = null;
22469
- }
22470
- function makeSlotsExpand(root, r, pos, d) {
22471
- const rk = root.info.rank[r];
22472
- for (let i = rk.n - 1; i > pos; i--) {
22473
- const v = rk.v[i];
22474
- v.info.order = i + d - 1;
22475
- rk.v[v.info.order] = v;
22476
- }
22477
- for (let i = pos + 1; i < pos + d; i++) rk.v[i] = null;
22478
- }
22479
- function makeSlots(root, r, pos, d) {
22480
- if (d <= 0) makeSlotsContract(root, r, pos, d);
22481
- else makeSlotsExpand(root, r, pos, d);
22482
- root.info.rank[r].n += d - 1;
22483
- }
22484
- function cloneVn(g, vn) {
22485
- const r = vn.info.rank ?? 0;
22486
- makeSlots(g, r, vn.info.order, 2);
22487
- const rv = virtualNode(g);
22488
- rv.info.lw = vn.info.lw;
22489
- rv.info.rw = vn.info.rw;
22490
- rv.info.rank = r;
22491
- rv.info.order = (vn.info.order ?? 0) + 1;
22492
- g.info.rank[r].v[rv.info.order] = rv;
22493
- return rv;
22494
- }
22495
- function safeOtherEdge(e) {
22496
- if (!e.tail.info.other) e.tail.info.other = { list: [], size: 0 };
22497
- const other = e.tail.info.other;
22498
- for (let i = 0; i < other.size; i++) if (other.list[i] === e) return;
22499
- other.list[other.size++] = e;
22500
- }
22501
- function portsEqSimple(orig, e) {
22502
- const hp = orig.info.head_port;
22503
- const tp = orig.info.tail_port;
22504
- const ehp = e.info.head_port;
22505
- const etp = e.info.tail_port;
22506
- return hp.defined === ehp.defined && tp.defined === etp.defined && (!hp.defined || hp.p.x === ehp.p.x && hp.p.y === ehp.p.y) && (!tp.defined || tp.p.x === etp.p.x && tp.p.y === etp.p.y);
22507
- }
22508
- function mapPathAdjacentMulti(from, to, orig, ve, type) {
22509
- const root = dotRoot(from.root);
22510
- let u = from;
22511
- for (let r = from.info.rank ?? 0; r < (to.info.rank ?? 0); r++) {
22512
- const v = r < (to.info.rank ?? 0) - 1 ? cloneVn(root, ve.head) : to;
22513
- const e = virtualEdge(u, v, orig);
22514
- e.info.edge_type = type;
22515
- u = v;
22516
- ve.info.count = (ve.info.count ?? 1) - 1;
22517
- ve = ve.head.info.out.list[0];
22518
- }
22519
- }
22520
- function mapPathAdjacentSingle(from, to, orig, ve, type) {
22521
- const existing = findFastEdge(from, to);
22522
- if (existing !== void 0 && portsEqSimple(orig, existing)) {
22523
- orig.info.to_virt = existing;
22524
- existing.info.edge_type = type;
22525
- existing.info.count = (existing.info.count ?? 1) + 1;
22526
- if (from.info.node_type === NORMAL && to.info.node_type === NORMAL)
22527
- safeOtherEdge(orig);
22528
- } else {
22529
- orig.info.to_virt = void 0;
22530
- const e = virtualEdge(from, to, orig);
22531
- e.info.edge_type = type;
22532
- ve.info.count = (ve.info.count ?? 1) - 1;
22533
- }
22534
- }
22535
- function mapPathLongSingle(from, to, orig, ve, type) {
22536
- let e;
22537
- if (ve.tail !== from) {
22538
- orig.info.to_virt = void 0;
22539
- e = orig.info.to_virt = virtualEdge(from, ve.head, orig);
22540
- deleteFastEdge(ve);
22541
- } else {
22542
- e = ve;
22543
- }
22544
- while ((e.head.info.rank ?? 0) !== (to.info.rank ?? 0))
22545
- e = e.head.info.out.list[0];
22546
- if (e.head !== to) {
22547
- const old = e;
22548
- e = virtualEdge(e.tail, to, orig);
22549
- e.info.edge_type = type;
22550
- deleteFastEdge(old);
22551
- }
22552
- }
22553
- function mapPathMultiEdge(from, to, orig, ve, type) {
22554
- orig.info.to_virt = void 0;
22555
- const span = (to.info.rank ?? 0) - (from.info.rank ?? 0);
22556
- if (span === 1) {
22557
- const ex = findFastEdge(from, to);
22558
- if (ex !== void 0 && portsEqSimple(orig, ex)) {
22559
- mergeOneway(orig, ex);
22560
- if (from.info.node_type === NORMAL && to.info.node_type === NORMAL)
22561
- safeOtherEdge(orig);
22562
- return;
22563
- }
22564
- }
22565
- mapPathAdjacentMulti(from, to, orig, ve, type);
22566
- }
22567
- function mapPath(from, to, orig, ve, type) {
22568
- if (ve.tail === from && ve.head === to) return;
22569
- const span = (to.info.rank ?? 0) - (from.info.rank ?? 0);
22570
- const cnt = ve.info.count ?? 1;
22571
- if (cnt > 1) mapPathMultiEdge(from, to, orig, ve, type);
22572
- else if (span === 1) mapPathAdjacentSingle(from, to, orig, ve, type);
22573
- else mapPathLongSingle(from, to, orig, ve, type);
22574
- }
22575
- function makeInterclustChain(from, to, orig) {
22576
- const u = mapInterclustNode(from);
22577
- const v = mapInterclustNode(to);
22578
- const type = u === from && v === to ? VIRTUAL : CLUSTER_EDGE;
22579
- mapPath(u, v, orig, orig.info.to_virt, type);
22580
- }
22581
-
22582
21525
  // src/layout/dot/cluster.ts
22583
21526
  function interclexpMergeable(prev, e) {
22584
21527
  if (!prev) return false;
@@ -22858,15 +21801,325 @@ function markLowclusterBasic(g) {
22858
21801
  for (let c = 1; c <= nClust; c++) markLowclusterBasic(g.info.clust[c - 1]);
22859
21802
  const outByTail = outEdgesByTail(g.edges);
22860
21803
  for (const n of nodesInSeq(g)) {
22861
- if (n.info.clust === void 0) n.info.clust = g;
22862
- const oes = outByTail.get(n);
22863
- if (oes === void 0) continue;
22864
- for (const orig of oes) markLowclusterChain(orig, g);
21804
+ if (n.info.clust === void 0) n.info.clust = g;
21805
+ const oes = outByTail.get(n);
21806
+ if (oes === void 0) continue;
21807
+ for (const orig of oes) markLowclusterChain(orig, g);
21808
+ }
21809
+ }
21810
+ function markLowclusters(root) {
21811
+ markLowclustersZap(root);
21812
+ markLowclusterBasic(root);
21813
+ }
21814
+
21815
+ // src/layout/dot/classify.ts
21816
+ function portsEq(e, f) {
21817
+ const ehp = e.info.head_port;
21818
+ const fhp = f.info.head_port;
21819
+ const etp = e.info.tail_port;
21820
+ const ftp = f.info.tail_port;
21821
+ const headMatch = ehp.p.x === fhp.p.x && ehp.p.y === fhp.p.y || !ehp.defined;
21822
+ const tailMatch = etp.p.x === ftp.p.x && etp.p.y === ftp.p.y || !etp.defined;
21823
+ return ehp.defined === fhp.defined && headMatch && tailMatch;
21824
+ }
21825
+ function nonconstraintEdge(e) {
21826
+ return e.info.constraint === false;
21827
+ }
21828
+ var WNODE_ORDINARY = 0;
21829
+ var WNODE_SINGLETON = 1;
21830
+ var WNODE_VIRTUAL = 2;
21831
+ var CLASSIFY_WEIGHT_TABLE = [[1, 1, 1], [1, 2, 2], [1, 2, 4]];
21832
+ function epClass(n) {
21833
+ if (n.info.node_type === VIRTUAL) return WNODE_VIRTUAL;
21834
+ if ((n.info.weight_class ?? 2) <= 1) return WNODE_SINGLETON;
21835
+ return WNODE_ORDINARY;
21836
+ }
21837
+ function applyVirtualWeight(e) {
21838
+ const t = CLASSIFY_WEIGHT_TABLE[epClass(e.tail)][epClass(e.head)];
21839
+ e.info.weight = (e.info.weight ?? 1) * t;
21840
+ }
21841
+ function interclust1TRank(e) {
21842
+ const clust = e.tail.info.clust;
21843
+ return clust ? (e.tail.info.rank ?? 0) - (clust.info.leader?.info.rank ?? 0) : 0;
21844
+ }
21845
+ function interclust1HRank(e) {
21846
+ const clust = e.head.info.clust;
21847
+ return clust ? (e.head.info.rank ?? 0) - (clust.info.leader?.info.rank ?? 0) : 0;
21848
+ }
21849
+ function interclust1Lengths(e) {
21850
+ const offset = (e.info.minlen ?? 1) + interclust1TRank(e) - interclust1HRank(e);
21851
+ return offset > 0 ? [0, offset] : [-offset, 0];
21852
+ }
21853
+ function interclust1(g, t, h, e) {
21854
+ const [tLen, hLen] = interclust1Lengths(e);
21855
+ const v = virtualNode(g);
21856
+ v.info.node_type = SLACKNODE;
21857
+ const t0 = ufFind(t);
21858
+ const h0 = ufFind(h);
21859
+ const w = e.info.weight ?? 1;
21860
+ const rt = makeAuxEdge(v, t0, tLen, CL_BACK * w);
21861
+ const rh = makeAuxEdge(v, h0, hLen, w);
21862
+ rt.info.to_orig = e;
21863
+ rh.info.to_orig = e;
21864
+ }
21865
+ function class1Edge(g, e) {
21866
+ if (e.info.to_virt !== void 0) return;
21867
+ if (nonconstraintEdge(e)) return;
21868
+ const t = ufFind(e.tail);
21869
+ const h = ufFind(e.head);
21870
+ if (t === h) return;
21871
+ if (t.info.clust || h.info.clust) {
21872
+ interclust1(g, e.tail, e.head, e);
21873
+ return;
21874
+ }
21875
+ const rep = findFastEdge(t, h);
21876
+ if (rep !== void 0) mergeOneway(e, rep);
21877
+ else virtualEdge(t, h, e);
21878
+ }
21879
+ function class1(g) {
21880
+ markClusters(g);
21881
+ for (const n of nodesInSeq(g)) {
21882
+ for (const e of n.outEdges(g)) class1Edge(g, e);
21883
+ }
21884
+ }
21885
+ function labelVnodeDimen(orig) {
21886
+ const lbl = orig.info.label;
21887
+ return lbl?.dimen;
21888
+ }
21889
+ function labelVnode(g, orig) {
21890
+ const dimen = labelVnodeDimen(orig);
21891
+ const v = virtualNode(g);
21892
+ v.info.label = orig.info.label;
21893
+ v.info.lw = dotRoot(g).info.nodesep ?? 0;
21894
+ if (!orig.info.label_ontop && dimen) {
21895
+ const flip = dotRoot(g).info.flip === true;
21896
+ v.info.ht = flip ? dimen.x : dimen.y;
21897
+ v.info.rw = flip ? dimen.y : dimen.x;
21898
+ }
21899
+ return v;
21900
+ }
21901
+ function incrWidth(g, v) {
21902
+ const width = Math.floor((g.info.nodesep ?? 0) / 2);
21903
+ v.info.lw = (v.info.lw ?? 0) + width;
21904
+ v.info.rw = (v.info.rw ?? 0) + width;
21905
+ }
21906
+ function plainVnode(g) {
21907
+ const v = virtualNode(g);
21908
+ incrWidth(g, v);
21909
+ return v;
21910
+ }
21911
+ function leaderOf(v) {
21912
+ if (v.info.ranktype !== CLUSTER) return ufFind(v);
21913
+ return v.info.clust.info.rankleader[v.info.rank ?? 0];
21914
+ }
21915
+ function chainVnode(g, orig, r, labelRank) {
21916
+ if (r === labelRank) return labelVnode(g, orig);
21917
+ return plainVnode(g);
21918
+ }
21919
+ function makeChain(g, from, to, orig) {
21920
+ const labelRank = orig.info.label !== void 0 ? Math.floor(((from.info.rank ?? 0) + (to.info.rank ?? 0)) / 2) : -1;
21921
+ let u = from;
21922
+ const toRank = to.info.rank ?? 0;
21923
+ for (let r = (from.info.rank ?? 0) + 1; r <= toRank; r++) {
21924
+ const v = r < toRank ? (() => {
21925
+ const n = chainVnode(g, orig, r, labelRank);
21926
+ n.info.rank = r;
21927
+ return n;
21928
+ })() : to;
21929
+ const e = virtualEdge(u, v, orig);
21930
+ applyVirtualWeight(e);
21931
+ u = v;
21932
+ }
21933
+ }
21934
+ function nodeRank3(n) {
21935
+ return n.info.rank ?? 0;
21936
+ }
21937
+ function edgeCount(e) {
21938
+ return e.info.count ?? 1;
21939
+ }
21940
+ function edgeXpenalty(e) {
21941
+ return e.info.xpenalty ?? 0;
21942
+ }
21943
+ function edgeWeight3(e) {
21944
+ return e.info.weight ?? 1;
21945
+ }
21946
+ function nextVirtEdge(e) {
21947
+ return e.head.info.out?.list[0];
21948
+ }
21949
+ function mergeChainStep(rep, e, updateCount) {
21950
+ if (updateCount) rep.info.count = edgeCount(rep) + edgeCount(e);
21951
+ rep.info.xpenalty = edgeXpenalty(rep) + edgeXpenalty(e);
21952
+ rep.info.weight = edgeWeight3(rep) + edgeWeight3(e);
21953
+ return nextVirtEdge(rep);
21954
+ }
21955
+ function mergeChain(g, e, f, updateCount) {
21956
+ const lastrank = Math.max(e.tail.info.rank ?? 0, e.head.info.rank ?? 0);
21957
+ e.info.to_virt = f;
21958
+ let rep = f;
21959
+ while (rep !== void 0) {
21960
+ if ((rep.head.info.rank ?? 0) === lastrank) {
21961
+ mergeChainStep(rep, e, updateCount);
21962
+ break;
21963
+ }
21964
+ incrWidth(g, rep.head);
21965
+ rep = mergeChainStep(rep, e, updateCount);
21966
+ }
21967
+ }
21968
+ function mergeable(e, f) {
21969
+ if (!e || !f) return false;
21970
+ return e.tail === f.tail && e.head === f.head && e.info.label === f.info.label && portsEq(e, f);
21971
+ }
21972
+ function interclrepChain(g, e, t, h) {
21973
+ makeChain(g, t, h, e);
21974
+ let cur = e.info.to_virt;
21975
+ while (cur !== void 0 && nodeRank3(cur.head) <= nodeRank3(h)) {
21976
+ cur.info.edge_type = CLUSTER_EDGE;
21977
+ cur = cur.head.info.out?.list[0];
21978
+ }
21979
+ }
21980
+ function interclrep(g, e) {
21981
+ let t = leaderOf(e.tail);
21982
+ let h = leaderOf(e.head);
21983
+ if (nodeRank3(t) > nodeRank3(h)) {
21984
+ const tmp = t;
21985
+ t = h;
21986
+ h = tmp;
21987
+ }
21988
+ if (t.info.clust === h.info.clust) return;
21989
+ const ve = findFastEdge(t, h);
21990
+ if (ve !== void 0) {
21991
+ mergeChain(g, e, ve, true);
21992
+ return;
21993
+ }
21994
+ if (nodeRank3(t) === nodeRank3(h)) return;
21995
+ interclrepChain(g, e, t, h);
21996
+ }
21997
+ function isClusterEdge(e) {
21998
+ return e.tail.info.ranktype === CLUSTER || e.head.info.ranktype === CLUSTER;
21999
+ }
22000
+ function handleClusterMergeable(g, e, prev) {
22001
+ if (prev.info.to_virt !== void 0) {
22002
+ mergeChain(g, e, prev.info.to_virt, false);
22003
+ otherEdge(e);
22004
+ } else if ((e.tail.info.rank ?? 0) === (e.head.info.rank ?? 0)) {
22005
+ mergeOneway(e, prev);
22006
+ otherEdge(e);
22007
+ }
22008
+ return prev;
22009
+ }
22010
+ function handleClusterEdge(g, e, prev) {
22011
+ if (mergeable(prev, e)) return handleClusterMergeable(g, e, prev);
22012
+ interclrep(g, e);
22013
+ return e;
22014
+ }
22015
+ function concentrateOrMerge(g, e, prev) {
22016
+ if (dotRoot(g).info.concentrate ?? false) {
22017
+ e.info.edge_type = IGNORED;
22018
+ } else if (prev.info.to_virt !== void 0) {
22019
+ mergeChain(g, e, prev.info.to_virt, true);
22020
+ otherEdge(e);
22021
+ }
22022
+ }
22023
+ function handleMultiSameRank(e, prev) {
22024
+ if ((e.tail.info.rank ?? 0) !== (e.head.info.rank ?? 0)) return false;
22025
+ mergeOneway(e, prev);
22026
+ otherEdge(e);
22027
+ return true;
22028
+ }
22029
+ function handleMultiParallel(g, e, prev) {
22030
+ if (e.info.label !== void 0 || prev.info.label !== void 0) return false;
22031
+ if (!portsEq(e, prev)) return false;
22032
+ concentrateOrMerge(g, e, prev);
22033
+ return true;
22034
+ }
22035
+ function handleMultiEdge(g, e, prev) {
22036
+ if (!prev || e.tail !== prev.tail || e.head !== prev.head) return false;
22037
+ if (handleMultiSameRank(e, prev)) return true;
22038
+ return handleMultiParallel(g, e, prev);
22039
+ }
22040
+ function oppEdgeConcOrMerge(g, e, opp) {
22041
+ if (e.info.label !== void 0 || opp.info.label !== void 0) return false;
22042
+ if (!portsEq(e, opp)) return false;
22043
+ if (dotRoot(g).info.concentrate ?? false) {
22044
+ e.info.edge_type = IGNORED;
22045
+ opp.info.conc_opp_flag = true;
22046
+ } else {
22047
+ otherEdge(e);
22048
+ mergeChain(g, e, opp.info.to_virt, true);
22049
+ }
22050
+ return true;
22051
+ }
22052
+ function tryOppEdge(g, e, opp) {
22053
+ if (opp.head !== e.tail) return false;
22054
+ if (opp.info.edge_type === IGNORED) return false;
22055
+ if (opp.info.to_virt === void 0) makeChain(g, opp.tail, opp.head, opp);
22056
+ return oppEdgeConcOrMerge(g, e, opp);
22057
+ }
22058
+ function handleBackEdge(g, e) {
22059
+ for (const opp of e.head.outEdges(g)) {
22060
+ if (tryOppEdge(g, e, opp)) return void 0;
22061
+ }
22062
+ makeChain(g, e.head, e.tail, e);
22063
+ return e;
22064
+ }
22065
+ function class2EdgeSameRep(g, e) {
22066
+ if (nodeRank3(e.tail) === nodeRank3(e.head)) {
22067
+ flatEdge(g, e);
22068
+ return e;
22069
+ }
22070
+ if (nodeRank3(e.head) > nodeRank3(e.tail)) {
22071
+ makeChain(g, e.tail, e.head, e);
22072
+ return e;
22073
+ }
22074
+ return handleBackEdge(g, e);
22075
+ }
22076
+ function class2OneEdge(g, e, prev) {
22077
+ if (e.info.to_virt !== void 0) return e;
22078
+ if (isClusterEdge(e)) return handleClusterEdge(g, e, prev);
22079
+ if (handleMultiEdge(g, e, prev)) return prev;
22080
+ if (e.tail === e.head) {
22081
+ otherEdge(e);
22082
+ return e;
22083
+ }
22084
+ const t = ufFind(e.tail);
22085
+ const h = ufFind(e.head);
22086
+ if (e.tail !== t || e.head !== h) return prev;
22087
+ return class2EdgeSameRep(g, e);
22088
+ }
22089
+ function class2ProcessNodeEdges(g, oes) {
22090
+ let prev;
22091
+ for (const e of oes) {
22092
+ const next = class2OneEdge(g, e, prev);
22093
+ prev = next !== void 0 ? next : prev;
22094
+ }
22095
+ }
22096
+ function weightClass(n) {
22097
+ return n.info.weight_class ?? 0;
22098
+ }
22099
+ function incrWeightClass(n) {
22100
+ if (weightClass(n) <= 2) n.info.weight_class = weightClass(n) + 1;
22101
+ }
22102
+ function class2WeightClasses(g) {
22103
+ for (const e of g.edges) {
22104
+ incrWeightClass(e.head);
22105
+ incrWeightClass(e.tail);
22106
+ }
22107
+ }
22108
+ function class2ProcessNodes(g) {
22109
+ const outIdx = buildOutEdgeIndex(g);
22110
+ for (const n of nodesInSeq(g)) {
22111
+ if (n.info.clust === void 0 && n === ufFind(n)) fastNode(g, n);
22112
+ class2ProcessNodeEdges(g, outIdx.get(n) ?? []);
22865
22113
  }
22866
22114
  }
22867
- function markLowclusters(root) {
22868
- markLowclustersZap(root);
22869
- markLowclusterBasic(root);
22115
+ function class2(g) {
22116
+ g.info.nlist = void 0;
22117
+ markClusters(g);
22118
+ const nClust = g.info.n_cluster ?? 0;
22119
+ for (let c = 1; c <= nClust; c++) buildSkeleton(g, g.info.clust[c - 1]);
22120
+ class2WeightClasses(g);
22121
+ class2ProcessNodes(g);
22122
+ if (g !== dotRoot(g)) g.info.comp = [g.info.nlist ?? null];
22870
22123
  }
22871
22124
 
22872
22125
  // src/layout/dot/rank.ts
@@ -23129,450 +22382,1223 @@ function gMaxrankVal(g) {
23129
22382
  function gNCluster(g) {
23130
22383
  return g.info.n_cluster ?? 0;
23131
22384
  }
23132
- function gClust(g) {
23133
- return g.info.clust ?? [];
22385
+ function gClust(g) {
22386
+ return g.info.clust ?? [];
22387
+ }
22388
+ function nRank(n) {
22389
+ return n.info.rank ?? 0;
22390
+ }
22391
+ function nRanktype(n) {
22392
+ return n.info.ranktype ?? 0;
22393
+ }
22394
+ function gMaxrankDef(g) {
22395
+ return g.info.maxrank ?? -1;
22396
+ }
22397
+ function gMinrankDef(g) {
22398
+ return g.info.minrank ?? Number.MAX_SAFE_INTEGER;
22399
+ }
22400
+ function setMinmax(g) {
22401
+ const lr = gLeaderRank(g);
22402
+ g.info.minrank = gMinrankVal(g) + lr;
22403
+ g.info.maxrank = gMaxrankVal(g) + lr;
22404
+ const cl = gClust(g);
22405
+ const nc = gNCluster(g);
22406
+ for (let c = 1; c <= nc; c++) setMinmax(cl[c - 1]);
22407
+ }
22408
+ function minmaxEdgesReverse(n, isOut) {
22409
+ const rt = n.info.ranktype ?? 0;
22410
+ const flag = isOut ? rt === SINKRANK : rt === SOURCERANK;
22411
+ const list = isOut ? n.info.out : n.info.in;
22412
+ if (list) {
22413
+ while (list.size > 0) reverseEdge(list.list[0]);
22414
+ }
22415
+ return flag ? 1 : 0;
22416
+ }
22417
+ function minmaxEdges(g) {
22418
+ if (!g.info.maxset && !g.info.minset) return [0, 0];
22419
+ if (g.info.minset) g.info.minset = ufFind(g.info.minset);
22420
+ if (g.info.maxset) g.info.maxset = ufFind(g.info.maxset);
22421
+ const slenY = g.info.maxset ? minmaxEdgesReverse(g.info.maxset, true) : 0;
22422
+ const slenX = g.info.minset ? minmaxEdgesReverse(g.info.minset, false) : 0;
22423
+ return [slenX, slenY];
22424
+ }
22425
+ function nOutEdge0(n) {
22426
+ return n.info.out?.list[0];
22427
+ }
22428
+ function nInEdge0(n) {
22429
+ return n.info.in?.list[0];
22430
+ }
22431
+ function mmEdges2CheckMax(g, n, slen1) {
22432
+ const out = n.info.out;
22433
+ if ((!out || out.size === 0) && g.info.maxset && n !== g.info.maxset) {
22434
+ const ref = nOutEdge0(n) ?? nInEdge0(n);
22435
+ const e = virtualEdge(n, g.info.maxset, ref);
22436
+ e.info.minlen = slen1;
22437
+ e.info.weight = 0;
22438
+ return true;
22439
+ }
22440
+ return false;
22441
+ }
22442
+ function mmEdges2CheckMin(g, n, slen0) {
22443
+ const inp = n.info.in;
22444
+ if ((!inp || inp.size === 0) && g.info.minset && n !== g.info.minset) {
22445
+ const ref = nInEdge0(n) ?? nOutEdge0(n);
22446
+ const e = virtualEdge(g.info.minset, n, ref);
22447
+ e.info.minlen = slen0;
22448
+ e.info.weight = 0;
22449
+ return true;
22450
+ }
22451
+ return false;
22452
+ }
22453
+ function minmaxEdges2(g, slen) {
22454
+ if (!g.info.maxset && !g.info.minset) return false;
22455
+ let added = false;
22456
+ for (const n of nodesInSeq(g)) {
22457
+ if (n !== ufFind(n)) continue;
22458
+ if (mmEdges2CheckMax(g, n, slen[1])) added = true;
22459
+ if (mmEdges2CheckMin(g, n, slen[0])) added = true;
22460
+ }
22461
+ return added;
22462
+ }
22463
+ function rank1(g) {
22464
+ const nslimit1 = g.attrs.get("nslimit1") ?? g.graphDefaultsSnapshot?.get("nslimit1") ?? g.root.attrs.get("nslimit1");
22465
+ const maxiter = nslimit1 ? scaleClamp(g.nodes.size, parseFloat(nslimit1)) : Number.MAX_SAFE_INTEGER;
22466
+ const comp = g.info.comp ?? [];
22467
+ const hasClusters = (g.info.n_cluster ?? 0) > 0;
22468
+ for (let c = 0; c < comp.length; c++) {
22469
+ g.info.nlist = comp[c];
22470
+ rank(g, hasClusters ? 0 : 1, maxiter);
22471
+ }
22472
+ }
22473
+ function expandNode(g, n) {
22474
+ const leader = ufFind(n);
22475
+ if (leader !== n) n.info.rank = nRank(n) + nRank(leader);
22476
+ if (gMaxrankDef(g) < nRank(n)) g.info.maxrank = n.info.rank;
22477
+ if (gMinrankDef(g) > nRank(n)) g.info.minrank = n.info.rank;
22478
+ if (nRanktype(n) !== 0 && nRanktype(n) !== LEAFSET) ufSingleton(n);
22479
+ }
22480
+ function expandRankPostprocess(g) {
22481
+ if (clType === LOCAL) {
22482
+ const cl = gClust(g);
22483
+ for (let c = 1; c <= gNCluster(g); c++) setMinmax(cl[c - 1]);
22484
+ } else {
22485
+ findClusters(g);
22486
+ }
22487
+ }
22488
+ function expandRanksets(g) {
22489
+ const first = g.nodes.values().next().value;
22490
+ if (!first) {
22491
+ g.info.minrank = 0;
22492
+ g.info.maxrank = 0;
22493
+ return;
22494
+ }
22495
+ g.info.minrank = Number.MAX_SAFE_INTEGER;
22496
+ g.info.maxrank = -1;
22497
+ for (const n of nodesInSeq(g)) expandNode(g, n);
22498
+ if (g === (g.info.dotroot ?? g.root)) expandRankPostprocess(g);
22499
+ }
22500
+ function dot1Rank(g) {
22501
+ edgelabelRanks(g);
22502
+ collapseSets(g, g);
22503
+ class1(g);
22504
+ const slen = minmaxEdges(g);
22505
+ decompose(g, 0);
22506
+ acyclic(g);
22507
+ if (minmaxEdges2(g, slen)) decompose(g, 0);
22508
+ rank1(g);
22509
+ expandRanksets(g);
22510
+ cleanup1(g);
22511
+ }
22512
+ function dotRank(g) {
22513
+ if (mapbool2(g.attrs.get("newrank"))) {
22514
+ g.info.flags = (g.info.flags ?? 0) | NEW_RANK;
22515
+ dot2Rank(g);
22516
+ } else {
22517
+ dot1Rank(g);
22518
+ }
22519
+ }
22520
+
22521
+ // src/common/record.ts
22522
+ var HASTEXT = 1;
22523
+ var HASPORT = 2;
22524
+ var HASTABLE = 4;
22525
+ var INTEXT = 8;
22526
+ var INPORT = 16;
22527
+ var BOTTOM2 = 1;
22528
+ var RIGHT2 = 2;
22529
+ var TOP2 = 4;
22530
+ var LEFT2 = 8;
22531
+ var PAD_X = 16;
22532
+ var PAD_Y = 8;
22533
+ function makeField() {
22534
+ return {
22535
+ size: { x: 0, y: 0 },
22536
+ b: { ll: { x: 0, y: 0 }, ur: { x: 0, y: 0 } },
22537
+ n_flds: 0,
22538
+ lp: null,
22539
+ fld: null,
22540
+ id: null,
22541
+ LR: 0,
22542
+ sides: 0
22543
+ };
22544
+ }
22545
+ function recIsEscapedDelim(s, j) {
22546
+ if (s[j] !== "\\") return false;
22547
+ const nx = s[j + 1];
22548
+ return nx === "{" || nx === "}" || nx === "|" || nx === "\\";
22549
+ }
22550
+ function recCountFields(p) {
22551
+ let maxf = 1;
22552
+ let cnt = 0;
22553
+ for (let j = p.i; j < p.s.length; j++) {
22554
+ if (recIsEscapedDelim(p.s, j)) {
22555
+ j++;
22556
+ continue;
22557
+ }
22558
+ const c = p.s[j];
22559
+ if (c === "{") cnt++;
22560
+ else if (c === "}") cnt--;
22561
+ else if (c === "|" && cnt === 0) maxf++;
22562
+ if (cnt < 0) break;
22563
+ }
22564
+ return maxf;
22565
+ }
22566
+ function recOpenPort(p, st) {
22567
+ if (st.mode & (HASTABLE | HASPORT)) return -1;
22568
+ st.mode |= HASPORT | INPORT;
22569
+ p.i++;
22570
+ st.pbuf = [];
22571
+ st.hspIdx = 0;
22572
+ return 0;
22573
+ }
22574
+ function recClosePort(p, st) {
22575
+ if (!(st.mode & INPORT)) return -1;
22576
+ const t = st.pbuf;
22577
+ if (t.length > 1 && st.hspIdx !== t.length - 1 && t[t.length - 1] === " ") t.pop();
22578
+ st.tmpport = t.join("");
22579
+ st.mode &= ~INPORT;
22580
+ p.i++;
22581
+ return 0;
22582
+ }
22583
+ function recOpenTable(p, st, LR) {
22584
+ p.i++;
22585
+ if (st.mode !== 0 || p.i >= p.s.length) return -1;
22586
+ st.mode = HASTABLE;
22587
+ const sub = parseReclbl(p, LR ? 0 : 1, false);
22588
+ if (sub === null) return -1;
22589
+ st.rv.fld[st.fi++] = sub;
22590
+ st.fp = sub;
22591
+ return 0;
22592
+ }
22593
+ function recFlushText(p, st) {
22594
+ if (!(st.mode & (HASTEXT | HASTABLE))) {
22595
+ st.mode |= HASTEXT;
22596
+ st.tbuf.push(" ");
22597
+ }
22598
+ if (st.mode & HASTEXT) {
22599
+ const t = st.tbuf;
22600
+ if (t.length > 1 && st.hstIdx !== t.length - 1 && t[t.length - 1] === " ") t.pop();
22601
+ st.fp.lp = makeAnyLabel(
22602
+ t.join(""),
22603
+ false,
22604
+ { fontname: p.lbl.fontname, fontsize: p.lbl.fontsize, fontcolor: p.lbl.fontcolor },
22605
+ p.measurer,
22606
+ p.obj
22607
+ );
22608
+ st.fp.LR = 1;
22609
+ st.tbuf = [];
22610
+ st.hstIdx = 0;
22611
+ }
22612
+ }
22613
+ function recEndField(p, st, flag) {
22614
+ const c = p.i < p.s.length ? p.s[p.i] : "";
22615
+ if (c === "" && !flag || st.mode & INPORT) return -1;
22616
+ if (!(st.mode & HASTABLE)) {
22617
+ st.fp = makeField();
22618
+ st.rv.fld[st.fi++] = st.fp;
22619
+ }
22620
+ if (st.tmpport !== null) {
22621
+ st.fp.id = st.tmpport;
22622
+ st.tmpport = null;
22623
+ }
22624
+ recFlushText(p, st);
22625
+ if (c !== "") {
22626
+ if (c === "}") {
22627
+ p.i++;
22628
+ st.rv.n_flds = st.fi;
22629
+ return 1;
22630
+ }
22631
+ st.mode = 0;
22632
+ p.i++;
22633
+ return 0;
22634
+ }
22635
+ st.rv.n_flds = st.fi;
22636
+ return 1;
22637
+ }
22638
+ function recBackslash(p, st) {
22639
+ const nx = p.s[p.i + 1];
22640
+ if (nx !== void 0) {
22641
+ if (nx < " ") {
22642
+ } else if (nx === " " && !p.lbl.html) {
22643
+ st.ishardspace = true;
22644
+ } else {
22645
+ st.tbuf.push("\\");
22646
+ st.mode |= INTEXT | HASTEXT;
22647
+ }
22648
+ p.i++;
22649
+ }
22650
+ }
22651
+ function recPushText(st, c, html) {
22652
+ const afterSpace = st.tbuf[st.tbuf.length - 1] === " ";
22653
+ if (!(c === " " && !st.ishardspace && afterSpace && !html)) st.tbuf.push(c);
22654
+ if (st.ishardspace) st.hstIdx = st.tbuf.length - 1;
22655
+ }
22656
+ function recPushPort(st, c) {
22657
+ const atStartOrSpace = st.pbuf.length === 0 || st.pbuf[st.pbuf.length - 1] === " ";
22658
+ if (!(c === " " && !st.ishardspace && atStartOrSpace)) st.pbuf.push(c);
22659
+ if (st.ishardspace) st.hspIdx = st.pbuf.length - 1;
22660
+ }
22661
+ function recTextChar(p, st, c) {
22662
+ if (st.mode & HASTABLE && c !== " ") return -1;
22663
+ if (!(st.mode & (INTEXT | INPORT)) && c !== " ") st.mode |= INTEXT | HASTEXT;
22664
+ if (st.mode & INTEXT) recPushText(st, c, p.lbl.html);
22665
+ else if (st.mode & INPORT) recPushPort(st, c);
22666
+ p.i++;
22667
+ return 0;
22668
+ }
22669
+ function recDispatch(p, st, LR, flag) {
22670
+ const c = p.s[p.i];
22671
+ switch (c) {
22672
+ case "<":
22673
+ if (p.lbl.html) return recTextChar(p, st, c);
22674
+ return recOpenPort(p, st);
22675
+ case ">":
22676
+ if (p.lbl.html) return recTextChar(p, st, c);
22677
+ return recClosePort(p, st);
22678
+ case "{":
22679
+ return recOpenTable(p, st, LR);
22680
+ case "}":
22681
+ case "|":
22682
+ case void 0:
22683
+ return recEndField(p, st, flag);
22684
+ case "\\":
22685
+ recBackslash(p, st);
22686
+ return recTextChar(p, st, p.s[p.i]);
22687
+ default:
22688
+ return recTextChar(p, st, c);
22689
+ }
22690
+ }
22691
+ function parseReclbl(p, LR, flag) {
22692
+ const rv = makeField();
22693
+ rv.fld = new Array(recCountFields(p));
22694
+ rv.LR = LR;
22695
+ const st = {
22696
+ rv,
22697
+ fi: 0,
22698
+ mode: 0,
22699
+ tbuf: [],
22700
+ hstIdx: 0,
22701
+ pbuf: [],
22702
+ hspIdx: 0,
22703
+ tmpport: null,
22704
+ ishardspace: false,
22705
+ fp: null
22706
+ };
22707
+ for (; ; ) {
22708
+ if (p.i < p.s.length && p.s[p.i] < " " && p.s[p.i] !== "") {
22709
+ p.i++;
22710
+ continue;
22711
+ }
22712
+ const r = recDispatch(p, st, LR, flag);
22713
+ if (r === -1) return null;
22714
+ if (r === 1) break;
22715
+ if (p.i > p.s.length) break;
22716
+ }
22717
+ rv.n_flds = st.fi;
22718
+ return rv;
22719
+ }
22720
+ function recLabelDimen(n, g, f) {
22721
+ const dimen = { x: f.lp.dimen.x, y: f.lp.dimen.y };
22722
+ if (dimen.x > 0 || dimen.y > 0) {
22723
+ const m = nodeAttr(n, g, "margin");
22724
+ const parts = m !== void 0 ? m.split(",").map(parseFloat) : [];
22725
+ if (parts.length > 0 && !Number.isNaN(parts[0])) {
22726
+ dimen.x += 2 * parts[0] * 72;
22727
+ dimen.y += 2 * (parts.length > 1 && !Number.isNaN(parts[1]) ? parts[1] : parts[0]) * 72;
22728
+ } else {
22729
+ dimen.x += PAD_X;
22730
+ dimen.y += PAD_Y;
22731
+ }
22732
+ }
22733
+ return dimen;
22734
+ }
22735
+ function sizeReclbl(n, g, f) {
22736
+ let d;
22737
+ if (f.lp) {
22738
+ d = recLabelDimen(n, g, f);
22739
+ } else {
22740
+ d = { x: 0, y: 0 };
22741
+ for (let i = 0; i < f.n_flds; i++) {
22742
+ const d0 = sizeReclbl(n, g, f.fld[i]);
22743
+ if (f.LR) {
22744
+ d.x += d0.x;
22745
+ d.y = Math.max(d.y, d0.y);
22746
+ } else {
22747
+ d.y += d0.y;
22748
+ d.x = Math.max(d.x, d0.x);
22749
+ }
22750
+ }
22751
+ }
22752
+ f.size = d;
22753
+ return d;
22754
+ }
22755
+ function resizeReclbl(f, sz, nojustify) {
22756
+ const d = { x: sz.x - f.size.x, y: sz.y - f.size.y };
22757
+ f.size = sz;
22758
+ if (f.lp && !nojustify) {
22759
+ f.lp.space.x += d.x;
22760
+ f.lp.space.y += d.y;
22761
+ }
22762
+ if (f.n_flds) {
22763
+ const inc2 = f.LR ? d.x / f.n_flds : d.y / f.n_flds;
22764
+ for (let i = 0; i < f.n_flds; i++) {
22765
+ const sf = f.fld[i];
22766
+ const amt = Math.trunc((i + 1) * inc2) - Math.trunc(i * inc2);
22767
+ const newsz = f.LR ? { x: sf.size.x + amt, y: sz.y } : { x: sz.x, y: sf.size.y + amt };
22768
+ resizeReclbl(sf, newsz, nojustify);
22769
+ }
22770
+ }
22771
+ }
22772
+ function recSideMask(f, i, last) {
22773
+ if (f.LR) {
22774
+ if (i === 0) return i === last ? TOP2 | BOTTOM2 | RIGHT2 | LEFT2 : TOP2 | BOTTOM2 | LEFT2;
22775
+ return i === last ? TOP2 | BOTTOM2 | RIGHT2 : TOP2 | BOTTOM2;
22776
+ }
22777
+ if (i === 0) return i === last ? TOP2 | BOTTOM2 | RIGHT2 | LEFT2 : TOP2 | RIGHT2 | LEFT2;
22778
+ return i === last ? LEFT2 | BOTTOM2 | RIGHT2 : LEFT2 | RIGHT2;
22779
+ }
22780
+ function posReclbl(f, ul, sides) {
22781
+ f.sides = sides;
22782
+ f.b = {
22783
+ ll: { x: ul.x, y: ul.y - f.size.y },
22784
+ ur: { x: ul.x + f.size.x, y: ul.y }
22785
+ };
22786
+ const last = f.n_flds - 1;
22787
+ const pos = { x: ul.x, y: ul.y };
22788
+ for (let i = 0; i <= last; i++) {
22789
+ const mask = sides ? recSideMask(f, i, last) : 0;
22790
+ posReclbl(f.fld[i], { x: pos.x, y: pos.y }, sides & mask);
22791
+ if (f.LR) pos.x += f.fld[i].size.x;
22792
+ else pos.y -= f.fld[i].size.y;
22793
+ }
22794
+ }
22795
+ function attrBool(n, g, key) {
22796
+ return mapbool2(nodeAttr(n, g, key));
22797
+ }
22798
+ function recAttrSize(n, g) {
22799
+ const w = nodeAttr(n, g, "width");
22800
+ const h = nodeAttr(n, g, "height");
22801
+ return {
22802
+ x: (w !== void 0 ? parseFloat(w) : 0.75) * 72,
22803
+ y: (h !== void 0 ? parseFloat(h) : 0.5) * 72
22804
+ };
22805
+ }
22806
+ function recParseOrFallback(lbl, measurer, flip, obj) {
22807
+ const p = { s: lbl.text, i: 0, lbl, measurer, obj };
22808
+ const info = parseReclbl(p, flip, true);
22809
+ if (info !== null) return info;
22810
+ const fb = { s: "\\N", i: 0, lbl, measurer, obj };
22811
+ return parseReclbl(fb, flip, true);
22812
+ }
22813
+ function recordInit(n, g, measurer) {
22814
+ const lbl = n.info.label;
22815
+ const flip = ((g.root.info.rankdir ?? 0) >> 2 & 1) === 1 ? 0 : 1;
22816
+ const info = recParseOrFallback(lbl, measurer, flip, n);
22817
+ sizeReclbl(n, g, info);
22818
+ const sz = recAttrSize(n, g);
22819
+ if (!attrBool(n, g, "fixedsize")) {
22820
+ sz.x = Math.max(info.size.x, sz.x);
22821
+ sz.y = Math.max(info.size.y, sz.y);
22822
+ }
22823
+ resizeReclbl(info, sz, attrBool(n, g, "nojustify"));
22824
+ posReclbl(info, { x: -sz.x / 2, y: sz.y / 2 }, BOTTOM2 | RIGHT2 | TOP2 | LEFT2);
22825
+ n.info.width = info.size.x / 72;
22826
+ n.info.height = (info.size.y + 1) / 72;
22827
+ const ns = gvNodesize(info.size.x, info.size.y + 1, g.root.info.flip === true);
22828
+ n.info.lw = ns.lw;
22829
+ n.info.rw = ns.rw;
22830
+ n.info.ht = ns.ht;
22831
+ n.info.shape_info = info;
22832
+ }
22833
+ function recordMakeLabel(n, g, measurer) {
22834
+ const labelText = nodeAttr(n, g, "label") ?? n.name;
22835
+ const { fontname, fontsize, fontcolor } = readFontAttrs(n, g);
22836
+ n.info.label = makeLabel(labelText, fontname, fontsize, fontcolor, measurer);
22837
+ }
22838
+ function recordNodeInit(n, g, measurer) {
22839
+ recordMakeLabel(n, g, measurer);
22840
+ recordInit(n, g, measurer);
22841
+ }
22842
+ function genFields(job, n, f) {
22843
+ const renderer = job.renderer;
22844
+ const coord = n.info.coord ?? { x: 0, y: 0 };
22845
+ if (f.lp) {
22846
+ const mid = {
22847
+ x: (f.b.ll.x + f.b.ur.x) / 2 + coord.x,
22848
+ y: (f.b.ll.y + f.b.ur.y) / 2 + coord.y
22849
+ };
22850
+ renderLabel(f.lp, mid, renderer, job);
22851
+ }
22852
+ for (let i = 0; i < f.n_flds; i++) {
22853
+ if (i > 0) genFieldSeparator(job, coord, f, f.fld[i]);
22854
+ genFields(job, n, f.fld[i]);
22855
+ }
22856
+ }
22857
+ function genFieldSeparator(job, coord, f, child) {
22858
+ const a = { x: 0, y: 0 };
22859
+ const b = { x: 0, y: 0 };
22860
+ if (f.LR) {
22861
+ a.x = child.b.ll.x;
22862
+ a.y = child.b.ll.y;
22863
+ b.x = a.x;
22864
+ b.y = child.b.ur.y;
22865
+ } else {
22866
+ b.x = child.b.ur.x;
22867
+ b.y = child.b.ur.y;
22868
+ a.x = child.b.ll.x;
22869
+ a.y = b.y;
22870
+ }
22871
+ const pts = [
22872
+ transformPoint({ x: a.x + coord.x, y: a.y + coord.y }, job),
22873
+ transformPoint({ x: b.x + coord.x, y: b.y + coord.y }, job)
22874
+ ];
22875
+ job.renderer.polyline(pts, job);
22876
+ }
22877
+ function recordGencode(rawJob, rawNode) {
22878
+ const job = rawJob;
22879
+ const n = rawNode;
22880
+ if (!job.renderer) return;
22881
+ const f = n.info.shape_info;
22882
+ if (!f) return;
22883
+ const coord = n.info.coord ?? { x: 0, y: 0 };
22884
+ const ll = { x: f.b.ll.x + coord.x, y: f.b.ll.y + coord.y };
22885
+ const ur = { x: f.b.ur.x + coord.x, y: f.b.ur.y + coord.y };
22886
+ const filled = job.obj !== null && applyNodeStyle(job.obj, n, job);
22887
+ drawRecordBox(job, n, ll, ur, filled);
22888
+ genFields(job, n, f);
23134
22889
  }
23135
- function nRank(n) {
23136
- return n.info.rank ?? 0;
22890
+ function drawRecordBox(job, n, ll, ur, filled) {
22891
+ const isMrecord = nodeAttr(n, n.root, "shape") === "Mrecord";
22892
+ const rounded = isMrecord || parseStyleFlags(nodeAttr(n, n.root, "style")).rounded;
22893
+ if (rounded) {
22894
+ const af = [{ x: ll.x, y: ll.y }, { x: ur.x, y: ll.y }, { x: ur.x, y: ur.y }, { x: ll.x, y: ur.y }];
22895
+ emitRoundedBezier(af, { x: 0, y: 0 }, filled, { renderer: job.renderer, job });
22896
+ return;
22897
+ }
22898
+ const pts = [{ x: ll.x, y: ll.y }, { x: ll.x, y: ur.y }, { x: ur.x, y: ur.y }, { x: ur.x, y: ll.y }].map((q) => transformPoint(q, job));
22899
+ job.renderer.polygon(pts, filled, job);
23137
22900
  }
23138
- function nRanktype(n) {
23139
- return n.info.ranktype ?? 0;
22901
+
22902
+ // src/common/poly-init.ts
22903
+ var DEFAULT_LW = 27;
22904
+ var DEFAULT_RW = 27;
22905
+ var DEFAULT_HT = 36;
22906
+ function nodeAttr(n, g, key) {
22907
+ const own = n.attrs.get(key);
22908
+ if (own !== void 0) return own;
22909
+ if (n.nodeDefaultsSnapshot !== void 0) return n.nodeDefaultsSnapshot.get(key);
22910
+ return g.nodeDefaults.get(key) ?? (g !== g.root ? g.root.nodeDefaults.get(key) : void 0);
23140
22911
  }
23141
- function gMaxrankDef(g) {
23142
- return g.info.maxrank ?? -1;
22912
+ function readFontAttrs(n, g) {
22913
+ return {
22914
+ fontname: nodeAttr(n, g, "fontname") ?? DEFAULT_FONTNAME,
22915
+ fontsize: parseFloat(nodeAttr(n, g, "fontsize") ?? String(DEFAULT_FONTSIZE2)),
22916
+ fontcolor: nodeAttr(n, g, "fontcolor") ?? DEFAULT_COLOR2
22917
+ };
23143
22918
  }
23144
- function gMinrankDef(g) {
23145
- return g.info.minrank ?? Number.MAX_SAFE_INTEGER;
22919
+ function assignShapeInfo(n, polyDesc) {
22920
+ const w = n.info.width !== void 0 ? n.info.width * 72 : (n.info.lw || DEFAULT_LW) + (n.info.rw || DEFAULT_RW);
22921
+ const h = n.info.height !== void 0 ? n.info.height * 72 : n.info.ht || DEFAULT_HT;
22922
+ const base = n.info.base_width !== void 0 && n.info.base_height !== void 0 ? { w: n.info.base_width * 72, h: n.info.base_height * 72 } : void 0;
22923
+ n.info.shape_info = {
22924
+ ...polyDesc,
22925
+ vertices: computeVertices(polyDesc, w, h, base)
22926
+ };
23146
22927
  }
23147
- function setMinmax(g) {
23148
- const lr = gLeaderRank(g);
23149
- g.info.minrank = gMinrankVal(g) + lr;
23150
- g.info.maxrank = gMaxrankVal(g) + lr;
23151
- const cl = gClust(g);
23152
- const nc = gNCluster(g);
23153
- for (let c = 1; c <= nc; c++) setMinmax(cl[c - 1]);
22928
+ function buildNodeLabel(n, g, measurer) {
22929
+ if (n.info.label !== void 0) return;
22930
+ const labelAttr = nodeAttr(n, g, "label");
22931
+ const font = readFontAttrs(n, g);
22932
+ const isHtml = labelAttr !== void 0 && isHtmlValue(labelAttr);
22933
+ const content = isHtml ? htmlValueContent(labelAttr) : labelAttr ?? n.name;
22934
+ n.info.label = makeAnyLabel(content, isHtml, font, measurer, n);
23154
22935
  }
23155
- function minmaxEdgesReverse(n, isOut) {
23156
- const rt = n.info.ranktype ?? 0;
23157
- const flag = isOut ? rt === SINKRANK : rt === SOURCERANK;
23158
- const list = isOut ? n.info.out : n.info.in;
23159
- if (list) {
23160
- while (list.size > 0) reverseEdge(list.list[0]);
22936
+ function polyInit(n, g, measurer) {
22937
+ const shapeName = nodeAttr(n, g, "shape") ?? "ellipse";
22938
+ const shapefile = nodeAttr(n, g, "shapefile");
22939
+ n.info.shape = bindShape(shapeName, shapefile);
22940
+ if (shapefile !== void 0 && shapefile !== "" && shapeName !== "epsf") {
22941
+ console.error(`Warning: No or improper shapefile="${shapefile}" for node "${n.name}"`);
23161
22942
  }
23162
- return flag ? 1 : 0;
23163
- }
23164
- function minmaxEdges(g) {
23165
- if (!g.info.maxset && !g.info.minset) return [0, 0];
23166
- if (g.info.minset) g.info.minset = ufFind(g.info.minset);
23167
- if (g.info.maxset) g.info.maxset = ufFind(g.info.maxset);
23168
- const slenY = g.info.maxset ? minmaxEdgesReverse(g.info.maxset, true) : 0;
23169
- const slenX = g.info.minset ? minmaxEdgesReverse(g.info.minset, false) : 0;
23170
- return [slenX, slenY];
22943
+ if (n.info.shape.kind === 2 /* SH_RECORD */) {
22944
+ if (n.info.shape_info === void 0) recordNodeInit(n, g, measurer);
22945
+ return;
22946
+ }
22947
+ buildNodeLabel(n, g, measurer);
22948
+ if (n.info.shape_info !== void 0) return;
22949
+ const polyDesc = n.info.shape.polygon;
22950
+ if (polyDesc !== null) assignShapeInfo(n, polyDesc);
23171
22951
  }
23172
- function nOutEdge0(n) {
23173
- return n.info.out?.list[0];
22952
+
22953
+ // src/render/svg-multicolor.ts
22954
+ var THIN_LINE = 0.5;
22955
+ function rationalFunction(x, c) {
22956
+ return (x * (x * c[0] + c[1]) + c[2]) / (x + c[3]);
23174
22957
  }
23175
- function nInEdge0(n) {
23176
- return n.info.in?.list[0];
22958
+ var COEFFS3LOW = [
22959
+ [
22960
+ [3.85268, -21.229, -0.330434, 0.0127842],
22961
+ [-1.61486, 0.706564, 0.225945, 0.263682],
22962
+ [-0.910164, 0.388383, 551445e-8, 671814e-8],
22963
+ [-0.630184, 0.192402, 98871e-7, 0.0102527]
22964
+ ],
22965
+ [
22966
+ [-0.162211, 9.94329, 0.13723, 0.0124084],
22967
+ [-0.253135, 187735e-8, 0.0230286, 0.01264],
22968
+ [-0.0695069, -0.0437594, 0.0120636, 0.0163087],
22969
+ [-0.0328856, -926032e-8, -173573e-8, 527385e-8]
22970
+ ]
22971
+ ];
22972
+ var COEFFS3HIGH = [
22973
+ [
22974
+ [0.0899116, -19.2349, -4.11711, 0.183362],
22975
+ [0.138148, -1.45804, 1.32044, 1.38474],
22976
+ [0.230903, -0.450262, 0.219963, 0.414038],
22977
+ [0.0590565, -0.101062, 0.0430592, 0.0204699]
22978
+ ],
22979
+ [
22980
+ [0.0164649, 9.89394, 0.0919496, 760802e-8],
22981
+ [0.0191603, -0.0322058, 0.0134667, -0.0825018],
22982
+ [0.0156192, -0.017535, 326508e-8, -0.228157],
22983
+ [-0.0236752, 0.0405821, -0.0173086, 0.176187]
22984
+ ]
22985
+ ];
22986
+ var SAFETY3 = [1e-3, 4.98, 0.207, 67e-4];
22987
+ function estimateError(a, b, etaA, etaB) {
22988
+ const eta = 0.5 * (etaA + etaB);
22989
+ const x = b / a;
22990
+ const dEta = etaB - etaA;
22991
+ const cos2 = Math.cos(2 * eta);
22992
+ const cos4 = Math.cos(4 * eta);
22993
+ const cos6 = Math.cos(6 * eta);
22994
+ const c = x < 0.25 ? COEFFS3LOW : COEFFS3HIGH;
22995
+ const c0 = rationalFunction(x, c[0][0]) + cos2 * rationalFunction(x, c[0][1]) + cos4 * rationalFunction(x, c[0][2]) + cos6 * rationalFunction(x, c[0][3]);
22996
+ const c1 = rationalFunction(x, c[1][0]) + cos2 * rationalFunction(x, c[1][1]) + cos4 * rationalFunction(x, c[1][2]) + cos6 * rationalFunction(x, c[1][3]);
22997
+ return rationalFunction(x, SAFETY3) * a * Math.exp(c0 + c1 * dEta);
23177
22998
  }
23178
- function mmEdges2CheckMax(g, n, slen1) {
23179
- const out = n.info.out;
23180
- if ((!out || out.size === 0) && g.info.maxset && n !== g.info.maxset) {
23181
- const ref = nOutEdge0(n) ?? nInEdge0(n);
23182
- const e = virtualEdge(n, g.info.maxset, ref);
23183
- e.info.minlen = slen1;
23184
- e.info.weight = 0;
23185
- return true;
22999
+ function allSubdivsBelowThreshold(a, b, eta1, n, dEta) {
23000
+ let etaA = eta1;
23001
+ for (let i = 0; i < n; i++) {
23002
+ if (estimateError(a, b, etaA, etaA + dEta) > 1e-5) return false;
23003
+ etaA += dEta;
23186
23004
  }
23187
- return false;
23005
+ return true;
23188
23006
  }
23189
- function mmEdges2CheckMin(g, n, slen0) {
23190
- const inp = n.info.in;
23191
- if ((!inp || inp.size === 0) && g.info.minset && n !== g.info.minset) {
23192
- const ref = nInEdge0(n) ?? nOutEdge0(n);
23193
- const e = virtualEdge(g.info.minset, n, ref);
23194
- e.info.minlen = slen0;
23195
- e.info.weight = 0;
23196
- return true;
23007
+ function numSubdivisions(a, b, eta1, eta2) {
23008
+ let n = 1;
23009
+ while (n < 1024) {
23010
+ const dEta = (eta2 - eta1) / n;
23011
+ if (dEta <= 0.5 * Math.PI && allSubdivsBelowThreshold(a, b, eta1, n, dEta)) break;
23012
+ n <<= 1;
23197
23013
  }
23198
- return false;
23014
+ return n;
23199
23015
  }
23200
- function minmaxEdges2(g, slen) {
23201
- if (!g.info.maxset && !g.info.minset) return false;
23202
- let added = false;
23203
- for (const n of nodesInSeq(g)) {
23204
- if (n !== ufFind(n)) continue;
23205
- if (mmEdges2CheckMax(g, n, slen[1])) added = true;
23206
- if (mmEdges2CheckMin(g, n, slen[0])) added = true;
23207
- }
23208
- return added;
23016
+ function initArcPath(pts, e, eta1) {
23017
+ const cosE = Math.cos(eta1);
23018
+ const sinE = Math.sin(eta1);
23019
+ const xB = e.cx + e.xsemi * cosE;
23020
+ const yB = e.cy + e.ysemi * sinE;
23021
+ pts.push(
23022
+ { x: e.cx, y: e.cy },
23023
+ { x: e.cx, y: e.cy },
23024
+ { x: xB, y: yB },
23025
+ { x: xB, y: yB }
23026
+ );
23027
+ return { xB, yB, xBDot: -e.xsemi * sinE, yBDot: e.ysemi * cosE };
23209
23028
  }
23210
- function rank1(g) {
23211
- const nslimit1 = g.attrs.get("nslimit1") ?? g.graphDefaultsSnapshot?.get("nslimit1") ?? g.root.attrs.get("nslimit1");
23212
- const maxiter = nslimit1 ? scaleClamp(g.nodes.size, parseFloat(nslimit1)) : Number.MAX_SAFE_INTEGER;
23213
- const comp = g.info.comp ?? [];
23214
- const hasClusters = (g.info.n_cluster ?? 0) > 0;
23215
- for (let c = 0; c < comp.length; c++) {
23216
- g.info.nlist = comp[c];
23217
- rank(g, hasClusters ? 0 : 1, maxiter);
23218
- }
23029
+ function stepBezier(pts, state3, e, sp) {
23030
+ const xA = state3.xB;
23031
+ const yA = state3.yB;
23032
+ const xADot = state3.xBDot;
23033
+ const yADot = state3.yBDot;
23034
+ const newEta = sp.etaB + sp.dEta;
23035
+ const cosE = Math.cos(newEta);
23036
+ const sinE = Math.sin(newEta);
23037
+ state3.xB = e.cx + e.xsemi * cosE;
23038
+ state3.yB = e.cy + e.ysemi * sinE;
23039
+ state3.xBDot = -e.xsemi * sinE;
23040
+ state3.yBDot = e.ysemi * cosE;
23041
+ pts.push({ x: xA + sp.alpha * xADot, y: yA + sp.alpha * yADot });
23042
+ pts.push({ x: state3.xB - sp.alpha * state3.xBDot, y: state3.yB - sp.alpha * state3.yBDot });
23043
+ pts.push({ x: state3.xB, y: state3.yB });
23044
+ return newEta;
23219
23045
  }
23220
- function expandNode(g, n) {
23221
- const leader = ufFind(n);
23222
- if (leader !== n) n.info.rank = nRank(n) + nRank(leader);
23223
- if (gMaxrankDef(g) < nRank(n)) g.info.maxrank = n.info.rank;
23224
- if (gMinrankDef(g) > nRank(n)) g.info.minrank = n.info.rank;
23225
- if (nRanktype(n) !== 0 && nRanktype(n) !== LEAFSET) ufSingleton(n);
23046
+ function ellipticWedge(e, angle0, angle1) {
23047
+ const TWOPI2 = 2 * Math.PI;
23048
+ const eta1 = Math.atan2(Math.sin(angle0) / e.ysemi, Math.cos(angle0) / e.xsemi);
23049
+ let eta2 = Math.atan2(Math.sin(angle1) / e.ysemi, Math.cos(angle1) / e.xsemi);
23050
+ eta2 -= TWOPI2 * Math.floor((eta2 - eta1) / TWOPI2);
23051
+ if (angle1 - angle0 > Math.PI && eta2 - eta1 < Math.PI) eta2 += TWOPI2;
23052
+ const n = numSubdivisions(e.xsemi, e.ysemi, eta1, eta2);
23053
+ const dEta = (eta2 - eta1) / n;
23054
+ const t = Math.tan(0.5 * dEta);
23055
+ const alpha = Math.sin(dEta) * (Math.sqrt(4 + 3 * t * t) - 1) / 3;
23056
+ const pts = [];
23057
+ const state3 = initArcPath(pts, e, eta1);
23058
+ let sp = { etaB: eta1, dEta, alpha };
23059
+ for (let i = 0; i < n; i++) sp = { ...sp, etaB: stepBezier(pts, state3, e, sp) };
23060
+ pts.push({ x: state3.xB, y: state3.yB }, { x: e.cx, y: e.cy }, { x: e.cx, y: e.cy });
23061
+ return pts;
23226
23062
  }
23227
- function expandRankPostprocess(g) {
23228
- if (clType === LOCAL) {
23229
- const cl = gClust(g);
23230
- for (let c = 1; c <= gNCluster(g); c++) setMinmax(cl[c - 1]);
23231
- } else {
23232
- findClusters(g);
23233
- }
23063
+ function drawWedge(seg2, e, ctx) {
23064
+ const TWOPI2 = 2 * Math.PI;
23065
+ const angle1 = seg2.isLast ? TWOPI2 : seg2.angle0 + TWOPI2 * seg2.t;
23066
+ const obj = ctx.job.obj;
23067
+ if (obj !== null) obj.fillColor = resolveRenderColor(seg2.color);
23068
+ const ptsUp = ellipticWedge(e, seg2.angle0, angle1);
23069
+ ctx.renderer.bezier(ptsUp.map((p) => ({ x: p.x, y: -p.y })), true, ctx.job);
23070
+ return angle1;
23234
23071
  }
23235
- function expandRanksets(g) {
23236
- const first = g.nodes.values().next().value;
23237
- if (!first) {
23238
- g.info.minrank = 0;
23239
- g.info.maxrank = 0;
23240
- return;
23072
+ function wedgedEllipse(job, pf, clrs, renderer) {
23073
+ const { segs, error } = parseSegs(clrs);
23074
+ if (error === 1 || error === 2) return error;
23075
+ const ctrX = (pf[0].x + pf[1].x) / 2;
23076
+ const ctrY = (pf[0].y + pf[1].y) / 2;
23077
+ const e = {
23078
+ cx: ctrX,
23079
+ cy: -ctrY,
23080
+ xsemi: pf[1].x - ctrX,
23081
+ ysemi: Math.abs(pf[1].y - ctrY)
23082
+ };
23083
+ const ctx = { job, renderer };
23084
+ const obj = job.obj;
23085
+ const saved = obj !== null ? obj.penWidth : 1;
23086
+ if (obj !== null && saved > THIN_LINE) obj.penWidth = THIN_LINE;
23087
+ let angle0 = 0;
23088
+ for (let i = 0; i < segs.length; i++) {
23089
+ const s = segs[i];
23090
+ if (s.color === null) break;
23091
+ if (s.t > 0) {
23092
+ angle0 = drawWedge({ angle0, t: s.t, isLast: i + 1 === segs.length, color: s.color }, e, ctx);
23093
+ }
23241
23094
  }
23242
- g.info.minrank = Number.MAX_SAFE_INTEGER;
23243
- g.info.maxrank = -1;
23244
- for (const n of nodesInSeq(g)) expandNode(g, n);
23245
- if (g === (g.info.dotroot ?? g.root)) expandRankPostprocess(g);
23095
+ if (obj !== null && saved > THIN_LINE) obj.penWidth = saved;
23096
+ return error;
23246
23097
  }
23247
- function dot1Rank(g) {
23248
- edgelabelRanks(g);
23249
- collapseSets(g, g);
23250
- class1(g);
23251
- const slen = minmaxEdges(g);
23252
- decompose(g, 0);
23253
- acyclic(g);
23254
- if (minmaxEdges2(g, slen)) decompose(g, 0);
23255
- rank1(g);
23256
- expandRanksets(g);
23257
- cleanup1(g);
23098
+ function drawBand(p, seg2, ctx) {
23099
+ const obj = ctx.job.obj;
23100
+ if (obj !== null) obj.fillColor = resolveRenderColor(seg2.color);
23101
+ p[1].x = p[2].x = seg2.isLast ? seg2.lastx : p[0].x + seg2.segWidth;
23102
+ ctx.renderer.polygon([...p], true, ctx.job);
23103
+ p[0].x = p[3].x = p[1].x;
23258
23104
  }
23259
- function dotRank(g) {
23260
- if (mapbool2(g.attrs.get("newrank"))) {
23261
- g.info.flags = (g.info.flags ?? 0) | NEW_RANK;
23262
- dot2Rank(g);
23263
- } else {
23264
- dot1Rank(g);
23105
+ function stripedBox(job, pts, clrs, rotate, renderer) {
23106
+ const { segs, error } = parseSegs(clrs);
23107
+ if (error === 1 || error === 2) return error;
23108
+ const p = rotate ? [{ ...pts[2] }, { ...pts[3] }, { ...pts[0] }, { ...pts[1] }] : [{ ...pts[0] }, { ...pts[1] }, { ...pts[2] }, { ...pts[3] }];
23109
+ const lastx = p[1].x;
23110
+ const xdelta = p[1].x - p[0].x;
23111
+ p[1].x = p[2].x = p[0].x;
23112
+ const ctx = { job, renderer };
23113
+ const obj = job.obj;
23114
+ const saved = obj !== null ? obj.penWidth : 1;
23115
+ if (obj !== null && saved > THIN_LINE) obj.penWidth = THIN_LINE;
23116
+ for (let i = 0; i < segs.length; i++) {
23117
+ const s = segs[i];
23118
+ if (s.color === null) break;
23119
+ if (s.t > 0) {
23120
+ drawBand(p, { color: s.color, isLast: i + 1 === segs.length, segWidth: xdelta * s.t, lastx }, ctx);
23121
+ }
23265
23122
  }
23123
+ if (obj !== null && saved > THIN_LINE) obj.penWidth = saved;
23124
+ return error;
23266
23125
  }
23267
23126
 
23268
- // src/layout/dot/classify.ts
23269
- function portsEq(e, f) {
23270
- const ehp = e.info.head_port;
23271
- const fhp = f.info.head_port;
23272
- const etp = e.info.tail_port;
23273
- const ftp = f.info.tail_port;
23274
- const headMatch = ehp.p.x === fhp.p.x && ehp.p.y === fhp.p.y || !ehp.defined;
23275
- const tailMatch = etp.p.x === ftp.p.x && etp.p.y === ftp.p.y || !etp.defined;
23276
- return ehp.defined === fhp.defined && headMatch && tailMatch;
23277
- }
23278
- function nonconstraintEdge(e) {
23279
- return e.info.constraint === false;
23280
- }
23281
- var WNODE_ORDINARY = 0;
23282
- var WNODE_SINGLETON = 1;
23283
- var WNODE_VIRTUAL = 2;
23284
- var CLASSIFY_WEIGHT_TABLE = [[1, 1, 1], [1, 2, 2], [1, 2, 4]];
23285
- function epClass(n) {
23286
- if (n.info.node_type === VIRTUAL) return WNODE_VIRTUAL;
23287
- if ((n.info.weight_class ?? 2) <= 1) return WNODE_SINGLETON;
23288
- return WNODE_ORDINARY;
23127
+ // src/render/xml-escape.ts
23128
+ var RE_DQUOTE = new RegExp('"', "g");
23129
+ var RE_SQUOTE = new RegExp("'", "g");
23130
+ var RE_AMP_NONENTITY = /&(?![A-Za-z]+;|#[0-9]+;|#x[0-9A-Fa-f]+;)/g;
23131
+ function escapeXml(s) {
23132
+ let r = s.replace(RE_AMP_NONENTITY, "&amp;");
23133
+ r = r.replace(/</g, "&lt;");
23134
+ r = r.replace(/>/g, "&gt;");
23135
+ r = r.replace(RE_DQUOTE, "&quot;");
23136
+ r = r.replace(RE_SQUOTE, "&#39;");
23137
+ return r;
23289
23138
  }
23290
- function applyVirtualWeight(e) {
23291
- const t = CLASSIFY_WEIGHT_TABLE[epClass(e.tail)][epClass(e.head)];
23292
- e.info.weight = (e.info.weight ?? 1) * t;
23139
+ function escapeXmlTitle(s) {
23140
+ let r = escapeXml(s);
23141
+ r = r.replace(/-/g, "&#45;");
23142
+ r = r.replace(/ {2,}/g, (m) => " " + "&#160;".repeat(m.length - 1));
23143
+ return r;
23293
23144
  }
23294
- function interclust1TRank(e) {
23295
- const clust = e.tail.info.clust;
23296
- return clust ? (e.tail.info.rank ?? 0) - (clust.info.leader?.info.rank ?? 0) : 0;
23145
+ function escapeXmlText(s) {
23146
+ let r = escapeXml(s);
23147
+ r = r.replace(/-/g, "&#45;");
23148
+ r = r.replace(/\n/g, "&#10;");
23149
+ r = r.replace(/\r/g, "&#13;");
23150
+ r = r.replace(/ {2,}/g, (m) => " " + "&#160;".repeat(m.length - 1));
23151
+ return r;
23297
23152
  }
23298
- function interclust1HRank(e) {
23299
- const clust = e.head.info.clust;
23300
- return clust ? (e.head.info.rank ?? 0) - (clust.info.leader?.info.rank ?? 0) : 0;
23153
+
23154
+ // src/gvc/device-cluster.ts
23155
+ function applyClusterGradient(obj, fill) {
23156
+ obj.fill = fill.kind === "radial" ? 3 /* Radial */ : 2 /* Linear */;
23157
+ obj.fillColor = resolveRenderColor(fill.fillColor);
23158
+ obj.stopColor = resolveRenderColor(fill.stopColor);
23159
+ obj.gradientFrac = fill.frac;
23160
+ obj.gradientAngle = fill.angle;
23301
23161
  }
23302
- function interclust1Lengths(e) {
23303
- const offset = (e.info.minlen ?? 1) + interclust1TRank(e) - interclust1HRank(e);
23304
- return offset > 0 ? [0, offset] : [-offset, 0];
23162
+ function clusterAttr(sg, key) {
23163
+ for (let g = sg; g !== null; g = g.parent) {
23164
+ const v = g.attrs.get(key);
23165
+ if (v !== void 0) return v;
23166
+ }
23167
+ return void 0;
23305
23168
  }
23306
- function interclust1(g, t, h, e) {
23307
- const [tLen, hLen] = interclust1Lengths(e);
23308
- const v = virtualNode(g);
23309
- v.info.node_type = SLACKNODE;
23310
- const t0 = ufFind(t);
23311
- const h0 = ufFind(h);
23312
- const w = e.info.weight ?? 1;
23313
- const rt = makeAuxEdge(v, t0, tLen, CL_BACK * w);
23314
- const rh = makeAuxEdge(v, h0, hLen, w);
23315
- rt.info.to_orig = e;
23316
- rh.info.to_orig = e;
23169
+ function clusterStyle(sg) {
23170
+ return clusterAttr(sg, "style");
23317
23171
  }
23318
- function class1Edge(g, e) {
23319
- if (e.info.to_virt !== void 0) return;
23320
- if (nonconstraintEdge(e)) return;
23321
- const t = ufFind(e.tail);
23322
- const h = ufFind(e.head);
23323
- if (t === h) return;
23324
- if (t.info.clust || h.info.clust) {
23325
- interclust1(g, e.tail, e.head, e);
23326
- return;
23327
- }
23328
- const rep = findFastEdge(t, h);
23329
- if (rep !== void 0) mergeOneway(e, rep);
23330
- else virtualEdge(t, h, e);
23172
+ function clusterPeripheries(sg) {
23173
+ const raw = clusterAttr(sg, "peripheries");
23174
+ if (raw === void 0 || raw.length === 0) return 1;
23175
+ const v = parseInt(raw, 10);
23176
+ if (Number.isNaN(v)) return 1;
23177
+ return v < 0 ? 0 : v;
23331
23178
  }
23332
- function class1(g) {
23333
- markClusters(g);
23334
- for (const n of nodesInSeq(g)) {
23335
- for (const e of n.outEdges(g)) class1Edge(g, e);
23336
- }
23179
+ function applyClusterPenState(obj, sg) {
23180
+ const flags = parseStyleFlags(clusterStyle(sg));
23181
+ const pen = clusterAttr(sg, "pencolor") ?? clusterAttr(sg, "color");
23182
+ obj.penColor = clusterPeripheries(sg) === 0 ? resolveRenderColor("transparent") : resolveRenderColor(resolvePenColor(pen));
23183
+ obj.penWidth = resolvePenWidth(flags, clusterAttr(sg, "penwidth"));
23184
+ obj.pen = resolvePenType(flags);
23337
23185
  }
23338
- function labelVnodeDimen(orig) {
23339
- const lbl = orig.info.label;
23340
- return lbl?.dimen;
23186
+ function clusterAttrsOf(sg) {
23187
+ return {
23188
+ style: clusterStyle(sg),
23189
+ color: clusterAttr(sg, "color"),
23190
+ pencolor: clusterAttr(sg, "pencolor"),
23191
+ fillcolor: clusterAttr(sg, "fillcolor"),
23192
+ bgcolor: clusterAttr(sg, "bgcolor"),
23193
+ penwidth: clusterAttr(sg, "penwidth"),
23194
+ gradientangle: clusterAttr(sg, "gradientangle")
23195
+ };
23341
23196
  }
23342
- function labelVnode(g, orig) {
23343
- const dimen = labelVnodeDimen(orig);
23344
- const v = virtualNode(g);
23345
- v.info.label = orig.info.label;
23346
- v.info.lw = dotRoot(g).info.nodesep ?? 0;
23347
- if (!orig.info.label_ontop && dimen) {
23348
- const flip = dotRoot(g).info.flip === true;
23349
- v.info.ht = flip ? dimen.x : dimen.y;
23350
- v.info.rw = flip ? dimen.y : dimen.x;
23351
- }
23352
- return v;
23197
+ function applyClusterObjState(sg, job) {
23198
+ const fillRes = resolveClusterFillEx(clusterAttrsOf(sg));
23199
+ if (job.obj === null) return false;
23200
+ const obj = job.obj;
23201
+ return withColorScheme(clusterAttr(sg, "colorscheme"), () => {
23202
+ applyClusterPenState(obj, sg);
23203
+ if (fillRes.kind === "none") {
23204
+ obj.fill = 0 /* None */;
23205
+ return false;
23206
+ }
23207
+ if (fillRes.kind === "solid") {
23208
+ obj.fill = 1 /* Solid */;
23209
+ obj.fillColor = resolveRenderColor(fillRes.color);
23210
+ return true;
23211
+ }
23212
+ applyClusterGradient(obj, fillRes);
23213
+ return true;
23214
+ });
23353
23215
  }
23354
- function incrWidth(g, v) {
23355
- const width = Math.floor((g.info.nodesep ?? 0) / 2);
23356
- v.info.lw = (v.info.lw ?? 0) + width;
23357
- v.info.rw = (v.info.rw ?? 0) + width;
23216
+
23217
+ // src/render/svg-id.ts
23218
+ function svgClass(kind, classAttr) {
23219
+ return classAttr !== void 0 && classAttr.length > 0 ? 'class="' + kind + " " + escapeXmlTitle(classAttr) + '"' : 'class="' + kind + '"';
23358
23220
  }
23359
- function plainVnode(g) {
23360
- const v = virtualNode(g);
23361
- incrWidth(g, v);
23362
- return v;
23221
+ function svgNodeId(n, job) {
23222
+ return job.objId(n.attrs.get("id"), "node" + (n.id + 1));
23363
23223
  }
23364
- function leaderOf(v) {
23365
- if (v.info.ranktype !== CLUSTER) return ufFind(v);
23366
- return v.info.clust.info.rankleader[v.info.rank ?? 0];
23224
+ function svgEdgeId(e, job) {
23225
+ return job.objId(e.attrs.get("id"), "edge" + e.graphSeq);
23367
23226
  }
23368
- function chainVnode(g, orig, r, labelRank) {
23369
- if (r === labelRank) return labelVnode(g, orig);
23370
- return plainVnode(g);
23227
+ function svgClusterId(sg, job) {
23228
+ return job.objId(sg.attrs.get("id"), "clust" + sg.seq);
23371
23229
  }
23372
- function makeChain(g, from, to, orig) {
23373
- const labelRank = orig.info.label !== void 0 ? Math.floor(((from.info.rank ?? 0) + (to.info.rank ?? 0)) / 2) : -1;
23374
- let u = from;
23375
- const toRank = to.info.rank ?? 0;
23376
- for (let r = (from.info.rank ?? 0) + 1; r <= toRank; r++) {
23377
- const v = r < toRank ? (() => {
23378
- const n = chainVnode(g, orig, r, labelRank);
23379
- n.info.rank = r;
23380
- return n;
23381
- })() : to;
23382
- const e = virtualEdge(u, v, orig);
23383
- applyVirtualWeight(e);
23384
- u = v;
23385
- }
23230
+ function svgGraphId(g, job) {
23231
+ return job.objId(g.attrs.get("id"), "graph0", true);
23386
23232
  }
23387
- function nodeRank3(n) {
23388
- return n.info.rank ?? 0;
23233
+ function svgNodeClass(n) {
23234
+ return svgClass("node", nodeAttr(n, n.root, "class"));
23389
23235
  }
23390
- function edgeCount(e) {
23391
- return e.info.count ?? 1;
23236
+ function svgEdgeClass(e) {
23237
+ return svgClass("edge", e.attrs.get("class"));
23392
23238
  }
23393
- function edgeXpenalty(e) {
23394
- return e.info.xpenalty ?? 0;
23239
+ function svgClusterClass(sg) {
23240
+ return svgClass("cluster", clusterAttr(sg, "class"));
23395
23241
  }
23396
- function edgeWeight3(e) {
23397
- return e.info.weight ?? 1;
23242
+ function svgGraphClass(g) {
23243
+ return svgClass("graph", g.attrs.get("class"));
23398
23244
  }
23399
- function nextVirtEdge(e) {
23400
- return e.head.info.out?.list[0];
23245
+
23246
+ // src/common/poly-gencode.ts
23247
+ function isMulticolor(fillcolor) {
23248
+ return fillcolor.includes(":");
23401
23249
  }
23402
- function mergeChainStep(rep, e, updateCount) {
23403
- if (updateCount) rep.info.count = edgeCount(rep) + edgeCount(e);
23404
- rep.info.xpenalty = edgeXpenalty(rep) + edgeXpenalty(e);
23405
- rep.info.weight = edgeWeight3(rep) + edgeWeight3(e);
23406
- return nextVirtEdge(rep);
23250
+ function renderEllipse(ring, coord, renderer, job, filled) {
23251
+ const rx = Math.abs((ring[1].x - ring[0].x) / 2);
23252
+ const ry = Math.abs((ring[1].y - ring[0].y) / 2);
23253
+ const center = transformPoint(coord, job);
23254
+ renderer.ellipse(center, rx, ry, filled, job);
23407
23255
  }
23408
- function mergeChain(g, e, f, updateCount) {
23409
- const lastrank = Math.max(e.tail.info.rank ?? 0, e.head.info.rank ?? 0);
23410
- e.info.to_virt = f;
23411
- let rep = f;
23412
- while (rep !== void 0) {
23413
- if ((rep.head.info.rank ?? 0) === lastrank) {
23414
- mergeChainStep(rep, e, updateCount);
23415
- break;
23416
- }
23417
- incrWidth(g, rep.head);
23418
- rep = mergeChainStep(rep, e, updateCount);
23256
+ function renderPolygon(ring, coord, renderer, job, filled) {
23257
+ const pts = ring.map((v) => transformPoint({ x: v.x + coord.x, y: v.y + coord.y }, job));
23258
+ renderer.polygon(pts, filled, job);
23259
+ }
23260
+ function renderEllipseRing(ring, coord, filled, j, ctx) {
23261
+ if (ctx.style.wedged && j === 0 && isMulticolor(ctx.fillcolor)) {
23262
+ const pf = ring.map(
23263
+ (v) => transformPoint({ x: v.x + coord.x, y: v.y + coord.y }, ctx.job)
23264
+ );
23265
+ wedgedEllipse(ctx.job, pf, ctx.fillcolor, ctx.renderer);
23266
+ renderEllipse(ring, coord, ctx.renderer, ctx.job, false);
23267
+ } else {
23268
+ renderEllipse(ring, coord, ctx.renderer, ctx.job, filled);
23419
23269
  }
23270
+ if (ctx.diagonals) mcircleHack(ring, coord, ctx);
23420
23271
  }
23421
- function mergeable(e, f) {
23422
- if (!e || !f) return false;
23423
- return e.tail === f.tail && e.head === f.head && e.info.label === f.info.label && portsEq(e, f);
23272
+ function renderStripedRing(ring, coord, ctx) {
23273
+ const af = ring.map((v) => transformPoint({ x: v.x + coord.x, y: v.y + coord.y }, ctx.job));
23274
+ stripedBox(ctx.job, af, ctx.fillcolor, true, ctx.renderer);
23275
+ renderPolygon(ring, coord, ctx.renderer, ctx.job, false);
23424
23276
  }
23425
- function interclrepChain(g, e, t, h) {
23426
- makeChain(g, t, h, e);
23427
- let cur = e.info.to_virt;
23428
- while (cur !== void 0 && nodeRank3(cur.head) <= nodeRank3(h)) {
23429
- cur.info.edge_type = CLUSTER_EDGE;
23430
- cur = cur.head.info.out?.list[0];
23431
- }
23277
+ function renderPolyRing(ring, coord, filled, j, ctx) {
23278
+ if (ctx.style.striped && j === 0) renderStripedRing(ring, coord, ctx);
23279
+ else if (ctx.underline) underlineDraw(ring, coord, filled, ctx);
23280
+ else if (ctx.shape !== 0 && ctx.shape !== STAR || ctx.diagonals || ctx.rounded) {
23281
+ drawRoundCorners(ring, coord, filled, ctx);
23282
+ } else renderPolygon(ring, coord, ctx.renderer, ctx.job, filled);
23432
23283
  }
23433
- function interclrep(g, e) {
23434
- let t = leaderOf(e.tail);
23435
- let h = leaderOf(e.head);
23436
- if (nodeRank3(t) > nodeRank3(h)) {
23437
- const tmp = t;
23438
- t = h;
23439
- h = tmp;
23440
- }
23441
- if (t.info.clust === h.info.clust) return;
23442
- const ve = findFastEdge(t, h);
23443
- if (ve !== void 0) {
23444
- mergeChain(g, e, ve, true);
23445
- return;
23284
+ function renderPeripheries(poly, coord, filled, ctx) {
23285
+ const sides = poly.sides <= 2 ? 2 : poly.sides;
23286
+ const verts = poly.vertices;
23287
+ for (let j = 0; j < poly.peripheries; j++) {
23288
+ const ring = verts.slice(j * sides, (j + 1) * sides);
23289
+ if (ring.length < sides) break;
23290
+ const ringFilled = j === 0 ? filled : false;
23291
+ if (poly.sides <= 2) {
23292
+ renderEllipseRing(ring, coord, ringFilled, j, ctx);
23293
+ } else {
23294
+ renderPolyRing(ring, coord, ringFilled, j, ctx);
23295
+ }
23446
23296
  }
23447
- if (nodeRank3(t) === nodeRank3(h)) return;
23448
- interclrepChain(g, e, t, h);
23449
23297
  }
23450
- function isClusterEdge(e) {
23451
- return e.tail.info.ranktype === CLUSTER || e.head.info.ranktype === CLUSTER;
23298
+ function renderLabel(label, coord, renderer, job) {
23299
+ if (label.u.kind !== "txt" || label.u.nspans < 1) return;
23300
+ label.pos = coord;
23301
+ label.set = true;
23302
+ const VALIGN_TOP2 = "t".charCodeAt(0);
23303
+ const VALIGN_BOTTOM2 = "b".charCodeAt(0);
23304
+ let py = label.valign === VALIGN_TOP2 ? coord.y + label.space.y / 2 - label.fontsize : label.valign === VALIGN_BOTTOM2 ? coord.y - label.space.y / 2 + label.dimen.y - label.fontsize : coord.y + label.dimen.y / 2 - label.fontsize;
23305
+ for (let i = 0; i < label.u.nspans; i++) {
23306
+ const span = label.u.span[i];
23307
+ const px = span.just === "l" ? coord.x - label.space.x / 2 : span.just === "r" ? coord.x + label.space.x / 2 : coord.x;
23308
+ gvrenderTextspan(renderer, { x: px, y: py }, span, job);
23309
+ py -= span.size.y;
23310
+ }
23452
23311
  }
23453
- function handleClusterMergeable(g, e, prev) {
23454
- if (prev.info.to_virt !== void 0) {
23455
- mergeChain(g, e, prev.info.to_virt, false);
23456
- otherEdge(e);
23457
- } else if ((e.tail.info.rank ?? 0) === (e.head.info.rank ?? 0)) {
23458
- mergeOneway(e, prev);
23459
- otherEdge(e);
23312
+ function renderNodeLabel(n, coord, renderer, job) {
23313
+ const label = n.info.label;
23314
+ if (label === void 0) return;
23315
+ if (label.html && label.u.kind === "html") {
23316
+ label.pos = coord;
23317
+ label.set = true;
23318
+ const html = label.u.html;
23319
+ withLabelEmitState(job, () => emitHtmlLabel(html, coord, renderer, job));
23320
+ } else {
23321
+ renderLabel(label, coord, renderer, job);
23460
23322
  }
23461
- return prev;
23462
23323
  }
23463
- function handleClusterEdge(g, e, prev) {
23464
- if (mergeable(prev, e)) return handleClusterMergeable(g, e, prev);
23465
- interclrep(g, e);
23466
- return e;
23324
+ function anchorAttr2(n, key) {
23325
+ const v = nodeAttr(n, n.root, key);
23326
+ return v !== void 0 && v !== "" ? v : void 0;
23467
23327
  }
23468
- function concentrateOrMerge(g, e, prev) {
23469
- if (dotRoot(g).info.concentrate ?? false) {
23470
- e.info.edge_type = IGNORED;
23471
- } else if (prev.info.to_virt !== void 0) {
23472
- mergeChain(g, e, prev.info.to_virt, true);
23473
- otherEdge(e);
23474
- }
23328
+ function resolveTooltip(n, tooltip) {
23329
+ if (tooltip !== void 0) return substObjAnchor(interpretCRNL(tooltip), n);
23330
+ const label = n.info.label;
23331
+ return label?.text ?? "";
23475
23332
  }
23476
- function handleMultiSameRank(e, prev) {
23477
- if ((e.tail.info.rank ?? 0) !== (e.head.info.rank ?? 0)) return false;
23478
- mergeOneway(e, prev);
23479
- otherEdge(e);
23333
+ function beginNodeAnchor(n, renderer, job) {
23334
+ const url = anchorAttr2(n, "href") ?? anchorAttr2(n, "URL");
23335
+ const tooltip = anchorAttr2(n, "tooltip");
23336
+ if (url === void 0 && tooltip === void 0) return false;
23337
+ renderer.beginAnchor?.(
23338
+ url !== void 0 ? substObjAnchor(url, n) : "",
23339
+ resolveTooltip(n, tooltip),
23340
+ anchorAttr2(n, "target") ?? "",
23341
+ svgNodeId(n, job),
23342
+ job
23343
+ );
23480
23344
  return true;
23481
23345
  }
23482
- function handleMultiParallel(g, e, prev) {
23483
- if (e.info.label !== void 0 || prev.info.label !== void 0) return false;
23484
- if (!portsEq(e, prev)) return false;
23485
- concentrateOrMerge(g, e, prev);
23486
- return true;
23346
+ function applyGradientFields(obj, fill) {
23347
+ obj.fill = fill.kind === "radial" ? 3 /* Radial */ : 2 /* Linear */;
23348
+ obj.fillColor = resolveRenderColor(fill.fillColor);
23349
+ obj.stopColor = resolveRenderColor(fill.stopColor);
23350
+ obj.gradientFrac = fill.frac;
23351
+ obj.gradientAngle = fill.angle;
23487
23352
  }
23488
- function handleMultiEdge(g, e, prev) {
23489
- if (!prev || e.tail !== prev.tail || e.head !== prev.head) return false;
23490
- if (handleMultiSameRank(e, prev)) return true;
23491
- return handleMultiParallel(g, e, prev);
23353
+ function isPointNode(n) {
23354
+ return n.info.shape?.kind === 3 /* SH_POINT */;
23492
23355
  }
23493
- function oppEdgeConcOrMerge(g, e, opp) {
23494
- if (e.info.label !== void 0 || opp.info.label !== void 0) return false;
23495
- if (!portsEq(e, opp)) return false;
23496
- if (dotRoot(g).info.concentrate ?? false) {
23497
- e.info.edge_type = IGNORED;
23498
- opp.info.conc_opp_flag = true;
23499
- } else {
23500
- otherEdge(e);
23501
- mergeChain(g, e, opp.info.to_virt, true);
23356
+ function findFillDflt(n) {
23357
+ const fillcolor = nodeAttr(n, n.root, "fillcolor");
23358
+ if (fillcolor !== void 0 && fillcolor !== "") return fillcolor;
23359
+ const color = nodeAttr(n, n.root, "color");
23360
+ if (color !== void 0 && color !== "") return color;
23361
+ return "black";
23362
+ }
23363
+ function applyFillState(obj, n, job) {
23364
+ obj.id = svgNodeId(n, job);
23365
+ if (isPointNode(n)) {
23366
+ obj.fill = 1 /* Solid */;
23367
+ obj.fillColor = resolveRenderColor(findFillDflt(n));
23368
+ return true;
23369
+ }
23370
+ const fillRes = resolveNodeFillEx({
23371
+ style: nodeAttr(n, n.root, "style"),
23372
+ fillcolor: nodeAttr(n, n.root, "fillcolor"),
23373
+ color: nodeAttr(n, n.root, "color"),
23374
+ gradientangle: nodeAttr(n, n.root, "gradientangle")
23375
+ });
23376
+ if (fillRes.kind === "none") {
23377
+ obj.fill = 0 /* None */;
23378
+ return false;
23502
23379
  }
23380
+ if (fillRes.kind === "solid") {
23381
+ obj.fill = 1 /* Solid */;
23382
+ obj.fillColor = resolveRenderColor(fillRes.color);
23383
+ return true;
23384
+ }
23385
+ applyGradientFields(obj, fillRes);
23503
23386
  return true;
23504
23387
  }
23505
- function tryOppEdge(g, e, opp) {
23506
- if (opp.head !== e.tail) return false;
23507
- if (opp.info.edge_type === IGNORED) return false;
23508
- if (opp.info.to_virt === void 0) makeChain(g, opp.tail, opp.head, opp);
23509
- return oppEdgeConcOrMerge(g, e, opp);
23388
+ function applyPenState(obj, styleAttr, colorAttr, penwidthAttr) {
23389
+ const flags = parseStyleFlags(styleAttr);
23390
+ obj.penColor = resolveRenderColor(resolvePenColor(colorAttr));
23391
+ obj.pen = resolvePenType(flags);
23392
+ obj.penWidth = resolvePenWidth(flags, penwidthAttr);
23393
+ obj.rawStyle = styleTokens(styleAttr);
23510
23394
  }
23511
- function handleBackEdge(g, e) {
23512
- for (const opp of e.head.outEdges(g)) {
23513
- if (tryOppEdge(g, e, opp)) return void 0;
23514
- }
23515
- makeChain(g, e.head, e.tail, e);
23516
- return e;
23395
+ function applyNodeStyle(obj, n, job) {
23396
+ const styleAttr = nodeAttr(n, n.root, "style");
23397
+ const colorAttr = nodeAttr(n, n.root, "color");
23398
+ const filled = applyFillState(obj, n, job);
23399
+ applyPenState(obj, styleAttr, colorAttr, nodeAttr(n, n.root, "penwidth"));
23400
+ return filled;
23517
23401
  }
23518
- function class2EdgeSameRep(g, e) {
23519
- if (nodeRank3(e.tail) === nodeRank3(e.head)) {
23520
- flatEdge(g, e);
23521
- return e;
23402
+ function prepareDrawPoly(poly, filled, obj) {
23403
+ if (poly.peripheries !== 0 || !filled) return poly;
23404
+ obj.penColor = { type: "string", s: "transparent" };
23405
+ return { ...poly, peripheries: 1 };
23406
+ }
23407
+ function vertexScale(n, poly) {
23408
+ const info = n.info;
23409
+ if (poly.vertices == null || info.width === void 0 || info.height === void 0) {
23410
+ return poly;
23522
23411
  }
23523
- if (nodeRank3(e.head) > nodeRank3(e.tail)) {
23524
- makeChain(g, e.tail, e.head, e);
23525
- return e;
23412
+ const xsize = (info.lw + info.rw) / (info.width * 72);
23413
+ const ysize = info.ht / (info.height * 72);
23414
+ if (Math.abs(xsize - 1) < 1e-9 && Math.abs(ysize - 1) < 1e-9) return poly;
23415
+ return {
23416
+ ...poly,
23417
+ vertices: poly.vertices.map((v) => ({ x: v.x * xsize, y: v.y * ysize }))
23418
+ };
23419
+ }
23420
+ function resolveNodeDrawCtx(job, n) {
23421
+ const rawPoly = n.info.shape_info;
23422
+ if (rawPoly === void 0 || rawPoly.vertices === void 0) return null;
23423
+ const poly = vertexScale(n, rawPoly);
23424
+ const coord = n.info.coord ?? { x: 0, y: 0 };
23425
+ const obj = job.obj;
23426
+ const filled = obj !== null && applyNodeStyle(obj, n, job);
23427
+ const drawPoly = obj !== null ? prepareDrawPoly(poly, filled, obj) : poly;
23428
+ const styleFlags = parseStyleFlags(nodeAttr(n, n.root, "style"));
23429
+ const ringCtx = {
23430
+ renderer: job.renderer,
23431
+ job,
23432
+ style: styleFlags,
23433
+ fillcolor: nodeAttr(n, n.root, "fillcolor") ?? "",
23434
+ ...specialCornerFlags(drawPoly.option, styleFlags)
23435
+ };
23436
+ return { poly: drawPoly, coord, filled, ringCtx };
23437
+ }
23438
+ function specialCornerFlags(opt, style) {
23439
+ return {
23440
+ shape: opt.shape,
23441
+ diagonals: opt.diagonals || style.diagonals,
23442
+ rounded: opt.rounded || style.rounded,
23443
+ underline: opt.underline || style.underline
23444
+ };
23445
+ }
23446
+ function polyGencode(rawJob, rawNode) {
23447
+ const job = rawJob;
23448
+ const n = rawNode;
23449
+ const renderer = job.renderer;
23450
+ if (!renderer) return;
23451
+ const ctx = resolveNodeDrawCtx(job, n);
23452
+ if (ctx === null) return;
23453
+ const clustersLast = (job.flags & EMIT_CLUSTERS_LAST) !== 0;
23454
+ const savedShape = job.obj?.urlMapShape;
23455
+ const savedPts = job.obj?.urlMapPts;
23456
+ let inAnchor = clustersLast ? false : beginNodeAnchor(n, renderer, job);
23457
+ renderPeripheries(ctx.poly, ctx.coord, ctx.filled, ctx.ringCtx);
23458
+ if (!isPointNode(n)) renderNodeLabel(n, ctx.coord, renderer, job);
23459
+ if (clustersLast) {
23460
+ if (job.obj && savedPts !== void 0 && savedShape !== void 0) {
23461
+ job.obj.urlMapShape = savedShape;
23462
+ job.obj.urlMapPts = savedPts;
23463
+ }
23464
+ inAnchor = beginNodeAnchor(n, renderer, job);
23526
23465
  }
23527
- return handleBackEdge(g, e);
23466
+ if (inAnchor) renderer.endAnchor?.(job);
23528
23467
  }
23529
- function class2OneEdge(g, e, prev) {
23530
- if (e.info.to_virt !== void 0) return e;
23531
- if (isClusterEdge(e)) return handleClusterEdge(g, e, prev);
23532
- if (handleMultiEdge(g, e, prev)) return prev;
23533
- if (e.tail === e.head) {
23534
- otherEdge(e);
23535
- return e;
23468
+
23469
+ // src/common/poly-inside.ts
23470
+ function sameSide(p0, p1, L0, L1) {
23471
+ const a = -(L1.y - L0.y);
23472
+ const b = L1.x - L0.x;
23473
+ const c = a * L0.x + b * L0.y;
23474
+ const s0 = a * p0.x + b * p0.y - c >= 0;
23475
+ const s1 = a * p1.x + b * p1.y - c >= 0;
23476
+ return s0 === s1;
23477
+ }
23478
+ function fixedShapeSize(poly) {
23479
+ let xmax = 0;
23480
+ let ymax = 0;
23481
+ for (const v of poly.vertices ?? []) {
23482
+ xmax = Math.max(xmax, Math.abs(v.x));
23483
+ ymax = Math.max(ymax, Math.abs(v.y));
23536
23484
  }
23537
- const t = ufFind(e.tail);
23538
- const h = ufFind(e.head);
23539
- if (e.tail !== t || e.head !== h) return prev;
23540
- return class2EdgeSameRep(g, e);
23485
+ return { w: 2 * xmax, h: 2 * ymax };
23541
23486
  }
23542
- function class2ProcessNodeEdges(g, oes) {
23543
- let prev;
23544
- for (const e of oes) {
23545
- const next = class2OneEdge(g, e, prev);
23546
- prev = next !== void 0 ? next : prev;
23487
+ function insideDims(n, xsize, ysize) {
23488
+ const w = 72 * (n.info.width || xsize / 72);
23489
+ const h = 72 * (n.info.height || ysize / 72);
23490
+ return { w, h, ow: 72 * n.info.outline_width || w, oh: 72 * n.info.outline_height || h };
23491
+ }
23492
+ function insideScale(n, poly) {
23493
+ const flip = n.root.info.flip === true;
23494
+ if (poly.option.fixedshape) {
23495
+ const { w: w2, h: h2 } = fixedShapeSize(poly);
23496
+ const xsize2 = flip ? h2 : w2;
23497
+ const ysize2 = flip ? w2 : h2;
23498
+ return {
23499
+ scalex: xsize2 !== 0 ? w2 / xsize2 : w2,
23500
+ scaley: ysize2 !== 0 ? h2 / ysize2 : h2,
23501
+ boxURx: w2 / 2,
23502
+ boxURy: h2 / 2
23503
+ };
23547
23504
  }
23505
+ const lwrw = n.info.lw + n.info.rw;
23506
+ const xsize = flip ? n.info.ht : lwrw;
23507
+ const ysize = flip ? lwrw : n.info.ht;
23508
+ const { w, h, ow, oh } = insideDims(n, xsize, ysize);
23509
+ return {
23510
+ scalex: xsize !== 0 ? w / xsize : w,
23511
+ scaley: ysize !== 0 ? h / ysize : h,
23512
+ boxURx: ow / 2,
23513
+ boxURy: oh / 2
23514
+ };
23548
23515
  }
23549
- function weightClass(n) {
23550
- return n.info.weight_class ?? 0;
23516
+ function polygonWalk(P, vertex, sides) {
23517
+ const O = { x: 0, y: 0 };
23518
+ let i = 0;
23519
+ let i1 = 1 % sides;
23520
+ const Q = vertex[i];
23521
+ const R2 = vertex[i1];
23522
+ if (!sameSide(P, O, Q, R2)) return false;
23523
+ const s = sameSide(P, Q, R2, O);
23524
+ if (s && sameSide(P, R2, O, Q)) return true;
23525
+ for (let j = 1; j < sides; j++) {
23526
+ if (s) {
23527
+ i = i1;
23528
+ i1 = (i + 1) % sides;
23529
+ } else {
23530
+ i1 = i;
23531
+ i = (i + sides - 1) % sides;
23532
+ }
23533
+ if (!sameSide(P, O, vertex[i], vertex[i1])) return false;
23534
+ }
23535
+ return true;
23551
23536
  }
23552
- function incrWeightClass(n) {
23553
- if (weightClass(n) <= 2) n.info.weight_class = weightClass(n) + 1;
23537
+ function insideShape(n, poly, p) {
23538
+ const sc = insideScale(n, poly);
23539
+ const P = { x: p.x * sc.scalex, y: p.y * sc.scaley };
23540
+ if (Math.abs(P.x) > sc.boxURx || Math.abs(P.y) > sc.boxURy) return false;
23541
+ if (poly.sides <= 2) {
23542
+ return Math.hypot(P.x / sc.boxURx, P.y / sc.boxURy) < 1;
23543
+ }
23544
+ const outerStart = (Math.max(poly.peripheries, 1) - 1) * poly.sides;
23545
+ const outer = poly.vertices.slice(outerStart, outerStart + poly.sides);
23546
+ const ring = polygonOutlineRing(outer, poly.sides, poly.penwidth ?? 1);
23547
+ return polygonWalk(P, ring, poly.sides);
23554
23548
  }
23555
- function class2WeightClasses(g) {
23556
- for (const e of g.edges) {
23557
- incrWeightClass(e.head);
23558
- incrWeightClass(e.tail);
23549
+ function polyInside(ctx, p) {
23550
+ const n = ctx.node;
23551
+ if (n === void 0) return false;
23552
+ const rankdir = (n.root.info.rankdir ?? 0) & 3;
23553
+ const P = rankdir === 0 ? p : ccwrotatepf(p, rankdir * 90);
23554
+ if (ctx.bp) {
23555
+ const b = ctx.bp;
23556
+ return P.x >= b.ll.x && P.x <= b.ur.x && P.y >= b.ll.y && P.y <= b.ur.y;
23559
23557
  }
23558
+ const poly = n.info.shape_info;
23559
+ if (poly === void 0 || poly.vertices === null) return false;
23560
+ return insideShape(n, poly, P);
23560
23561
  }
23561
- function class2ProcessNodes(g) {
23562
- const outIdx = buildOutEdgeIndex(g);
23563
- for (const n of nodesInSeq(g)) {
23564
- if (n.info.clust === void 0 && n === ufFind(n)) fastNode(g, n);
23565
- class2ProcessNodeEdges(g, outIdx.get(n) ?? []);
23562
+ function starInside(ctx, p) {
23563
+ const n = ctx.node;
23564
+ if (n === void 0) return false;
23565
+ const rankdir = (n.root.info.rankdir ?? 0) & 3;
23566
+ const P = rankdir === 0 ? p : ccwrotatepf(p, rankdir * 90);
23567
+ if (ctx.bp) {
23568
+ const b = ctx.bp;
23569
+ return P.x >= b.ll.x && P.x <= b.ur.x && P.y >= b.ll.y && P.y <= b.ur.y;
23570
+ }
23571
+ const poly = n.info.shape_info;
23572
+ if (poly === void 0 || poly.vertices === null) return false;
23573
+ const sides = poly.sides;
23574
+ const outerStart = (Math.max(poly.peripheries, 1) - 1) * sides;
23575
+ const outer = poly.vertices.slice(outerStart, outerStart + sides);
23576
+ const ring = polygonOutlineRing(outer, sides, poly.penwidth ?? 1);
23577
+ const O = { x: 0, y: 0 };
23578
+ let outcnt = 0;
23579
+ for (let i = 0; i < sides; i += 2) {
23580
+ const Q = ring[i];
23581
+ const R2 = ring[(i + 4) % sides];
23582
+ if (!sameSide(P, O, Q, R2)) outcnt++;
23583
+ if (outcnt === 2) return false;
23566
23584
  }
23585
+ return true;
23567
23586
  }
23568
- function class2(g) {
23569
- g.info.nlist = void 0;
23570
- markClusters(g);
23571
- const nClust = g.info.n_cluster ?? 0;
23572
- for (let c = 1; c <= nClust; c++) buildSkeleton(g, g.info.clust[c - 1]);
23573
- class2WeightClasses(g);
23574
- class2ProcessNodes(g);
23575
- if (g !== dotRoot(g)) g.info.comp = [g.info.nlist ?? null];
23587
+ function recordInside(ctx, p) {
23588
+ const n = ctx.node;
23589
+ if (n === void 0) return false;
23590
+ const rankdir = (n.root.info.rankdir ?? 0) & 3;
23591
+ const P = rankdir === 0 ? p : ccwrotatepf(p, rankdir * 90);
23592
+ let bb;
23593
+ if (ctx.bp) {
23594
+ bb = ctx.bp;
23595
+ } else {
23596
+ const fld = n.info.shape_info;
23597
+ if (!fld?.b) return false;
23598
+ bb = fld.b;
23599
+ }
23600
+ const pw = 0.5;
23601
+ return P.x >= bb.ll.x - pw && P.x <= bb.ur.x + pw && P.y >= bb.ll.y - pw && P.y <= bb.ur.y + pw;
23576
23602
  }
23577
23603
 
23578
23604
  // src/common/edge-label-init.ts
@@ -23939,7 +23965,7 @@ function gdRankdir(n) {
23939
23965
  function gdFlip(n) {
23940
23966
  return (gdRankdir(n) & 1) !== 0;
23941
23967
  }
23942
- function cwrotatepf(p, cwrot) {
23968
+ function cwrotatepf2(p, cwrot) {
23943
23969
  switch (cwrot) {
23944
23970
  case 90:
23945
23971
  return { x: p.y, y: -p.x };
@@ -24086,7 +24112,7 @@ function setOrder(pp, q) {
24086
24112
  pp.order = MC_SCALE * a / (2 * Math.PI) | 0;
24087
24113
  }
24088
24114
  function applyDir(pp, bp, dir, rd, definedFinal) {
24089
- const q = cwrotatepf(dir.p, 90 * rd);
24115
+ const q = cwrotatepf2(dir.p, 90 * rd);
24090
24116
  pp.p = q;
24091
24117
  pp.bp = bp;
24092
24118
  pp.side = dir.dyna ? dir.side : invflipSide(dir.side, rd);
@@ -24102,7 +24128,7 @@ function nodeInsideFn(n) {
24102
24128
  }
24103
24129
  function compassPoint(n, insideFn, yArg, xArg, rd) {
24104
24130
  let p = { x: xArg, y: yArg };
24105
- if (rd) p = cwrotatepf(p, 90 * rd);
24131
+ if (rd) p = cwrotatepf2(p, 90 * rd);
24106
24132
  const curve = [{ x: 0, y: 0 }, { x: 0, y: 0 }, { x: p.x, y: p.y }, { x: p.x, y: p.y }];
24107
24133
  const ctx = { nodeCoord: n.info.coord, rw: n.info.rw, bp: null, node: n };
24108
24134
  bezierClip(ctx, insideFn, curve, true);
@@ -32109,31 +32135,13 @@ function splay(root, key, keyOf, compare) {
32109
32135
  }
32110
32136
 
32111
32137
  // src/cdt/bag.ts
32112
- function findByIdentity(start, target, key, keyOf, compare) {
32113
- let cur = start;
32114
- let parent = null;
32115
- while (cur !== null) {
32116
- if (cur.obj === target) return [cur, parent];
32117
- if (compare(key, keyOf(cur.obj)) !== 0) return [null, null];
32118
- parent = cur;
32119
- cur = cur.left;
32120
- }
32121
- return [null, null];
32122
- }
32123
- function unlinkNode(root, cur, parent) {
32124
- const left = cur.left;
32125
- const right = cur.right;
32126
- let replacement;
32127
- if (left === null) {
32128
- replacement = right;
32129
- } else {
32130
- const maxLeft = splayMax(left);
32131
- maxLeft.right = right;
32132
- replacement = maxLeft;
32133
- }
32134
- if (parent === null) return replacement;
32135
- parent.left = replacement;
32136
- return root;
32138
+ function removeRoot(root) {
32139
+ const left = root.left;
32140
+ const right = root.right;
32141
+ if (left === null) return right;
32142
+ const maxLeft = splayMax(left);
32143
+ maxLeft.right = right;
32144
+ return maxLeft;
32137
32145
  }
32138
32146
  var DtBag = class {
32139
32147
  _root = null;
@@ -32172,16 +32180,13 @@ var DtBag = class {
32172
32180
  const key = this._keyOf(obj);
32173
32181
  this._root = splay(this._root, key, this._keyOf, this._compare);
32174
32182
  if (this._compare(key, this._keyOf(this._root.obj)) !== 0) return false;
32175
- const [cur, parent] = findByIdentity(
32176
- this._root,
32177
- obj,
32178
- key,
32179
- this._keyOf,
32180
- this._compare
32181
- );
32182
- if (cur === null) return false;
32183
- const newRoot = unlinkNode(this._root, cur, parent);
32184
- this._root = newRoot;
32183
+ while (this._root.obj !== obj) {
32184
+ const nxt = this.next(this._root.obj);
32185
+ if (nxt === void 0 || this._compare(key, this._keyOf(nxt)) !== 0) {
32186
+ return false;
32187
+ }
32188
+ }
32189
+ this._root = removeRoot(this._root);
32185
32190
  this._size--;
32186
32191
  return true;
32187
32192
  }
@@ -52464,7 +52469,7 @@ var XdotParser = class _XdotParser {
52464
52469
  let accounted = 0;
52465
52470
  let j = 0;
52466
52471
  while (accounted < len) {
52467
- if (cur + j >= s.length) break;
52472
+ if (cur + j >= s.length) return null;
52468
52473
  const ch = s[cur + j];
52469
52474
  const prev = j > 0 ? s[cur + j - 1] : "";
52470
52475
  out += ch;