@knowvah/dot-engine 1.2.3 → 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.
package/dist/index.js CHANGED
@@ -10105,12 +10105,15 @@ function parseAttrs(raw) {
10105
10105
  }
10106
10106
  return out;
10107
10107
  }
10108
+ function normalizeTag(tag) {
10109
+ return tag === "TH" ? "TR" : tag;
10110
+ }
10108
10111
  function parseCloseToken(inner) {
10109
10112
  const body = inner.slice(1).trim();
10110
10113
  const sp = body.search(/\s/);
10111
10114
  const tag = (sp === -1 ? body : body.slice(0, sp)).toUpperCase();
10112
10115
  checkTag(tag);
10113
- return { type: "close", tag };
10116
+ return { type: "close", tag: normalizeTag(tag) };
10114
10117
  }
10115
10118
  function cleanText(raw) {
10116
10119
  const isKeep = (c) => c === " " || c === " " || c === "\n" || c === "\r";
@@ -10144,12 +10147,13 @@ function scanTag(src, start, tokens) {
10144
10147
  function parseOpenToken(inner) {
10145
10148
  const sp = inner.search(/\s/);
10146
10149
  if (sp === -1) {
10147
- checkTag(inner.toUpperCase());
10148
- 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("") };
10149
10153
  }
10150
10154
  const tag = inner.slice(0, sp).toUpperCase();
10151
10155
  checkTag(tag);
10152
- return { type: "open", tag, attrs: parseAttrs(inner.slice(sp + 1)) };
10156
+ return { type: "open", tag: normalizeTag(tag), attrs: parseAttrs(inner.slice(sp + 1)) };
10153
10157
  }
10154
10158
  function tokenize(src) {
10155
10159
  const tokens = [];
@@ -10374,7 +10378,7 @@ var buildCell = (content, a) => ({
10374
10378
  });
10375
10379
  var parseCell = (s, attrs, fontStack) => buildCell(parseCellContent(s, attrs, fontStack), attrs);
10376
10380
  var processRowToken = (s, t, cells, fontStack) => {
10377
- if (t.type === "open" && (t.tag === "TD" || t.tag === "TH")) {
10381
+ if (t.type === "open" && t.tag === "TD") {
10378
10382
  consume(s);
10379
10383
  cells.push(parseCell(s, t.attrs, fontStack));
10380
10384
  return;
@@ -16880,1504 +16884,241 @@ function assembleResult(p, dimen, grown, fixedshape) {
16880
16884
  };
16881
16885
  }
16882
16886
 
16883
- // src/common/record.ts
16884
- var HASTEXT = 1;
16885
- var HASPORT = 2;
16886
- var HASTABLE = 4;
16887
- var INTEXT = 8;
16888
- var INPORT = 16;
16889
- var BOTTOM2 = 1;
16890
- var RIGHT2 = 2;
16891
- var TOP2 = 4;
16892
- var LEFT2 = 8;
16893
- var PAD_X = 16;
16894
- var PAD_Y = 8;
16895
- function makeField() {
16896
- return {
16897
- size: { x: 0, y: 0 },
16898
- b: { ll: { x: 0, y: 0 }, ur: { x: 0, y: 0 } },
16899
- n_flds: 0,
16900
- lp: null,
16901
- fld: null,
16902
- id: null,
16903
- LR: 0,
16904
- sides: 0
16905
- };
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;
16906
16895
  }
16907
- function recIsEscapedDelim(s, j) {
16908
- if (s[j] !== "\\") return false;
16909
- const nx = s[j + 1];
16910
- 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
+ }
16911
16903
  }
16912
- function recCountFields(p) {
16913
- let maxf = 1;
16914
- let cnt = 0;
16915
- for (let j = p.i; j < p.s.length; j++) {
16916
- if (recIsEscapedDelim(p.s, j)) {
16917
- j++;
16918
- 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];
16919
16925
  }
16920
- const c = p.s[j];
16921
- if (c === "{") cnt++;
16922
- else if (c === "}") cnt--;
16923
- else if (c === "|" && cnt === 0) maxf++;
16924
- if (cnt < 0) break;
16925
16926
  }
16926
- return maxf;
16927
+ return void 0;
16927
16928
  }
16928
- function recOpenPort(p, st) {
16929
- if (st.mode & (HASTABLE | HASPORT)) return -1;
16930
- st.mode |= HASPORT | INPORT;
16931
- p.i++;
16932
- st.pbuf = [];
16933
- st.hspIdx = 0;
16934
- 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 };
16935
16932
  }
16936
- function recClosePort(p, st) {
16937
- if (!(st.mode & INPORT)) return -1;
16938
- const t = st.pbuf;
16939
- if (t.length > 1 && st.hspIdx !== t.length - 1 && t[t.length - 1] === " ") t.pop();
16940
- st.tmpport = t.join("");
16941
- st.mode &= ~INPORT;
16942
- p.i++;
16943
- 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);
16944
16938
  }
16945
- function recOpenTable(p, st, LR) {
16946
- p.i++;
16947
- if (st.mode !== 0 || p.i >= p.s.length) return -1;
16948
- st.mode = HASTABLE;
16949
- const sub = parseReclbl(p, LR ? 0 : 1, false);
16950
- if (sub === null) return -1;
16951
- st.rv.fld[st.fi++] = sub;
16952
- st.fp = sub;
16953
- 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;
16954
16952
  }
16955
- function recFlushText(p, st) {
16956
- if (!(st.mode & (HASTEXT | HASTABLE))) {
16957
- st.mode |= HASTEXT;
16958
- st.tbuf.push(" ");
16959
- }
16960
- if (st.mode & HASTEXT) {
16961
- const t = st.tbuf;
16962
- if (t.length > 1 && st.hstIdx !== t.length - 1 && t[t.length - 1] === " ") t.pop();
16963
- st.fp.lp = makeAnyLabel(
16964
- t.join(""),
16965
- false,
16966
- { fontname: p.lbl.fontname, fontsize: p.lbl.fontsize, fontcolor: p.lbl.fontcolor },
16967
- p.measurer,
16968
- p.obj
16969
- );
16970
- st.fp.LR = 1;
16971
- st.tbuf = [];
16972
- 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;
16973
16963
  }
16964
+ return e;
16974
16965
  }
16975
- function recEndField(p, st, flag) {
16976
- const c = p.i < p.s.length ? p.s[p.i] : "";
16977
- if (c === "" && !flag || st.mode & INPORT) return -1;
16978
- if (!(st.mode & HASTABLE)) {
16979
- st.fp = makeField();
16980
- st.rv.fld[st.fi++] = st.fp;
16981
- }
16982
- if (st.tmpport !== null) {
16983
- st.fp.id = st.tmpport;
16984
- st.tmpport = null;
16985
- }
16986
- recFlushText(p, st);
16987
- if (c !== "") {
16988
- if (c === "}") {
16989
- p.i++;
16990
- st.rv.n_flds = st.fi;
16991
- return 1;
16992
- }
16993
- st.mode = 0;
16994
- p.i++;
16995
- return 0;
16996
- }
16997
- st.rv.n_flds = st.fi;
16998
- return 1;
16966
+ function virtualEdge(u, v, orig) {
16967
+ const e = newVirtualEdge(u, v, orig);
16968
+ fastEdge(e);
16969
+ return e;
16999
16970
  }
17000
- function recBackslash(p, st) {
17001
- const nx = p.s[p.i + 1];
17002
- if (nx !== void 0) {
17003
- if (nx < " ") {
17004
- } else if (nx === " " && !p.lbl.html) {
17005
- st.ishardspace = true;
17006
- } else {
17007
- st.tbuf.push("\\");
17008
- st.mode |= INTEXT | HASTEXT;
17009
- }
17010
- p.i++;
17011
- }
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;
17012
16976
  }
17013
- function recPushText(st, c, html) {
17014
- const afterSpace = st.tbuf[st.tbuf.length - 1] === " ";
17015
- if (!(c === " " && !st.ishardspace && afterSpace && !html)) st.tbuf.push(c);
17016
- 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
+ }
17017
16984
  }
17018
- function recPushPort(st, c) {
17019
- const atStartOrSpace = st.pbuf.length === 0 || st.pbuf[st.pbuf.length - 1] === " ";
17020
- if (!(c === " " && !st.ishardspace && atStartOrSpace)) st.pbuf.push(c);
17021
- 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);
17022
16989
  }
17023
- function recTextChar(p, st, c) {
17024
- if (st.mode & HASTABLE && c !== " ") return -1;
17025
- if (!(st.mode & (INTEXT | INPORT)) && c !== " ") st.mode |= INTEXT | HASTEXT;
17026
- if (st.mode & INTEXT) recPushText(st, c, p.lbl.html);
17027
- else if (st.mode & INPORT) recPushPort(st, c);
17028
- p.i++;
17029
- 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);
17030
16994
  }
17031
- function recDispatch(p, st, LR, flag) {
17032
- const c = p.s[p.i];
17033
- switch (c) {
17034
- case "<":
17035
- if (p.lbl.html) return recTextChar(p, st, c);
17036
- return recOpenPort(p, st);
17037
- case ">":
17038
- if (p.lbl.html) return recTextChar(p, st, c);
17039
- return recClosePort(p, st);
17040
- case "{":
17041
- return recOpenTable(p, st, LR);
17042
- case "}":
17043
- case "|":
17044
- case void 0:
17045
- return recEndField(p, st, flag);
17046
- case "\\":
17047
- recBackslash(p, st);
17048
- return recTextChar(p, st, p.s[p.i]);
17049
- default:
17050
- return recTextChar(p, st, c);
17051
- }
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;
17052
17001
  }
17053
- function parseReclbl(p, LR, flag) {
17054
- const rv = makeField();
17055
- rv.fld = new Array(recCountFields(p));
17056
- rv.LR = LR;
17057
- const st = {
17058
- rv,
17059
- fi: 0,
17060
- mode: 0,
17061
- tbuf: [],
17062
- hstIdx: 0,
17063
- pbuf: [],
17064
- hspIdx: 0,
17065
- tmpport: null,
17066
- ishardspace: false,
17067
- fp: null
17068
- };
17069
- for (; ; ) {
17070
- if (p.i < p.s.length && p.s[p.i] < " " && p.s[p.i] !== "") {
17071
- p.i++;
17072
- 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];
17073
17009
  }
17074
- const r = recDispatch(p, st, LR, flag);
17075
- if (r === -1) return null;
17076
- if (r === 1) break;
17077
- if (p.i > p.s.length) break;
17078
- }
17079
- rv.n_flds = st.fi;
17080
- return rv;
17081
- }
17082
- function recLabelDimen(n, g, f) {
17083
- const dimen = { x: f.lp.dimen.x, y: f.lp.dimen.y };
17084
- if (dimen.x > 0 || dimen.y > 0) {
17085
- const m = nodeAttr(n, g, "margin");
17086
- const parts = m !== void 0 ? m.split(",").map(parseFloat) : [];
17087
- if (parts.length > 0 && !Number.isNaN(parts[0])) {
17088
- dimen.x += 2 * parts[0] * 72;
17089
- dimen.y += 2 * (parts.length > 1 && !Number.isNaN(parts[1]) ? parts[1] : parts[0]) * 72;
17090
- } else {
17091
- dimen.x += PAD_X;
17092
- 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];
17093
17013
  }
17094
17014
  }
17095
- return dimen;
17015
+ return void 0;
17096
17016
  }
17097
- function sizeReclbl(n, g, f) {
17098
- let d;
17099
- if (f.lp) {
17100
- 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);
17101
17023
  } else {
17102
- d = { x: 0, y: 0 };
17103
- for (let i = 0; i < f.n_flds; i++) {
17104
- const d0 = sizeReclbl(n, g, f.fld[i]);
17105
- if (f.LR) {
17106
- d.x += d0.x;
17107
- d.y = Math.max(d.y, d0.y);
17108
- } else {
17109
- d.y += d0.y;
17110
- d.x = Math.max(d.x, d0.x);
17111
- }
17112
- }
17024
+ virtualEdge(e.head, e.tail, e);
17113
17025
  }
17114
- f.size = d;
17115
- return d;
17116
17026
  }
17117
- function resizeReclbl(f, sz, nojustify) {
17118
- const d = { x: sz.x - f.size.x, y: sz.y - f.size.y };
17119
- f.size = sz;
17120
- if (f.lp && !nojustify) {
17121
- f.lp.space.x += d.x;
17122
- f.lp.space.y += d.y;
17123
- }
17124
- if (f.n_flds) {
17125
- const inc2 = f.LR ? d.x / f.n_flds : d.y / f.n_flds;
17126
- for (let i = 0; i < f.n_flds; i++) {
17127
- const sf = f.fld[i];
17128
- const amt = Math.trunc((i + 1) * inc2) - Math.trunc(i * inc2);
17129
- const newsz = f.LR ? { x: sf.size.x + amt, y: sz.y } : { x: sz.x, y: sf.size.y + amt };
17130
- resizeReclbl(sf, newsz, nojustify);
17131
- }
17132
- }
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;
17133
17032
  }
17134
- function recSideMask(f, i, last) {
17135
- if (f.LR) {
17136
- if (i === 0) return i === last ? TOP2 | BOTTOM2 | RIGHT2 | LEFT2 : TOP2 | BOTTOM2 | LEFT2;
17137
- return i === last ? TOP2 | BOTTOM2 | RIGHT2 : TOP2 | BOTTOM2;
17138
- }
17139
- if (i === 0) return i === last ? TOP2 | BOTTOM2 | RIGHT2 | LEFT2 : TOP2 | RIGHT2 | LEFT2;
17140
- 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;
17141
17037
  }
