@knowvah/dot-engine 2.6.3 → 2.6.5
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/common/arrows-shapes-poly.d.ts.map +1 -1
- package/dist/common/bezier.d.ts +12 -0
- package/dist/common/bezier.d.ts.map +1 -0
- package/dist/common/htmltable-attr-warn.d.ts +41 -0
- package/dist/common/htmltable-attr-warn.d.ts.map +1 -0
- package/dist/common/htmltable-fontinfo.d.ts +42 -0
- package/dist/common/htmltable-fontinfo.d.ts.map +1 -0
- package/dist/common/htmltable-lex-expat.d.ts +63 -0
- package/dist/common/htmltable-lex-expat.d.ts.map +1 -0
- package/dist/common/htmltable-lex-units.d.ts +32 -0
- package/dist/common/htmltable-lex-units.d.ts.map +1 -0
- package/dist/common/htmltable-lex.d.ts +10 -2
- package/dist/common/htmltable-lex.d.ts.map +1 -1
- package/dist/common/htmltable-parse-attrs.d.ts +7 -5
- package/dist/common/htmltable-parse-attrs.d.ts.map +1 -1
- package/dist/common/htmltable-parse-font.d.ts +33 -0
- package/dist/common/htmltable-parse-font.d.ts.map +1 -0
- package/dist/common/htmltable-parse-state.d.ts +39 -0
- package/dist/common/htmltable-parse-state.d.ts.map +1 -0
- package/dist/common/htmltable-parse.d.ts +18 -23
- package/dist/common/htmltable-parse.d.ts.map +1 -1
- package/dist/common/htmltable-pos.d.ts.map +1 -1
- package/dist/common/htmltable-types.d.ts +33 -3
- package/dist/common/htmltable-types.d.ts.map +1 -1
- package/dist/common/htmltable.d.ts +3 -2
- package/dist/common/htmltable.d.ts.map +1 -1
- package/dist/common/spline-midpoint.d.ts.map +1 -1
- package/dist/common/splines-geom.d.ts +5 -6
- package/dist/common/splines-geom.d.ts.map +1 -1
- package/dist/common/splines-routespl.d.ts.map +1 -1
- package/dist/common/taper.d.ts.map +1 -1
- package/dist/gvc/anchor.d.ts.map +1 -1
- package/dist/index.js +1366 -648
- package/dist/index.js.map +4 -4
- package/dist/layout/dot/compound-clip.d.ts +5 -5
- package/dist/layout/dot/compound-clip.d.ts.map +1 -1
- package/dist/layout/dot/compound-geom.d.ts +2 -7
- package/dist/layout/dot/compound-geom.d.ts.map +1 -1
- package/dist/layout/dot/compound.d.ts +1 -1
- package/dist/layout/dot/compound.d.ts.map +1 -1
- package/dist/layout/dot/edge-route-clip.d.ts +1 -1
- package/dist/layout/dot/edge-route-clip.d.ts.map +1 -1
- package/dist/layout/dot/ortho-adapter.d.ts +13 -4
- package/dist/layout/dot/ortho-adapter.d.ts.map +1 -1
- package/dist/layout/dot/splines-flat-labeled.d.ts.map +1 -1
- package/dist/layout/dot/splines-label.d.ts.map +1 -1
- package/dist/layout/neato/bfs.d.ts +10 -3
- package/dist/layout/neato/bfs.d.ts.map +1 -1
- package/dist/layout/neato/init.d.ts +6 -11
- package/dist/layout/neato/init.d.ts.map +1 -1
- package/dist/layout/neato/splines.d.ts.map +1 -1
- package/dist/parser/index.d.ts.map +1 -1
- package/dist/parser/scan-token.d.ts +40 -0
- package/dist/parser/scan-token.d.ts.map +1 -0
- package/dist/render/svg-edge-split.d.ts.map +1 -1
- package/dist/render.js +1388 -670
- package/dist/render.js.map +4 -4
- package/package.json +1 -1
- package/src/common/arrows-shapes-poly.ts +9 -10
- package/src/common/bezier.ts +33 -0
- package/src/common/htmltable-attr-warn.ts +270 -0
- package/src/common/htmltable-fontinfo.ts +83 -0
- package/src/common/htmltable-lex-expat.ts +357 -0
- package/src/common/htmltable-lex-units.ts +75 -0
- package/src/common/htmltable-lex.ts +221 -160
- package/src/common/htmltable-parse-attrs.ts +10 -14
- package/src/common/htmltable-parse-font.ts +92 -0
- package/src/common/htmltable-parse-state.ts +64 -0
- package/src/common/htmltable-parse.ts +138 -98
- package/src/common/htmltable-pos.ts +9 -8
- package/src/common/htmltable-types.ts +35 -3
- package/src/common/htmltable.ts +14 -7
- package/src/common/spline-midpoint.ts +2 -22
- package/src/common/splines-geom.ts +5 -25
- package/src/common/splines-routespl.ts +21 -13
- package/src/common/taper.ts +2 -14
- package/src/gvc/anchor.ts +5 -14
- package/src/layout/dot/__fixtures__/2796-flat-labeled-lost.dot +161 -0
- package/src/layout/dot/compound-clip.ts +9 -19
- package/src/layout/dot/compound-geom.ts +6 -23
- package/src/layout/dot/compound.ts +1 -1
- package/src/layout/dot/edge-route-clip.ts +6 -29
- package/src/layout/dot/ortho-adapter.ts +5 -5
- package/src/layout/dot/splines-flat-labeled.ts +3 -1
- package/src/layout/dot/splines-label.ts +3 -29
- package/src/layout/neato/bfs.ts +13 -4
- package/src/layout/neato/init.ts +15 -15
- package/src/layout/neato/splines.ts +4 -8
- package/src/parser/index.ts +13 -1
- package/src/parser/scan-token.ts +289 -0
- package/src/render/svg-edge-split.ts +5 -13
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import type { Point, Box } from '../model/geom.js';
|
|
12
|
+
import { bezier as evalBezier } from './bezier.js';
|
|
12
13
|
|
|
13
14
|
// ---------------------------------------------------------------------------
|
|
14
15
|
// Approximate equality
|
|
@@ -29,33 +30,12 @@ export function approxEqPt(p: Point, q: Point, tol: number): boolean {
|
|
|
29
30
|
// ---------------------------------------------------------------------------
|
|
30
31
|
|
|
31
32
|
/**
|
|
32
|
-
* Evaluates cubic Bezier sp[] at parameter t
|
|
33
|
-
*
|
|
34
|
-
* When right !== null, fills right[0..3] with the right subdivision.
|
|
35
|
-
* Returns the point on the curve.
|
|
33
|
+
* Evaluates cubic Bezier sp[] at parameter t (left/right fill as in C): the
|
|
34
|
+
* shared fused bezier(), re-exported under the name this module's callers use.
|
|
36
35
|
*
|
|
37
|
-
* @see lib/common/
|
|
36
|
+
* @see lib/common/utils.c:Bezier
|
|
38
37
|
*/
|
|
39
|
-
export
|
|
40
|
-
sp: Point[],
|
|
41
|
-
t: number,
|
|
42
|
-
left: Point[] | null,
|
|
43
|
-
right: Point[] | null,
|
|
44
|
-
): Point {
|
|
45
|
-
const ab: Point = { x: sp[0].x + t * (sp[1].x - sp[0].x), y: sp[0].y + t * (sp[1].y - sp[0].y) };
|
|
46
|
-
const bc: Point = { x: sp[1].x + t * (sp[2].x - sp[1].x), y: sp[1].y + t * (sp[2].y - sp[1].y) };
|
|
47
|
-
const cd: Point = { x: sp[2].x + t * (sp[3].x - sp[2].x), y: sp[2].y + t * (sp[3].y - sp[2].y) };
|
|
48
|
-
const abbc: Point = { x: ab.x + t * (bc.x - ab.x), y: ab.y + t * (bc.y - ab.y) };
|
|
49
|
-
const bccd: Point = { x: bc.x + t * (cd.x - bc.x), y: bc.y + t * (cd.y - bc.y) };
|
|
50
|
-
const pt: Point = { x: abbc.x + t * (bccd.x - abbc.x), y: abbc.y + t * (bccd.y - abbc.y) };
|
|
51
|
-
if (left !== null) {
|
|
52
|
-
left[0] = sp[0]; left[1] = ab; left[2] = abbc; left[3] = pt;
|
|
53
|
-
}
|
|
54
|
-
if (right !== null) {
|
|
55
|
-
right[0] = pt; right[1] = bccd; right[2] = cd; right[3] = sp[3];
|
|
56
|
-
}
|
|
57
|
-
return pt;
|
|
58
|
-
}
|
|
38
|
+
export { evalBezier };
|
|
59
39
|
|
|
60
40
|
// ---------------------------------------------------------------------------
|
|
61
41
|
// Bounding box update
|
|
@@ -14,6 +14,7 @@ import type { Path } from './types.js';
|
|
|
14
14
|
import { shortestPath, routeSpline, makePolyline } from '../pathplan/index.js';
|
|
15
15
|
import type { Poly } from '../pathplan/types.js';
|
|
16
16
|
import { INIT_DELTA, LOOP_TRIES, ROUTESPL_FUDGE } from './splines-constants.js';
|
|
17
|
+
import { fma } from './fma.js';
|
|
17
18
|
|
|
18
19
|
// ---------------------------------------------------------------------------
|
|
19
20
|
// Stage-dump hook (diagnosis only; null in production — same pattern as
|
|
@@ -193,21 +194,28 @@ export function checkPath(boxn: number, boxes: Box[], pp: Path): boolean {
|
|
|
193
194
|
// limitBoxes helpers
|
|
194
195
|
// ---------------------------------------------------------------------------
|
|
195
196
|
|
|
196
|
-
/**
|
|
197
|
+
/** C's inlined de Casteljau: `sp[k].x += t * (sp[k+1].x - sp[k].x)`, which clang
|
|
198
|
+
* contracts to fma(t, b - a, a) (oracle `_limitBoxes`: fsub + fmadd, x12). Not
|
|
199
|
+
* utils.c:Bezier's form, so it does not use the shared bezier().
|
|
200
|
+
* @see lib/common/routespl.c:limitBoxes (lines 251-262)
|
|
201
|
+
*/
|
|
197
202
|
function deCasteljauPoint(
|
|
198
203
|
p0: Point, p1: Point, p2: Point, p3: Point, t: number,
|
|
199
204
|
): Point {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
205
|
+
let s0x = p0.x, s0y = p0.y, s1x = p1.x, s1y = p1.y, s2x = p2.x, s2y = p2.y;
|
|
206
|
+
s0x = fma(t, s1x - s0x, s0x);
|
|
207
|
+
s0y = fma(t, s1y - s0y, s0y);
|
|
208
|
+
s1x = fma(t, s2x - s1x, s1x);
|
|
209
|
+
s1y = fma(t, s2y - s1y, s1y);
|
|
210
|
+
s2x = fma(t, p3.x - s2x, s2x);
|
|
211
|
+
s2y = fma(t, p3.y - s2y, s2y);
|
|
212
|
+
s0x = fma(t, s1x - s0x, s0x);
|
|
213
|
+
s0y = fma(t, s1y - s0y, s0y);
|
|
214
|
+
s1x = fma(t, s2x - s1x, s1x);
|
|
215
|
+
s1y = fma(t, s2y - s1y, s1y);
|
|
216
|
+
s0x = fma(t, s1x - s0x, s0x);
|
|
217
|
+
s0y = fma(t, s1y - s0y, s0y);
|
|
218
|
+
return { x: s0x, y: s0y };
|
|
211
219
|
}
|
|
212
220
|
|
|
213
221
|
/** Update box x-extents for a sample point if it lies in the y-band. */
|
|
@@ -253,7 +261,7 @@ export function limitBoxes(
|
|
|
253
261
|
pn: number,
|
|
254
262
|
delta: number,
|
|
255
263
|
): void {
|
|
256
|
-
const numDiv =
|
|
264
|
+
const numDiv = delta * boxn; // C: const double num_div (routespl.c:242)
|
|
257
265
|
for (let splinepi = 0; splinepi + 3 < pn; splinepi += 3) {
|
|
258
266
|
sampleBezierSegment(boxes, boxn, pps, splinepi, numDiv);
|
|
259
267
|
}
|
package/src/common/taper.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
// @see lib/common/taper.c:taper
|
|
10
10
|
|
|
11
11
|
import type { Point, Bezier } from '../model/geom.js';
|
|
12
|
+
import { bezier } from './bezier.js';
|
|
12
13
|
|
|
13
14
|
/** Sample points per Bézier segment. @see taper.c:BEZIERSUBDIVISION */
|
|
14
15
|
const BEZIER_SUBDIVISION = 20;
|
|
@@ -65,19 +66,6 @@ function l2dist(p0: Point, p1: Point): number {
|
|
|
65
66
|
return Math.hypot(p0.x - p1.x, p0.y - p1.y);
|
|
66
67
|
}
|
|
67
68
|
|
|
68
|
-
/** Evaluate a cubic Bézier at t via de Casteljau. @see lib/common/utils.c:Bezier */
|
|
69
|
-
function bezierPoint(v: readonly Point[], t: number): Point {
|
|
70
|
-
const vx = [v[0]!.x, v[1]!.x, v[2]!.x, v[3]!.x];
|
|
71
|
-
const vy = [v[0]!.y, v[1]!.y, v[2]!.y, v[3]!.y];
|
|
72
|
-
for (let i = 1; i <= 3; i++) {
|
|
73
|
-
for (let j = 0; j <= 3 - i; j++) {
|
|
74
|
-
vx[j] = (1.0 - t) * vx[j]! + t * vx[j + 1]!;
|
|
75
|
-
vy[j] = (1.0 - t) * vy[j]! + t * vy[j + 1]!;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return { x: vx[0]!, y: vy[0]! };
|
|
79
|
-
}
|
|
80
|
-
|
|
81
69
|
interface PathPoint {
|
|
82
70
|
x: number;
|
|
83
71
|
y: number;
|
|
@@ -107,7 +95,7 @@ function pathtolines(bez: Bezier): PathPoint[] {
|
|
|
107
95
|
for (let j = 1; j <= 3; j++) V[j] = A[i + j]!;
|
|
108
96
|
let p0 = V[0]!;
|
|
109
97
|
for (let step = 1; step <= BEZIER_SUBDIVISION; step++) {
|
|
110
|
-
const p1 =
|
|
98
|
+
const p1 = bezier(V, step / BEZIER_SUBDIVISION, null, null);
|
|
111
99
|
linelen += l2dist(p0, p1);
|
|
112
100
|
push(p1, linelen);
|
|
113
101
|
p0 = p1;
|
package/src/gvc/anchor.ts
CHANGED
|
@@ -20,6 +20,7 @@ import type { GraphObj } from '../common/subst.js';
|
|
|
20
20
|
import { substObjAnchor, interpretCRNL } from '../common/subst.js';
|
|
21
21
|
import { parseStyleFlags } from '../common/style-resolve.js';
|
|
22
22
|
import { nodeAttr } from '../common/poly-init.js';
|
|
23
|
+
import { bezier } from '../common/bezier.js';
|
|
23
24
|
import type { RendererPlugin } from './context.js';
|
|
24
25
|
import { MapShape, type ObjState, type RenderJob } from './job.js';
|
|
25
26
|
|
|
@@ -447,20 +448,10 @@ function checkControlPoints(cp: Point[]): boolean {
|
|
|
447
448
|
/** de Casteljau split of a cubic at t=0.5, returning left & right control sets.
|
|
448
449
|
* @see lib/common/utils.c:Bezier */
|
|
449
450
|
function bezierHalf(v: Point[]): { left: Point[]; right: Point[] } {
|
|
450
|
-
const
|
|
451
|
-
const
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
for (let j = 0; j <= 3 - i; j++) {
|
|
455
|
-
const a = vt[i - 1]![j]!;
|
|
456
|
-
const b = vt[i - 1]![j + 1]!;
|
|
457
|
-
vt[i]![j] = { x: (1 - t) * a.x + t * b.x, y: (1 - t) * a.y + t * b.y };
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
return {
|
|
461
|
-
left: [vt[0]![0]!, vt[1]![0]!, vt[2]![0]!, vt[3]![0]!],
|
|
462
|
-
right: [vt[3]![0]!, vt[2]![1]!, vt[1]![2]!, vt[0]![3]!],
|
|
463
|
-
};
|
|
451
|
+
const left: Point[] = [];
|
|
452
|
+
const right: Point[] = [];
|
|
453
|
+
bezier(v, 0.5, left, right);
|
|
454
|
+
return { left, right };
|
|
464
455
|
}
|
|
465
456
|
|
|
466
457
|
/** approx_bezier: flatten a cubic to a polyline. @see lib/common/emit.c */
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// Reduced (ddmin) from graphviz tests/2796.dot: one labeled flat edge whose
|
|
2
|
+
// routesplines fails. Native 16.1.0 reports the failure once.
|
|
3
|
+
digraph "troublesome" {
|
|
4
|
+
rankdir=LR
|
|
5
|
+
I -> 36
|
|
6
|
+
subgraph cluster_0 {
|
|
7
|
+
}
|
|
8
|
+
subgraph cluster_6 {
|
|
9
|
+
57
|
|
10
|
+
12
|
|
11
|
+
}
|
|
12
|
+
subgraph cluster_10 {
|
|
13
|
+
26
|
|
14
|
+
}
|
|
15
|
+
subgraph cluster_14 {
|
|
16
|
+
}
|
|
17
|
+
subgraph cluster_17 {
|
|
18
|
+
}
|
|
19
|
+
subgraph cluster_18 {
|
|
20
|
+
}
|
|
21
|
+
subgraph cluster_21 {
|
|
22
|
+
55
|
|
23
|
+
}
|
|
24
|
+
subgraph cluster_23 {
|
|
25
|
+
}
|
|
26
|
+
subgraph cluster_24 {
|
|
27
|
+
}
|
|
28
|
+
subgraph cluster_33 {
|
|
29
|
+
39
|
|
30
|
+
4
|
|
31
|
+
1
|
|
32
|
+
}
|
|
33
|
+
subgraph cluster_35 {
|
|
34
|
+
}
|
|
35
|
+
subgraph cluster_37 {
|
|
36
|
+
}
|
|
37
|
+
subgraph cluster_38 {
|
|
38
|
+
}
|
|
39
|
+
subgraph cluster_39 {
|
|
40
|
+
}
|
|
41
|
+
subgraph cluster_40 {
|
|
42
|
+
46
|
|
43
|
+
}
|
|
44
|
+
subgraph cluster_41 {
|
|
45
|
+
}
|
|
46
|
+
subgraph cluster_42 {
|
|
47
|
+
}
|
|
48
|
+
1 -> 48 [label="p1"]
|
|
49
|
+
2 -> 48 [label="!p0 & !p1"]
|
|
50
|
+
3 -> 26 [label="p0 & p2"]
|
|
51
|
+
4 -> 1 [label="p0 & p1 & p2"]
|
|
52
|
+
4 -> 48 [label="!p1"]
|
|
53
|
+
12 -> 57 [label="p0 & p1"]
|
|
54
|
+
13 -> 28 [label="p0 & p1 & p2"]
|
|
55
|
+
15 -> 16 [label="!p0 & p1 & p2"]
|
|
56
|
+
16 -> 26 [label="p0 & p2"]
|
|
57
|
+
17 -> 3 [label="!p0 & !p2"]
|
|
58
|
+
17 -> 21 [label="p0 & !p2"]
|
|
59
|
+
20 -> 48 [label="!p0 & p1"]
|
|
60
|
+
20 -> 50 [label="p0 & !p1"]
|
|
61
|
+
21 -> 3 [label="!p0 & p1 & !p2"]
|
|
62
|
+
21 -> 12 [label="p0 & p1 & p2"]
|
|
63
|
+
21 -> 48 [label="!p0 & !p1"]
|
|
64
|
+
21 -> 57 [label="p0 & !p1"]
|
|
65
|
+
22 -> 48 [label="!p0"]
|
|
66
|
+
22 -> 52 [label="p0 & p2"]
|
|
67
|
+
23 -> 14 [label="p0 & p1 & p2"]
|
|
68
|
+
23 -> 21 [label="p0 & p1 & !p2"]
|
|
69
|
+
23 -> 30 [label="p0 & !p1 & !p2"]
|
|
70
|
+
23 -> 48 [label="(!p0 & !p1) | (!p0 & p2)"]
|
|
71
|
+
23 -> 52 [label="p0 & !p1 & p2"]
|
|
72
|
+
24 -> 3 [label="!p0 & p1 & !p2"]
|
|
73
|
+
24 -> 15 [label="p0 & p1 & !p2"]
|
|
74
|
+
24 -> 52 [label="p0 & !p1 & p2"]
|
|
75
|
+
25 -> 18 [label="!p0 & p1 & !p2"]
|
|
76
|
+
25 -> 34 [label="!p0 & p1 & p2"]
|
|
77
|
+
26 -> 48 [label="p1"]
|
|
78
|
+
27 -> 48 [label="!p0 & !p2"]
|
|
79
|
+
27 -> 57 [label="p0 & !p2"]
|
|
80
|
+
28 -> 29 [label="p0 & !p1 & !p2"]
|
|
81
|
+
28 -> 48 [label="!p0 | p1"]
|
|
82
|
+
29 -> 48 [label="!p0 | !p1"]
|
|
83
|
+
30 -> 48 [label="!p0"]
|
|
84
|
+
32 -> 30 [label="p0 & !p1 & !p2"]
|
|
85
|
+
32 -> 48 [label="!p0"]
|
|
86
|
+
32 -> 52 [label="p0 & p2"]
|
|
87
|
+
32 -> 55 [label="p0 & p1 & !p2"]
|
|
88
|
+
33 -> 48 [label="!p0"]
|
|
89
|
+
33 -> 52 [label="p0 & p2"]
|
|
90
|
+
33 -> 55 [label="p0 & !p2"]
|
|
91
|
+
34 -> 0 [label="p0 & !p2"]
|
|
92
|
+
34 -> 2 [label="p0 & p2"]
|
|
93
|
+
34 -> 48 [label="!p0"]
|
|
94
|
+
35 -> 9 [label="p0 & !p1 & !p2"]
|
|
95
|
+
35 -> 14 [label="p0 & !p1 & p2"]
|
|
96
|
+
35 -> 55 [label="p0 & p1 & !p2"]
|
|
97
|
+
36 -> 5 [label="!p0 & !p1 & !p2"]
|
|
98
|
+
36 -> 6 [label="p0 & !p1 & p2"]
|
|
99
|
+
36 -> 17 [label="p0 & !p1 & !p2"]
|
|
100
|
+
36 -> 37 [label="p1 & !p2"]
|
|
101
|
+
36 -> 38 [label="p1 & p2"]
|
|
102
|
+
36 -> 44 [label="!p0 & !p1 & p2"]
|
|
103
|
+
37 -> 10 [label="!p0 & !p1 & !p2"]
|
|
104
|
+
37 -> 23 [label="p0 & !p1 & !p2"]
|
|
105
|
+
38 -> 24 [label="p0 & !p1 & !p2"]
|
|
106
|
+
38 -> 35 [label="p0 & !p1 & p2"]
|
|
107
|
+
38 -> 37 [label="!p0 & p1 & !p2"]
|
|
108
|
+
38 -> 39 [label="p0 & p1 & p2"]
|
|
109
|
+
38 -> 44 [label="!p0 & !p1 & p2"]
|
|
110
|
+
38 -> 53 [label="p0 & p1 & !p2"]
|
|
111
|
+
39 -> 5 [label="!p0 & !p1 & !p2"]
|
|
112
|
+
39 -> 24 [label="p0 & !p1 & !p2"]
|
|
113
|
+
39 -> 35 [label="p0 & !p1 & p2"]
|
|
114
|
+
39 -> 43 [label="p0 & p1 & p2"]
|
|
115
|
+
39 -> 44 [label="!p0 & !p1 & p2"]
|
|
116
|
+
39 -> 48 [label="!p0 & p1"]
|
|
117
|
+
39 -> 54 [label="p0 & p1 & !p2"]
|
|
118
|
+
40 -> 10 [label="!p0 & !p1 & !p2"]
|
|
119
|
+
41 -> 5 [label="!p0 & !p1 & !p2"]
|
|
120
|
+
42 -> 5 [label="!p0 & !p1 & !p2"]
|
|
121
|
+
42 -> 44 [label="!p0 & !p1 & p2"]
|
|
122
|
+
42 -> 48 [label="p1"]
|
|
123
|
+
42 -> 51 [label="p0 & !p1 & p2"]
|
|
124
|
+
43 -> 32 [label="p0 & !p1 & !p2"]
|
|
125
|
+
43 -> 33 [label="p0 & !p1 & p2"]
|
|
126
|
+
43 -> 48 [label="!p0"]
|
|
127
|
+
43 -> 54 [label="p0 & p1 & !p2"]
|
|
128
|
+
44 -> 19 [label="p0 & p2"]
|
|
129
|
+
44 -> 20 [label="p0 & !p2"]
|
|
130
|
+
44 -> 48 [label="!p0"]
|
|
131
|
+
45 -> 28 [label="p0 & p2"]
|
|
132
|
+
45 -> 29 [label="p0 & !p2"]
|
|
133
|
+
45 -> 48 [label="!p0"]
|
|
134
|
+
46 -> 3 [label="!p0 & p1 & !p2"]
|
|
135
|
+
46 -> 48 [label="!p1 | (!p0 & p2)"]
|
|
136
|
+
46 -> 51 [label="p0 & p1 & p2"]
|
|
137
|
+
46 -> 56 [label="p0 & p1 & !p2"]
|
|
138
|
+
47 -> 3 [label="!p0 & p1 & !p2"]
|
|
139
|
+
47 -> 48 [label="!p1"]
|
|
140
|
+
47 -> 51 [label="p0 & p1 & p2"]
|
|
141
|
+
47 -> 56 [label="p0 & p1 & !p2"]
|
|
142
|
+
49 -> 40 [label="!p0 & p1 & !p2"]
|
|
143
|
+
49 -> 41 [label="!p0 & p1 & p2"]
|
|
144
|
+
49 -> 42 [label="p0 & p1 & p2"]
|
|
145
|
+
49 -> 48 [label="!p1"]
|
|
146
|
+
51 -> 4 [label="p0 & !p1 & !p2"]
|
|
147
|
+
51 -> 48 [label="p1 | (!p0 & p2)"]
|
|
148
|
+
52 -> 48 [label="!p0"]
|
|
149
|
+
52 -> 57 [label="p0 & p1"]
|
|
150
|
+
53 -> 22 [label="p0 & !p1 & !p2"]
|
|
151
|
+
53 -> 33 [label="p0 & !p1 & p2"]
|
|
152
|
+
53 -> 39 [label="p0 & p1 & p2"]
|
|
153
|
+
53 -> 40 [label="!p0 & p1 & !p2"]
|
|
154
|
+
53 -> 41 [label="!p0 & p1 & p2"]
|
|
155
|
+
53 -> 48 [label="!p0 & !p1"]
|
|
156
|
+
54 -> 22 [label="p0 & !p1 & !p2"]
|
|
157
|
+
54 -> 48 [label="!p0"]
|
|
158
|
+
55 -> 48 [label="!p0"]
|
|
159
|
+
55 -> 57 [label="p0 & !p1"]
|
|
160
|
+
56 -> 3 [label="!p0 & p1 & !p2"]
|
|
161
|
+
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import type { Point, Box } from '../../model/geom.js';
|
|
11
11
|
import { cround } from '../../common/arith.js';
|
|
12
|
+
import { bezier } from '../../common/bezier.js';
|
|
12
13
|
|
|
13
14
|
/** Sign comparison matching C fcmp(). @see lib/util/gv_math.h:fcmp */
|
|
14
15
|
export function fcmp(a: number, b: number): number {
|
|
@@ -31,26 +32,15 @@ export function midPointf(a: Point, b: Point): Point {
|
|
|
31
32
|
// De Casteljau subdivision
|
|
32
33
|
// ---------------------------------------------------------------------------
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return [
|
|
40
|
-
{ x: u * prev[0].x + t * prev[1].x, y: u * prev[0].y + t * prev[1].y },
|
|
41
|
-
{ x: u * prev[1].x + t * prev[2].x, y: u * prev[1].y + t * prev[2].y },
|
|
42
|
-
{ x: u * prev[2].x + t * prev[3].x, y: u * prev[2].y + t * prev[3].y },
|
|
43
|
-
{ x: 0, y: 0 },
|
|
44
|
-
];
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** Subdivide cubic Bezier at t; return left or right half. @see lib/common/utils.c:Bezier */
|
|
35
|
+
/**
|
|
36
|
+
* Subdivide cubic Bezier at t; return left or right half, through the shared
|
|
37
|
+
* fused bezier().
|
|
38
|
+
* @see lib/common/utils.c:Bezier
|
|
39
|
+
*/
|
|
48
40
|
export function subdivideBezier(v: readonly Point[], t: number, side: 'left' | 'right'): Point[] {
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const r3 = casteljauStep(r2, t);
|
|
53
|
-
return side === 'left' ? [r0[0], r1[0], r2[0], r3[0]] : [r3[0], r2[1], r1[2], r0[3]];
|
|
41
|
+
const half: Point[] = [];
|
|
42
|
+
bezier([...v], t, side === 'left' ? half : null, side === 'right' ? half : null);
|
|
43
|
+
return half;
|
|
54
44
|
}
|
|
55
45
|
|
|
56
46
|
// ---------------------------------------------------------------------------
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import type { Point, Box } from '../../model/geom.js';
|
|
12
12
|
import { cround } from '../../common/arith.js';
|
|
13
|
+
import { bezier } from '../../common/bezier.js';
|
|
13
14
|
|
|
14
15
|
// ---------------------------------------------------------------------------
|
|
15
16
|
// Primitive helpers
|
|
@@ -49,24 +50,10 @@ export function midPointf(a: Point, b: Point): Point {
|
|
|
49
50
|
// Bezier subdivision
|
|
50
51
|
// ---------------------------------------------------------------------------
|
|
51
52
|
|
|
52
|
-
/** One triangle row for De Casteljau; avoids nested array allocation. */
|
|
53
|
-
type CasteljauRow = [Point, Point, Point, Point];
|
|
54
|
-
|
|
55
|
-
/** Compute one row of the De Casteljau triangle at parameter t. */
|
|
56
|
-
export function casteljauStep(prev: CasteljauRow, t: number): CasteljauRow {
|
|
57
|
-
const u = 1 - t;
|
|
58
|
-
return [
|
|
59
|
-
{ x: u * prev[0].x + t * prev[1].x, y: u * prev[0].y + t * prev[1].y },
|
|
60
|
-
{ x: u * prev[1].x + t * prev[2].x, y: u * prev[1].y + t * prev[2].y },
|
|
61
|
-
{ x: u * prev[2].x + t * prev[3].x, y: u * prev[2].y + t * prev[3].y },
|
|
62
|
-
{ x: 0, y: 0 }, // unused slot; keeps tuple type uniform
|
|
63
|
-
];
|
|
64
|
-
}
|
|
65
|
-
|
|
66
53
|
/**
|
|
67
54
|
* De Casteljau subdivision of a cubic Bezier at parameter t.
|
|
68
|
-
* Returns left-half or right-half control points
|
|
69
|
-
*
|
|
55
|
+
* Returns left-half or right-half control points through the shared fused
|
|
56
|
+
* bezier().
|
|
70
57
|
*
|
|
71
58
|
* @see lib/common/utils.c:Bezier
|
|
72
59
|
*/
|
|
@@ -75,13 +62,9 @@ export function subdivideBezier(
|
|
|
75
62
|
t: number,
|
|
76
63
|
side: 'left' | 'right',
|
|
77
64
|
): Point[] {
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const r3 = casteljauStep(r2, t);
|
|
82
|
-
return side === 'left'
|
|
83
|
-
? [r0[0], r1[0], r2[0], r3[0]]
|
|
84
|
-
: [r3[0], r2[1], r1[2], r0[3]];
|
|
65
|
+
const half: Point[] = [];
|
|
66
|
+
bezier([...v], t, side === 'left' ? half : null, side === 'right' ? half : null);
|
|
67
|
+
return half;
|
|
85
68
|
}
|
|
86
69
|
|
|
87
70
|
// ---------------------------------------------------------------------------
|
|
@@ -19,7 +19,7 @@ import { dist } from '../../common/arrows-geometry.js';
|
|
|
19
19
|
|
|
20
20
|
// Re-export geometry helpers so existing callers (tests) import from one place.
|
|
21
21
|
export {
|
|
22
|
-
fcmp, inBoxf, midPointf,
|
|
22
|
+
fcmp, inBoxf, midPointf, subdivideBezier,
|
|
23
23
|
countVertCross, countHorzCross, tryUpdateIntersect,
|
|
24
24
|
splineIntersectf,
|
|
25
25
|
tryLeftSide, tryRightSide, tryBottomSide, tryTopSide, boxIntersectf,
|
|
@@ -11,49 +11,26 @@
|
|
|
11
11
|
import type { Point } from '../../model/geom.js';
|
|
12
12
|
import { parseArrow, resolveArrowType } from '../../common/arrows.js';
|
|
13
13
|
import { arrowLength } from '../../common/arrows-shapes.js';
|
|
14
|
+
import { bezier } from '../../common/bezier.js';
|
|
14
15
|
|
|
15
16
|
// ---------------------------------------------------------------------------
|
|
16
17
|
// De Casteljau subdivision
|
|
17
18
|
// @see lib/common/utils.c:Bezier
|
|
18
19
|
// ---------------------------------------------------------------------------
|
|
19
20
|
|
|
20
|
-
/**
|
|
21
|
-
* Build the De Casteljau triangle for a cubic Bezier at parameter t.
|
|
22
|
-
* v[i][j] = (1-t)*v[i-1][j] + t*v[i-1][j+1].
|
|
23
|
-
* @see lib/common/utils.c:Bezier (triangle computation section)
|
|
24
|
-
*/
|
|
25
|
-
function deCasteljauTriangle(sp: Point[], t: number): Point[][] {
|
|
26
|
-
const u = 1 - t;
|
|
27
|
-
const v: Point[][] = [
|
|
28
|
-
[sp[0], sp[1], sp[2], sp[3]],
|
|
29
|
-
[{ x: 0, y: 0 }, { x: 0, y: 0 }, { x: 0, y: 0 }, { x: 0, y: 0 }],
|
|
30
|
-
[{ x: 0, y: 0 }, { x: 0, y: 0 }, { x: 0, y: 0 }, { x: 0, y: 0 }],
|
|
31
|
-
[{ x: 0, y: 0 }, { x: 0, y: 0 }, { x: 0, y: 0 }, { x: 0, y: 0 }],
|
|
32
|
-
];
|
|
33
|
-
for (let i = 1; i <= 3; i++) {
|
|
34
|
-
for (let j = 0; j <= 3 - i; j++) {
|
|
35
|
-
v[i][j] = {
|
|
36
|
-
x: u * v[i - 1][j].x + t * v[i - 1][j + 1].x,
|
|
37
|
-
y: u * v[i - 1][j].y + t * v[i - 1][j + 1].y,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return v;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
21
|
/**
|
|
45
22
|
* De Casteljau subdivision of a cubic Bezier at parameter t.
|
|
46
|
-
* Returns [left4, right4, midpoint].
|
|
23
|
+
* Returns [left4, right4, midpoint], computed by the shared fused bezier().
|
|
47
24
|
* @see lib/common/utils.c:Bezier
|
|
48
25
|
*/
|
|
49
26
|
export function bezierSubdivide(
|
|
50
27
|
sp: Point[],
|
|
51
28
|
t: number,
|
|
52
29
|
): [Point[], Point[], Point] {
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
return [left, right,
|
|
30
|
+
const left: Point[] = [];
|
|
31
|
+
const right: Point[] = [];
|
|
32
|
+
const mid = bezier(sp, t, left, right);
|
|
33
|
+
return [left, right, mid];
|
|
57
34
|
}
|
|
58
35
|
|
|
59
36
|
// ---------------------------------------------------------------------------
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// SPDX-License-Identifier: EPL-2.0
|
|
2
2
|
/**
|
|
3
3
|
* Dot-local adapter between the dot `Graph` model and the `orthoEdges`
|
|
4
|
-
* pipeline (`src/ortho`). Mirrors neato's
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* pipeline (`src/ortho`). Mirrors neato's `OrthoHelper` (`neato/splines.ts`);
|
|
5
|
+
* the two share only the concentrate dedup (`isConcentrateDup`), as C has one
|
|
6
|
+
* gather loop while dotgen and neatogen each have their own call site into
|
|
7
|
+
* `ortho.c:orthoEdges`.
|
|
8
8
|
*
|
|
9
9
|
* @see lib/dotgen/dotsplines.c:dot_splines_ (EDGETYPE_ORTHO branch)
|
|
10
10
|
* @see src/layout/neato/splines.ts:OrthoHelper
|
|
@@ -56,7 +56,7 @@ function buildNodes(nodeArr: Node[]): OrthoNodeArr {
|
|
|
56
56
|
* (min, max) and makes one isInPS/addPS pair on it.
|
|
57
57
|
* @see lib/ortho/ortho.c:1221-1229 (orthoEdges Concentrate PS)
|
|
58
58
|
*/
|
|
59
|
-
function isConcentrateDup(ps: PointSet, e: Edge): boolean {
|
|
59
|
+
export function isConcentrateDup(ps: PointSet, e: Edge): boolean {
|
|
60
60
|
const ti = e.tail.id;
|
|
61
61
|
const hi = e.head.id;
|
|
62
62
|
const lo = ti <= hi ? ti : hi;
|
|
@@ -149,7 +149,9 @@ export function makeFlatLabeledEdge(g: Graph, e: Edge): boolean {
|
|
|
149
149
|
// Degenerate route (routesplines pn=0): label set, no spline installed — C's
|
|
150
150
|
// make_flat_labeled_edge returns the same way; emit's edge_in_box then decides
|
|
151
151
|
// whether the (untranslated) label overlaps the clip. Still HANDLED → true.
|
|
152
|
-
|
|
152
|
+
// C's dot_splines_ visits the edge once, so mark it lost: the routeDotEdges
|
|
153
|
+
// backstop must not route (and report the failure) a second time.
|
|
154
|
+
if (ps === null || ps.length === 0) { e.info.lost = true; return true; }
|
|
153
155
|
if (!tailIsLeft) ps.reverse();
|
|
154
156
|
clipAndInstall(e, e.head, ps, ps.length, { ...buildDotSinfo(), ignoreSwap: true });
|
|
155
157
|
return true;
|
|
@@ -17,6 +17,7 @@ import { IGNORED } from './rank.js';
|
|
|
17
17
|
import { lateDouble } from '../../common/nodeinit.js';
|
|
18
18
|
import { nodesInSeq } from './decomp.js';
|
|
19
19
|
import { RADIANS } from '../../common/arith.js';
|
|
20
|
+
import { bezier } from '../../common/bezier.js';
|
|
20
21
|
|
|
21
22
|
// ---------------------------------------------------------------------------
|
|
22
23
|
// TextLabel interface (minimal — full type deferred to Batch 5b)
|
|
@@ -125,33 +126,6 @@ export const PORT_LABEL_DISTANCE = 10;
|
|
|
125
126
|
/** Default port-label angle in degrees (CW negative). @see lib/common/const.h:PORT_LABEL_ANGLE */
|
|
126
127
|
export const PORT_LABEL_ANGLE = -25;
|
|
127
128
|
|
|
128
|
-
// ---------------------------------------------------------------------------
|
|
129
|
-
// cubicBezierAt — de Casteljau at parameter t (Bezier() in utils.c)
|
|
130
|
-
// @see lib/common/utils.c:175-203
|
|
131
|
-
// ---------------------------------------------------------------------------
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Evaluate a cubic Bezier curve at parameter t using the de Casteljau
|
|
135
|
-
* triangle computation. Requires pts[0..3]. No Left/Right subdivision
|
|
136
|
-
* output needed here, so they are omitted.
|
|
137
|
-
*
|
|
138
|
-
* @see lib/common/utils.c:Bezier
|
|
139
|
-
*/
|
|
140
|
-
function cubicBezierAt(pts: readonly { x: number; y: number }[], t: number): { x: number; y: number } {
|
|
141
|
-
// Triangle computation (degree = 3)
|
|
142
|
-
const p0 = pts[0], p1 = pts[1], p2 = pts[2], p3 = pts[3];
|
|
143
|
-
const mt = 1.0 - t;
|
|
144
|
-
// Level 1
|
|
145
|
-
const q0 = { x: mt * p0.x + t * p1.x, y: mt * p0.y + t * p1.y };
|
|
146
|
-
const q1 = { x: mt * p1.x + t * p2.x, y: mt * p1.y + t * p2.y };
|
|
147
|
-
const q2 = { x: mt * p2.x + t * p3.x, y: mt * p2.y + t * p3.y };
|
|
148
|
-
// Level 2
|
|
149
|
-
const r0 = { x: mt * q0.x + t * q1.x, y: mt * q0.y + t * q1.y };
|
|
150
|
-
const r1 = { x: mt * q1.x + t * q2.x, y: mt * q1.y + t * q2.y };
|
|
151
|
-
// Level 3
|
|
152
|
-
return { x: mt * r0.x + t * r1.x, y: mt * r0.y + t * r1.y };
|
|
153
|
-
}
|
|
154
|
-
|
|
155
129
|
// ---------------------------------------------------------------------------
|
|
156
130
|
// Bezier endpoint extraction helpers
|
|
157
131
|
// @see lib/common/splines.c:place_portlabel:1331-1351
|
|
@@ -171,7 +145,7 @@ function tailEndpoints(bez: BezierSeg): { pe: { x: number; y: number }; pf: { x:
|
|
|
171
145
|
return { pe: bez.sp, pf: bez.list[0] };
|
|
172
146
|
}
|
|
173
147
|
const pe = bez.list[0];
|
|
174
|
-
const pf =
|
|
148
|
+
const pf = bezier(bez.list, 0.1, null, null);
|
|
175
149
|
return { pe, pf };
|
|
176
150
|
}
|
|
177
151
|
|
|
@@ -192,7 +166,7 @@ function headEndpoints(bez: BezierSeg): { pe: { x: number; y: number }; pf: { x:
|
|
|
192
166
|
}
|
|
193
167
|
const pe = bez.list[bez.size - 1];
|
|
194
168
|
const last4 = bez.list.slice(bez.size - 4, bez.size);
|
|
195
|
-
const pf =
|
|
169
|
+
const pf = bezier(last4, 0.9, null, null);
|
|
196
170
|
return { pe, pf };
|
|
197
171
|
}
|
|
198
172
|
|
package/src/layout/neato/bfs.ts
CHANGED
|
@@ -33,7 +33,13 @@ export function bfsFixDisconnected(
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* Process one BFS vertex: enqueue unvisited neighbours. The bump is 1 when
|
|
38
|
+
* graph[0] has no ewgts (C NULL, the port's empty array), else the float
|
|
39
|
+
* ewgts truncated to DistType (int).
|
|
40
|
+
* @see lib/neatogen/bfs.c:bfs (bfs.c:41-43)
|
|
41
|
+
* @internal
|
|
42
|
+
*/
|
|
37
43
|
export function bfsVisitNeighbors(
|
|
38
44
|
vertex: number,
|
|
39
45
|
graph: VtxData[],
|
|
@@ -42,10 +48,12 @@ export function bfsVisitNeighbors(
|
|
|
42
48
|
): number {
|
|
43
49
|
const vd = graph[vertex];
|
|
44
50
|
const d = dist[vertex];
|
|
51
|
+
const unit = graph[0].ewgts.length === 0;
|
|
45
52
|
for (let i = 1; i < vd.nedges; i++) {
|
|
46
53
|
const nb = vd.edges[i];
|
|
47
54
|
if (dist[nb] < 0) {
|
|
48
|
-
|
|
55
|
+
// C ewgts is float*: round to float32, then (DistType) truncates
|
|
56
|
+
dist[nb] = d + (unit ? 1 : Math.trunc(Math.fround(vd.ewgts[i])));
|
|
49
57
|
queue.push(nb);
|
|
50
58
|
}
|
|
51
59
|
}
|
|
@@ -57,8 +65,9 @@ export function bfsVisitNeighbors(
|
|
|
57
65
|
// ---------------------------------------------------------------------------
|
|
58
66
|
|
|
59
67
|
/**
|
|
60
|
-
* Single-source BFS
|
|
61
|
-
*
|
|
68
|
+
* Single-source BFS from `src`: first visit wins, each hop bumps by 1 or by
|
|
69
|
+
* the int-truncated ewgts (see bfsVisitNeighbors). Unreached nodes get
|
|
70
|
+
* `closestDist + 10`.
|
|
62
71
|
*
|
|
63
72
|
* @see lib/neatogen/bfs.c:bfs
|
|
64
73
|
*/
|