@knowvah/dot-engine 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/dist/common/arith.d.ts +12 -0
  2. package/dist/common/arith.d.ts.map +1 -1
  3. package/dist/common/edge-in-box.d.ts +31 -0
  4. package/dist/common/edge-in-box.d.ts.map +1 -0
  5. package/dist/common/htmltable-emit.d.ts +1 -1
  6. package/dist/common/htmltable-emit.d.ts.map +1 -1
  7. package/dist/common/make-label.d.ts +3 -1
  8. package/dist/common/make-label.d.ts.map +1 -1
  9. package/dist/common/poly-gencode.d.ts +12 -1
  10. package/dist/common/poly-gencode.d.ts.map +1 -1
  11. package/dist/gvc/device.d.ts.map +1 -1
  12. package/dist/gvc/emit-gates.d.ts +35 -0
  13. package/dist/gvc/emit-gates.d.ts.map +1 -0
  14. package/dist/gvc/job.d.ts +4 -0
  15. package/dist/gvc/job.d.ts.map +1 -1
  16. package/dist/gvc/viewport.d.ts +13 -0
  17. package/dist/gvc/viewport.d.ts.map +1 -1
  18. package/dist/index.js +1030 -742
  19. package/dist/index.js.map +4 -4
  20. package/dist/layout/circo/blockpath.d.ts +1 -38
  21. package/dist/layout/circo/blockpath.d.ts.map +1 -1
  22. package/dist/layout/circo/crossings.d.ts +59 -0
  23. package/dist/layout/circo/crossings.d.ts.map +1 -0
  24. package/dist/layout/dot/edge-route-chain.d.ts +5 -3
  25. package/dist/layout/dot/edge-route-chain.d.ts.map +1 -1
  26. package/dist/layout/dot/edge-route.d.ts.map +1 -1
  27. package/dist/layout/dot/index.d.ts +10 -2
  28. package/dist/layout/dot/index.d.ts.map +1 -1
  29. package/dist/layout/dot/ortho-adapter.d.ts +7 -3
  30. package/dist/layout/dot/ortho-adapter.d.ts.map +1 -1
  31. package/dist/layout/dot/pack-components.d.ts +4 -1
  32. package/dist/layout/dot/pack-components.d.ts.map +1 -1
  33. package/dist/layout/dot/splines-flat-multi.d.ts +7 -5
  34. package/dist/layout/dot/splines-flat-multi.d.ts.map +1 -1
  35. package/dist/layout/dot/splines-flat.d.ts +2 -13
  36. package/dist/layout/dot/splines-flat.d.ts.map +1 -1
  37. package/dist/layout/dot/splines-route.d.ts.map +1 -1
  38. package/dist/layout/neato/constraint-adjust.d.ts +32 -0
  39. package/dist/layout/neato/constraint-adjust.d.ts.map +1 -1
  40. package/dist/layout/neato/multispline.d.ts.map +1 -1
  41. package/dist/layout/neato/splines.d.ts.map +1 -1
  42. package/dist/layout/pack/poly-place.d.ts.map +1 -1
  43. package/dist/layout/sfdp/__fixtures__/pcp-rotate-native.d.ts +23 -0
  44. package/dist/layout/sfdp/__fixtures__/pcp-rotate-native.d.ts.map +1 -0
  45. package/dist/layout/sfdp/spring-driver.d.ts +6 -0
  46. package/dist/layout/sfdp/spring-driver.d.ts.map +1 -1
  47. package/dist/ortho/index.d.ts +4 -1
  48. package/dist/ortho/index.d.ts.map +1 -1
  49. package/dist/ortho/maze.d.ts +5 -2
  50. package/dist/ortho/maze.d.ts.map +1 -1
  51. package/dist/ortho/partition.d.ts +8 -1
  52. package/dist/ortho/partition.d.ts.map +1 -1
  53. package/dist/ortho/trap-segment.d.ts +2 -1
  54. package/dist/ortho/trap-segment.d.ts.map +1 -1
  55. package/dist/ortho/trapezoid.d.ts.map +1 -1
  56. package/dist/parser/index.d.ts +0 -7
  57. package/dist/parser/index.d.ts.map +1 -1
  58. package/dist/parser/number-scan.d.ts +31 -0
  59. package/dist/parser/number-scan.d.ts.map +1 -0
  60. package/dist/pathplan/route.d.ts.map +1 -1
  61. package/dist/pathplan/solvers.d.ts +15 -3
  62. package/dist/pathplan/solvers.d.ts.map +1 -1
  63. package/dist/render/dot/edge-draw.d.ts +12 -0
  64. package/dist/render/dot/edge-draw.d.ts.map +1 -1
  65. package/dist/render/svg-graph.d.ts +6 -5
  66. package/dist/render/svg-graph.d.ts.map +1 -1
  67. package/dist/render/svg.d.ts +2 -21
  68. package/dist/render/svg.d.ts.map +1 -1
  69. package/dist/render.js +1030 -742
  70. package/dist/render.js.map +4 -4
  71. package/dist/xdot/parse.d.ts.map +1 -1
  72. package/package.json +1 -1
  73. package/src/common/arith.ts +25 -0
  74. package/src/common/edge-in-box.ts +54 -0
  75. package/src/common/graph-init.ts +3 -3
  76. package/src/common/htmltable-emit.ts +4 -2
  77. package/src/common/make-label.ts +3 -1
  78. package/src/common/poly-gencode.ts +18 -4
  79. package/src/gvc/device.ts +8 -41
  80. package/src/gvc/edge-labels.ts +30 -13
  81. package/src/gvc/emit-gates.ts +89 -0
  82. package/src/gvc/job.ts +4 -0
  83. package/src/gvc/viewport.ts +29 -0
  84. package/src/layout/circo/blockpath.ts +6 -125
  85. package/src/layout/circo/crossings.ts +171 -0
  86. package/src/layout/dot/__fixtures__/2784.dot +1 -0
  87. package/src/layout/dot/__fixtures__/2784.native-16.1.svg +48 -0
  88. package/src/layout/dot/edge-route-chain.ts +11 -5
  89. package/src/layout/dot/edge-route.ts +19 -8
  90. package/src/layout/dot/index.ts +14 -4
  91. package/src/layout/dot/ortho-adapter.ts +11 -6
  92. package/src/layout/dot/pack-components.ts +11 -4
  93. package/src/layout/dot/splines-flat-multi.ts +21 -8
  94. package/src/layout/dot/splines-flat.ts +8 -35
  95. package/src/layout/dot/splines-route.ts +10 -2
  96. package/src/layout/dot/splines.ts +6 -6
  97. package/src/layout/neato/constraint-adjust.ts +10 -4
  98. package/src/layout/neato/multispline.ts +26 -9
  99. package/src/layout/neato/splines.ts +7 -7
  100. package/src/layout/pack/poly-place.ts +9 -2
  101. package/src/layout/sfdp/__fixtures__/pcp-rotate-native.ts +94 -0
  102. package/src/layout/sfdp/spring-driver.ts +45 -13
  103. package/src/ortho/index.ts +22 -13
  104. package/src/ortho/maze.ts +8 -2
  105. package/src/ortho/partition.ts +17 -2
  106. package/src/ortho/trap-segment.ts +47 -24
  107. package/src/ortho/trapezoid.ts +24 -15
  108. package/src/parser/dot.js +345 -380
  109. package/src/parser/dot.pegjs +25 -10
  110. package/src/parser/index.ts +15 -0
  111. package/src/parser/number-scan.ts +118 -0
  112. package/src/pathplan/route.ts +79 -34
  113. package/src/pathplan/solvers.ts +78 -50
  114. package/src/render/dot/edge-draw.ts +25 -0
  115. package/src/render/svg-graph.ts +77 -47
  116. package/src/render/svg-helpers.ts +2 -2
  117. package/src/render/svg.ts +4 -41
  118. package/src/xdot/parse.ts +19 -5