17142
- function posReclbl(f, ul, sides) {
17143
- f.sides = sides;
17144
- f.b = {
17145
- ll: { x: ul.x, y: ul.y - f.size.y },
17146
- ur: { x: ul.x + f.size.x, y: ul.y }
17147
- };
17148
- const last = f.n_flds - 1;
17149
- const pos = { x: ul.x, y: ul.y };
17150
- for (let i = 0; i <= last; i++) {
17151
- const mask = sides ? recSideMask(f, i, last) : 0;
17152
- posReclbl(f.fld[i], { x: pos.x, y: pos.y }, sides & mask);
17153
- if (f.LR) pos.x += f.fld[i].size.x;
17154
- 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
+ }
17155
17052
  }
17156
17053
  }
17157
- function attrBool(n, g, key) {
17158
- const s = nodeAttr(n, g, key);
17159
- if (!s || s.toLowerCase() === "false" || s.toLowerCase() === "no") return false;
17160
- if (s.toLowerCase() === "true" || s.toLowerCase() === "yes") return true;
17161
- 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;
17162
17065
  }
17163
- function recAttrSize(n, g) {
17164
- const w = nodeAttr(n, g, "width");
17165
- const h = nodeAttr(n, g, "height");
17166
- return {
17167
- x: (w !== void 0 ? parseFloat(w) : 0.75) * 72,
17168
- y: (h !== void 0 ? parseFloat(h) : 0.5) * 72
17169
- };
17066
+ function otherEdge(e) {
17067
+ if (!e.tail.info.other) e.tail.info.other = { list: [], size: 0 };
17068
+ elistAppend(e.tail.info.other, e);
17170
17069
  }
17171
- function recParseOrFallback(lbl, measurer, flip, obj) {
17172
- const p = { s: lbl.text, i: 0, lbl, measurer, obj };
17173
- const info = parseReclbl(p, flip, true);
17174
- if (info !== null) return info;
17175
- const fb = { s: "\\N", i: 0, lbl, measurer, obj };
17176
- 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;
17177
17076
  }
17178
- function recordInit(n, g, measurer) {
17179
- const lbl = n.info.label;
17180
- const flip = ((g.root.info.rankdir ?? 0) >> 2 & 1) === 1 ? 0 : 1;
17181
- const info = recParseOrFallback(lbl, measurer, flip, n);
17182
- sizeReclbl(n, g, info);
17183
- const sz = recAttrSize(n, g);
17184
- if (!attrBool(n, g, "fixedsize")) {
17185
- sz.x = Math.max(info.size.x, sz.x);
17186
- 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;
17187
17089
  }
17188
- resizeReclbl(info, sz, attrBool(n, g, "nojustify"));
17189
- posReclbl(info, { x: -sz.x / 2, y: sz.y / 2 }, BOTTOM2 | RIGHT2 | TOP2 | LEFT2);
17190
- n.info.width = info.size.x / 72;
17191
- n.info.height = (info.size.y + 1) / 72;
17192
- const ns = gvNodesize(info.size.x, info.size.y + 1, g.root.info.flip === true);
17193
- n.info.lw = ns.lw;
17194
- n.info.rw = ns.rw;
17195
- n.info.ht = ns.ht;
17196
- 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;
17197
17097
  }
17198
- function recordMakeLabel(n, g, measurer) {
17199
- const labelText = nodeAttr(n, g, "label") ?? n.name;
17200
- const { fontname, fontsize, fontcolor } = readFontAttrs(n, g);
17201
- 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);
17202
17107
  }
17203
- function recordNodeInit(n, g, measurer) {
17204
- recordMakeLabel(n, g, measurer);
17205
- 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;
17206
17112
  }
