@knowvah/dot-engine 2.4.0 → 2.5.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knowvah/dot-engine",
3
- "version": "2.4.0",
3
+ "version": "2.5.0",
4
4
  "description": "Faithful TypeScript port of Graphviz (dot, neato, fdp, sfdp, circo, twopi, osage, patchwork) — no C: no native binary, no WASM. Oracle-verified against the C implementation, runs in the browser.",
5
5
  "keywords": [
6
6
  "graphviz",
@@ -17,6 +17,7 @@ import type { PackInfo } from './types.js';
17
17
  import { spiralSearch } from './spiral-search.js';
18
18
  import { gvQsort } from '../../util/bsd-qsort.js';
19
19
  import { cround } from '../../common/arith.js';
20
+ import { d2i } from '../../util/math.js';
20
21
 
21
22
  /** Max average polyomino size constant. @see lib/pack/pack.c:C */
22
23
  const C = 100;
@@ -73,18 +74,27 @@ export function computeStep(ng: number, bbs: Box[], margin: number): number {
73
74
  c -= W * H;
74
75
  }
75
76
  const d = b * b - 4.0 * a * c;
76
- if (d < 0) return 1;
77
- const root = Math.floor((-b + Math.sqrt(d)) / (2 * a));
78
- return root <= 0 ? 1 : root;
77
+ // C `assert(d >= 0)` is compiled out of the Release oracle, so a negative d
78
+ // gives r = NaN. `root = (int)l1` is `fcvtzs w` in the native arm64 build
79
+ // (objdump of libgvc `_computeStep`): NaN converts to 0, and out-of-range
80
+ // values saturate at INT_MAX/INT_MIN (1314: l1 = 7.4e10 → step INT_MAX).
81
+ const r = Math.sqrt(d);
82
+ const l1 = (-b + r) / (2 * a);
83
+ let root = Number.isNaN(l1) ? 0 : d2i(l1);
84
+ if (root === 0) root = 1;
85
+ return root;
79
86
  }
80
87
 
81
88
  /**
82
89
  * Number of grid cells required to cover length x at cell size s.
83
90
  *
91
+ * C `(int)ceil(x / s)` is `fcvtps w` in the native arm64 build (objdump of
92
+ * libgvc `_genBox`, `_placeGraph`), which saturates at INT_MAX.
93
+ *
84
94
  * @see lib/pack/pack.c:GRID
85
95
  */
86
96
  export function gridCells(x: number, s: number): number {
87
- return Math.ceil(x / s);
97
+ return d2i(Math.ceil(x / s));
88
98
  }
89
99
 
90
100
  /**
@@ -188,9 +198,12 @@ export function fits(x: number, y: number, info: GInfo, ctx: PlaceCtx): Point |
188
198
  // twopi/sfdp), so a `.5` LL is ordinary and Math.round would translate the
189
199
  // whole placed component by 1pt.
190
200
  // @see lib/pack/pack.c:435-438 (fits: `const pointf LL = {.x = round(...)}`)
201
+ // C `step * x` is int * int: a 32-bit `mul w` that wraps before the result
202
+ // is widened to double (objdump of libgvc `_fits`). Matters only once
203
+ // computeStep has saturated at INT_MAX.
191
204
  const place: Point = {
192
- x: ctx.step * x - cround(bb.ll.x),
193
- y: ctx.step * y - cround(bb.ll.y),
205
+ x: Math.imul(ctx.step, x) - cround(bb.ll.x),
206
+ y: Math.imul(ctx.step, y) - cround(bb.ll.y),
194
207
  };
195
208
  markCells(info.cells, x, y, ctx.ps);
196
209
  return place;