@@ -198,6 +198,7 @@ export function swapSegEndpoints(s: SegmentT): void {
198
198
 
199
199
  /**
200
200
  * Insert one segment into the trapezoidation.
201
+ * @returns 0 on success, -1 when threading met an invalid trapezoid (16.1)
201
202
  * @see lib/ortho/trapezoid.c:add_segment
202
203
  */
203
204
  export function addSegment(
@@ -205,7 +206,7 @@ export function addSegment(
205
206
  seg: SegmentT[],
206
207
  tr: TrapT[],
207
208
  qs: QNode[],
208
- ): void {
209
+ ): number {
209
210
  const s = { ...seg[segnum] };
210
211
  let isSwapped = false;
211
212
  if (greaterThanOrEq(s.v1, s.v0) && !equalTo(s.v1, s.v0)) {
@@ -214,31 +215,49 @@ export function addSegment(
214
215
  isSwapped = true;
215
216
  }
216
217
 
217
- let tfirst: number;
218
- if (!inserted(segnum, seg, isSwapped ? LASTPT : FIRSTPT)) {
219
- tfirst = insertV0(s, seg, tr, qs, segnum);
220
- } else {
221
- tfirst = locateEndpoint(s.v0, s.v1, s.root0, seg, qs);
222
- }
218
+ const ctx: ThreadCtx = { s, seg, tr, qs, segnum, tribot: false, isSwapped };
219
+ const tfirst = firstTrap(ctx);
220
+ const tlast = lastTrap(ctx);
221
+ if (threadSegment(ctx, tfirst, tlast) !== 0) return -1;
222
+ seg[segnum].isInserted = true;
223
+ return 0;
224
+ }
223
225
 
224
- let tlast: number;
225
- let tribot = false;
226
- if (!inserted(segnum, seg, isSwapped ? FIRSTPT : LASTPT)) {
227
- tlast = insertV1(s, seg, tr, qs, segnum);
228
- } else {
229
- tlast = locateEndpoint(s.v1, s.v0, s.root1, seg, qs);
230
- tribot = true;
226
+ /** add_segment locals the threading loop reads (one C stack frame). */
227
+ interface ThreadCtx {
228
+ s: SegmentT; seg: SegmentT[]; tr: TrapT[]; qs: QNode[];
229
+ segnum: number; tribot: boolean; isSwapped: boolean;
230
+ }
231
+
232
+ /** add_segment: insert v0 in the tree, or locate it if already present. */
233
+ function firstTrap(c: ThreadCtx): number {
234
+ if (!inserted(c.segnum, c.seg, c.isSwapped ? LASTPT : FIRSTPT)) {
235
+ return insertV0(c.s, c.seg, c.tr, c.qs, c.segnum);
231
236
  }
237
+ return locateEndpoint(c.s.v0, c.s.v1, c.s.root0, c.seg, c.qs);
238
+ }
232
239
 
233
- threadSegment(s, seg, tr, qs, segnum, tfirst, tlast, tribot, isSwapped);
234
- seg[segnum].isInserted = true;
240
+ /**
241
+ * add_segment: insert v1 in the tree, or (v1 already present) get the
242
+ * lowermost intersecting trapezoid and mark the bottom as a triangle.
243
+ */
244
+ function lastTrap(c: ThreadCtx): number {
245
+ if (!inserted(c.segnum, c.seg, c.isSwapped ? FIRSTPT : LASTPT)) {
246
+ return insertV1(c.s, c.seg, c.tr, c.qs, c.segnum);
247
+ }
248
+ c.tribot = true;
249
+ return locateEndpoint(c.s.v1, c.s.v0, c.s.root1, c.seg, c.qs);
235
250
  }
236
251
 
237
- function threadSegment(
238
- s: SegmentT, seg: SegmentT[], tr: TrapT[], qs: QNode[],
239
- segnum: number, tfirst: number, tlast: number,
240
- tribot: boolean, isSwapped: boolean,
241
- ): void {
252
+ /**
253
+ * Split every trapezoid s crosses, top to bottom, then merge both sides.
254
+ * Returns -1 (after C's stderr line) when a crossed trapezoid has no valid
255
+ * lower neighbour — graphviz 16.1 (3c01aaeb4) returns from add_segment there;
256
+ * 15.x printed "add_segment: error" and broke out of the loop.
257
+ * @see lib/ortho/trapezoid.c:add_segment (threading loop)
258
+ */
259
+ function threadSegment(c: ThreadCtx, tfirst: number, tlast: number): number {
260
+ const { s, seg, tr, qs, segnum, tribot, isSwapped } = c;
242
261
  let tfirstr = INVALID_TRAP;
243
262
  let tlastr = INVALID_TRAP;
244
263
  let t = tfirst;
@@ -258,12 +277,17 @@ function threadSegment(
258
277
  if (equalTo(tr[t].lo, tr[tlast].lo)) tlastr = tn;
259
278
 
260
279
  const tSav = t; const tnSav = tn;
280
+ if (!isValidTrap(tr[t].d0) && !isValidTrap(tr[t].d1)) { // error
281
+ console.error("trapezoid segment construction failed");
282
+ return -1;
283
+ }
261
284
  t = advanceT(s, seg, tr, t, tn, tlast, segnum, isSwapped, tribot);
262
285
  tr[tSav].rseg = segnum; tr[tnSav].lseg = segnum;
263
286
  }
264
287
 
265
288
  mergeTrapezoids(segnum, tfirst, tlast, S_LEFT, tr, qs);
266
289
  mergeTrapezoids(segnum, tfirstr, tlastr, S_RIGHT, tr, qs);
290
+ return 0;
267
291
  }
268
292
 
269
293
  function advanceT(
@@ -271,9 +295,8 @@ function advanceT(
271
295
  t: number, tn: number, tlast: number,
272
296
  segnum: number, isSwapped: boolean, tribot: boolean,
273
297
  ): number {
274
- if (!isValidTrap(tr[t].d0) && !isValidTrap(tr[t].d1)) {
275
- return INVALID_TRAP; // error
276
- } else if (isValidTrap(tr[t].d0) && !isValidTrap(tr[t].d1)) {
298
+ // The "neither below is valid" error case returns from threadSegment first.
299
+ if (isValidTrap(tr[t].d0) && !isValidTrap(tr[t].d1)) {
277
300
  handleD0Only(s, seg, tr, t, tn, tlast, segnum, isSwapped, tribot);
278
301
  return tr[t].d0;
279
302
  } else if (!isValidTrap(tr[t].d0) && isValidTrap(tr[t].d1)) {
@@ -31,29 +31,20 @@ export function constructTrapezoids(
31
31
  permute: number[],
32
32
  ): TrapT[] {
33
33
  const qs: QNode[] = [];
34
- const tr: TrapT[] = [];
35
- // index 0 is a sentinel (invalid trap)
36
- tr.push({
37
- lseg: 0, rseg: 0,
38
- hi: { x: 0, y: 0 }, lo: { x: 0, y: 0 },
39
- u0: 0, u1: 0, d0: 0, d1: 0,
40
- sink: 0, usave: 0, uside: 0, isValid: false,
41
- });
34
+ const tr: TrapT[] = [sentinelTrap()];
42
35
 
43
36
  let segi = 0;
44
37
  const root = initQueryStructure(permute[segi++], seg, tr, qs);
38
+ seedRoots(nseg, seg, root);
45
39
 
46
- for (let i = 1; i <= nseg; i++) {
47
- seg[i].root0 = root;
48
- seg[i].root1 = root;
49
- }
50
-
40
+ // C (16.1, 3660b260e): an add_segment failure LIST_FREEs the trapezoid list
41
+ // and jumps to `done`, so the caller receives an EMPTY list.
51
42
  const logstar = mathLogstarN(nseg);
52
43
  for (let h = 1; h <= logstar; h++) {
53
44
  const lo = mathN(nseg, h - 1) + 1;
54
45
  const hi = mathN(nseg, h);
55
46
  for (let i = lo; i <= hi; i++) {
56
- addSegment(permute[segi++], seg, tr, qs);
47
+ if (addSegment(permute[segi++], seg, tr, qs) !== 0) return [];
57
48
  }
58
49
  for (let i = 1; i <= nseg; i++) {
59
50
  findNewRoots(i, seg, tr, qs);
@@ -62,12 +53,30 @@ export function constructTrapezoids(
62
53
 
63
54
  const remaining = mathN(nseg, logstar) + 1;
64
55
  for (let i = remaining; i <= nseg; i++) {
65
- addSegment(permute[segi++], seg, tr, qs);
56
+ if (addSegment(permute[segi++], seg, tr, qs) !== 0) return [];
66
57
  }
67
58
 
68
59
  return tr;
69
60
  }
70
61
 
62
+ /** Index 0 of the trapezoid list is a sentinel (invalid trap). */
63
+ function sentinelTrap(): TrapT {
64
+ return {
65
+ lseg: 0, rseg: 0,
66
+ hi: { x: 0, y: 0 }, lo: { x: 0, y: 0 },
67
+ u0: 0, u1: 0, d0: 0, d1: 0,
68
+ sink: 0, usave: 0, uside: 0, isValid: false,
69
+ };
70
+ }
71
+
72
+ /** construct_trapezoids: every segment starts at the initial query root. */
73
+ function seedRoots(nseg: number, seg: SegmentT[], root: number): void {
74
+ for (let i = 1; i <= nseg; i++) {
75
+ seg[i].root0 = root;
76
+ seg[i].root1 = root;
77
+ }
78
+ }
79
+
71
80
  // ─── init_query_structure ─────────────────────────────────────────────────────
72
81
 
73
82
  import {