17207
- function genFields(job, n, f) {
17208
- const renderer = job.renderer;
17209
- const coord = n.info.coord ?? { x: 0, y: 0 };
17210
- if (f.lp) {
17211
- const mid = {
17212
- x: (f.b.ll.x + f.b.ur.x) / 2 + coord.x,
17213
- y: (f.b.ll.y + f.b.ur.y) / 2 + coord.y
17214
- };
17215
- renderLabel(f.lp, mid, renderer, job);
17216
- }
17217
- for (let i = 0; i < f.n_flds; i++) {
17218
- if (i > 0) genFieldSeparator(job, coord, f, f.fld[i]);
17219
- genFields(job, n, f.fld[i]);
17220
- }
17221
- }
17222
- function genFieldSeparator(job, coord, f, child) {
17223
- const a = { x: 0, y: 0 };
17224
- const b = { x: 0, y: 0 };
17225
- if (f.LR) {
17226
- a.x = child.b.ll.x;
17227
- a.y = child.b.ll.y;
17228
- b.x = a.x;
17229
- b.y = child.b.ur.y;
17230
- } else {
17231
- b.x = child.b.ur.x;
17232
- b.y = child.b.ur.y;
17233
- a.x = child.b.ll.x;
17234
- a.y = b.y;
17235
- }
17236
- const pts = [
17237
- transformPoint({ x: a.x + coord.x, y: a.y + coord.y }, job),
17238
- transformPoint({ x: b.x + coord.x, y: b.y + coord.y }, job)
17239
- ];
17240
- job.renderer.polyline(pts, job);
17241
- }
17242
- function recordGencode(rawJob, rawNode) {
17243
- const job = rawJob;
17244
- const n = rawNode;
17245
- if (!job.renderer) return;
17246
- const f = n.info.shape_info;
17247
- if (!f) return;
17248
- const coord = n.info.coord ?? { x: 0, y: 0 };
17249
- const ll = { x: f.b.ll.x + coord.x, y: f.b.ll.y + coord.y };
17250
- const ur = { x: f.b.ur.x + coord.x, y: f.b.ur.y + coord.y };
17251
- const filled = job.obj !== null && applyNodeStyle(job.obj, n, job);
17252
- drawRecordBox(job, n, ll, ur, filled);
17253
- genFields(job, n, f);
17254
- }
17255
- function drawRecordBox(job, n, ll, ur, filled) {
17256
- const isMrecord = nodeAttr(n, n.root, "shape") === "Mrecord";
17257
- const rounded = isMrecord || parseStyleFlags(nodeAttr(n, n.root, "style")).rounded;
17258
- if (rounded) {
17259
- 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 }];
17260
- emitRoundedBezier(af, { x: 0, y: 0 }, filled, { renderer: job.renderer, job });
17261
- return;
17262
- }
17263
- 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));
17264
- job.renderer.polygon(pts, filled, job);
17265
- }
17266
-
17267
- // src/common/poly-init.ts
17268
- var DEFAULT_LW = 27;
17269
- var DEFAULT_RW = 27;
17270
- var DEFAULT_HT = 36;
17271
- function nodeAttr(n, g, key) {
17272
- const own = n.attrs.get(key);
17273
- if (own !== void 0) return own;
17274
- if (n.nodeDefaultsSnapshot !== void 0) return n.nodeDefaultsSnapshot.get(key);
17275
- return g.nodeDefaults.get(key) ?? (g !== g.root ? g.root.nodeDefaults.get(key) : void 0);
17276
- }
17277
- function readFontAttrs(n, g) {
17278
- return {
17279
- fontname: nodeAttr(n, g, "fontname") ?? DEFAULT_FONTNAME,
17280
- fontsize: parseFloat(nodeAttr(n, g, "fontsize") ?? String(DEFAULT_FONTSIZE2)),
17281
- fontcolor: nodeAttr(n, g, "fontcolor") ?? DEFAULT_COLOR2
17282
- };
17283
- }
17284
- function assignShapeInfo(n, polyDesc) {
17285
- const w = n.info.width !== void 0 ? n.info.width * 72 : (n.info.lw || DEFAULT_LW) + (n.info.rw || DEFAULT_RW);
17286
- const h = n.info.height !== void 0 ? n.info.height * 72 : n.info.ht || DEFAULT_HT;
17287
- 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;
17288
- n.info.shape_info = {
17289
- ...polyDesc,
17290
- vertices: computeVertices(polyDesc, w, h, base)
17291
- };
17292
- }
17293
- function buildNodeLabel(n, g, measurer) {
17294
- if (n.info.label !== void 0) return;
17295
- const labelAttr = nodeAttr(n, g, "label");
17296
- const font = readFontAttrs(n, g);
17297
- const isHtml = labelAttr !== void 0 && isHtmlValue(labelAttr);
17298
- const content = isHtml ? htmlValueContent(labelAttr) : labelAttr ?? n.name;
17299
- n.info.label = makeAnyLabel(content, isHtml, font, measurer, n);
17300
- }
17301
- function polyInit(n, g, measurer) {
17302
- const shapeName = nodeAttr(n, g, "shape") ?? "ellipse";
17303
- const shapefile = nodeAttr(n, g, "shapefile");
17304
- n.info.shape = bindShape(shapeName, shapefile);
17305
- if (shapefile !== void 0 && shapefile !== "" && shapeName !== "epsf") {
17306
- console.error(`Warning: No or improper shapefile="${shapefile}" for node "${n.name}"`);
17307
- }
17308
- if (n.info.shape.kind === 2 /* SH_RECORD */) {
17309
- if (n.info.shape_info === void 0) recordNodeInit(n, g, measurer);
17310
- return;
17311
- }
17312
- buildNodeLabel(n, g, measurer);
17313
- if (n.info.shape_info !== void 0) return;
17314
- const polyDesc = n.info.shape.polygon;
17315
- if (polyDesc !== null) assignShapeInfo(n, polyDesc);
17316
- }
17317
-
17318
- // src/render/svg-multicolor.ts
17319
- var THIN_LINE = 0.5;
17320
- function rationalFunction(x, c) {
17321
- return (x * (x * c[0] + c[1]) + c[2]) / (x + c[3]);
17322
- }
17323
- var COEFFS3LOW = [
17324
- [
17325
- [3.85268, -21.229, -0.330434, 0.0127842],
17326
- [-1.61486, 0.706564, 0.225945, 0.263682],
17327
- [-0.910164, 0.388383, 551445e-8, 671814e-8],
17328
- [-0.630184, 0.192402, 98871e-7, 0.0102527]
17329
- ],
17330
- [
17331
- [-0.162211, 9.94329, 0.13723, 0.0124084],
17332
- [-0.253135, 187735e-8, 0.0230286, 0.01264],
17333
- [-0.0695069, -0.0437594, 0.0120636, 0.0163087],
17334
- [-0.0328856, -926032e-8, -173573e-8, 527385e-8]
17335
- ]
17336
- ];
17337
- var COEFFS3HIGH = [
17338
- [
17339
- [0.0899116, -19.2349, -4.11711, 0.183362],
17340
- [0.138148, -1.45804, 1.32044, 1.38474],
17341
- [0.230903, -0.450262, 0.219963, 0.414038],
17342
- [0.0590565, -0.101062, 0.0430592, 0.0204699]
17343
- ],
17344
- [
17345
- [0.0164649, 9.89394, 0.0919496, 760802e-8],
17346
- [0.0191603, -0.0322058, 0.0134667, -0.0825018],
17347
- [0.0156192, -0.017535, 326508e-8, -0.228157],
17348
- [-0.0236752, 0.0405821, -0.0173086, 0.176187]
17349
- ]
17350
- ];
17351
- var SAFETY3 = [1e-3, 4.98, 0.207, 67e-4];
17352
- function estimateError(a, b, etaA, etaB) {
17353
- const eta = 0.5 * (etaA + etaB);
17354
- const x = b / a;
17355
- const dEta = etaB - etaA;
17356
- const cos2 = Math.cos(2 * eta);
17357
- const cos4 = Math.cos(4 * eta);
17358
- const cos6 = Math.cos(6 * eta);
17359
- const c = x < 0.25 ? COEFFS3LOW : COEFFS3HIGH;
17360
- 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]);
17361
- 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]);
17362
- return rationalFunction(x, SAFETY3) * a * Math.exp(c0 + c1 * dEta);
17363
- }
17364
- function allSubdivsBelowThreshold(a, b, eta1, n, dEta) {
17365
- let etaA = eta1;
17366
- for (let i = 0; i < n; i++) {
17367
- if (estimateError(a, b, etaA, etaA + dEta) > 1e-5) return false;
17368
- etaA += dEta;
17369
- }
17370
- return true;
17371
- }
17372
- function numSubdivisions(a, b, eta1, eta2) {
17373
- let n = 1;
17374
- while (n < 1024) {
17375
- const dEta = (eta2 - eta1) / n;
17376
- if (dEta <= 0.5 * Math.PI && allSubdivsBelowThreshold(a, b, eta1, n, dEta)) break;
17377
- n <<= 1;
17378
- }
17379
- return n;
17380
- }
17381
- function initArcPath(pts, e, eta1) {
17382
- const cosE = Math.cos(eta1);
17383
- const sinE = Math.sin(eta1);
17384
- const xB = e.cx + e.xsemi * cosE;
17385
- const yB = e.cy + e.ysemi * sinE;
17386
- pts.push(
17387
- { x: e.cx, y: e.cy },
17388
- { x: e.cx, y: e.cy },
17389
- { x: xB, y: yB },
17390
- { x: xB, y: yB }
17391
- );
17392
- return { xB, yB, xBDot: -e.xsemi * sinE, yBDot: e.ysemi * cosE };
17393
- }
17394
- function stepBezier(pts, state3, e, sp) {
17395
- const xA = state3.xB;
17396
- const yA = state3.yB;
17397
- const xADot = state3.xBDot;
17398
- const yADot = state3.yBDot;
17399
- const newEta = sp.etaB + sp.dEta;
17400
- const cosE = Math.cos(newEta);
17401
- const sinE = Math.sin(newEta);
17402
- state3.xB = e.cx + e.xsemi * cosE;
17403
- state3.yB = e.cy + e.ysemi * sinE;
17404
- state3.xBDot = -e.xsemi * sinE;
17405
- state3.yBDot = e.ysemi * cosE;
17406
- pts.push({ x: xA + sp.alpha * xADot, y: yA + sp.alpha * yADot });
17407
- pts.push({ x: state3.xB - sp.alpha * state3.xBDot, y: state3.yB - sp.alpha * state3.yBDot });
17408
- pts.push({ x: state3.xB, y: state3.yB });
17409
- return newEta;
17410
- }
17411
- function ellipticWedge(e, angle0, angle1) {
17412
- const TWOPI2 = 2 * Math.PI;
17413
- const eta1 = Math.atan2(Math.sin(angle0) / e.ysemi, Math.cos(angle0) / e.xsemi);
17414
- let eta2 = Math.atan2(Math.sin(angle1) / e.ysemi, Math.cos(angle1) / e.xsemi);
17415
- eta2 -= TWOPI2 * Math.floor((eta2 - eta1) / TWOPI2);
17416
- if (angle1 - angle0 > Math.PI && eta2 - eta1 < Math.PI) eta2 += TWOPI2;
17417
- const n = numSubdivisions(e.xsemi, e.ysemi, eta1, eta2);
17418
- const dEta = (eta2 - eta1) / n;
17419
- const t = Math.tan(0.5 * dEta);
17420
- const alpha = Math.sin(dEta) * (Math.sqrt(4 + 3 * t * t) - 1) / 3;
17421
- const pts = [];
17422
- const state3 = initArcPath(pts, e, eta1);
17423
- let sp = { etaB: eta1, dEta, alpha };
17424
- for (let i = 0; i < n; i++) sp = { ...sp, etaB: stepBezier(pts, state3, e, sp) };
17425
- pts.push({ x: state3.xB, y: state3.yB }, { x: e.cx, y: e.cy }, { x: e.cx, y: e.cy });
17426
- return pts;
17427
- }
17428
- function drawWedge(seg2, e, ctx) {
17429
- const TWOPI2 = 2 * Math.PI;
17430
- const angle1 = seg2.isLast ? TWOPI2 : seg2.angle0 + TWOPI2 * seg2.t;
17431
- const obj = ctx.job.obj;
17432
- if (obj !== null) obj.fillColor = resolveRenderColor(seg2.color);
17433
- const ptsUp = ellipticWedge(e, seg2.angle0, angle1);
17434
- ctx.renderer.bezier(ptsUp.map((p) => ({ x: p.x, y: -p.y })), true, ctx.job);
17435
- return angle1;
17436
- }
17437
- function wedgedEllipse(job, pf, clrs, renderer) {
17438
- const { segs, error } = parseSegs(clrs);
17439
- if (error === 1 || error === 2) return error;
17440
- const ctrX = (pf[0].x + pf[1].x) / 2;
17441
- const ctrY = (pf[0].y + pf[1].y) / 2;
17442
- const e = {
17443
- cx: ctrX,
17444
- cy: -ctrY,
17445
- xsemi: pf[1].x - ctrX,
17446
- ysemi: Math.abs(pf[1].y - ctrY)
17447
- };
17448
- const ctx = { job, renderer };
17449
- const obj = job.obj;
17450
- const saved = obj !== null ? obj.penWidth : 1;
17451
- if (obj !== null && saved > THIN_LINE) obj.penWidth = THIN_LINE;
17452
- let angle0 = 0;
17453
- for (let i = 0; i < segs.length; i++) {
17454
- const s = segs[i];
17455
- if (s.color === null) break;
17456
- if (s.t > 0) {
17457
- angle0 = drawWedge({ angle0, t: s.t, isLast: i + 1 === segs.length, color: s.color }, e, ctx);
17458
- }
17459
- }
17460
- if (obj !== null && saved > THIN_LINE) obj.penWidth = saved;
17461
- return error;
17462
- }
17463
- function drawBand(p, seg2, ctx) {
17464
- const obj = ctx.job.obj;
17465
- if (obj !== null) obj.fillColor = resolveRenderColor(seg2.color);
17466
- p[1].x = p[2].x = seg2.isLast ? seg2.lastx : p[0].x + seg2.segWidth;
17467
- ctx.renderer.polygon([...p], true, ctx.job);
17468
- p[0].x = p[3].x = p[1].x;
17469
- }
17470
- function stripedBox(job, pts, clrs, rotate, renderer) {
17471
- const { segs, error } = parseSegs(clrs);
17472
- if (error === 1 || error === 2) return error;
17473
- const p = rotate ? [{ ...pts[2] }, { ...pts[3] }, { ...pts[0] }, { ...pts[1] }] : [{ ...pts[0] }, { ...pts[1] }, { ...pts[2] }, { ...pts[3] }];
17474
- const lastx = p[1].x;
17475
- const xdelta = p[1].x - p[0].x;
17476
- p[1].x = p[2].x = p[0].x;
17477
- const ctx = { job, renderer };
17478
- const obj = job.obj;
17479
- const saved = obj !== null ? obj.penWidth : 1;
17480
- if (obj !== null && saved > THIN_LINE) obj.penWidth = THIN_LINE;
17481
- for (let i = 0; i < segs.length; i++) {
17482
- const s = segs[i];
17483
- if (s.color === null) break;
17484
- if (s.t > 0) {
17485
- drawBand(p, { color: s.color, isLast: i + 1 === segs.length, segWidth: xdelta * s.t, lastx }, ctx);
17486
- }
17487
- }
17488
- if (obj !== null && saved > THIN_LINE) obj.penWidth = saved;
17489
- return error;
17490
- }
17491
-
17492
- // src/render/xml-escape.ts
17493
- var RE_DQUOTE = new RegExp('"', "g");
17494
- var RE_SQUOTE = new RegExp("'", "g");
17495
- var RE_AMP_NONENTITY = /&(?![A-Za-z]+;|#[0-9]+;|#x[0-9A-Fa-f]+;)/g;
17496
- function escapeXml(s) {
17497
- let r = s.replace(RE_AMP_NONENTITY, "&amp;");
17498
- r = r.replace(/</g, "&lt;");
17499
- r = r.replace(/>/g, "&gt;");
17500
- r = r.replace(RE_DQUOTE, "&quot;");
17501
- r = r.replace(RE_SQUOTE, "&#39;");
17502
- return r;
17503
- }
17504
- function escapeXmlTitle(s) {
17505
- let r = escapeXml(s);
17506
- r = r.replace(/-/g, "&#45;");
17507
- r = r.replace(/ {2,}/g, (m) => " " + "&#160;".repeat(m.length - 1));
17508
- return r;
17509
- }
17510
- function escapeXmlText(s) {
17511
- let r = escapeXml(s);
17512
- r = r.replace(/-/g, "&#45;");
17513
- r = r.replace(/\n/g, "&#10;");
17514
- r = r.replace(/\r/g, "&#13;");
17515
- r = r.replace(/ {2,}/g, (m) => " " + "&#160;".repeat(m.length - 1));
17516
- return r;
17517
- }
17518
-
17519
- // src/gvc/device-cluster.ts
17520
- function applyClusterGradient(obj, fill) {
17521
- obj.fill = fill.kind === "radial" ? 3 /* Radial */ : 2 /* Linear */;
17522
- obj.fillColor = resolveRenderColor(fill.fillColor);
17523
- obj.stopColor = resolveRenderColor(fill.stopColor);
17524
- obj.gradientFrac = fill.frac;
17525
- obj.gradientAngle = fill.angle;
17526
- }
17527
- function clusterAttr(sg, key) {
17528
- for (let g = sg; g !== null; g = g.parent) {
17529
- const v = g.attrs.get(key);
17530
- if (v !== void 0) return v;
17531
- }
17532
- return void 0;
17533
- }
17534
- function clusterStyle(sg) {
17535
- return clusterAttr(sg, "style");
17536
- }
17537
- function clusterPeripheries(sg) {
17538
- const raw = clusterAttr(sg, "peripheries");
17539
- if (raw === void 0 || raw.length === 0) return 1;
17540
- const v = parseInt(raw, 10);
17541
- if (Number.isNaN(v)) return 1;
17542
- return v < 0 ? 0 : v;
17543
- }
17544
- function applyClusterPenState(obj, sg) {
17545
- const flags = parseStyleFlags(clusterStyle(sg));
17546
- const pen = clusterAttr(sg, "pencolor") ?? clusterAttr(sg, "color");
17547
- obj.penColor = clusterPeripheries(sg) === 0 ? resolveRenderColor("transparent") : resolveRenderColor(resolvePenColor(pen));
17548
- obj.penWidth = resolvePenWidth(flags, clusterAttr(sg, "penwidth"));
17549
- obj.pen = resolvePenType(flags);
17550
- }
17551
- function clusterAttrsOf(sg) {
17552
- return {
17553
- style: clusterStyle(sg),
17554
- color: clusterAttr(sg, "color"),
17555
- pencolor: clusterAttr(sg, "pencolor"),
17556
- fillcolor: clusterAttr(sg, "fillcolor"),
17557
- bgcolor: clusterAttr(sg, "bgcolor"),
17558
- penwidth: clusterAttr(sg, "penwidth"),
17559
- gradientangle: clusterAttr(sg, "gradientangle")
17560
- };
17561
- }
17562
- function applyClusterObjState(sg, job) {
17563
- const fillRes = resolveClusterFillEx(clusterAttrsOf(sg));
17564
- if (job.obj === null) return false;
17565
- const obj = job.obj;
17566
- return withColorScheme(clusterAttr(sg, "colorscheme"), () => {
17567
- applyClusterPenState(obj, sg);
17568
- if (fillRes.kind === "none") {
17569
- obj.fill = 0 /* None */;
17570
- return false;
17571
- }
17572
- if (fillRes.kind === "solid") {
17573
- obj.fill = 1 /* Solid */;
17574
- obj.fillColor = resolveRenderColor(fillRes.color);
17575
- return true;
17576
- }
17577
- applyClusterGradient(obj, fillRes);
17578
- return true;
17579
- });
17580
- }
17581
-
17582
- // src/render/svg-id.ts
17583
- function svgClass(kind, classAttr) {
17584
- return classAttr !== void 0 && classAttr.length > 0 ? 'class="' + kind + " " + escapeXmlTitle(classAttr) + '"' : 'class="' + kind + '"';
17585
- }
17586
- function svgNodeId(n, job) {
17587
- return job.objId(n.attrs.get("id"), "node" + (n.id + 1));
17588
- }
17589
- function svgEdgeId(e, job) {
17590
- return job.objId(e.attrs.get("id"), "edge" + e.graphSeq);
17591
- }
17592
- function svgClusterId(sg, job) {
17593
- return job.objId(sg.attrs.get("id"), "clust" + sg.seq);
17594
- }
17595
- function svgGraphId(g, job) {
17596
- return job.objId(g.attrs.get("id"), "graph0", true);
17597
- }
17598
- function svgNodeClass(n) {
17599
- return svgClass("node", nodeAttr(n, n.root, "class"));
17600
- }
17601
- function svgEdgeClass(e) {
17602
- return svgClass("edge", e.attrs.get("class"));
17603
- }
17604
- function svgClusterClass(sg) {
17605
- return svgClass("cluster", clusterAttr(sg, "class"));
17606
- }
17607
- function svgGraphClass(g) {
17608
- return svgClass("graph", g.attrs.get("class"));
17609
- }
17610
-
17611
- // src/common/poly-gencode.ts
17612
- function isMulticolor(fillcolor) {
17613
- return fillcolor.includes(":");
17614
- }
17615
- function renderEllipse(ring, coord, renderer, job, filled) {
17616
- const rx = Math.abs((ring[1].x - ring[0].x) / 2);
17617
- const ry = Math.abs((ring[1].y - ring[0].y) / 2);
17618
- const center = transformPoint(coord, job);
17619
- renderer.ellipse(center, rx, ry, filled, job);
17620
- }
17621
- function renderPolygon(ring, coord, renderer, job, filled) {
17622
- const pts = ring.map((v) => transformPoint({ x: v.x + coord.x, y: v.y + coord.y }, job));
17623
- renderer.polygon(pts, filled, job);
17624
- }
17625
- function renderEllipseRing(ring, coord, filled, j, ctx) {
17626
- if (ctx.style.wedged && j === 0 && isMulticolor(ctx.fillcolor)) {
17627
- const pf = ring.map(
17628
- (v) => transformPoint({ x: v.x + coord.x, y: v.y + coord.y }, ctx.job)
17629
- );
17630
- wedgedEllipse(ctx.job, pf, ctx.fillcolor, ctx.renderer);
17631
- renderEllipse(ring, coord, ctx.renderer, ctx.job, false);
17632
- } else {
17633
- renderEllipse(ring, coord, ctx.renderer, ctx.job, filled);
17634
- }
17635
- if (ctx.diagonals) mcircleHack(ring, coord, ctx);
17636
- }
17637
- function renderStripedRing(ring, coord, ctx) {
17638
- const af = ring.map((v) => transformPoint({ x: v.x + coord.x, y: v.y + coord.y }, ctx.job));
17639
- stripedBox(ctx.job, af, ctx.fillcolor, true, ctx.renderer);
17640
- renderPolygon(ring, coord, ctx.renderer, ctx.job, false);
17641
- }
17642
- function renderPolyRing(ring, coord, filled, j, ctx) {
17643
- if (ctx.style.striped && j === 0) renderStripedRing(ring, coord, ctx);
17644
- else if (ctx.underline) underlineDraw(ring, coord, filled, ctx);
17645
- else if (ctx.shape !== 0 && ctx.shape !== STAR || ctx.diagonals || ctx.rounded) {
17646
- drawRoundCorners(ring, coord, filled, ctx);
17647
- } else renderPolygon(ring, coord, ctx.renderer, ctx.job, filled);
17648
- }
17649
- function renderPeripheries(poly, coord, filled, ctx) {
17650
- const sides = poly.sides <= 2 ? 2 : poly.sides;
17651
- const verts = poly.vertices;
17652
- for (let j = 0; j < poly.peripheries; j++) {
17653
- const ring = verts.slice(j * sides, (j + 1) * sides);
17654
- if (ring.length < sides) break;
17655
- const ringFilled = j === 0 ? filled : false;
17656
- if (poly.sides <= 2) {
17657
- renderEllipseRing(ring, coord, ringFilled, j, ctx);
17658
- } else {
17659
- renderPolyRing(ring, coord, ringFilled, j, ctx);
17660
- }
17661
- }
17662
- }
17663
- function renderLabel(label, coord, renderer, job) {
17664
- if (label.u.kind !== "txt" || label.u.nspans < 1) return;
17665
- label.pos = coord;
17666
- label.set = true;
17667
- const VALIGN_TOP2 = "t".charCodeAt(0);
17668
- const VALIGN_BOTTOM2 = "b".charCodeAt(0);
17669
- 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;
17670
- for (let i = 0; i < label.u.nspans; i++) {
17671
- const span = label.u.span[i];
17672
- const px = span.just === "l" ? coord.x - label.space.x / 2 : span.just === "r" ? coord.x + label.space.x / 2 : coord.x;
17673
- gvrenderTextspan(renderer, { x: px, y: py }, span, job);
17674
- py -= span.size.y;
17675
- }
17676
- }
17677
- function renderNodeLabel(n, coord, renderer, job) {
17678
- const label = n.info.label;
17679
- if (label === void 0) return;
17680
- if (label.html && label.u.kind === "html") {
17681
- label.pos = coord;
17682
- label.set = true;
17683
- const html = label.u.html;
17684
- withLabelEmitState(job, () => emitHtmlLabel(html, coord, renderer, job));
17685
- } else {
17686
- renderLabel(label, coord, renderer, job);
17687
- }
17688
- }
17689
- function anchorAttr2(n, key) {
17690
- const v = nodeAttr(n, n.root, key);
17691
- return v !== void 0 && v !== "" ? v : void 0;
17692
- }
17693
- function resolveTooltip(n, tooltip) {
17694
- if (tooltip !== void 0) return substObjAnchor(interpretCRNL(tooltip), n);
17695
- const label = n.info.label;
17696
- return label?.text ?? "";
17697
- }
17698
- function beginNodeAnchor(n, renderer, job) {
17699
- const url = anchorAttr2(n, "href") ?? anchorAttr2(n, "URL");
17700
- const tooltip = anchorAttr2(n, "tooltip");
17701
- if (url === void 0 && tooltip === void 0) return false;
17702
- renderer.beginAnchor?.(
17703
- url !== void 0 ? substObjAnchor(url, n) : "",
17704
- resolveTooltip(n, tooltip),
17705
- anchorAttr2(n, "target") ?? "",
17706
- svgNodeId(n, job),
17707
- job
17708
- );
17709
- return true;
17710
- }
17711
- function applyGradientFields(obj, fill) {
17712
- obj.fill = fill.kind === "radial" ? 3 /* Radial */ : 2 /* Linear */;
17713
- obj.fillColor = resolveRenderColor(fill.fillColor);
17714
- obj.stopColor = resolveRenderColor(fill.stopColor);
17715
- obj.gradientFrac = fill.frac;
17716
- obj.gradientAngle = fill.angle;
17717
- }
17718
- function isPointNode(n) {
17719
- return n.info.shape?.kind === 3 /* SH_POINT */;
17720
- }
17721
- function findFillDflt(n) {
17722
- const fillcolor = nodeAttr(n, n.root, "fillcolor");
17723
- if (fillcolor !== void 0 && fillcolor !== "") return fillcolor;
17724
- const color = nodeAttr(n, n.root, "color");
17725
- if (color !== void 0 && color !== "") return color;
17726
- return "black";
17727
- }
17728
- function applyFillState(obj, n, job) {
17729
- obj.id = svgNodeId(n, job);
17730
- if (isPointNode(n)) {
17731
- obj.fill = 1 /* Solid */;
17732
- obj.fillColor = resolveRenderColor(findFillDflt(n));
17733
- return true;
17734
- }
17735
- const fillRes = resolveNodeFillEx({
17736
- style: nodeAttr(n, n.root, "style"),
17737
- fillcolor: nodeAttr(n, n.root, "fillcolor"),
17738
- color: nodeAttr(n, n.root, "color"),
17739
- gradientangle: nodeAttr(n, n.root, "gradientangle")
17740
- });
17741
- if (fillRes.kind === "none") {
17742
- obj.fill = 0 /* None */;
17743
- return false;
17744
- }
17745
- if (fillRes.kind === "solid") {
17746
- obj.fill = 1 /* Solid */;
17747
- obj.fillColor = resolveRenderColor(fillRes.color);
17748
- return true;
17749
- }
17750
- applyGradientFields(obj, fillRes);
17751
- return true;
17752
- }
17753
- function applyPenState(obj, styleAttr, colorAttr, penwidthAttr) {
17754
- const flags = parseStyleFlags(styleAttr);
17755
- obj.penColor = resolveRenderColor(resolvePenColor(colorAttr));
17756
- obj.pen = resolvePenType(flags);
17757
- obj.penWidth = resolvePenWidth(flags, penwidthAttr);
17758
- obj.rawStyle = styleTokens(styleAttr);
17759
- }
17760
- function applyNodeStyle(obj, n, job) {
17761
- const styleAttr = nodeAttr(n, n.root, "style");
17762
- const colorAttr = nodeAttr(n, n.root, "color");
17763
- const filled = applyFillState(obj, n, job);
17764
- applyPenState(obj, styleAttr, colorAttr, nodeAttr(n, n.root, "penwidth"));
17765
- return filled;
17766
- }
17767
- function prepareDrawPoly(poly, filled, obj) {
17768
- if (poly.peripheries !== 0 || !filled) return poly;
17769
- obj.penColor = { type: "string", s: "transparent" };
17770
- return { ...poly, peripheries: 1 };
17771
- }
17772
- function vertexScale(n, poly) {
17773
- const info = n.info;
17774
- if (poly.vertices == null || info.width === void 0 || info.height === void 0) {
17775
- return poly;
17776
- }
17777
- const xsize = (info.lw + info.rw) / (info.width * 72);
17778
- const ysize = info.ht / (info.height * 72);
17779
- if (Math.abs(xsize - 1) < 1e-9 && Math.abs(ysize - 1) < 1e-9) return poly;
17780
- return {
17781
- ...poly,
17782
- vertices: poly.vertices.map((v) => ({ x: v.x * xsize, y: v.y * ysize }))
17783
- };
17784
- }
17785
- function resolveNodeDrawCtx(job, n) {
17786
- const rawPoly = n.info.shape_info;
17787
- if (rawPoly === void 0 || rawPoly.vertices === void 0) return null;
17788
- const poly = vertexScale(n, rawPoly);
17789
- const coord = n.info.coord ?? { x: 0, y: 0 };
17790
- const obj = job.obj;
17791
- const filled = obj !== null && applyNodeStyle(obj, n, job);
17792
- const drawPoly = obj !== null ? prepareDrawPoly(poly, filled, obj) : poly;
17793
- const styleFlags = parseStyleFlags(nodeAttr(n, n.root, "style"));
17794
- const ringCtx = {
17795
- renderer: job.renderer,
17796
- job,
17797
- style: styleFlags,
17798
- fillcolor: nodeAttr(n, n.root, "fillcolor") ?? "",
17799
- ...specialCornerFlags(drawPoly.option, styleFlags)
17800
- };
17801
- return { poly: drawPoly, coord, filled, ringCtx };
17802
- }
17803
- function specialCornerFlags(opt, style) {
17804
- return {
17805
- shape: opt.shape,
17806
- diagonals: opt.diagonals || style.diagonals,
17807
- rounded: opt.rounded || style.rounded,
17808
- underline: opt.underline || style.underline
17809
- };
17810
- }
17811
- function polyGencode(rawJob, rawNode) {
17812
- const job = rawJob;
17813
- const n = rawNode;
17814
- const renderer = job.renderer;
17815
- if (!renderer) return;
17816
- const ctx = resolveNodeDrawCtx(job, n);
17817
- if (ctx === null) return;
17818
- const clustersLast = (job.flags & EMIT_CLUSTERS_LAST) !== 0;
17819
- const savedShape = job.obj?.urlMapShape;
17820
- const savedPts = job.obj?.urlMapPts;
17821
- let inAnchor = clustersLast ? false : beginNodeAnchor(n, renderer, job);
17822
- renderPeripheries(ctx.poly, ctx.coord, ctx.filled, ctx.ringCtx);
17823
- if (!isPointNode(n)) renderNodeLabel(n, ctx.coord, renderer, job);
17824
- if (clustersLast) {
17825
- if (job.obj && savedPts !== void 0 && savedShape !== void 0) {
17826
- job.obj.urlMapShape = savedShape;
17827
- job.obj.urlMapPts = savedPts;
17828
- }
17829
- inAnchor = beginNodeAnchor(n, renderer, job);
17830
- }
17831
- if (inAnchor) renderer.endAnchor?.(job);
17832
- }
17833
-
17834
- // src/common/poly-inside.ts
17835
- function sameSide(p0, p1, L0, L1) {
17836
- const a = -(L1.y - L0.y);
17837
- const b = L1.x - L0.x;
17838
- const c = a * L0.x + b * L0.y;
17839
- const s0 = a * p0.x + b * p0.y - c >= 0;
17840
- const s1 = a * p1.x + b * p1.y - c >= 0;
17841
- return s0 === s1;
17842
- }
17843
- function fixedShapeSize(poly) {
17844
- let xmax = 0;
17845
- let ymax = 0;
17846
- for (const v of poly.vertices ?? []) {
17847
- xmax = Math.max(xmax, Math.abs(v.x));
17848
- ymax = Math.max(ymax, Math.abs(v.y));
17849
- }
17850
- return { w: 2 * xmax, h: 2 * ymax };
17851
- }
17852
- function insideDims(n, xsize, ysize) {
17853
- const w = 72 * (n.info.width || xsize / 72);
17854
- const h = 72 * (n.info.height || ysize / 72);
17855
- return { w, h, ow: 72 * n.info.outline_width || w, oh: 72 * n.info.outline_height || h };
17856
- }
17857
- function insideScale(n, poly) {
17858
- const flip = n.root.info.flip === true;
17859
- if (poly.option.fixedshape) {
17860
- const { w: w2, h: h2 } = fixedShapeSize(poly);
17861
- const xsize2 = flip ? h2 : w2;
17862
- const ysize2 = flip ? w2 : h2;
17863
- return {
17864
- scalex: xsize2 !== 0 ? w2 / xsize2 : w2,
17865
- scaley: ysize2 !== 0 ? h2 / ysize2 : h2,
17866
- boxURx: w2 / 2,
17867
- boxURy: h2 / 2
17868
- };
17869
- }
17870
- const lwrw = n.info.lw + n.info.rw;
17871
- const xsize = flip ? n.info.ht : lwrw;
17872
- const ysize = flip ? lwrw : n.info.ht;
17873
- const { w, h, ow, oh } = insideDims(n, xsize, ysize);
17874
- return {
17875
- scalex: xsize !== 0 ? w / xsize : w,
17876
- scaley: ysize !== 0 ? h / ysize : h,
17877
- boxURx: ow / 2,
17878
- boxURy: oh / 2
17879
- };
17880
- }
17881
- function polygonWalk(P, vertex, sides) {
17882
- const O = { x: 0, y: 0 };
17883
- let i = 0;
17884
- let i1 = 1 % sides;
17885
- const Q = vertex[i];
17886
- const R2 = vertex[i1];
17887
- if (!sameSide(P, O, Q, R2)) return false;
17888
- const s = sameSide(P, Q, R2, O);
17889
- if (s && sameSide(P, R2, O, Q)) return true;
17890
- for (let j = 1; j < sides; j++) {
17891
- if (s) {
17892
- i = i1;
17893
- i1 = (i + 1) % sides;
17894
- } else {
17895
- i1 = i;
17896
- i = (i + sides - 1) % sides;
17897
- }
17898
- if (!sameSide(P, O, vertex[i], vertex[i1])) return false;
17899
- }
17900
- return true;
17901
- }
17902
- function insideShape(n, poly, p) {
17903
- const sc = insideScale(n, poly);
17904
- const P = { x: p.x * sc.scalex, y: p.y * sc.scaley };
17905
- if (Math.abs(P.x) > sc.boxURx || Math.abs(P.y) > sc.boxURy) return false;
17906
- if (poly.sides <= 2) {
17907
- return Math.hypot(P.x / sc.boxURx, P.y / sc.boxURy) < 1;
17908
- }
17909
- const outerStart = (Math.max(poly.peripheries, 1) - 1) * poly.sides;
17910
- const outer = poly.vertices.slice(outerStart, outerStart + poly.sides);
17911
- const ring = polygonOutlineRing(outer, poly.sides, poly.penwidth ?? 1);
17912
- return polygonWalk(P, ring, poly.sides);
17913
- }
17914
- function polyInside(ctx, p) {
17915
- const n = ctx.node;
17916
- if (n === void 0) return false;
17917
- const rankdir = (n.root.info.rankdir ?? 0) & 3;
17918
- const P = rankdir === 0 ? p : ccwrotatepf(p, rankdir * 90);
17919
- if (ctx.bp) {
17920
- const b = ctx.bp;
17921
- return P.x >= b.ll.x && P.x <= b.ur.x && P.y >= b.ll.y && P.y <= b.ur.y;
17922
- }
17923
- const poly = n.info.shape_info;
17924
- if (poly === void 0 || poly.vertices === null) return false;
17925
- return insideShape(n, poly, P);
17926
- }
17927
- function starInside(ctx, p) {
17928
- const n = ctx.node;
17929
- if (n === void 0) return false;
17930
- const rankdir = (n.root.info.rankdir ?? 0) & 3;
17931
- const P = rankdir === 0 ? p : ccwrotatepf(p, rankdir * 90);
17932
- if (ctx.bp) {
17933
- const b = ctx.bp;
17934
- return P.x >= b.ll.x && P.x <= b.ur.x && P.y >= b.ll.y && P.y <= b.ur.y;
17935
- }
17936
- const poly = n.info.shape_info;
17937
- if (poly === void 0 || poly.vertices === null) return false;
17938
- const sides = poly.sides;
17939
- const outerStart = (Math.max(poly.peripheries, 1) - 1) * sides;
17940
- const outer = poly.vertices.slice(outerStart, outerStart + sides);
17941
- const ring = polygonOutlineRing(outer, sides, poly.penwidth ?? 1);
17942
- const O = { x: 0, y: 0 };
17943
- let outcnt = 0;
17944
- for (let i = 0; i < sides; i += 2) {
17945
- const Q = ring[i];
17946
- const R2 = ring[(i + 4) % sides];
17947
- if (!sameSide(P, O, Q, R2)) outcnt++;
17948
- if (outcnt === 2) return false;
17949
- }
17950
- return true;
17951
- }
17952
- function recordInside(ctx, p) {
17953
- const n = ctx.node;
17954
- if (n === void 0) return false;
17955
- const rankdir = (n.root.info.rankdir ?? 0) & 3;
17956
- const P = rankdir === 0 ? p : ccwrotatepf(p, rankdir * 90);
17957
- let bb;
17958
- if (ctx.bp) {
17959
- bb = ctx.bp;
17960
- } else {
17961
- const fld = n.info.shape_info;
17962
- if (!fld?.b) return false;
17963
- bb = fld.b;
17964
- }
17965
- const pw = 0.5;
17966
- 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;
17967
- }
17968
-
17969
- // src/layout/dot/fastgr.ts
17970
- var VIRTUAL = 1;
17971
- var NORMAL = 0;
17972
- var FLATORDER = 4;
17973
- var REVERSED = 3;
17974
- var MC_SCALE = 256;
17975
- function elistAppend(el, e) {
17976
- el.list[el.size++] = e;
17977
- }
17978
- function zapinlist(el, e) {
17979
- let i = 0;
17980
- while (i < el.size && el.list[i] !== e) i++;
17981
- if (i < el.size) {
17982
- el.list[i] = el.list[--el.size];
17983
- el.list[el.size] = void 0;
17984
- }
17985
- }
17986
- function deleteFastEdge(e) {
17987
- if (e.tail.info.out) zapinlist(e.tail.info.out, e);
17988
- if (e.head.info.in) zapinlist(e.head.info.in, e);
17989
- }
17990
- function fastEdge(e) {
17991
- if (!e.tail.info.out) e.tail.info.out = { list: [], size: 0 };
17992
- if (!e.head.info.in) e.head.info.in = { list: [], size: 0 };
17993
- elistAppend(e.tail.info.out, e);
17994
- elistAppend(e.head.info.in, e);
17995
- }
17996
- function findFastEdge(u, v) {
17997
- const uOut = u.info.out;
17998
- const vIn = v.info.in;
17999
- if (uOut === void 0 || vIn === void 0) return void 0;
18000
- if (uOut.size <= vIn.size) {
18001
- for (let i = 0; i < uOut.size; i++) {
18002
- if (uOut.list[i].head === v) return uOut.list[i];
18003
- }
18004
- } else {
18005
- for (let i = 0; i < vIn.size; i++) {
18006
- if (vIn.list[i].tail === u) return vIn.list[i];
18007
- }
18008
- }
18009
- return void 0;
18010
- }
18011
- function copyPort(p) {
18012
- 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;
18013
- 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 };
18014
- }
18015
- function copyVirtualPorts(e, orig) {
18016
- if (e.tail === orig.tail) e.info.tail_port = copyPort(orig.info.tail_port);
18017
- else if (e.tail === orig.head) e.info.tail_port = copyPort(orig.info.head_port);
18018
- if (e.head === orig.head) e.info.head_port = copyPort(orig.info.head_port);
18019
- else if (e.head === orig.tail) e.info.head_port = copyPort(orig.info.tail_port);
18020
- }
18021
- function copyVirtualEdgeInfo(e, orig) {
18022
- e.info.count = orig.info.count;
18023
- e.info.xpenalty = orig.info.xpenalty;
18024
- e.info.weight = orig.info.weight;
18025
- e.info.minlen = orig.info.minlen;
18026
- copyVirtualPorts(e, orig);
18027
- e.info.label = orig.info.label;
18028
- e.info.head_label = orig.info.head_label;
18029
- e.info.tail_label = orig.info.tail_label;
18030
- e.info.xlabel = orig.info.xlabel;
18031
- if (orig.info.to_virt === void 0) orig.info.to_virt = e;
18032
- e.info.to_orig = orig;
18033
- e.seq = orig.seq;
18034
- }
18035
- function newVirtualEdge(u, v, orig) {
18036
- const e = new Edge(u, v, "");
18037
- e.info.edge_type = VIRTUAL;
18038
- if (orig) {
18039
- copyVirtualEdgeInfo(e, orig);
18040
- } else {
18041
- e.info.weight = 1;
18042
- e.info.xpenalty = 1;
18043
- e.info.count = 1;
18044
- e.info.minlen = 1;
18045
- }
18046
- return e;
18047
- }
18048
- function virtualEdge(u, v, orig) {
18049
- const e = newVirtualEdge(u, v, orig);
18050
- fastEdge(e);
18051
- return e;
18052
- }
18053
- function mergeWeightsInto(f, ew, em, ex) {
18054
- f.info.weight = (f.info.weight ?? 0) + ew;
18055
- f.info.minlen = Math.max(f.info.minlen ?? 1, em);
18056
- f.info.count = (f.info.count ?? 1) + 1;
18057
- f.info.xpenalty = (f.info.xpenalty ?? 0) + ex;
18058
- }
18059
- function basicMerge(e, rep) {
18060
- const ew = e.info.weight ?? 1;
18061
- const em = e.info.minlen ?? 1;
18062
- const ex = e.info.xpenalty ?? 0;
18063
- for (let f = rep; f !== void 0; f = f.info.to_virt) {
18064
- mergeWeightsInto(f, ew, em, ex);
18065
- }
18066
- }
18067
- function mergeOneway(e, rep) {
18068
- if (e.info.to_virt !== void 0) return;
18069
- e.info.to_virt = rep;
18070
- basicMerge(e, rep);
18071
- }
18072
- function deleteFlatEdge(e) {
18073
- e.info.to_virt = void 0;
18074
- if (e.tail.info.flat_out) zapinlist(e.tail.info.flat_out, e);
18075
- if (e.head.info.flat_in) zapinlist(e.head.info.flat_in, e);
18076
- }
18077
- function flatEdge(g, e) {
18078
- if (!e.tail.info.flat_out) e.tail.info.flat_out = { list: [], size: 0 };
18079
- if (!e.head.info.flat_in) e.head.info.flat_in = { list: [], size: 0 };
18080
- elistAppend(e.tail.info.flat_out, e);
18081
- elistAppend(e.head.info.flat_in, e);
18082
- g.info.has_flat_edges = true;
18083
- }
18084
- function findFlatEdge(u, v) {
18085
- const uOut = u.info.flat_out;
18086
- const vIn = v.info.flat_in;
18087
- if (uOut === void 0 || vIn === void 0) return void 0;
18088
- if (uOut.size <= vIn.size) {
18089
- for (let i = 0; i < uOut.size; i++) {
18090
- if (uOut.list[i].head === v) return uOut.list[i];
18091
- }
18092
- } else {
18093
- for (let i = 0; i < vIn.size; i++) {
18094
- if (vIn.list[i].tail === u) return vIn.list[i];
18095
- }
18096
- }
18097
- return void 0;
18098
- }
18099
- function reverseEdge(e) {
18100
- deleteFastEdge(e);
18101
- e.info.reversed = true;
18102
- const f = findFastEdge(e.head, e.tail);
18103
- if (f !== void 0) {
18104
- mergeOneway(e, f);
18105
- } else {
18106
- virtualEdge(e.head, e.tail, e);
18107
- }
18108
- }
18109
- function fastNode(g, n) {
18110
- n.info.next = g.info.nlist;
18111
- if (g.info.nlist !== void 0) g.info.nlist.info.prev = n;
18112
- n.info.prev = void 0;
18113
- g.info.nlist = n;
18114
- }
18115
- function deleteFastNode(g, n) {
18116
- if (n.info.prev !== void 0) n.info.prev.info.next = n.info.next;
18117
- else g.info.nlist = n.info.next;
18118
- if (n.info.next !== void 0) n.info.next.info.prev = n.info.prev;
18119
- }
18120
- function removeFromRank(g, n) {
18121
- const r = n.info.rank !== void 0 ? n.info.rank : 0;
18122
- const rank3 = g.info.rank;
18123
- if (rank3 === void 0) return;
18124
- const rk = rank3[r];
18125
- for (let j = 0; j < rk.n; j++) {
18126
- const v = rk.v[j];
18127
- if (v === n) {
18128
- for (j++; j < rk.n; j++) {
18129
- rk.v[j - 1] = rk.v[j];
18130
- }
18131
- rk.n--;
18132
- break;
18133
- }
18134
- }
18135
- }
18136
- function virtualNode(g) {
18137
- const n = new Node(0, "", g.root);
18138
- n.info.node_type = VIRTUAL;
18139
- n.info.lw = 1;
18140
- n.info.rw = 1;
18141
- n.info.ht = 1;
18142
- n.info.UF_size = 1;
18143
- n.info.in = { list: [], size: 0 };
18144
- n.info.out = { list: [], size: 0 };
18145
- fastNode(g, n);
18146
- return n;
18147
- }
18148
- function otherEdge(e) {
18149
- if (!e.tail.info.other) e.tail.info.other = { list: [], size: 0 };
18150
- elistAppend(e.tail.info.other, e);
18151
- }
18152
-
18153
- // src/layout/dot/decomp.ts
18154
- function nodesInSeq(g) {
18155
- return [...g.nodes.values()].sort((a, b) => a.id - b.id);
18156
- }
18157
- function ufFind(n) {
18158
- while (n.info.UF_parent !== void 0 && n.info.UF_parent !== n) {
18159
- const gp = n.info.UF_parent.info.UF_parent;
18160
- if (gp !== void 0) n.info.UF_parent = gp;
18161
- n = n.info.UF_parent;
18162
- }
18163
- return n;
18164
- }
18165
- function ufUnion(u, v) {
18166
- if (u === v) return u;
18167
- if (u.info.UF_parent === void 0) {
18168
- u.info.UF_parent = u;
18169
- u.info.UF_size = 1;
18170
- } else u = ufFind(u);
18171
- if (v.info.UF_parent === void 0) {
18172
- v.info.UF_parent = v;
18173
- v.info.UF_size = 1;
18174
- } else v = ufFind(v);
18175
- if (u === v) return u;
18176
- const us = u.info.UF_size ?? 0;
18177
- const vs = v.info.UF_size ?? 0;
18178
- v.info.UF_parent = u;
18179
- u.info.UF_size = us + vs;
18180
- return u;
18181
- }
18182
- function ufSingleton(u) {
18183
- u.info.UF_size = 1;
18184
- u.info.UF_parent = void 0;
18185
- u.info.ranktype = 0;
18186
- }
18187
- function ufSetname(u, v) {
18188
- u.info.UF_parent = v;
18189
- v.info.UF_size = (v.info.UF_size ?? 0) + (u.info.UF_size ?? 0);
18190
- }
18191
- function decompPushNeighbors(stk, el, n, cmark) {
18192
- if (!el || el.size === 0) return;
18193
- for (let i = el.size - 1; i >= 0; i--) {
18194
- const e = el.list[i];
18195
- const other = e.head === n ? e.tail : e.head;
18196
- if (other.info.mark !== cmark && other === ufFind(other)) {
18197
- other.info.mark = cmark + 1;
18198
- stk.push(other);
18199
- }
18200
- }
18201
- }
18202
- function decompSearch(g, start, cmark) {
18203
- const stk = [];
18204
- let lastNode;
18205
- start.info.mark = cmark + 1;
18206
- stk.push(start);
18207
- g.info.nlist = void 0;
18208
- let top;
18209
- while ((top = stk.pop()) !== void 0) {
18210
- if (top.info.mark === cmark) continue;
18211
- top.info.mark = cmark;
18212
- if (lastNode !== void 0) {
18213
- top.info.prev = lastNode;
18214
- lastNode.info.next = top;
18215
- } else {
18216
- top.info.prev = void 0;
18217
- g.info.nlist = top;
18218
- }
18219
- lastNode = top;
18220
- top.info.next = void 0;
18221
- decompPushNeighbors(stk, top.info.flat_in, top, cmark);
18222
- decompPushNeighbors(stk, top.info.flat_out, top, cmark);
18223
- decompPushNeighbors(stk, top.info.in, top, cmark);
18224
- decompPushNeighbors(stk, top.info.out, top, cmark);
18225
- }
18226
- }
18227
- var _dc = { cmark: 0 };
18228
- function resolveNode(n, pass) {
18229
- if (pass > 0) {
18230
- const subg = n.info.clust;
18231
- if (subg) return subg.info.rankleader?.[n.info.rank ?? 0];
18232
- }
18233
- return n === ufFind(n) ? n : void 0;
18234
- }
18235
- function decompose(g, pass) {
18236
- if (++_dc.cmark === 0) _dc.cmark = 1;
18237
- const cmark = _dc.cmark;
18238
- g.info.comp = [];
18239
- for (const n of nodesInSeq(g)) {
18240
- const v = resolveNode(n, pass);
18241
- if (v !== void 0 && v.info.mark !== cmark) {
18242
- decompSearch(g, v, cmark);
18243
- g.info.comp.push(g.info.nlist);
18244
- }
18245
- }
18246
- }
18247
-
18248
- // src/layout/dot/mincross-utils.ts
18249
- var CONVERGENCE = 0.995;
18250
- function matrixGet(m, row, col) {
18251
- if (row >= m.nrows || col >= m.ncols) return false;
18252
- const idx = row * m.ncols + col;
18253
- return (m.data[idx >> 3] >> (idx & 7) & 1) === 1;
18254
- }
18255
- function matrixSet(m, row, col) {
18256
- if (row >= m.nrows || col >= m.ncols) matrixExpand(m, row, col);
18257
- const idx = row * m.ncols + col;
18258
- m.data[idx >> 3] |= 1 << (idx & 7);
18259
- }
18260
- function matrixCopyBits(m, data, ncols) {
18261
- for (let r = 0; r < m.nrows; r++) {
18262
- for (let c = 0; c < m.ncols; c++) {
18263
- if (!matrixGet(m, r, c)) continue;
18264
- const idx = r * ncols + c;
18265
- data[idx >> 3] |= 1 << (idx & 7);
18266
- }
18267
- }
18268
- }
18269
- function matrixExpand(m, row, col) {
18270
- const nrows = Math.max(m.nrows, row + 1);
18271
- const ncols = Math.max(m.ncols, col + 1);
18272
- const bits = nrows * ncols;
18273
- const bytes = (bits >> 3) + (bits & 7 ? 1 : 0);
18274
- const data = new Uint8Array(bytes);
18275
- matrixCopyBits(m, data, ncols);
18276
- m.nrows = nrows;
18277
- m.ncols = ncols;
18278
- m.data = data;
18279
- }
18280
- function newMatrix(rows, cols) {
18281
- const bits = rows * cols;
18282
- const bytes = (bits >> 3) + (bits & 7 ? 1 : 0);
18283
- return { nrows: rows, ncols: cols, data: new Uint8Array(bytes) };
18284
- }
18285
- function dotRoot(g) {
18286
- return g.info.dotroot ?? g.root;
18287
- }
18288
- function agContainsNode(g, n) {
18289
- return g.nodes.get(n.name) === n;
18290
- }
18291
- function agContainsEdge(g, e) {
18292
- return g.edges.includes(e);
18293
- }
18294
- function rankGet(rank3, i) {
18295
- return rank3.v[(rank3.vStart ?? 0) + i];
18296
- }
18297
- function rankSet(rank3, i, n) {
18298
- rank3.v[(rank3.vStart ?? 0) + i] = n;
18299
- }
18300
- function isNormalNodeOf(g, v) {
18301
- return v.info.node_type === NORMAL && agContainsNode(g, v);
18302
- }
18303
- function isVnodeOfEdgeOf(g, v) {
18304
- if (v.info.node_type !== VIRTUAL) return false;
18305
- const inSz = v.info.in ? v.info.in.size : 0;
18306
- const outSz = v.info.out ? v.info.out.size : 0;
18307
- if (inSz !== 1 || outSz !== 1) return false;
18308
- let e = v.info.out.list[0];
18309
- while (e.info.edge_type !== NORMAL && e.info.to_orig) e = e.info.to_orig;
18310
- return agContainsEdge(g, e);
18311
- }
18312
- function insideCluster(g, v) {
18313
- return isNormalNodeOf(g, v) || isVnodeOfEdgeOf(g, v);
18314
- }
18315
- function neighborNode(ctx, v, dir) {
18316
- const rk = ctx.root.info.rank?.[v.info.rank ?? 0];
18317
- if (!rk) return void 0;
18318
- const order = v.info.order ?? 0;
18319
- return (dir < 0 ? order > 0 ? rk.v[order - 1] : void 0 : rk.v[order + 1]) ?? void 0;
18320
- }
18321
- function furthestNode(ctx, g, v, dir) {
18322
- let rv = v;
18323
- let u = v;
18324
- while ((u = neighborNode(ctx, u, dir)) !== void 0) {
18325
- if (isNormalNodeOf(g, u) || isVnodeOfEdgeOf(g, u)) rv = u;
18326
- }
18327
- return rv;
18328
- }
18329
-
18330
- // src/common/splines-geom.ts
18331
- function approxEqPt(p, q, tol) {
18332
- const dx = p.x - q.x;
18333
- const dy = p.y - q.y;
18334
- return dx * dx + dy * dy < tol * tol;
18335
- }
18336
- function evalBezier(sp, t, left, right) {
18337
- const ab = { x: sp[0].x + t * (sp[1].x - sp[0].x), y: sp[0].y + t * (sp[1].y - sp[0].y) };
18338
- const bc = { x: sp[1].x + t * (sp[2].x - sp[1].x), y: sp[1].y + t * (sp[2].y - sp[1].y) };
18339
- const cd = { x: sp[2].x + t * (sp[3].x - sp[2].x), y: sp[2].y + t * (sp[3].y - sp[2].y) };
18340
- const abbc = { x: ab.x + t * (bc.x - ab.x), y: ab.y + t * (bc.y - ab.y) };
18341
- const bccd = { x: bc.x + t * (cd.x - bc.x), y: bc.y + t * (cd.y - bc.y) };
18342
- const pt = { x: abbc.x + t * (bccd.x - abbc.x), y: abbc.y + t * (bccd.y - abbc.y) };
18343
- if (left !== null) {
18344
- left[0] = sp[0];
18345
- left[1] = ab;
18346
- left[2] = abbc;
18347
- left[3] = pt;
18348
- }
18349
- if (right !== null) {
18350
- right[0] = pt;
18351
- right[1] = bccd;
18352
- right[2] = cd;
18353
- right[3] = sp[3];
18354
- }
18355
- return pt;
18356
- }
18357
- var HW = 2;
18358
- var SMALL = 1e-10;
18359
- function ptToLine2(a, b, p) {
18360
- const dx = b.x - a.x;
18361
- const dy = b.y - a.y;
18362
- let a2 = (p.y - a.y) * dx - (p.x - a.x) * dy;
18363
- a2 *= a2;
18364
- if (a2 < SMALL) return 0;
18365
- return a2 / (dx * dx + dy * dy);
18366
- }
18367
- function checkControlPoints(cp) {
18368
- const dis1 = ptToLine2(cp[0], cp[3], cp[1]);
18369
- const dis2 = ptToLine2(cp[0], cp[3], cp[2]);
18370
- return dis1 < HW * HW && dis2 < HW * HW;
18371
- }
18372
- function anyOutside(bb, cp) {
18373
- return cp.some((p) => p.x > bb.ur.x || p.x < bb.ll.x || p.y > bb.ur.y || p.y < bb.ll.y);
18374
- }
18375
- function expandByPoints(bb, cp) {
18376
- for (const p of cp) {
18377
- if (p.x > bb.ur.x) bb.ur.x = p.x;
18378
- else if (p.x < bb.ll.x) bb.ll.x = p.x;
18379
- if (p.y > bb.ur.y) bb.ur.y = p.y;
18380
- else if (p.y < bb.ll.y) bb.ll.y = p.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);
17115
+ }
17116
+ function expandByPoints(bb, cp) {
17117
+ for (const p of cp) {
17118
+ if (p.x > bb.ur.x) bb.ur.x = p.x;
17119
+ else if (p.x < bb.ll.x) bb.ll.x = p.x;
17120
+ if (p.y > bb.ur.y) bb.ur.y = p.y;
17121
+ else if (p.y < bb.ll.y) bb.ll.y = p.y;
18381
17122
  }
18382
17123
  }
