@knowvah/dot-engine 2.6.11 → 2.6.12
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/async/render-async.d.ts.map +1 -1
- package/dist/common/agerr.d.ts +37 -0
- package/dist/common/agerr.d.ts.map +1 -0
- package/dist/common/arrows-shapes-poly.d.ts.map +1 -1
- package/dist/common/color.d.ts.map +1 -1
- package/dist/common/crand.d.ts +0 -20
- package/dist/common/crand.d.ts.map +1 -1
- package/dist/common/emit-once.d.ts +6 -0
- package/dist/common/emit-once.d.ts.map +1 -0
- package/dist/common/graph-init.d.ts.map +1 -1
- package/dist/common/htmltable-attr-warn.d.ts.map +1 -1
- package/dist/common/htmltable-emit-fill.d.ts +9 -0
- package/dist/common/htmltable-emit-fill.d.ts.map +1 -1
- package/dist/common/htmltable-emit-rules.d.ts.map +1 -1
- package/dist/common/htmltable-lex-expat.d.ts +1 -6
- package/dist/common/htmltable-lex-expat.d.ts.map +1 -1
- package/dist/common/htmltable.d.ts +1 -7
- package/dist/common/htmltable.d.ts.map +1 -1
- package/dist/common/poly-gencode.d.ts.map +1 -1
- package/dist/common/poly-init.d.ts.map +1 -1
- package/dist/common/postproc.d.ts.map +1 -1
- package/dist/common/random.d.ts.map +1 -1
- package/dist/common/render-state.d.ts +8 -0
- package/dist/common/render-state.d.ts.map +1 -0
- package/dist/common/splines-geom.d.ts +8 -0
- package/dist/common/splines-geom.d.ts.map +1 -1
- package/dist/common/splines-routespl.d.ts.map +1 -1
- package/dist/common/textmeasure-lookup.d.ts.map +1 -1
- package/dist/common/textmeasure.d.ts.map +1 -1
- package/dist/gvc/anchor.d.ts.map +1 -1
- package/dist/gvc/device-cluster.d.ts.map +1 -1
- package/dist/gvc/device-labels.d.ts +14 -0
- package/dist/gvc/device-labels.d.ts.map +1 -1
- package/dist/gvc/device.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +765 -451
- package/dist/index.js.map +4 -4
- package/dist/layout/dot/cluster.d.ts.map +1 -1
- package/dist/layout/dot/conc.d.ts.map +1 -1
- package/dist/layout/dot/decomp.d.ts.map +1 -1
- package/dist/layout/dot/edge-route-clip.d.ts +18 -10
- package/dist/layout/dot/edge-route-clip.d.ts.map +1 -1
- package/dist/layout/dot/mincross-build.d.ts.map +1 -1
- package/dist/layout/dot/mincross-cross.d.ts.map +1 -1
- package/dist/layout/dot/rank.d.ts.map +1 -1
- package/dist/layout/dot/splines.d.ts.map +1 -1
- package/dist/layout/fdp/index.d.ts.map +1 -1
- package/dist/layout/fdp/tlayout-parms.d.ts.map +1 -1
- package/dist/layout/fdp/xlayout.d.ts.map +1 -1
- package/dist/layout/neato/edge-len.d.ts.map +1 -1
- package/dist/layout/neato/fdp-adjust.d.ts.map +1 -1
- package/dist/layout/neato/init.d.ts +4 -10
- package/dist/layout/neato/init.d.ts.map +1 -1
- package/dist/layout/neato/kk.d.ts.map +1 -1
- package/dist/layout/neato/multispline-router.d.ts.map +1 -1
- package/dist/layout/neato/multispline.d.ts.map +1 -1
- package/dist/layout/neato/poly.d.ts.map +1 -1
- package/dist/layout/neato/sgd.d.ts.map +1 -1
- package/dist/layout/neato/start.d.ts.map +1 -1
- package/dist/ortho/index.d.ts.map +1 -1
- package/dist/parser/index.d.ts.map +1 -1
- package/dist/render/color-resolve.d.ts +49 -1
- package/dist/render/color-resolve.d.ts.map +1 -1
- package/dist/render/public.d.ts.map +1 -1
- package/dist/render/svg-edge-split.d.ts +2 -0
- package/dist/render/svg-edge-split.d.ts.map +1 -1
- package/dist/render/xdot-public.d.ts.map +1 -1
- package/dist/render.js +513 -200
- package/dist/render.js.map +4 -4
- package/package.json +1 -1
- package/src/async/render-async.ts +6 -0
- package/src/common/agerr.ts +96 -0
- package/src/common/arrows-shapes-poly.ts +19 -5
- package/src/common/color.ts +38 -10
- package/src/common/crand.ts +8 -2
- package/src/common/emit-once.ts +27 -0
- package/src/common/graph-init.ts +2 -1
- package/src/common/htmltable-attr-warn.ts +3 -4
- package/src/common/htmltable-emit-fill.ts +48 -0
- package/src/common/htmltable-emit-rules.ts +2 -0
- package/src/common/htmltable-lex-expat.ts +78 -23
- package/src/common/htmltable.ts +15 -16
- package/src/common/poly-gencode.ts +14 -2
- package/src/common/poly-init.ts +2 -1
- package/src/common/postproc.ts +4 -1
- package/src/common/random.ts +11 -1
- package/src/common/render-state.ts +36 -0
- package/src/common/splines-geom.ts +8 -4
- package/src/common/splines-routespl.ts +2 -1
- package/src/common/textmeasure-lookup.ts +10 -3
- package/src/common/textmeasure.ts +45 -2
- package/src/gvc/anchor.ts +1 -12
- package/src/gvc/device-cluster.ts +37 -9
- package/src/gvc/device-labels.ts +27 -0
- package/src/gvc/device.ts +18 -6
- package/src/index.ts +3 -0
- package/src/layout/dot/cluster.ts +2 -1
- package/src/layout/dot/conc.ts +6 -5
- package/src/layout/dot/decomp.ts +3 -0
- package/src/layout/dot/edge-route-clip.ts +27 -21
- package/src/layout/dot/mincross-build.ts +2 -0
- package/src/layout/dot/mincross-cross.ts +2 -0
- package/src/layout/dot/rank.ts +2 -0
- package/src/layout/dot/splines.ts +2 -1
- package/src/layout/fdp/index.ts +2 -1
- package/src/layout/fdp/tlayout-parms.ts +9 -2
- package/src/layout/fdp/xlayout.ts +10 -2
- package/src/layout/neato/cdt-surface.ts +6 -6
- package/src/layout/neato/edge-len.ts +2 -1
- package/src/layout/neato/fdp-adjust.ts +3 -2
- package/src/layout/neato/init.ts +11 -11
- package/src/layout/neato/kk.ts +2 -1
- package/src/layout/neato/multispline-router.ts +3 -3
- package/src/layout/neato/multispline.ts +3 -2
- package/src/layout/neato/poly.ts +3 -2
- package/src/layout/neato/sgd.ts +5 -2
- package/src/layout/neato/start.ts +14 -10
- package/src/ortho/index.ts +3 -1
- package/src/parser/dot.js +4 -1
- package/src/parser/dot.pegjs +5 -1
- package/src/parser/index.ts +4 -3
- package/src/render/color-resolve.ts +193 -4
- package/src/render/public.ts +2 -0
- package/src/render/svg-edge-split.ts +4 -2
- package/src/render/xdot-public.ts +2 -0
|
@@ -40,6 +40,7 @@ export {
|
|
|
40
40
|
constrainingFlatEdge, countConstraining, postorder,
|
|
41
41
|
flatReorderBuildTemprank, flatReorderFixEdges, flatReorderRank, flatReorder,
|
|
42
42
|
} from './mincross-flat.js';
|
|
43
|
+
import { registerRenderState } from '../../common/render-state.js';
|
|
43
44
|
|
|
44
45
|
// allocate_ranks — @see lib/dotgen/mincross.c:allocate_ranks
|
|
45
46
|
export function makeEmptyRank(): RankEntry {
|
|
@@ -99,6 +100,7 @@ export function allocateRanks(g: Graph): void {
|
|
|
99
100
|
* distinct names rather than colliding/deduping by name).
|
|
100
101
|
*/
|
|
101
102
|
let fillSeq = 0;
|
|
103
|
+
registerRenderState(() => { fillSeq = 0; });
|
|
102
104
|
|
|
103
105
|
/**
|
|
104
106
|
* Create a placeholder fill node in the `_new_rank` subgraph at `rank`.
|
|
@@ -18,12 +18,14 @@ import { CLUSTER } from './rank.js';
|
|
|
18
18
|
import {
|
|
19
19
|
MincrossContext, matrixGet, rankGet,
|
|
20
20
|
} from './mincross-utils.js';
|
|
21
|
+
import { registerRenderState } from '../../common/render-state.js';
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* Mirror of C's file-global `ReMincross`. Set true only during the remincross
|
|
24
25
|
* pass so left2right tightens the cluster constraint. @see mincross.c
|
|
25
26
|
*/
|
|
26
27
|
let reMincross = false;
|
|
28
|
+
registerRenderState(() => { reMincross = false; });
|
|
27
29
|
export function setReMincross(b: boolean): void { reMincross = b; }
|
|
28
30
|
|
|
29
31
|
// ---------------------------------------------------------------------------
|
package/src/layout/dot/rank.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { rank } from './ns.js';
|
|
|
12
12
|
import { dot2Rank } from './rank-dot2.js';
|
|
13
13
|
import { class1 } from './classify.js';
|
|
14
14
|
import { pruneForeignClusterNodes } from './cluster.js';
|
|
15
|
+
import { registerRenderState } from '../../common/render-state.js';
|
|
15
16
|
|
|
16
17
|
// ---------------------------------------------------------------------------
|
|
17
18
|
// Constants @see lib/common/const.h
|
|
@@ -54,6 +55,7 @@ export const IGNORED = 6;
|
|
|
54
55
|
/** Global cluster layout type. @see lib/common/globals.h:CL_type */
|
|
55
56
|
export let clType = LOCAL;
|
|
56
57
|
export function setClType(t: number): void { clType = t; }
|
|
58
|
+
registerRenderState(() => { clType = LOCAL; });
|
|
57
59
|
|
|
58
60
|
// ---------------------------------------------------------------------------
|
|
59
61
|
// Utility helpers
|
|
@@ -26,6 +26,7 @@ import { dispatchOrthoEdges } from './ortho-adapter.js';
|
|
|
26
26
|
import { routeEdgeGroups } from './splines-groups.js';
|
|
27
27
|
import { placePortLabels, placeRegularEdgeLabels, setEdgeLabelPos } from './splines-label.js';
|
|
28
28
|
import { nodesInSeq } from './decomp.js';
|
|
29
|
+
import { agerrLineOn } from '../../common/agerr.js';
|
|
29
30
|
|
|
30
31
|
// ---------------------------------------------------------------------------
|
|
31
32
|
// Edge-type flag constants
|
|
@@ -473,7 +474,7 @@ function orthoDispatch(g: Graph): number {
|
|
|
473
474
|
function curvedTop(g: Graph): void {
|
|
474
475
|
resetRW(g);
|
|
475
476
|
if (((g.root.info.has_labels ?? 0) & EDGE_LABEL) !== 0) {
|
|
476
|
-
|
|
477
|
+
agerrLineOn('warn', 'edge labels with splines=curved not supported in dot - use xlabels\n');
|
|
477
478
|
}
|
|
478
479
|
}
|
|
479
480
|
|
package/src/layout/fdp/index.ts
CHANGED
|
@@ -27,6 +27,7 @@ import { fdpLayout, mkClusters } from './layout.js';
|
|
|
27
27
|
import { gdata } from './fdp-model.js';
|
|
28
28
|
import { graphInit } from '../../common/graph-init.js';
|
|
29
29
|
import { csrand } from '../../common/crand.js';
|
|
30
|
+
import { agerrLineOn } from '../../common/agerr.js';
|
|
30
31
|
|
|
31
32
|
export { fdpLayout, mkClusters, evalPositions, setBB } from './layout.js';
|
|
32
33
|
export { fdpTLayout } from './tlayout.js';
|
|
@@ -93,7 +94,7 @@ function fdpSplines(g: Graph): void {
|
|
|
93
94
|
);
|
|
94
95
|
}
|
|
95
96
|
if (g.info.n_cluster_edges) { // HAS_CLUST_EDGE(g)
|
|
96
|
-
|
|
97
|
+
agerrLineOn('warn', CLUSTER_EDGE_WARNING);
|
|
97
98
|
et = EDGETYPE_LINE;
|
|
98
99
|
} else {
|
|
99
100
|
splineEdges1(g, et);
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
import type { Graph } from '../../model/graph.js';
|
|
16
16
|
import { lateDouble, lateInt } from '../../common/nodeinit.js';
|
|
17
17
|
import { type XParams, aggetGraph } from './fdp-model.js';
|
|
18
|
+
import { registerRenderState } from '../../common/render-state.js';
|
|
18
19
|
|
|
19
20
|
// ---------------------------------------------------------------------------
|
|
20
21
|
// Constants — @see lib/fdpgen/tlayout.c:96-101, lib/neatogen/neato.h:27-30
|
|
@@ -90,13 +91,19 @@ export interface TParms {
|
|
|
90
91
|
loopcnt: number;
|
|
91
92
|
}
|
|
92
93
|
|
|
93
|
-
/**
|
|
94
|
-
|
|
94
|
+
/** C's zero-initialized static parms_t. */
|
|
95
|
+
const PARMS_INIT: Readonly<TParms> = {
|
|
95
96
|
useGrid: 0, useNew: 0, seed: 0, numIters: 0, maxIters: 0, unscaled: 0,
|
|
96
97
|
C: 0, Tfact: 0, K: 0, T0: 0, smode: 0, Cell: 0, Wd: 0, Ht: 0,
|
|
97
98
|
pass1: 0, loopcnt: 0,
|
|
98
99
|
};
|
|
99
100
|
|
|
101
|
+
/** Module-level mutable state, mirroring the C static. @see tlayout.c:parms */
|
|
102
|
+
export const parms: TParms = { ...PARMS_INIT };
|
|
103
|
+
// fdpParms is not reset: it is the -L command-line configuration (args.c),
|
|
104
|
+
// and the one field a render writes (K) is set by fdpInitParams before any read.
|
|
105
|
+
registerRenderState(() => { Object.assign(parms, PARMS_INIT); });
|
|
106
|
+
|
|
100
107
|
/** Linear cooling schedule. @see lib/fdpgen/tlayout.c:cool */
|
|
101
108
|
export function cool(t: number): number {
|
|
102
109
|
return parms.T0 * (parms.maxIters - t) / parms.maxIters;
|
|
@@ -36,6 +36,7 @@ import { libmHypot } from '../../common/libm-hypot.js';
|
|
|
36
36
|
import { fma, fms } from '../../common/fma.js';
|
|
37
37
|
import { normalizeG } from './normalize.js';
|
|
38
38
|
import { simpleScale } from '../neato/simple-scale.js';
|
|
39
|
+
import { registerRenderState } from '../../common/render-state.js';
|
|
39
40
|
|
|
40
41
|
/** @see lib/fdpgen/xlayout.c:DFLT_overlap */
|
|
41
42
|
const DFLT_OVERLAP = '9:prism';
|
|
@@ -47,8 +48,8 @@ const PS2INCH = (x: number): number => x / 72;
|
|
|
47
48
|
// xParams / X_marg — static state (C statics, persist across calls)
|
|
48
49
|
// ---------------------------------------------------------------------------
|
|
49
50
|
|
|
50
|
-
/** @see lib/fdpgen/xlayout.c:xParams */
|
|
51
|
-
const
|
|
51
|
+
/** C's static initializer of xParams. @see lib/fdpgen/xlayout.c:xParams */
|
|
52
|
+
const XPARAMS_INIT: Readonly<XParams> = {
|
|
52
53
|
numIters: 60,
|
|
53
54
|
T0: 0.0,
|
|
54
55
|
K: 0.3,
|
|
@@ -56,8 +57,15 @@ const xParams: XParams = {
|
|
|
56
57
|
loopcnt: 0,
|
|
57
58
|
};
|
|
58
59
|
|
|
60
|
+
/** @see lib/fdpgen/xlayout.c:xParams */
|
|
61
|
+
const xParams: XParams = { ...XPARAMS_INIT };
|
|
62
|
+
|
|
59
63
|
/** @see lib/fdpgen/xlayout.c:X_marg */
|
|
60
64
|
let xMarg: ExpandT = { x: 0, y: 0, doAdd: false };
|
|
65
|
+
registerRenderState(() => {
|
|
66
|
+
Object.assign(xParams, XPARAMS_INIT);
|
|
67
|
+
xMarg = { x: 0, y: 0, doAdd: false };
|
|
68
|
+
});
|
|
61
69
|
|
|
62
70
|
/** Overlap/non-overlap repulsion strengths for one try. */
|
|
63
71
|
interface RepStrength {
|
|
@@ -354,14 +354,14 @@ class Cdt {
|
|
|
354
354
|
|
|
355
355
|
if (this.inCircle(v1, v2, v3, v4) > 0) {
|
|
356
356
|
const en = this.edgeOrNew(v3, v4);
|
|
357
|
-
// f3
|
|
358
|
-
//
|
|
359
|
-
// (
|
|
360
|
-
//
|
|
357
|
+
// C: f3 = gts_face_new(en, e5, e2), f4 = gts_face_new(en, e3, e4).
|
|
358
|
+
// The stored ring starts at C's t->e1 (en) because gts_triangle_vertices
|
|
359
|
+
// reads (e1-only, e1∩e2, e2-only): f3 → (v3, v4, v2), f4 → (v4, v3, v1).
|
|
360
|
+
// That is the vertex order mkSurface emits and triCenter sums in.
|
|
361
361
|
this.removeFace(f1);
|
|
362
362
|
this.removeFace(f2);
|
|
363
|
-
const f3 = this.addFace([v4, v2,
|
|
364
|
-
const f4 = this.addFace([
|
|
363
|
+
const f3 = this.addFace([v3, v4, v2], [en, e5, e2]);
|
|
364
|
+
const f4 = this.addFace([v4, v3, v1], [en, e3, e4]);
|
|
365
365
|
|
|
366
366
|
this.swapIfInCircle(f3, v4, v2, v3, e5, e2, en);
|
|
367
367
|
this.swapIfInCircle(f4, v1, v4, v3, e4, en, e3);
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import type { Graph } from '../../model/graph.js';
|
|
11
11
|
import type { Edge } from '../../model/edge.js';
|
|
12
|
+
import { agerrLineOn } from '../../common/agerr.js';
|
|
12
13
|
|
|
13
14
|
/** `dfltlen` passed by scan_graph_mode. @see lib/neatogen/stuff.c:scan_graph_mode */
|
|
14
15
|
export const DEFAULT_EDGE_LEN = 1.0;
|
|
@@ -24,7 +25,7 @@ export function lenattr(ep: Edge, g: Graph): number {
|
|
|
24
25
|
const val = /^\s*[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?/.exec(s);
|
|
25
26
|
const len = val === null ? Number.NaN : parseFloat(val[0]);
|
|
26
27
|
if (Number.isNaN(len) || len < 0 || len === 0) {
|
|
27
|
-
|
|
28
|
+
agerrLineOn('warn', `bad edge len "${s}" in ${g.name} - setting to ${DEFAULT_EDGE_LEN.toFixed(2)}`);
|
|
28
29
|
return DEFAULT_EDGE_LEN;
|
|
29
30
|
}
|
|
30
31
|
return len;
|
|
@@ -26,6 +26,7 @@ import { vpscAdjust } from './vpsc-adjust.js';
|
|
|
26
26
|
import { sepFactor } from './sep-factor.js';
|
|
27
27
|
import { lateDouble } from '../../common/nodeinit.js';
|
|
28
28
|
import { RenderError } from '../../errors.js';
|
|
29
|
+
import { agerrLineOn } from '../../common/agerr.js';
|
|
29
30
|
|
|
30
31
|
/** @see lib/neatogen/adjust.c:DFLT_MARGIN (points) */
|
|
31
32
|
const DFLT_MARGIN = 4;
|
|
@@ -161,7 +162,7 @@ export function warnUnrecognizedOverlap(flag: string | undefined): void {
|
|
|
161
162
|
const s = flag.toLowerCase();
|
|
162
163
|
if (s.startsWith('prism') || NAMED_MODES.has(s)) return;
|
|
163
164
|
if (mapBoolDflt(flag, false) === mapBoolDflt(flag, true)) return;
|
|
164
|
-
|
|
165
|
+
agerrLineOn('warn', `Unrecognized overlap value "${flag}" - using false`);
|
|
165
166
|
}
|
|
166
167
|
|
|
167
168
|
/**
|
|
@@ -203,7 +204,7 @@ function adjustLate(g: Graph, am: AdjustData): number {
|
|
|
203
204
|
case AM_IPSEP: return 0;
|
|
204
205
|
case AM_VPSC: return vpscAdjust(g);
|
|
205
206
|
default:
|
|
206
|
-
|
|
207
|
+
agerrLineOn('warn', `Unhandled adjust option ${am.print}`);
|
|
207
208
|
return 0;
|
|
208
209
|
}
|
|
209
210
|
}
|
package/src/layout/neato/init.ts
CHANGED
|
@@ -50,6 +50,7 @@ export const MODE_HIER = 2;
|
|
|
50
50
|
export const MODE_IPSEP = 3;
|
|
51
51
|
/** Stochastic gradient descent. @see lib/neatogen/neatoprocs.h */
|
|
52
52
|
export const MODE_SGD = 4;
|
|
53
|
+
/** `MaxIter` under MODE_SGD. @see neatoinit.c:1285 */ const SGD_ITERATIONS = 30;
|
|
53
54
|
|
|
54
55
|
// ---------------------------------------------------------------------------
|
|
55
56
|
// Model constants — @see lib/neatogen/defs.h
|
|
@@ -321,6 +322,13 @@ export function mapModelToStress(model: number): number {
|
|
|
321
322
|
// solveModel helpers
|
|
322
323
|
// ---------------------------------------------------------------------------
|
|
323
324
|
|
|
325
|
+
/** `MaxIter` per mode; `maxiter` goes through C `atoi` (no digits -> 0). @see neatoinit.c:1280-1287 */
|
|
326
|
+
export function neatoMaxIter(maxiter: string | undefined, mode: number, n: number): number {
|
|
327
|
+
if (maxiter !== undefined) return parseInt(maxiter, 10) || 0;
|
|
328
|
+
if (mode === MODE_MAJOR) return DFLT_ITERATIONS;
|
|
329
|
+
return mode === MODE_SGD ? SGD_ITERATIONS : 100 * n;
|
|
330
|
+
}
|
|
331
|
+
|
|
324
332
|
/** Run stress majorization and write positions back. @see lib/neatogen/neatoinit.c:majorization */
|
|
325
333
|
export function runMajorization(g: Graph, mode: number, model: number): void {
|
|
326
334
|
void model; // only MODEL_SHORTPATH distances are exercised by the suite
|
|
@@ -329,7 +337,7 @@ export function runMajorization(g: Graph, mode: number, model: number): void {
|
|
|
329
337
|
const haveLen = graphHasLen(g);
|
|
330
338
|
const vtx = makeGraphDataC(g, nodeList, haveLen, mode === MODE_HIER || mode === MODE_IPSEP);
|
|
331
339
|
checkStart(g); // C: srand48(seed) immediately before initLayout draws
|
|
332
|
-
const maxi =
|
|
340
|
+
const maxi = neatoMaxIter(g.attrs.get('maxiter'), mode, n);
|
|
333
341
|
const epsilon = lateDouble(g.attrs.get('epsilon'), 1e-4, 0); // DFLT_TOLERANCE
|
|
334
342
|
// C ipsep (stress_majorization_cola, constrained_majorization_ipsep.c:150) always uses
|
|
335
343
|
// compute_apsp_packed; kD_mkernel uses the weighted APSP iff graph->ewgts (stress.c:855).
|
|
@@ -389,11 +397,7 @@ export function makeGraphDataC(
|
|
|
389
397
|
return vtx;
|
|
390
398
|
}
|
|
391
399
|
|
|
392
|
-
/**
|
|
393
|
-
* Dispatch to the appropriate layout solver for the given mode.
|
|
394
|
-
*
|
|
395
|
-
* @see lib/neatogen/neatoinit.c:neatoLayout
|
|
396
|
-
*/
|
|
400
|
+
/** Dispatch to the layout solver for the mode. @see lib/neatogen/neatoinit.c:neatoLayout */
|
|
397
401
|
export function solveModel(g: Graph, mode: number, model: number): void {
|
|
398
402
|
if (g.nodes.size < 2) return;
|
|
399
403
|
assertSupported(g, mode, model);
|
|
@@ -411,11 +415,7 @@ export function solveModel(g: Graph, mode: number, model: number): void {
|
|
|
411
415
|
// neatoTranslate helpers
|
|
412
416
|
// ---------------------------------------------------------------------------
|
|
413
417
|
|
|
414
|
-
/**
|
|
415
|
-
* Find minimum X and Y across all node positions.
|
|
416
|
-
*
|
|
417
|
-
* @see lib/neatogen/neatoinit.c (translate logic)
|
|
418
|
-
*/
|
|
418
|
+
/** Minimum X and Y across all node positions. @see lib/neatogen/neatoinit.c (translate logic) */
|
|
419
419
|
export function findMinPos(g: Graph): { minX: number; minY: number } {
|
|
420
420
|
let minX = Infinity;
|
|
421
421
|
let minY = Infinity;
|
package/src/layout/neato/kk.ts
CHANGED
|
@@ -27,6 +27,7 @@ import { MODEL_MDS } from './init.js';
|
|
|
27
27
|
import { solve } from './kk-solve.js';
|
|
28
28
|
import { lenattr } from './edge-len.js';
|
|
29
29
|
import { newPathState, shortestPath, mdsModel, type Neighbour } from './kk-paths.js';
|
|
30
|
+
import { agerrLineOn } from '../../common/agerr.js';
|
|
30
31
|
|
|
31
32
|
/** `Ndim`: layout dimension (this port lays out in 2-D only). */
|
|
32
33
|
const NDIM = 2;
|
|
@@ -289,7 +290,7 @@ function moveNode(st: KkState, m: number): void {
|
|
|
289
290
|
function solveModel(g: Graph, st: KkState): void {
|
|
290
291
|
for (let m = chooseNode(st); m >= 0; m = chooseNode(st)) moveNode(st, m);
|
|
291
292
|
if (st.move === st.maxIter) {
|
|
292
|
-
|
|
293
|
+
agerrLineOn('warn', `Max. iterations (${st.maxIter}) reached on graph ${g.name}`);
|
|
293
294
|
}
|
|
294
295
|
}
|
|
295
296
|
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
import type { Point, Poly } from '../../pathplan/types.js';
|
|
20
20
|
import { wind } from '../../pathplan/visibility.js';
|
|
21
21
|
import { mkSurface } from './cdt-surface.js';
|
|
22
|
+
import { dist2 } from '../../common/spline-midpoint.js';
|
|
22
23
|
import { InternalError } from '../../errors.js';
|
|
23
24
|
|
|
24
25
|
/** index pair. @see multispline.c:ipair */
|
|
@@ -87,9 +88,8 @@ function sharedEdge(faces: number[], p3: number, q3: number): Ipair {
|
|
|
87
88
|
|
|
88
89
|
/** @see multispline.c:addTriEdge */
|
|
89
90
|
export function addTriEdge(g: Tgraph, t: number, h: number, seg: Ipair): void {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
g.nodes[t]!.ctr.y - g.nodes[h]!.ctr.y);
|
|
91
|
+
/* DIST = sqrt(fused DIST2): libgvplugin_neato_layout _addTriEdge fmul/fmadd/fsqrt */
|
|
92
|
+
const dist = Math.sqrt(dist2(g.nodes[t]!.ctr, g.nodes[h]!.ctr));
|
|
93
93
|
const idx = g.edges.length;
|
|
94
94
|
g.edges.push({ t, h, seg, dist });
|
|
95
95
|
g.nodes[t]!.edges.push(idx);
|
|
@@ -25,6 +25,7 @@ import { clipAndInstall } from '../../common/splines-clip.js';
|
|
|
25
25
|
import { makeStraightEdges, addEdgeLabels } from '../dot/straight-edges.js';
|
|
26
26
|
import type { Router, Ipair } from './multispline-router.js';
|
|
27
27
|
import { addEndpoint, edgeToSeg, triPath } from './multispline-router.js';
|
|
28
|
+
import { agwarningf } from '../../common/agerr.js';
|
|
28
29
|
|
|
29
30
|
export type { Router } from './multispline-router.js';
|
|
30
31
|
export { mkRouter } from './multispline-router.js';
|
|
@@ -339,8 +340,8 @@ function chainOf(e: Edge): Edge[] {
|
|
|
339
340
|
* @see multispline.c:genroute
|
|
340
341
|
*/
|
|
341
342
|
function warnNoControlPoints(e: Edge): number {
|
|
342
|
-
|
|
343
|
-
`
|
|
343
|
+
agwarningf(
|
|
344
|
+
`Could not create control points for multiple spline for edge (${e.tail.name},${e.head.name})`,
|
|
344
345
|
);
|
|
345
346
|
return 1;
|
|
346
347
|
}
|
package/src/layout/neato/poly.ts
CHANGED
|
@@ -19,6 +19,7 @@ import type { Node } from '../../model/node.js';
|
|
|
19
19
|
import type { Box, Point } from '../../model/geom.js';
|
|
20
20
|
import { ShapeKind } from '../../common/types.js';
|
|
21
21
|
import type { PolygonT } from '../../common/types.js';
|
|
22
|
+
import { agerrorf } from '../../common/agerr.js';
|
|
22
23
|
|
|
23
24
|
/** @see lib/neatogen/poly.c:BOX */
|
|
24
25
|
export const POLY_BOX = 1;
|
|
@@ -258,7 +259,7 @@ export function makeAddPoly(n: Node, xmargin: number, ymargin: number): Poly | n
|
|
|
258
259
|
case ShapeKind.SH_POINT:
|
|
259
260
|
return finishPoly(genRound(n, xmargin, ymargin), POLY_CIRCLE);
|
|
260
261
|
default:
|
|
261
|
-
|
|
262
|
+
agerrorf(`makeAddPoly: unknown shape type ${shapeName(n)}\n`);
|
|
262
263
|
return null;
|
|
263
264
|
}
|
|
264
265
|
}
|
|
@@ -296,7 +297,7 @@ function baseShape(n: Node): { verts: Point[]; kind: number } | null {
|
|
|
296
297
|
case ShapeKind.SH_POINT:
|
|
297
298
|
return { verts: genRound(n, 0, 0), kind: POLY_CIRCLE };
|
|
298
299
|
default:
|
|
299
|
-
|
|
300
|
+
agerrorf(`makePoly: unknown shape type ${shapeName(n)}\n`);
|
|
300
301
|
return null;
|
|
301
302
|
}
|
|
302
303
|
}
|
package/src/layout/neato/sgd.ts
CHANGED
|
@@ -17,6 +17,7 @@ import type { RkState } from '../../util/mt19937.js';
|
|
|
17
17
|
import { drand48 } from '../../common/random.js';
|
|
18
18
|
import { lateDouble } from '../../common/nodeinit.js';
|
|
19
19
|
import { checkStart, parseStart, INIT_RANDOM, INIT_REGULAR } from './start.js';
|
|
20
|
+
import { agerrLineOn } from '../../common/agerr.js';
|
|
20
21
|
|
|
21
22
|
// ---------------------------------------------------------------------------
|
|
22
23
|
// Model constants — @see lib/neatogen/defs.h
|
|
@@ -407,13 +408,15 @@ export function buildUnfixed(g: Graph, n: number): boolean[] {
|
|
|
407
408
|
*/
|
|
408
409
|
export function resolveModel(model: number): number {
|
|
409
410
|
if (model === MODEL_CIRCUIT) {
|
|
410
|
-
|
|
411
|
+
agerrLineOn(
|
|
412
|
+
'warn',
|
|
411
413
|
'circuit model not yet supported in Gmode=sgd, reverting to shortpath model',
|
|
412
414
|
);
|
|
413
415
|
return MODEL_SHORTPATH;
|
|
414
416
|
}
|
|
415
417
|
if (model === MODEL_MDS) {
|
|
416
|
-
|
|
418
|
+
agerrLineOn(
|
|
419
|
+
'warn',
|
|
417
420
|
'mds model not yet supported in Gmode=sgd, reverting to shortpath model',
|
|
418
421
|
);
|
|
419
422
|
return MODEL_SHORTPATH;
|
|
@@ -13,12 +13,14 @@
|
|
|
13
13
|
import { RenderError } from '../../errors.js';
|
|
14
14
|
import type { Graph } from '../../model/graph.js';
|
|
15
15
|
import { srand48 } from '../../common/random.js';
|
|
16
|
+
import { registerRenderState } from '../../common/render-state.js';
|
|
16
17
|
import { mapbool, isACluster } from '../dot/rank.js';
|
|
17
18
|
import { getPack } from '../pack/index.js';
|
|
18
19
|
import {
|
|
19
20
|
MODE_KK, MODE_MAJOR, MODE_HIER, MODE_IPSEP, MODE_SGD,
|
|
20
21
|
MODEL_CIRCUIT, MODEL_SUBSET,
|
|
21
22
|
} from './init.js';
|
|
23
|
+
import { agerrLineOn } from '../../common/agerr.js';
|
|
22
24
|
|
|
23
25
|
/** @see lib/neatogen/neato.h:INIT_SELF */
|
|
24
26
|
export const INIT_SELF = 0;
|
|
@@ -41,11 +43,12 @@ const WARN_POS_IGNORED = 'node positions are ignored unless start=random';
|
|
|
41
43
|
const WARN_SELF_IGNORED = 'start=0 not supported with mode=self - ignored';
|
|
42
44
|
|
|
43
45
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
46
|
+
* C's `static atomic_flag once` for the start=self warning under KK/SGD: once
|
|
47
|
+
* per process, so once per render here (AD-4 resets it at render entry).
|
|
48
|
+
* @see lib/neatogen/stuff.c:330
|
|
47
49
|
*/
|
|
48
|
-
const
|
|
50
|
+
const selfOnce = { warned: false };
|
|
51
|
+
registerRenderState(() => { selfOnce.warned = false; });
|
|
49
52
|
/** Roots already warned about the KK circuit fallback (one warning per graph). */
|
|
50
53
|
const circuitWarned = new WeakSet<object>();
|
|
51
54
|
|
|
@@ -96,7 +99,7 @@ export function checkStart(
|
|
|
96
99
|
): number {
|
|
97
100
|
const { init, seed } = parseStart(g.root.attrs.get('start'), dflt);
|
|
98
101
|
if (init !== INIT_RANDOM && [...g.nodes.values()].some((n) => n.attrs.has('pos'))) {
|
|
99
|
-
|
|
102
|
+
agerrLineOn('warn', WARN_POS_IGNORED);
|
|
100
103
|
}
|
|
101
104
|
if (init === INIT_REGULAR) initRegular(g, nG);
|
|
102
105
|
srand48(seed);
|
|
@@ -141,7 +144,7 @@ export function neatoMode(g: Graph): number {
|
|
|
141
144
|
if (str === undefined || str === '') return MODE_MAJOR;
|
|
142
145
|
const mode = modeByName().get(str);
|
|
143
146
|
if (mode !== undefined) return mode;
|
|
144
|
-
|
|
147
|
+
agerrLineOn('warn', `Illegal value ${str} for attribute "mode" in graph ${g.root.name} - ignored`);
|
|
145
148
|
return MODE_MAJOR;
|
|
146
149
|
}
|
|
147
150
|
|
|
@@ -161,9 +164,9 @@ function checkStartAttr(g: Graph, mode: number): void {
|
|
|
161
164
|
// @see lib/neatogen/neatoinit.c:1095, lib/neatogen/stress.c:884 (smart_ini)
|
|
162
165
|
if (mode === MODE_MAJOR || mode === MODE_IPSEP) unsupported('start', value ?? '', 'smart initialisation');
|
|
163
166
|
// @see lib/neatogen/stuff.c:330 (KK and SGD warn once and ignore it)
|
|
164
|
-
if ((mode === MODE_KK || mode === MODE_SGD) && !
|
|
165
|
-
|
|
166
|
-
|
|
167
|
+
if ((mode === MODE_KK || mode === MODE_SGD) && !selfOnce.warned) {
|
|
168
|
+
selfOnce.warned = true;
|
|
169
|
+
agerrLineOn('warn', WARN_SELF_IGNORED);
|
|
167
170
|
}
|
|
168
171
|
}
|
|
169
172
|
|
|
@@ -189,7 +192,8 @@ function kkCircuitFallsBack(g: Graph): boolean {
|
|
|
189
192
|
function warnCircuitDisconnected(g: Graph): void {
|
|
190
193
|
if (circuitWarned.has(g.root)) return;
|
|
191
194
|
circuitWarned.add(g.root);
|
|
192
|
-
|
|
195
|
+
agerrLineOn(
|
|
196
|
+
'warn',
|
|
193
197
|
`graph ${g.root.name} is disconnected. Hence, the circuit model\n`
|
|
194
198
|
+ 'is undefined. Reverting to the shortest path model.\n'
|
|
195
199
|
+ 'Alternatively, consider running neato using -Gpack=true or decomposing\n'
|
package/src/ortho/index.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
} from "./sgraph.js";
|
|
21
21
|
import { convertSPtoRoute, assignSegs, assignTracks, vtrack, htrack } from "./ortho-route.js";
|
|
22
22
|
import { gvQsort } from "../util/bsd-qsort.js";
|
|
23
|
+
import { agerrLineOn } from '../common/agerr.js';
|
|
23
24
|
|
|
24
25
|
export type { OrthoGraph, OrthoEdge, OrthoNode, OrthoPoint, ClipAndInstallFn };
|
|
25
26
|
export { SEED } from "./partition.js";
|
|
@@ -144,7 +145,8 @@ export function orthoEdges(
|
|
|
144
145
|
clipAndInstall?: ClipAndInstallFn,
|
|
145
146
|
): number {
|
|
146
147
|
if (useLbls) {
|
|
147
|
-
|
|
148
|
+
agerrLineOn(
|
|
149
|
+
'warn',
|
|
148
150
|
"Orthogonal edges do not currently handle edge labels. Try using xlabels.\n",
|
|
149
151
|
);
|
|
150
152
|
useLbls = false; // eslint-disable-line no-param-reassign
|
package/src/parser/dot.js
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
// https://peggyjs.org/
|
|
4
4
|
|
|
5
5
|
|
|
6
|
+
|
|
7
|
+
import { agwarningf } from "../common/agerr.js";
|
|
8
|
+
|
|
6
9
|
class peg$SyntaxError extends SyntaxError {
|
|
7
10
|
constructor(message, expected, found, location) {
|
|
8
11
|
super(message);
|
|
@@ -286,7 +289,7 @@ function peg$parse(input, options) {
|
|
|
286
289
|
function peg$f13(t, m, attrs) {
|
|
287
290
|
// grammar.y:attrstmt calls nomacros() when a macro name is present;
|
|
288
291
|
// the attributes are still applied unchanged.
|
|
289
|
-
if (m)
|
|
292
|
+
if (m) agwarningf("attribute macros not implemented", "error");
|
|
290
293
|
return { type: "attr", target: t, attrs: attrs };
|
|
291
294
|
}
|
|
292
295
|
function peg$f14(a) { return { type: "assign", key: a.key, value: a.value }; }
|
package/src/parser/dot.pegjs
CHANGED
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
// Architecture decision AD-11: this file is the canonical faithfulness
|
|
9
9
|
// artifact; every production cites its Bison rule or Flex token.
|
|
10
10
|
|
|
11
|
+
{{
|
|
12
|
+
import { agwarningf } from "../common/agerr.js";
|
|
13
|
+
}}
|
|
14
|
+
|
|
11
15
|
// ── Top-level rule ───────────────────────────────────────────────────────────
|
|
12
16
|
// grammar.y: graph : hdr body | error | /* empty */
|
|
13
17
|
// `end` is the offset just past the graph's closing brace: the last input the
|
|
@@ -71,7 +75,7 @@ AttrStmt
|
|
|
71
75
|
{
|
|
72
76
|
// grammar.y:attrstmt calls nomacros() when a macro name is present;
|
|
73
77
|
// the attributes are still applied unchanged.
|
|
74
|
-
if (m)
|
|
78
|
+
if (m) agwarningf("attribute macros not implemented", "error");
|
|
75
79
|
return { type: "attr", target: t, attrs: attrs };
|
|
76
80
|
}
|
|
77
81
|
/ a:AttrAssignment
|
package/src/parser/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { syntaxErrorMessage } from './scan-token.js';
|
|
|
18
18
|
import type { ParsedGraph } from './ast.js';
|
|
19
19
|
import type { GvErrorCode, GvExpectation } from '../errors.js';
|
|
20
20
|
import { DotEngineError, friendlyMessageFor, invalidArgType } from '../errors.js';
|
|
21
|
+
import { agerrFinished } from '../common/agerr.js';
|
|
21
22
|
|
|
22
23
|
// ── ParseError ────────────────────────────────────────────────────────────────
|
|
23
24
|
|
|
@@ -233,7 +234,7 @@ export function isPeggyError(err: unknown): err is {
|
|
|
233
234
|
function warnNumberAmbiguities(src: string, upTo: number): void {
|
|
234
235
|
for (const a of scanNumberAmbiguities(src, Stripper.strip(src))) {
|
|
235
236
|
if (a.offset > upTo) break;
|
|
236
|
-
|
|
237
|
+
agerrFinished(numberAmbiguityMessage(a), 'error');
|
|
237
238
|
}
|
|
238
239
|
}
|
|
239
240
|
|
|
@@ -250,7 +251,7 @@ export function parse(src: string): Graph {
|
|
|
250
251
|
if (isPeggyError(err)) {
|
|
251
252
|
const start = err.location.start;
|
|
252
253
|
warnNumberAmbiguities(src, start.offset);
|
|
253
|
-
|
|
254
|
+
agerrFinished(syntaxErrorMessage(src, start.offset));
|
|
254
255
|
const code: GvErrorCode =
|
|
255
256
|
err.found === null ? 'SYNTAX_UNEXPECTED_EOF' : 'SYNTAX_ERROR';
|
|
256
257
|
throw new ParseError(
|
|
@@ -282,7 +283,7 @@ export function parse(src: string): Graph {
|
|
|
282
283
|
const offset = err instanceof ParseError ? err.location.offset : undefined;
|
|
283
284
|
if (offset !== undefined) {
|
|
284
285
|
warnNumberAmbiguities(src, offset);
|
|
285
|
-
|
|
286
|
+
agerrFinished(syntaxErrorMessage(src, offset));
|
|
286
287
|
}
|
|
287
288
|
throw err;
|
|
288
289
|
}
|