@knowvah/dot-engine 2.7.1 → 2.8.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/dist/api.js.map +2 -2
- package/dist/common/agerr.d.ts +8 -1
- package/dist/common/agerr.d.ts.map +1 -1
- package/dist/common/fma.d.ts.map +1 -1
- package/dist/common/htmltable-emit-fill.d.ts.map +1 -1
- package/dist/common/htmltable-label.d.ts +3 -0
- package/dist/common/htmltable-label.d.ts.map +1 -1
- package/dist/common/htmltable-lex-attvalue.d.ts.map +1 -1
- package/dist/common/htmltable.d.ts +5 -0
- package/dist/common/htmltable.d.ts.map +1 -1
- package/dist/common/layers.d.ts +12 -0
- package/dist/common/layers.d.ts.map +1 -1
- package/dist/common/layout-state.d.ts +8 -0
- package/dist/common/layout-state.d.ts.map +1 -0
- package/dist/common/make-label.d.ts.map +1 -1
- package/dist/common/multicolor.d.ts +6 -3
- package/dist/common/multicolor.d.ts.map +1 -1
- package/dist/common/nodeinit.d.ts.map +1 -1
- package/dist/common/poly-init.d.ts +11 -0
- package/dist/common/poly-init.d.ts.map +1 -1
- package/dist/common/poly-sizing.d.ts +1 -0
- package/dist/common/poly-sizing.d.ts.map +1 -1
- package/dist/common/postproc.d.ts.map +1 -1
- package/dist/common/style-resolve.d.ts +11 -9
- package/dist/common/style-resolve.d.ts.map +1 -1
- package/dist/gvc/device-cluster.d.ts +5 -6
- package/dist/gvc/device-cluster.d.ts.map +1 -1
- package/dist/gvc/device.d.ts.map +1 -1
- package/dist/gvc/first-layer.d.ts +21 -5
- package/dist/gvc/first-layer.d.ts.map +1 -1
- package/dist/gvc/gvrender-set-style.d.ts.map +1 -1
- package/dist/gvc/usershape.d.ts +20 -0
- package/dist/gvc/usershape.d.ts.map +1 -1
- package/dist/index.js +494 -275
- package/dist/index.js.map +4 -4
- package/dist/layout/circo/index.d.ts.map +1 -1
- package/dist/layout/dot/init.d.ts +10 -0
- package/dist/layout/dot/init.d.ts.map +1 -1
- package/dist/layout/dot/splines.d.ts.map +1 -1
- package/dist/layout/fdp/init.d.ts.map +1 -1
- package/dist/layout/neato/conjgrad-mkernel.d.ts.map +1 -1
- package/dist/layout/neato/constrained-majorization.d.ts.map +1 -1
- package/dist/layout/neato/edge-len.d.ts +6 -2
- package/dist/layout/neato/edge-len.d.ts.map +1 -1
- package/dist/layout/neato/init.d.ts.map +1 -1
- package/dist/layout/neato/kk.d.ts.map +1 -1
- package/dist/layout/neato/make-graph-data.d.ts.map +1 -1
- package/dist/layout/neato/matrix-ops.d.ts +0 -6
- package/dist/layout/neato/matrix-ops.d.ts.map +1 -1
- package/dist/layout/neato/smart-ini-x.d.ts.map +1 -1
- package/dist/layout/neato/splines.d.ts.map +1 -1
- package/dist/layout/neato/start.d.ts.map +1 -1
- package/dist/layout/neato/stress-kernel.d.ts +2 -5
- package/dist/layout/neato/stress-kernel.d.ts.map +1 -1
- package/dist/layout/neato/stress.d.ts +6 -0
- package/dist/layout/neato/stress.d.ts.map +1 -1
- package/dist/layout/osage/index.d.ts.map +1 -1
- package/dist/layout/patchwork/index.d.ts.map +1 -1
- package/dist/layout/sfdp/init.d.ts.map +1 -1
- package/dist/layout/twopi/init.d.ts +12 -6
- package/dist/layout/twopi/init.d.ts.map +1 -1
- package/dist/model/cgraph-ops.d.ts +9 -0
- package/dist/model/cgraph-ops.d.ts.map +1 -1
- package/dist/render/color-resolve.d.ts +7 -0
- package/dist/render/color-resolve.d.ts.map +1 -1
- package/dist/render/json.d.ts +17 -2
- package/dist/render/json.d.ts.map +1 -1
- package/dist/render/map.d.ts +3 -5
- package/dist/render/map.d.ts.map +1 -1
- package/dist/render.js +500 -281
- package/dist/render.js.map +4 -4
- package/package.json +1 -1
- package/src/common/agerr.ts +69 -8
- package/src/common/fma.ts +11 -1
- package/src/common/htmltable-emit-fill.ts +11 -7
- package/src/common/htmltable-label.ts +6 -3
- package/src/common/htmltable-lex-attvalue.ts +17 -1
- package/src/common/htmltable.ts +10 -5
- package/src/common/layers.ts +31 -2
- package/src/common/layout-state.ts +35 -0
- package/src/common/make-label.ts +6 -2
- package/src/common/multicolor.ts +12 -6
- package/src/common/nodeinit.ts +2 -1
- package/src/common/poly-init.ts +18 -1
- package/src/common/poly-sizing.ts +4 -4
- package/src/common/postproc.ts +4 -1
- package/src/common/style-resolve.ts +118 -50
- package/src/gvc/device-cluster.ts +31 -39
- package/src/gvc/device.ts +55 -43
- package/src/gvc/first-layer.ts +60 -11
- package/src/gvc/gvrender-set-style.ts +1 -6
- package/src/gvc/usershape.ts +40 -0
- package/src/layout/circo/index.ts +4 -0
- package/src/layout/dot/init.ts +32 -0
- package/src/layout/dot/splines.ts +3 -0
- package/src/layout/fdp/init.ts +17 -0
- package/src/layout/neato/conjgrad-mkernel.ts +2 -3
- package/src/layout/neato/constrained-majorization.ts +2 -1
- package/src/layout/neato/edge-len.ts +39 -7
- package/src/layout/neato/init.ts +8 -3
- package/src/layout/neato/kk.ts +2 -1
- package/src/layout/neato/make-graph-data.ts +1 -2
- package/src/layout/neato/matrix-ops.ts +1 -11
- package/src/layout/neato/smart-ini-x.ts +1 -1
- package/src/layout/neato/splines.ts +3 -1
- package/src/layout/neato/start.ts +3 -2
- package/src/layout/neato/stress-kernel.ts +45 -86
- package/src/layout/neato/stress.ts +19 -0
- package/src/layout/osage/index.ts +8 -1
- package/src/layout/patchwork/index.ts +4 -0
- package/src/layout/sfdp/init.ts +3 -0
- package/src/layout/twopi/init.ts +21 -9
- package/src/layout/twopi/pipeline.ts +3 -3
- package/src/model/cgraph-ops.ts +19 -0
- package/src/render/color-resolve.ts +17 -2
- package/src/render/json.ts +9 -10
- package/src/render/map.ts +5 -6
package/src/gvc/usershape.ts
CHANGED
|
@@ -63,3 +63,43 @@ export function imageIsSupplied(name: string, sizer?: ImageSizer, resolver?: Ima
|
|
|
63
63
|
export function imageOpenWarning(name: string): string {
|
|
64
64
|
return `${STRERROR_ENOENT} while opening ${name}`;
|
|
65
65
|
}
|
|
66
|
+
|
|
67
|
+
/** @see lib/gvc/gvusershape.c:DEFAULT_DPI */
|
|
68
|
+
export const DEFAULT_DPI = 96;
|
|
69
|
+
/** @see lib/common/geom.h:POINTS_PER_INCH */
|
|
70
|
+
const POINTS_PER_INCH = 72;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The graph's `dpi` as `gvusershape_size` reads it: GD_drawing->dpi is
|
|
74
|
+
* late_double(dpi, resolution, 0) (input.c:705), and a value below 1 means
|
|
75
|
+
* the 96 default.
|
|
76
|
+
* @see lib/common/input.c:graph_init (dpi), lib/gvc/gvusershape.c:gvusershape_size
|
|
77
|
+
*/
|
|
78
|
+
export function usershapeDpi(attrs: ReadonlyMap<string, string>): number {
|
|
79
|
+
const lateDouble = (s: string | undefined, dflt: number): number => {
|
|
80
|
+
if (s === undefined || s === '') return dflt;
|
|
81
|
+
const v = Number(s);
|
|
82
|
+
return Number.isNaN(v) || s.trim() === '' ? dflt : Math.max(v, 0);
|
|
83
|
+
};
|
|
84
|
+
const dpi = lateDouble(attrs.get('dpi'), lateDouble(attrs.get('resolution'), 0));
|
|
85
|
+
return dpi >= 1 ? dpi : DEFAULT_DPI;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Image size in points: `gvusershape_size`. The caller's sizer reports pixels;
|
|
90
|
+
* the result is `(int)(px * 72 / dpi)` (the file's own dpi is unknown to a
|
|
91
|
+
* sizer, so `us->dpi` is 0 as for most formats). Null stands for C's (-1,-1):
|
|
92
|
+
* empty name or an image nobody supplies.
|
|
93
|
+
* @see lib/gvc/gvusershape.c:gvusershape_size, gvusershape_size_dpi
|
|
94
|
+
*/
|
|
95
|
+
export function usershapeSizePts(
|
|
96
|
+
name: string | undefined, dpi: number, sizer?: ImageSizer,
|
|
97
|
+
): { x: number; y: number } | null {
|
|
98
|
+
if (name === undefined || name === '') return null;
|
|
99
|
+
const px = sizer !== undefined ? sizer(name) : findImageSize(name);
|
|
100
|
+
if (px === null) return null;
|
|
101
|
+
return {
|
|
102
|
+
x: Math.trunc((px.w * POINTS_PER_INCH) / dpi),
|
|
103
|
+
y: Math.trunc((px.h * POINTS_PER_INCH) / dpi),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import type { Graph } from '../../model/graph.js';
|
|
21
|
+
import { gvCleanupEdgeLabels, gvCleanupNodeLabels } from '../dot/init.js';
|
|
21
22
|
import type { LayoutEngine } from '../../gvc/context.js';
|
|
22
23
|
import { circoInitGraph, freeNData } from './init.js';
|
|
23
24
|
import { circoLayout } from './circular.js';
|
|
@@ -72,6 +73,9 @@ export function circoLayoutFull(g: Graph): void {
|
|
|
72
73
|
|
|
73
74
|
/** @see lib/circogen/circularinit.c:circo_cleanup */
|
|
74
75
|
export function circoCleanup(g: Graph): void {
|
|
76
|
+
if (g.nodes.size === 0) return; // C: g is empty
|
|
77
|
+
for (const e of g.edges) gvCleanupEdgeLabels(e); // gv_cleanup_edge: per-node agfstout, all edges of root g
|
|
78
|
+
for (const n of g.nodes.values()) gvCleanupNodeLabels(n); // gv_cleanup_node
|
|
75
79
|
// Derived graph was stored in g.info.alg during circoLayout; clear it.
|
|
76
80
|
g.info.alg = undefined;
|
|
77
81
|
g.info.neato_nlist = undefined;
|
package/src/layout/dot/init.ts
CHANGED
|
@@ -275,6 +275,35 @@ export function removeFill(g: Graph): void {
|
|
|
275
275
|
// dotCleanup
|
|
276
276
|
// ---------------------------------------------------------------------------
|
|
277
277
|
|
|
278
|
+
/**
|
|
279
|
+
* The label frees shared by every engine's per-edge cleanup.
|
|
280
|
+
* @see lib/common/utils.c:gv_cleanup_edge
|
|
281
|
+
*/
|
|
282
|
+
export function gvCleanupEdgeLabels(e: Edge): void {
|
|
283
|
+
e.info.label = undefined;
|
|
284
|
+
e.info.xlabel = undefined;
|
|
285
|
+
e.info.head_label = undefined;
|
|
286
|
+
e.info.tail_label = undefined;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* The label frees shared by every non-dot engine's per-node cleanup.
|
|
291
|
+
* @see lib/common/utils.c:gv_cleanup_node
|
|
292
|
+
*/
|
|
293
|
+
export function gvCleanupNodeLabels(n: Node): void {
|
|
294
|
+
n.info.label = undefined;
|
|
295
|
+
n.info.xlabel = undefined;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Frees non-root subgraph labels, recursing into every subgraph first.
|
|
300
|
+
* @see lib/dotgen/dotinit.c:dot_cleanup_graph
|
|
301
|
+
*/
|
|
302
|
+
function dotCleanupGraph(g: Graph): void {
|
|
303
|
+
for (const subg of g.subgraphs.values()) dotCleanupGraph(subg);
|
|
304
|
+
if (g !== g.root) g.info.label = undefined;
|
|
305
|
+
}
|
|
306
|
+
|
|
278
307
|
/**
|
|
279
308
|
* Clears all edge lists and linked-list pointers from nodes in the fast-graph,
|
|
280
309
|
* releasing layout state without destroying the underlying graph structure.
|
|
@@ -284,6 +313,9 @@ export function removeFill(g: Graph): void {
|
|
|
284
313
|
* @see lib/dotgen/dotinit.c:dot_cleanup
|
|
285
314
|
*/
|
|
286
315
|
export function dotCleanup(g: Graph): void {
|
|
316
|
+
for (const e of g.edges) gvCleanupEdgeLabels(e); // gv_cleanup_edge (all out-edges)
|
|
317
|
+
for (const n of g.nodes.values()) gvCleanupNodeLabels(n); // dot_cleanup_node
|
|
318
|
+
dotCleanupGraph(g);
|
|
287
319
|
let n: Node | undefined = g.info.nlist;
|
|
288
320
|
while (n !== undefined) {
|
|
289
321
|
const next: Node | undefined = n.info.next;
|
|
@@ -27,6 +27,7 @@ import { routeEdgeGroups } from './splines-groups.js';
|
|
|
27
27
|
import { placePortLabels, placeRegularEdgeLabels, setEdgeLabelPos } from './splines-label.js';
|
|
28
28
|
import { nodesInSeq } from './decomp.js';
|
|
29
29
|
import { agerrLineOn } from '../../common/agerr.js';
|
|
30
|
+
import { setState, GVSPLINES } from '../../common/layout-state.js';
|
|
30
31
|
|
|
31
32
|
// ---------------------------------------------------------------------------
|
|
32
33
|
// Edge-type flag constants
|
|
@@ -462,6 +463,7 @@ function orthoDispatch(g: Graph): number {
|
|
|
462
463
|
// are placed via place_portlabel for ortho too. Skipping this left the
|
|
463
464
|
// labels unset, so the xlabels pass placed them instead (144_ortho).
|
|
464
465
|
placePortLabels(g);
|
|
466
|
+
setState(GVSPLINES); // @see dotsplines.c:477 (reached via goto finish)
|
|
465
467
|
g.info.edgeLabelsDone = true;
|
|
466
468
|
return 0;
|
|
467
469
|
}
|
|
@@ -487,6 +489,7 @@ function finalizeSplines(g: Graph, et: number, normalize: boolean): void {
|
|
|
487
489
|
if (normalize) edgeNormalize(g);
|
|
488
490
|
if (et !== EDGETYPE_CURVED) routeDotEdges(g);
|
|
489
491
|
placePortLabels(g);
|
|
492
|
+
setState(GVSPLINES); // @see dotsplines.c:477
|
|
490
493
|
g.info.edgeLabelsDone = true; // @see dotsplines.c:471 (EdgeLabelsDone = 1)
|
|
491
494
|
}
|
|
492
495
|
|
package/src/layout/fdp/init.ts
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import type { Graph } from '../../model/graph.js';
|
|
17
|
+
import { gvCleanupEdgeLabels, gvCleanupNodeLabels } from '../dot/init.js';
|
|
17
18
|
import type { Node } from '../../model/node.js';
|
|
18
19
|
import type { Edge } from '../../model/edge.js';
|
|
19
20
|
import { commonInitNodeEdge, lateDouble, layoutMeasurer } from '../../common/nodeinit.js';
|
|
@@ -99,12 +100,28 @@ export function fdpInitNodeEdge(g: Graph): void {
|
|
|
99
100
|
initialPositions(g);
|
|
100
101
|
}
|
|
101
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Frees each cluster label, recursively.
|
|
105
|
+
* @see lib/fdpgen/fdpinit.c:cleanup_subgs
|
|
106
|
+
*/
|
|
107
|
+
function fdpCleanupSubgs(g: Graph): void {
|
|
108
|
+
const nClust = g.info.n_cluster ?? 0;
|
|
109
|
+
for (let i = 1; i <= nClust; i++) {
|
|
110
|
+
const subg = g.info.clust![i - 1];
|
|
111
|
+
subg.info.label = undefined;
|
|
112
|
+
fdpCleanupSubgs(subg);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
102
116
|
/**
|
|
103
117
|
* Release fdp layout state (gv_cleanup analogue; the render pipeline
|
|
104
118
|
* runs before cleanup per the M2 ordering fix).
|
|
105
119
|
* @see lib/fdpgen/fdpinit.c:fdp_cleanup
|
|
106
120
|
*/
|
|
107
121
|
export function fdpCleanup(g: Graph): void {
|
|
122
|
+
for (const e of g.edges) gvCleanupEdgeLabels(e); // gv_cleanup_edge: per-node agfstout, all edges of root g
|
|
123
|
+
for (const n of g.nodes.values()) gvCleanupNodeLabels(n); // gv_cleanup_node
|
|
124
|
+
fdpCleanupSubgs(g);
|
|
108
125
|
for (const n of g.nodes.values()) {
|
|
109
126
|
n.info.alg = undefined;
|
|
110
127
|
n.info.pos = undefined;
|
|
@@ -6,9 +6,8 @@
|
|
|
6
6
|
* C statement `a += b * c` on floats is one `fmadd`/`fmla` (clang's default
|
|
7
7
|
* contraction), and a reduction the vectoriser took in blocks of 16 rounds
|
|
8
8
|
* the products of those leading elements before its in-order adds (strict FP
|
|
9
|
-
* forbids reassociation) while the scalar remainder is fused.
|
|
10
|
-
*
|
|
11
|
-
* needs the oracle's bits.
|
|
9
|
+
* forbids reassociation) while the scalar remainder is fused. These kernels run
|
|
10
|
+
* `stress_majorization_kD_mkernel` and the constrained-majorization driver.
|
|
12
11
|
*
|
|
13
12
|
* @see lib/neatogen/conjgrad.c:conjugate_gradient_mkernel
|
|
14
13
|
* @see lib/neatogen/matrix_ops.c:right_mult_with_vector_ff
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* @see lib/neatogen/constrained_majorization.c
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import { fma } from '../../common/fma.js';
|
|
17
18
|
import { RenderError } from '../../errors.js';
|
|
18
19
|
import type { Node } from '../../model/node.js';
|
|
19
20
|
import { conjugateGradientMkernelFused, rightMultWithVectorFFFused } from './conjgrad-mkernel.js';
|
|
@@ -21,7 +22,7 @@ import { computeHierarchy, type Hierarchy } from './compute-hierarchy.js';
|
|
|
21
22
|
import type { VtxData } from './dijkstra.js';
|
|
22
23
|
import { MODEL_CIRCUIT, MODEL_MDS, MODEL_SUBSET } from './init.js';
|
|
23
24
|
import {
|
|
24
|
-
|
|
25
|
+
invertSqrtVec, invertVec, orthog1, sqrtVecF, squareVec, vectorsInnerProductF,
|
|
25
26
|
} from './matrix-ops.js';
|
|
26
27
|
import type { DirectedVtxData } from './opt-arrangement.js';
|
|
27
28
|
import { computeYCoords } from './opt-arrangement.js';
|
|
@@ -8,12 +8,33 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import type { Graph } from '../../model/graph.js';
|
|
11
|
+
import { agNameOf } from '../../model/cgraph-ops.js';
|
|
11
12
|
import type { Edge } from '../../model/edge.js';
|
|
12
13
|
import { agwarningf } from '../../common/agerr.js';
|
|
14
|
+
import { buildOutEdgeIndex } from '../../model/node.js';
|
|
13
15
|
|
|
14
16
|
/** `dfltlen` passed by scan_graph_mode. @see lib/neatogen/stuff.c:scan_graph_mode */
|
|
15
17
|
export const DEFAULT_EDGE_LEN = 1.0;
|
|
16
18
|
|
|
19
|
+
/** sscanf("%lf") number prefix: decimal, hex, inf/infinity, nan (case-insensitive). */
|
|
20
|
+
const DOUBLE_PREFIX =
|
|
21
|
+
/^\s*([+-]?)(0x(?:[\da-f]+\.?[\da-f]*|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?|inf(?:inity)?|nan(?:\([\w]*\))?)/i;
|
|
22
|
+
|
|
23
|
+
/** `sscanf(s, "%lf", &v)`: the parsed value (NaN for "nan"), or null when nothing scans. */
|
|
24
|
+
function scanDouble(s: string): number | null {
|
|
25
|
+
const m = DOUBLE_PREFIX.exec(s);
|
|
26
|
+
if (m === null) return null;
|
|
27
|
+
const body = m[2]!.toLowerCase();
|
|
28
|
+
const sign = m[1] === '-' ? -1 : 1;
|
|
29
|
+
if (body.startsWith('nan')) return Number.NaN;
|
|
30
|
+
if (body.startsWith('inf')) return sign * Infinity;
|
|
31
|
+
if (!body.startsWith('0x')) return sign * parseFloat(body);
|
|
32
|
+
const [mant, exp] = body.slice(2).split('p');
|
|
33
|
+
const [ip = '', fp = ''] = mant!.split('.');
|
|
34
|
+
const digits = parseInt(ip + fp || '0', 16);
|
|
35
|
+
return sign * digits * 2 ** (Number(exp ?? 0) - 4 * fp.length);
|
|
36
|
+
}
|
|
37
|
+
|
|
17
38
|
/**
|
|
18
39
|
* The edge's `len`, or the default when it is absent or empty; a value that
|
|
19
40
|
* does not parse as a positive number warns and falls back to the default.
|
|
@@ -22,16 +43,27 @@ export const DEFAULT_EDGE_LEN = 1.0;
|
|
|
22
43
|
export function lenattr(ep: Edge, g: Graph): number {
|
|
23
44
|
const s = ep.attrs.get('len');
|
|
24
45
|
if (s === undefined || s === '') return DEFAULT_EDGE_LEN;
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
agwarningf(`bad edge len "${s}" in ${g.name} - setting to ${DEFAULT_EDGE_LEN.toFixed(2)}`);
|
|
46
|
+
const len = scanDouble(s);
|
|
47
|
+
if (len === null || len < 0 || len === 0) {
|
|
48
|
+
agwarningf(`bad edge len "${s}" in ${agNameOf(g)} - setting to ${DEFAULT_EDGE_LEN.toFixed(2)}`);
|
|
29
49
|
return DEFAULT_EDGE_LEN;
|
|
30
50
|
}
|
|
31
51
|
return len;
|
|
32
52
|
}
|
|
33
53
|
|
|
34
|
-
/**
|
|
35
|
-
|
|
36
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Store every edge's length in `info.dist` (ED_dist), visiting nodes in order and each
|
|
56
|
+
* node's out-edges in `agfstout` order as scan_graph_mode does; returns the total length.
|
|
57
|
+
* @see lib/neatogen/stuff.c:setEdgeLen
|
|
58
|
+
*/
|
|
59
|
+
export function setEdgeLen(g: Graph): number {
|
|
60
|
+
const out = buildOutEdgeIndex(g);
|
|
61
|
+
let total = 0;
|
|
62
|
+
for (const np of g.nodes.values()) {
|
|
63
|
+
for (const ep of out.get(np) ?? []) {
|
|
64
|
+
ep.info.dist = lenattr(ep, g);
|
|
65
|
+
total += ep.info.dist;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return total;
|
|
37
69
|
}
|
package/src/layout/neato/init.ts
CHANGED
|
@@ -11,12 +11,14 @@
|
|
|
11
11
|
|
|
12
12
|
import type { ShapeDesc } from '../../common/types.js';
|
|
13
13
|
import type { Graph } from '../../model/graph.js';
|
|
14
|
+
import { gvCleanupEdgeLabels, gvCleanupNodeLabels } from '../dot/init.js';
|
|
14
15
|
import type { Node } from '../../model/node.js';
|
|
15
16
|
import type { Edge } from '../../model/edge.js';
|
|
16
17
|
import type { VtxData } from './dijkstra.js';
|
|
17
18
|
import {
|
|
18
19
|
DFLT_ITERATIONS,
|
|
19
20
|
OPT_SMART_INIT as STRESS_OPT_SMART_INIT,
|
|
21
|
+
checkExp,
|
|
20
22
|
MODEL_MDS as STRESS_MODEL_MDS,
|
|
21
23
|
MODEL_CIRCUIT as STRESS_MODEL_CIRCUIT,
|
|
22
24
|
MODEL_SUBSET as STRESS_MODEL_SUBSET,
|
|
@@ -26,6 +28,7 @@ import { kkNeato } from './kk.js';
|
|
|
26
28
|
import {
|
|
27
29
|
checkStart, assertSupported, parseStart, INIT_RANDOM, INIT_REGULAR, INIT_SELF,
|
|
28
30
|
} from './start.js';
|
|
31
|
+
import { setEdgeLen } from './edge-len.js';
|
|
29
32
|
import { makeGraphDataC, graphHasLen } from './make-graph-data.js';
|
|
30
33
|
import type { DirectedVtxData } from './opt-arrangement.js';
|
|
31
34
|
import { stressMajorizationWithHierarchy } from './constrained-majorization.js';
|
|
@@ -37,7 +40,6 @@ import {
|
|
|
37
40
|
computeApspPacked,
|
|
38
41
|
computeWeightedApspPacked,
|
|
39
42
|
stressMajorizationKDMkernel,
|
|
40
|
-
OPT_EXP_FLAG,
|
|
41
43
|
} from './stress-kernel.js';
|
|
42
44
|
import { lateDouble } from '../../common/nodeinit.js';
|
|
43
45
|
import { inputscaleDivisor } from '../../common/utils-inputscale.js';
|
|
@@ -373,18 +375,19 @@ function solveStress(
|
|
|
373
375
|
const weighted = haveLen && mode !== MODE_IPSEP;
|
|
374
376
|
const Dij = weighted ? computeWeightedApspPacked(vtx, n) : computeApspPacked(vtx, n);
|
|
375
377
|
return stressMajorizationKDMkernel(Dij, n, dCoords, nodeList, {
|
|
376
|
-
dim: DFLT_DIM, opts, maxi, epsilon,
|
|
378
|
+
dim: DFLT_DIM, opts, maxi, epsilon, cola: mode === MODE_IPSEP,
|
|
377
379
|
});
|
|
378
380
|
}
|
|
379
381
|
|
|
380
382
|
/** Run stress majorization and write positions back. @see lib/neatogen/neatoinit.c:majorization */
|
|
381
383
|
export function runMajorization(g: Graph, mode: number, model: number): void {
|
|
382
384
|
const nodeList = assignNodeIds(g);
|
|
385
|
+
setEdgeLen(g); // scan_graph_mode else-branch: ED_dist for major/hier/ipsep
|
|
383
386
|
const n = nodeList.length;
|
|
384
387
|
const haveLen = graphHasLen(g);
|
|
385
388
|
// C: srand48(seed) immediately before initLayout draws; hier starts from self
|
|
386
389
|
const init = checkStart(g, n, mode === MODE_HIER ? INIT_SELF : INIT_RANDOM);
|
|
387
|
-
const opts = init === INIT_SELF ?
|
|
390
|
+
const opts = checkExp(g) | (init === INIT_SELF ? STRESS_OPT_SMART_INIT : 0);
|
|
388
391
|
const haveDir = mode === MODE_HIER || mode === MODE_IPSEP;
|
|
389
392
|
const vtx = makeGraphDataC(g, nodeList, haveLen, haveDir, mode);
|
|
390
393
|
const dCoords = [new Float64Array(n), new Float64Array(n)];
|
|
@@ -489,6 +492,8 @@ export function neatoSetAspect(g: Graph): void {
|
|
|
489
492
|
* @see lib/neatogen/neatoinit.c:neato_cleanup
|
|
490
493
|
*/
|
|
491
494
|
export function neatoCleanup(g: Graph): void {
|
|
495
|
+
for (const e of g.edges) gvCleanupEdgeLabels(e); // gv_cleanup_edge: per-node agfstout, all edges of root g
|
|
496
|
+
for (const n of g.nodes.values()) gvCleanupNodeLabels(n); // gv_cleanup_node
|
|
492
497
|
for (const [, n] of g.nodes) {
|
|
493
498
|
n.info.pos = undefined;
|
|
494
499
|
n.info.pinned = undefined;
|
package/src/layout/neato/kk.ts
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import type { Graph } from '../../model/graph.js';
|
|
20
|
+
import { agNameOf } from '../../model/cgraph-ops.js';
|
|
20
21
|
import type { Node } from '../../model/node.js';
|
|
21
22
|
import type { Edge } from '../../model/edge.js';
|
|
22
23
|
import { buildOutEdgeIndex } from '../../model/node.js';
|
|
@@ -290,7 +291,7 @@ function moveNode(st: KkState, m: number): void {
|
|
|
290
291
|
function solveModel(g: Graph, st: KkState): void {
|
|
291
292
|
for (let m = chooseNode(st); m >= 0; m = chooseNode(st)) moveNode(st, m);
|
|
292
293
|
if (st.move === st.maxIter) {
|
|
293
|
-
agwarningf(`Max. iterations (${st.maxIter}) reached on graph ${g
|
|
294
|
+
agwarningf(`Max. iterations (${st.maxIter}) reached on graph ${agNameOf(g)}`);
|
|
294
295
|
}
|
|
295
296
|
}
|
|
296
297
|
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
* @see lib/neatogen/neatoinit.c
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { lateDouble } from '../../common/nodeinit.js';
|
|
10
9
|
import type { Graph } from '../../model/graph.js';
|
|
11
10
|
import type { Node } from '../../model/node.js';
|
|
12
11
|
import type { DirectedVtxData } from './opt-arrangement.js';
|
|
@@ -129,7 +128,7 @@ function addNeighbours(g: Graph, np: Node, entry: DirectedVtxData, o: GraphDataO
|
|
|
129
128
|
if (ep.head === ep.tail) continue;
|
|
130
129
|
const vp = ep.tail === np ? ep.head : ep.tail;
|
|
131
130
|
const vid = vp.info.id!;
|
|
132
|
-
const dist = o.haveLen ?
|
|
131
|
+
const dist = o.haveLen ? (ep.info.dist ?? 0) : 1.0; // ED_dist (calloc 0)
|
|
133
132
|
const idx = seen.get(vid);
|
|
134
133
|
if (idx !== undefined) {
|
|
135
134
|
if (o.haveLen) entry.ewgts[idx] = Math.max(entry.ewgts[idx]!, dist);
|
|
@@ -11,21 +11,11 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { crand } from '../../common/crand.js';
|
|
14
|
-
import { fma
|
|
14
|
+
import { fma } from '../../common/fma.js';
|
|
15
15
|
import type { VtxData } from './dijkstra.js';
|
|
16
16
|
|
|
17
17
|
const fr = Math.fround;
|
|
18
18
|
|
|
19
|
-
/**
|
|
20
|
-
* fmadd: round(a * b + c) once. `common/fma` splits operands (Dekker), which
|
|
21
|
-
* turns an infinite operand into NaN where the hardware fmadd gives inf, so
|
|
22
|
-
* non-finite products and addends take the plain expression (exact then).
|
|
23
|
-
*/
|
|
24
|
-
export function fma(a: number, b: number, c: number): number {
|
|
25
|
-
const p = a * b;
|
|
26
|
-
return Number.isFinite(p) && Number.isFinite(c) ? softFma(a, b, c) : p + c;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
19
|
/** Subtract the mean (double precision). @see matrix_ops.c:orthog1 */
|
|
30
20
|
export function orthog1(n: number, vec: Float64Array): void {
|
|
31
21
|
let sum = 0;
|
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { crand } from '../../common/crand.js';
|
|
14
|
+
import { fma } from '../../common/fma.js';
|
|
14
15
|
import { conjugateGradientF } from './conjgrad.js';
|
|
15
16
|
import type { VtxData } from './dijkstra.js';
|
|
16
17
|
import { computeApsp } from './kkutils.js';
|
|
17
18
|
import {
|
|
18
19
|
BLOCK_NONE,
|
|
19
20
|
copyVector,
|
|
20
|
-
fma,
|
|
21
21
|
innerProduct,
|
|
22
22
|
norm,
|
|
23
23
|
scadd,
|
|
@@ -21,6 +21,7 @@ import type { SplineInfo, PolygonT, TextlabelT } from '../../common/types.js';
|
|
|
21
21
|
import { polygonOutlineRing } from '../../common/poly-sizing.js';
|
|
22
22
|
import { fma, fms } from '../../common/fma.js';
|
|
23
23
|
import { ShapeKind } from '../../common/types.js';
|
|
24
|
+
import { setState, GVSPLINES } from '../../common/layout-state.js';
|
|
24
25
|
import { esepFactor, type ExpandT } from './sep-factor.js';
|
|
25
26
|
import { libmCos, libmSin } from '../../common/libm-trig.js';
|
|
26
27
|
import type { Poly, VConfig } from '../../pathplan/types.js';
|
|
@@ -821,10 +822,11 @@ export function splineEdges(g: Graph): void {
|
|
|
821
822
|
}
|
|
822
823
|
// C splineEdges wrapper: coalesce equivalent edges before routing.
|
|
823
824
|
coalesceEdges(g);
|
|
824
|
-
if (edgetype === EDGETYPE_LINE) { RoutingHelper.straight(g, edgetype); return; }
|
|
825
|
+
if (edgetype === EDGETYPE_LINE) { RoutingHelper.straight(g, edgetype); setState(GVSPLINES); return; }
|
|
825
826
|
// C: margin = esepFactor(g) — the edge separation, default {3.2, 3.2, add}.
|
|
826
827
|
// @see lib/neatogen/neatosplines.c:746
|
|
827
828
|
splineEdgesImpl(g, esepFactor(g), edgetype);
|
|
829
|
+
setState(GVSPLINES); // State = GVSPLINES, neatosplines.c:778 (also the LINE path)
|
|
828
830
|
}
|
|
829
831
|
|
|
830
832
|
// ---------------------------------------------------------------------------
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { RenderError } from '../../errors.js';
|
|
17
|
+
import { agNameOf } from '../../model/cgraph-ops.js';
|
|
17
18
|
import type { Graph } from '../../model/graph.js';
|
|
18
19
|
import { srand48 } from '../../common/random.js';
|
|
19
20
|
import { registerRenderState } from '../../common/render-state.js';
|
|
@@ -147,7 +148,7 @@ export function neatoMode(g: Graph): number {
|
|
|
147
148
|
if (str === undefined || str === '') return MODE_MAJOR;
|
|
148
149
|
const mode = modeByName().get(str);
|
|
149
150
|
if (mode !== undefined) return mode;
|
|
150
|
-
agwarningf(`Illegal value ${str} for attribute "mode" in graph ${g.root
|
|
151
|
+
agwarningf(`Illegal value ${str} for attribute "mode" in graph ${agNameOf(g.root)} - ignored`);
|
|
151
152
|
return MODE_MAJOR;
|
|
152
153
|
}
|
|
153
154
|
|
|
@@ -195,7 +196,7 @@ function warnCircuitDisconnected(g: Graph): void {
|
|
|
195
196
|
circuitWarned.add(g.root);
|
|
196
197
|
agerrLineOn(
|
|
197
198
|
'warn',
|
|
198
|
-
`graph ${g.root
|
|
199
|
+
`graph ${agNameOf(g.root)} is disconnected. Hence, the circuit model\n`
|
|
199
200
|
+ 'is undefined. Reverting to the shortest path model.\n'
|
|
200
201
|
+ 'Alternatively, consider running neato using -Gpack=true or decomposing\n'
|
|
201
202
|
+ 'the graph into connected components.',
|