18383
17124
  function updateBbBz(bb, cp) {
@@ -20284,6 +19025,101 @@ function doGraphLabel(sg, measurer) {
20284
19025
  applyLabelBorder(sg, { x: label.dimen.x + 4 * GAP2, y: label.dimen.y + 2 * GAP2 });
20285
19026
  }
20286
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
+
20287
19123
  // src/layout/dot/acyclic.ts
20288
19124
  function dfsStep(stack) {
20289
19125
  const f = stack[stack.length - 1];
@@ -21826,6 +20662,216 @@ function dot2Rank(g) {
21826
20662
  readoutLevels(g, Xg, ncc);
21827
20663
  }
21828
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
+
21829
20875
  // src/layout/dot/mincross-cross.ts
21830
20876
  var reMincross = false;
21831
20877
  function setReMincross(b) {
@@ -22476,134 +21522,6 @@ function orderedEdges(ctx, g) {
22476
21522
  doOrderingForNodes(ctx, g);
22477
21523
  }
22478
21524
 
22479
- // src/layout/dot/cluster-path.ts
22480
- var CLUSTER_EDGE = 5;
22481
- function mapInterclustNode(n) {
22482
- const clust = n.info.clust;
22483
- if (clust === void 0 || clust.info.expanded) return n;
22484
- return clust.info.rankleader[n.info.rank ?? 0];
22485
- }
22486
- function makeSlotsContract(root, r, pos, d) {
22487
- const rk = root.info.rank[r];
22488
- for (let i = pos - d + 1; i < rk.n; i++) {
22489
- const v = rk.v[i];
22490
- v.info.order = i + d - 1;
22491
- rk.v[v.info.order] = v;
22492
- }
22493
- for (let i = rk.n + d - 1; i < rk.n; i++) rk.v[i] = null;
22494
- }
22495
- function makeSlotsExpand(root, r, pos, d) {
22496
- const rk = root.info.rank[r];
22497
- for (let i = rk.n - 1; i > pos; i--) {
22498
- const v = rk.v[i];
22499
- v.info.order = i + d - 1;
22500
- rk.v[v.info.order] = v;
22501
- }
22502
- for (let i = pos + 1; i < pos + d; i++) rk.v[i] = null;
22503
- }
22504
- function makeSlots(root, r, pos, d) {
22505
- if (d <= 0) makeSlotsContract(root, r, pos, d);
22506
- else makeSlotsExpand(root, r, pos, d);
22507
- root.info.rank[r].n += d - 1;
22508
- }
22509
- function cloneVn(g, vn) {
22510
- const r = vn.info.rank ?? 0;
22511
- makeSlots(g, r, vn.info.order, 2);
22512
- const rv = virtualNode(g);
22513
- rv.info.lw = vn.info.lw;
22514
- rv.info.rw = vn.info.rw;
22515
- rv.info.rank = r;
22516
- rv.info.order = (vn.info.order ?? 0) + 1;
22517
- g.info.rank[r].v[rv.info.order] = rv;
22518
- return rv;
22519
- }
22520
- function safeOtherEdge(e) {
22521
- if (!e.tail.info.other) e.tail.info.other = { list: [], size: 0 };
22522
- const other = e.tail.info.other;
22523
- for (let i = 0; i < other.size; i++) if (other.list[i] === e) return;
22524
- other.list[other.size++] = e;
22525
- }
22526
- function portsEqSimple(orig, e) {
22527
- const hp = orig.info.head_port;
22528
- const tp = orig.info.tail_port;
22529
- const ehp = e.info.head_port;
22530
- const etp = e.info.tail_port;
22531
- 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);
22532
- }
22533
- function mapPathAdjacentMulti(from, to, orig, ve, type) {
22534
- const root = dotRoot(from.root);
22535
- let u = from;
22536
- for (let r = from.info.rank ?? 0; r < (to.info.rank ?? 0); r++) {
22537
- const v = r < (to.info.rank ?? 0) - 1 ? cloneVn(root, ve.head) : to;
22538
- const e = virtualEdge(u, v, orig);
22539
- e.info.edge_type = type;
22540
- u = v;
22541
- ve.info.count = (ve.info.count ?? 1) - 1;
22542
- ve = ve.head.info.out.list[0];
22543
- }
22544
- }
22545
- function mapPathAdjacentSingle(from, to, orig, ve, type) {
22546
- const existing = findFastEdge(from, to);
22547
- if (existing !== void 0 && portsEqSimple(orig, existing)) {
22548
- orig.info.to_virt = existing;
22549
- existing.info.edge_type = type;
22550
- existing.info.count = (existing.info.count ?? 1) + 1;
22551
- if (from.info.node_type === NORMAL && to.info.node_type === NORMAL)
22552
- safeOtherEdge(orig);
22553
- } else {
22554
- orig.info.to_virt = void 0;
22555
- const e = virtualEdge(from, to, orig);
22556
- e.info.edge_type = type;
22557
- ve.info.count = (ve.info.count ?? 1) - 1;
22558
- }
22559
- }
22560
- function mapPathLongSingle(from, to, orig, ve, type) {
22561
- let e;
22562
- if (ve.tail !== from) {
22563
- orig.info.to_virt = void 0;
22564
- e = orig.info.to_virt = virtualEdge(from, ve.head, orig);
22565
- deleteFastEdge(ve);
22566
- } else {
22567
- e = ve;
22568
- }
22569
- while ((e.head.info.rank ?? 0) !== (to.info.rank ?? 0))
22570
- e = e.head.info.out.list[0];
22571
- if (e.head !== to) {
22572
- const old = e;
22573
- e = virtualEdge(e.tail, to, orig);
22574
- e.info.edge_type = type;
22575
- deleteFastEdge(old);
22576
- }
22577
- }
22578
- function mapPathMultiEdge(from, to, orig, ve, type) {
22579
- orig.info.to_virt = void 0;
22580
- const span = (to.info.rank ?? 0) - (from.info.rank ?? 0);
22581
- if (span === 1) {
22582
- const ex = findFastEdge(from, to);
22583
- if (ex !== void 0 && portsEqSimple(orig, ex)) {
22584
- mergeOneway(orig, ex);
22585
- if (from.info.node_type === NORMAL && to.info.node_type === NORMAL)
22586
- safeOtherEdge(orig);
22587
- return;
22588
- }
22589
- }
22590
- mapPathAdjacentMulti(from, to, orig, ve, type);
22591
- }
22592
- function mapPath(from, to, orig, ve, type) {
22593
- if (ve.tail === from && ve.head === to) return;
22594
- const span = (to.info.rank ?? 0) - (from.info.rank ?? 0);
22595
- const cnt = ve.info.count ?? 1;
22596
- if (cnt > 1) mapPathMultiEdge(from, to, orig, ve, type);
22597
- else if (span === 1) mapPathAdjacentSingle(from, to, orig, ve, type);
22598
- else mapPathLongSingle(from, to, orig, ve, type);
22599
- }
22600
- function makeInterclustChain(from, to, orig) {
22601
- const u = mapInterclustNode(from);
22602
- const v = mapInterclustNode(to);
22603
- const type = u === from && v === to ? VIRTUAL : CLUSTER_EDGE;
22604
- mapPath(u, v, orig, orig.info.to_virt, type);
22605
- }
22606
-
22607
21525
  // src/layout/dot/cluster.ts
22608
21526
  function interclexpMergeable(prev, e) {
22609
21527
  if (!prev) return false;
@@ -22883,15 +21801,325 @@ function markLowclusterBasic(g) {
22883
21801
  for (let c = 1; c <= nClust; c++) markLowclusterBasic(g.info.clust[c - 1]);
22884
21802
  const outByTail = outEdgesByTail(g.edges);
22885
21803
  for (const n of nodesInSeq(g)) {
22886
- if (n.info.clust === void 0) n.info.clust = g;
22887
- const oes = outByTail.get(n);
22888
- if (oes === void 0) continue;
22889
- 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) ?? []);
22890
22113
  }
22891
22114
  }
22892
- function markLowclusters(root) {
22893
- markLowclustersZap(root);
22894
- 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];
22895
22123
  }
22896
22124
 
22897
22125
  // src/layout/dot/rank.ts
@@ -23154,450 +22382,1223 @@ function gMaxrankVal(g) {
23154
22382
  function gNCluster(g) {
23155
22383
  return g.info.n_cluster ?? 0;
23156
22384
  }
23157
- function gClust(g) {
23158
- 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);
23159
22889
  }
23160
- function nRank(n) {
23161
- 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);
23162
22900
  }
23163
- function nRanktype(n) {
23164
- 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);
23165
22911
  }
23166
- function gMaxrankDef(g) {
23167
- 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
+ };
23168
22918
  }
23169
- function gMinrankDef(g) {
23170
- 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
+ };
23171
22927
  }
23172
- function setMinmax(g) {
23173
- const lr = gLeaderRank(g);
23174
- g.info.minrank = gMinrankVal(g) + lr;
23175
- g.info.maxrank = gMaxrankVal(g) + lr;
23176
- const cl = gClust(g);
23177
- const nc = gNCluster(g);
23178
- 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);
23179
22935
  }
23180
- function minmaxEdgesReverse(n, isOut) {
23181
- const rt = n.info.ranktype ?? 0;
23182
- const flag = isOut ? rt === SINKRANK : rt === SOURCERANK;
23183
- const list = isOut ? n.info.out : n.info.in;
23184
- if (list) {
23185
- 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}"`);
23186
22942
  }
23187
- return flag ? 1 : 0;
23188
- }
23189
- function minmaxEdges(g) {
23190
- if (!g.info.maxset && !g.info.minset) return [0, 0];
23191
- if (g.info.minset) g.info.minset = ufFind(g.info.minset);
23192
- if (g.info.maxset) g.info.maxset = ufFind(g.info.maxset);
23193
- const slenY = g.info.maxset ? minmaxEdgesReverse(g.info.maxset, true) : 0;
23194
- const slenX = g.info.minset ? minmaxEdgesReverse(g.info.minset, false) : 0;
23195
- 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);
23196
22951
  }
23197
- function nOutEdge0(n) {
23198
- 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]);
23199
22957
  }
23200
- function nInEdge0(n) {
23201
- 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);
23202
22998
  }
23203
- function mmEdges2CheckMax(g, n, slen1) {
23204
- const out = n.info.out;
23205
- if ((!out || out.size === 0) && g.info.maxset && n !== g.info.maxset) {
23206
- const ref = nOutEdge0(n) ?? nInEdge0(n);
23207
- const e = virtualEdge(n, g.info.maxset, ref);
23208
- e.info.minlen = slen1;
23209
- e.info.weight = 0;
23210
- 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;
23211
23004
  }
23212
- return false;
23005
+ return true;
23213
23006
  }
23214
- function mmEdges2CheckMin(g, n, slen0) {
23215
- const inp = n.info.in;
23216
- if ((!inp || inp.size === 0) && g.info.minset && n !== g.info.minset) {
23217
- const ref = nInEdge0(n) ?? nOutEdge0(n);
23218
- const e = virtualEdge(g.info.minset, n, ref);
23219
- e.info.minlen = slen0;
23220
- e.info.weight = 0;
23221
- 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;
23222
23013
  }
23223
- return false;
23014
+ return n;
23224
23015
  }
23225
- function minmaxEdges2(g, slen) {
23226
- if (!g.info.maxset && !g.info.minset) return false;
23227
- let added = false;
23228
- for (const n of nodesInSeq(g)) {
23229
- if (n !== ufFind(n)) continue;
23230
- if (mmEdges2CheckMax(g, n, slen[1])) added = true;
23231
- if (mmEdges2CheckMin(g, n, slen[0])) added = true;
23232
- }
23233
- 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 };
23234
23028
  }
23235
- function rank1(g) {
23236
- const nslimit1 = g.attrs.get("nslimit1") ?? g.graphDefaultsSnapshot?.get("nslimit1") ?? g.root.attrs.get("nslimit1");
23237
- const maxiter = nslimit1 ? scaleClamp(g.nodes.size, parseFloat(nslimit1)) : Number.MAX_SAFE_INTEGER;
23238
- const comp = g.info.comp ?? [];
23239
- const hasClusters = (g.info.n_cluster ?? 0) > 0;
23240
- for (let c = 0; c < comp.length; c++) {
23241
- g.info.nlist = comp[c];
23242
- rank(g, hasClusters ? 0 : 1, maxiter);
23243
- }
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;
23244
23045
  }
23245
- function expandNode(g, n) {
23246
- const leader = ufFind(n);
23247
- if (leader !== n) n.info.rank = nRank(n) + nRank(leader);
23248
- if (gMaxrankDef(g) < nRank(n)) g.info.maxrank = n.info.rank;
23249
- if (gMinrankDef(g) > nRank(n)) g.info.minrank = n.info.rank;
23250
- 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;
23251
23062
  }
23252
- function expandRankPostprocess(g) {
23253
- if (clType === LOCAL) {
23254
- const cl = gClust(g);
23255
- for (let c = 1; c <= gNCluster(g); c++) setMinmax(cl[c - 1]);
23256
- } else {
23257
- findClusters(g);
23258
- }
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;
23259
23071
  }
23260
- function expandRanksets(g) {
23261
- const first = g.nodes.values().next().value;
23262
- if (!first) {
23263
- g.info.minrank = 0;
23264
- g.info.maxrank = 0;
23265
- 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
+ }
23266
23094
  }
23267
- g.info.minrank = Number.MAX_SAFE_INTEGER;
23268
- g.info.maxrank = -1;
23269
- for (const n of nodesInSeq(g)) expandNode(g, n);
23270
- if (g === (g.info.dotroot ?? g.root)) expandRankPostprocess(g);
23095
+ if (obj !== null && saved > THIN_LINE) obj.penWidth = saved;
23096
+ return error;
23271
23097
  }
23272
- function dot1Rank(g) {
23273
- edgelabelRanks(g);
23274
- collapseSets(g, g);
23275
- class1(g);
23276
- const slen = minmaxEdges(g);
23277
- decompose(g, 0);
23278
- acyclic(g);
23279
- if (minmaxEdges2(g, slen)) decompose(g, 0);
23280
- rank1(g);
23281
- expandRanksets(g);
23282
- 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;
23283
23104
  }
23284
- function dotRank(g) {
23285
- if (mapbool2(g.attrs.get("newrank"))) {
23286
- g.info.flags = (g.info.flags ?? 0) | NEW_RANK;
23287
- dot2Rank(g);
23288
- } else {
23289
- 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
+ }
23290
23122
  }
23123
+ if (obj !== null && saved > THIN_LINE) obj.penWidth = saved;
23124
+ return error;
23291
23125
  }
23292
23126
 
23293
- // src/layout/dot/classify.ts
23294
- function portsEq(e, f) {
23295
- const ehp = e.info.head_port;
23296
- const fhp = f.info.head_port;
23297
- const etp = e.info.tail_port;
23298
- const ftp = f.info.tail_port;
23299
- const headMatch = ehp.p.x === fhp.p.x && ehp.p.y === fhp.p.y || !ehp.defined;
23300
- const tailMatch = etp.p.x === ftp.p.x && etp.p.y === ftp.p.y || !etp.defined;
23301
- return ehp.defined === fhp.defined && headMatch && tailMatch;
23302
- }
23303
- function nonconstraintEdge(e) {
23304
- return e.info.constraint === false;
23305
- }
23306
- var WNODE_ORDINARY = 0;
23307
- var WNODE_SINGLETON = 1;
23308
- var WNODE_VIRTUAL = 2;
23309
- var CLASSIFY_WEIGHT_TABLE = [[1, 1, 1], [1, 2, 2], [1, 2, 4]];
23310
- function epClass(n) {
23311
- if (n.info.node_type === VIRTUAL) return WNODE_VIRTUAL;
23312
- if ((n.info.weight_class ?? 2) <= 1) return WNODE_SINGLETON;
23313
- 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;
23314
23138
  }
23315
- function applyVirtualWeight(e) {
23316
- const t = CLASSIFY_WEIGHT_TABLE[epClass(e.tail)][epClass(e.head)];
23317
- 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;
23318
23144
  }
23319
- function interclust1TRank(e) {
23320
- const clust = e.tail.info.clust;
23321
- 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;
23322
23152
  }
23323
- function interclust1HRank(e) {
23324
- const clust = e.head.info.clust;
23325
- 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;
23326
23161
  }
23327
- function interclust1Lengths(e) {
23328
- const offset = (e.info.minlen ?? 1) + interclust1TRank(e) - interclust1HRank(e);
23329
- 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;
23330
23168
  }
23331
- function interclust1(g, t, h, e) {
23332
- const [tLen, hLen] = interclust1Lengths(e);
23333
- const v = virtualNode(g);
23334
- v.info.node_type = SLACKNODE;
23335
- const t0 = ufFind(t);
23336
- const h0 = ufFind(h);
23337
- const w = e.info.weight ?? 1;
23338
- const rt = makeAuxEdge(v, t0, tLen, CL_BACK * w);
23339
- const rh = makeAuxEdge(v, h0, hLen, w);
23340
- rt.info.to_orig = e;
23341
- rh.info.to_orig = e;
23169
+ function clusterStyle(sg) {
23170
+ return clusterAttr(sg, "style");
23342
23171
  }
23343
- function class1Edge(g, e) {
23344
- if (e.info.to_virt !== void 0) return;
23345
- if (nonconstraintEdge(e)) return;
23346
- const t = ufFind(e.tail);
23347
- const h = ufFind(e.head);
23348
- if (t === h) return;
23349
- if (t.info.clust || h.info.clust) {
23350
- interclust1(g, e.tail, e.head, e);
23351
- return;
23352
- }
23353
- const rep = findFastEdge(t, h);
23354
- if (rep !== void 0) mergeOneway(e, rep);
23355
- 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;
23356
23178
  }
23357
- function class1(g) {
23358
- markClusters(g);
23359
- for (const n of nodesInSeq(g)) {
23360
- for (const e of n.outEdges(g)) class1Edge(g, e);
23361
- }
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);
23362
23185
  }
23363
- function labelVnodeDimen(orig) {
23364
- const lbl = orig.info.label;
23365
- 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
+ };
23366
23196
  }
23367
- function labelVnode(g, orig) {
23368
- const dimen = labelVnodeDimen(orig);
23369
- const v = virtualNode(g);
23370
- v.info.label = orig.info.label;
23371
- v.info.lw = dotRoot(g).info.nodesep ?? 0;
23372
- if (!orig.info.label_ontop && dimen) {
23373
- const flip = dotRoot(g).info.flip === true;
23374
- v.info.ht = flip ? dimen.x : dimen.y;
23375
- v.info.rw = flip ? dimen.y : dimen.x;
23376
- }
23377
- 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
+ });
23378
23215
  }
23379
- function incrWidth(g, v) {
23380
- const width = Math.floor((g.info.nodesep ?? 0) / 2);
23381
- v.info.lw = (v.info.lw ?? 0) + width;
23382
- 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 + '"';
23383
23220
  }
23384
- function plainVnode(g) {
23385
- const v = virtualNode(g);
23386
- incrWidth(g, v);
23387
- return v;
23221
+ function svgNodeId(n, job) {
23222
+ return job.objId(n.attrs.get("id"), "node" + (n.id + 1));
23388
23223
  }
23389
- function leaderOf(v) {
23390
- if (v.info.ranktype !== CLUSTER) return ufFind(v);
23391
- 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);
23392
23226
  }
23393
- function chainVnode(g, orig, r, labelRank) {
23394
- if (r === labelRank) return labelVnode(g, orig);
23395
- return plainVnode(g);
23227
+ function svgClusterId(sg, job) {
23228
+ return job.objId(sg.attrs.get("id"), "clust" + sg.seq);
23396
23229
  }
23397
- function makeChain(g, from, to, orig) {
23398
- const labelRank = orig.info.label !== void 0 ? Math.floor(((from.info.rank ?? 0) + (to.info.rank ?? 0)) / 2) : -1;
23399
- let u = from;
23400
- const toRank = to.info.rank ?? 0;
23401
- for (let r = (from.info.rank ?? 0) + 1; r <= toRank; r++) {
23402
- const v = r < toRank ? (() => {
23403
- const n = chainVnode(g, orig, r, labelRank);
23404
- n.info.rank = r;
23405
- return n;
23406
- })() : to;
23407
- const e = virtualEdge(u, v, orig);
23408
- applyVirtualWeight(e);
23409
- u = v;
23410
- }
23230
+ function svgGraphId(g, job) {
23231
+ return job.objId(g.attrs.get("id"), "graph0", true);
23411
23232
  }
23412
- function nodeRank3(n) {
23413
- return n.info.rank ?? 0;
23233
+ function svgNodeClass(n) {
23234
+ return svgClass("node", nodeAttr(n, n.root, "class"));
23414
23235
  }
23415
- function edgeCount(e) {
23416
- return e.info.count ?? 1;
23236
+ function svgEdgeClass(e) {
23237
+ return svgClass("edge", e.attrs.get("class"));
23417
23238
  }
23418
- function edgeXpenalty(e) {
23419
- return e.info.xpenalty ?? 0;
23239
+ function svgClusterClass(sg) {
23240
+ return svgClass("cluster", clusterAttr(sg, "class"));
23420
23241
  }
23421
- function edgeWeight3(e) {
23422
- return e.info.weight ?? 1;
23242
+ function svgGraphClass(g) {
23243
+ return svgClass("graph", g.attrs.get("class"));
23423
23244
  }
23424
- function nextVirtEdge(e) {
23425
- return e.head.info.out?.list[0];
23245
+
23246
+ // src/common/poly-gencode.ts
23247
+ function isMulticolor(fillcolor) {
23248
+ return fillcolor.includes(":");
23426
23249
  }
23427
- function mergeChainStep(rep, e, updateCount) {
23428
- if (updateCount) rep.info.count = edgeCount(rep) + edgeCount(e);
23429
- rep.info.xpenalty = edgeXpenalty(rep) + edgeXpenalty(e);
23430
- rep.info.weight = edgeWeight3(rep) + edgeWeight3(e);
23431
- 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);
23432
23255
  }
23433
- function mergeChain(g, e, f, updateCount) {
23434
- const lastrank = Math.max(e.tail.info.rank ?? 0, e.head.info.rank ?? 0);
23435
- e.info.to_virt = f;
23436
- let rep = f;
23437
- while (rep !== void 0) {
23438
- if ((rep.head.info.rank ?? 0) === lastrank) {
23439
- mergeChainStep(rep, e, updateCount);
23440
- break;
23441
- }
23442
- incrWidth(g, rep.head);
23443
- 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);
23444
23269
  }
23270
+ if (ctx.diagonals) mcircleHack(ring, coord, ctx);
23445
23271
  }
23446
- function mergeable(e, f) {
23447
- if (!e || !f) return false;
23448
- 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);
23449
23276
  }
23450
- function interclrepChain(g, e, t, h) {
23451
- makeChain(g, t, h, e);
23452
- let cur = e.info.to_virt;
23453
- while (cur !== void 0 && nodeRank3(cur.head) <= nodeRank3(h)) {
23454
- cur.info.edge_type = CLUSTER_EDGE;
23455
- cur = cur.head.info.out?.list[0];
23456
- }
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);
23457
23283
  }
23458
- function interclrep(g, e) {
23459
- let t = leaderOf(e.tail);
23460
- let h = leaderOf(e.head);
23461
- if (nodeRank3(t) > nodeRank3(h)) {
23462
- const tmp = t;
23463
- t = h;
23464
- h = tmp;
23465
- }
23466
- if (t.info.clust === h.info.clust) return;
23467
- const ve = findFastEdge(t, h);
23468
- if (ve !== void 0) {
23469
- mergeChain(g, e, ve, true);
23470
- 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
+ }
23471
23296
  }
23472
- if (nodeRank3(t) === nodeRank3(h)) return;
23473
- interclrepChain(g, e, t, h);
23474
23297
  }
23475
- function isClusterEdge(e) {
23476
- 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
+ }
23477
23311
  }
23478
- function handleClusterMergeable(g, e, prev) {
23479
- if (prev.info.to_virt !== void 0) {
23480
- mergeChain(g, e, prev.info.to_virt, false);
23481
- otherEdge(e);
23482
- } else if ((e.tail.info.rank ?? 0) === (e.head.info.rank ?? 0)) {
23483
- mergeOneway(e, prev);
23484
- 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);
23485
23322
  }
23486
- return prev;
23487
23323
  }
23488
- function handleClusterEdge(g, e, prev) {
23489
- if (mergeable(prev, e)) return handleClusterMergeable(g, e, prev);
23490
- interclrep(g, e);
23491
- return e;
23324
+ function anchorAttr2(n, key) {
23325
+ const v = nodeAttr(n, n.root, key);
23326
+ return v !== void 0 && v !== "" ? v : void 0;
23492
23327
  }
23493
- function concentrateOrMerge(g, e, prev) {
23494
- if (dotRoot(g).info.concentrate ?? false) {
23495
- e.info.edge_type = IGNORED;
23496
- } else if (prev.info.to_virt !== void 0) {
23497
- mergeChain(g, e, prev.info.to_virt, true);
23498
- otherEdge(e);
23499
- }
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 ?? "";
23500
23332
  }
23501
- function handleMultiSameRank(e, prev) {
23502
- if ((e.tail.info.rank ?? 0) !== (e.head.info.rank ?? 0)) return false;
23503
- mergeOneway(e, prev);
23504
- 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
+ );
23505
23344
  return true;
23506
23345
  }
23507
- function handleMultiParallel(g, e, prev) {
23508
- if (e.info.label !== void 0 || prev.info.label !== void 0) return false;
23509
- if (!portsEq(e, prev)) return false;
23510
- concentrateOrMerge(g, e, prev);
23511
- 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;
23512
23352
  }
23513
- function handleMultiEdge(g, e, prev) {
23514
- if (!prev || e.tail !== prev.tail || e.head !== prev.head) return false;
23515
- if (handleMultiSameRank(e, prev)) return true;
23516
- return handleMultiParallel(g, e, prev);
23353
+ function isPointNode(n) {
23354
+ return n.info.shape?.kind === 3 /* SH_POINT */;
23517
23355
  }
23518
- function oppEdgeConcOrMerge(g, e, opp) {
23519
- if (e.info.label !== void 0 || opp.info.label !== void 0) return false;
23520
- if (!portsEq(e, opp)) return false;
23521
- if (dotRoot(g).info.concentrate ?? false) {
23522
- e.info.edge_type = IGNORED;
23523
- opp.info.conc_opp_flag = true;
23524
- } else {
23525
- otherEdge(e);
23526
- 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;
23379
+ }
23380
+ if (fillRes.kind === "solid") {
23381
+ obj.fill = 1 /* Solid */;
23382
+ obj.fillColor = resolveRenderColor(fillRes.color);
23383
+ return true;
23527
23384
  }
23385
+ applyGradientFields(obj, fillRes);
23528
23386
  return true;
23529
23387
  }
23530
- function tryOppEdge(g, e, opp) {
23531
- if (opp.head !== e.tail) return false;
23532
- if (opp.info.edge_type === IGNORED) return false;
23533
- if (opp.info.to_virt === void 0) makeChain(g, opp.tail, opp.head, opp);
23534
- 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);
23535
23394
  }
23536
- function handleBackEdge(g, e) {
23537
- for (const opp of e.head.outEdges(g)) {
23538
- if (tryOppEdge(g, e, opp)) return void 0;
23539
- }
23540
- makeChain(g, e.head, e.tail, e);
23541
- 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;
23542
23401
  }
23543
- function class2EdgeSameRep(g, e) {
23544
- if (nodeRank3(e.tail) === nodeRank3(e.head)) {
23545
- flatEdge(g, e);
23546
- 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;
23547
23411
  }
23548
- if (nodeRank3(e.head) > nodeRank3(e.tail)) {
23549
- makeChain(g, e.tail, e.head, e);
23550
- 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);
23551
23465
  }
23552
- return handleBackEdge(g, e);
23466
+ if (inAnchor) renderer.endAnchor?.(job);
23553
23467
  }
23554
- function class2OneEdge(g, e, prev) {
23555
- if (e.info.to_virt !== void 0) return e;
23556
- if (isClusterEdge(e)) return handleClusterEdge(g, e, prev);
23557
- if (handleMultiEdge(g, e, prev)) return prev;
23558
- if (e.tail === e.head) {
23559
- otherEdge(e);
23560
- 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));
23561
23484
  }
23562
- const t = ufFind(e.tail);
23563
- const h = ufFind(e.head);
23564
- if (e.tail !== t || e.head !== h) return prev;
23565
- return class2EdgeSameRep(g, e);
23485
+ return { w: 2 * xmax, h: 2 * ymax };
23566
23486
  }
23567
- function class2ProcessNodeEdges(g, oes) {
23568
- let prev;
23569
- for (const e of oes) {
23570
- const next = class2OneEdge(g, e, prev);
23571
- 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
+ };
23572
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
+ };
23573
23515
  }
23574
- function weightClass(n) {
23575
- 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;
23576
23536
  }
23577
- function incrWeightClass(n) {
23578
- 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);
23579
23548
  }
23580
- function class2WeightClasses(g) {
23581
- for (const e of g.edges) {
23582
- incrWeightClass(e.head);
23583
- 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;
23584
23557
  }
23558
+ const poly = n.info.shape_info;
23559
+ if (poly === void 0 || poly.vertices === null) return false;
23560
+ return insideShape(n, poly, P);
23585
23561
  }
23586
- function class2ProcessNodes(g) {
23587
- const outIdx = buildOutEdgeIndex(g);
23588
- for (const n of nodesInSeq(g)) {
23589
- if (n.info.clust === void 0 && n === ufFind(n)) fastNode(g, n);
23590
- 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;
23591
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;
23584
+ }
23585
+ return true;
23592
23586
  }
23593
- function class2(g) {
23594
- g.info.nlist = void 0;
23595
- markClusters(g);
23596
- const nClust = g.info.n_cluster ?? 0;
23597
- for (let c = 1; c <= nClust; c++) buildSkeleton(g, g.info.clust[c - 1]);
23598
- class2WeightClasses(g);
23599
- class2ProcessNodes(g);
23600
- 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;
23601
23602
  }
23602
23603
 
23603
23604
  // src/common/edge-label-init.ts
@@ -32134,31 +32135,13 @@ function splay(root, key, keyOf, compare) {
32134
32135
  }
32135
32136
 
32136
32137
  // src/cdt/bag.ts
32137
- function findByIdentity(start, target, key, keyOf, compare) {
32138
- let cur = start;
32139
- let parent = null;
32140
- while (cur !== null) {
32141
- if (cur.obj === target) return [cur, parent];
32142
- if (compare(key, keyOf(cur.obj)) !== 0) return [null, null];
32143
- parent = cur;
32144
- cur = cur.left;
32145
- }
32146
- return [null, null];
32147
- }
32148
- function unlinkNode(root, cur, parent) {
32149
- const left = cur.left;
32150
- const right = cur.right;
32151
- let replacement;
32152
- if (left === null) {
32153
- replacement = right;
32154
- } else {
32155
- const maxLeft = splayMax(left);
32156
- maxLeft.right = right;
32157
- replacement = maxLeft;
32158
- }
32159
- if (parent === null) return replacement;
32160
- parent.left = replacement;
32161
- 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;
32162
32145
  }
32163
32146
  var DtBag = class {
32164
32147
  _root = null;
@@ -32197,16 +32180,13 @@ var DtBag = class {
32197
32180
  const key = this._keyOf(obj);
32198
32181
  this._root = splay(this._root, key, this._keyOf, this._compare);
32199
32182
  if (this._compare(key, this._keyOf(this._root.obj)) !== 0) return false;
32200
- const [cur, parent] = findByIdentity(
32201
- this._root,
32202
- obj,
32203
- key,
32204
- this._keyOf,
32205
- this._compare
32206
- );
32207
- if (cur === null) return false;
32208
- const newRoot = unlinkNode(this._root, cur, parent);
32209
- 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);
32210
32190
  this._size--;
32211
32191
  return true;
32212
32192
  }
@@ -52489,7 +52469,7 @@ var XdotParser = class _XdotParser {
52489
52469
  let accounted = 0;
52490
52470
  let j = 0;
52491
52471
  while (accounted < len) {
52492
- if (cur + j >= s.length) break;
52472
+ if (cur + j >= s.length) return null;
52493
52473
  const ch = s[cur + j];
52494
52474
  const prev = j > 0 ? s[cur + j - 1] : "";
52495
52475
  out += ch;