@knowvah/dot-engine 2.6.10 → 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/html-entities.d.ts +13 -5
- package/dist/common/html-entities.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-chardata.d.ts +9 -0
- package/dist/common/htmltable-lex-chardata.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 +821 -471
- 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 +569 -220
- 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/html-entities.ts +77 -25
- 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-chardata.ts +42 -8
- 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
package/src/gvc/device.ts
CHANGED
|
@@ -42,11 +42,14 @@ import {
|
|
|
42
42
|
styleTokens,
|
|
43
43
|
} from '../common/style-resolve.js';
|
|
44
44
|
import { isPointNode } from '../common/poly-gencode.js';
|
|
45
|
-
import {
|
|
45
|
+
import {
|
|
46
|
+
resolveRenderColor, withColorScheme, reportEdgeColors, reportColorNames, backgroundColors,
|
|
47
|
+
setRendererKnownColors,
|
|
48
|
+
} from '../render/color-resolve.js';
|
|
46
49
|
import { emitRoundedBezier } from '../common/poly-shapes.js';
|
|
47
50
|
import { applyClusterObjState, clusterStyle, clusterPeripheries } from './device-cluster.js';
|
|
48
51
|
import { transformPoint } from './device-transform.js';
|
|
49
|
-
import { renderOneLabel, renderNodeXLabel, renderClusterLabel } from './device-labels.js';
|
|
52
|
+
import { renderOneLabel, renderNodeXLabel, renderClusterLabel, reportEdgeLabelColors } from './device-labels.js';
|
|
50
53
|
export { transformPoint, applyRotation, applyScale, buildPoint } from './device-transform.js';
|
|
51
54
|
export { renderOneLabel, renderNodeXLabel, renderClusterLabel } from './device-labels.js';
|
|
52
55
|
import { svgNodeId, svgEdgeId, svgClusterId, svgGraphId } from '../render/svg-id.js';
|
|
@@ -156,7 +159,7 @@ function setEdgePen(e: Edge, job: RenderJob): void {
|
|
|
156
159
|
const obj = job.obj;
|
|
157
160
|
const flags = parseStyleFlags(e.attrs.get('style'));
|
|
158
161
|
obj.penColor = withColorScheme(e.attrs.get('colorscheme'),
|
|
159
|
-
() => resolveRenderColor(resolvePenColor(e.attrs.get('color'))));
|
|
162
|
+
() => resolveRenderColor(resolvePenColor(e.attrs.get('color')), false));
|
|
160
163
|
obj.pen = resolvePenType(flags);
|
|
161
164
|
obj.penWidth = resolvePenWidth(flags, e.attrs.get('penwidth'));
|
|
162
165
|
// Raw style tokens for xdot's `S` ops (e.g. explicit style="solid"); SVG
|
|
@@ -189,6 +192,10 @@ export function renderEdge(e: Edge, renderer: RendererPlugin, job: RenderJob): v
|
|
|
189
192
|
// @see lib/common/emit.c:emit_edge (begin/end color context)
|
|
190
193
|
withColorScheme(e.attrs.get('colorscheme'), () => {
|
|
191
194
|
renderer.beginEdge(e, job);
|
|
195
|
+
// emit_edge_graphics, then emit_end_edge's labels: C resolves these names
|
|
196
|
+
// here whatever the renderer draws (the non-drawing ones included).
|
|
197
|
+
reportEdgeColors(e);
|
|
198
|
+
reportEdgeLabelColors(e);
|
|
192
199
|
renderer.endEdge(e, job);
|
|
193
200
|
});
|
|
194
201
|
} finally {
|
|
@@ -351,9 +358,13 @@ function renderPage(g: Graph, renderer: RendererPlugin, job: RenderJob, info: La
|
|
|
351
358
|
resolveObjAnchor(g, labelTextOf(g.info.label), svgGraphId(g, job), job.obj);
|
|
352
359
|
}
|
|
353
360
|
const anchored = beginAnchorIf(renderer, job);
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
361
|
+
// emit_page opens the graph's colorscheme around the background and label.
|
|
362
|
+
withColorScheme(g.attrs.get('colorscheme'), () => {
|
|
363
|
+
reportColorNames(backgroundColors(g.attrs.get('bgcolor'), renderer.type === 'svg'));
|
|
364
|
+
renderer.pageBackground?.(g, job);
|
|
365
|
+
// emit root-graph label before clusters/nodes @see lib/common/emit.c:emit_page
|
|
366
|
+
renderGraphLabel(g, renderer, job);
|
|
367
|
+
});
|
|
357
368
|
if (anchored) renderer.endAnchor?.(job);
|
|
358
369
|
// emit_view: clusters are drawn BEFORE nodes/edges normally, but the map
|
|
359
370
|
// device (EMIT_CLUSTERS_LAST) emits their <area> AFTER, so a node/edge area
|
|
@@ -459,6 +470,7 @@ export function render(ctx: GvcContext, g: Graph, format: string, inlineImages =
|
|
|
459
470
|
// @see lib/common/emit.c:3260 (gvc->rotation=90); :3390 (job->rotation)
|
|
460
471
|
job.rotation = parseLandscape(g) ? 90 : 0;
|
|
461
472
|
job.renderer = renderer;
|
|
473
|
+
setRendererKnownColors(renderer.type === 'svg'); // svg_knowncolors; others have none
|
|
462
474
|
resetHtmlAnchorIds(); // C: fresh anchorId per dot invocation
|
|
463
475
|
for (const n of g.nodes.values()) polyInit(n, g, job.measurer);
|
|
464
476
|
return renderGraph(g, job, renderer);
|
package/src/index.ts
CHANGED
|
@@ -22,6 +22,7 @@ import type { GvError, RenderResult } from './errors.js';
|
|
|
22
22
|
import type { EngineName } from './gvc/context.js';
|
|
23
23
|
import { render as deviceRender } from './gvc/device.js';
|
|
24
24
|
import { createDefaultContext } from './gvc/default-context.js';
|
|
25
|
+
import { resetRenderState } from './common/render-state.js';
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
|
|
@@ -90,6 +91,7 @@ function classifyError(err: unknown): GvError {
|
|
|
90
91
|
*/
|
|
91
92
|
export function renderSvg(dotSource: string, engine: EngineName): string {
|
|
92
93
|
checkRenderArgs(dotSource, engine);
|
|
94
|
+
resetRenderState(); // AD-4: one render = one native process
|
|
93
95
|
const ctx = createDefaultContext();
|
|
94
96
|
try {
|
|
95
97
|
// parse() is inside the try so any non-ParseError throw (e.g. a raw
|
|
@@ -122,6 +124,7 @@ export function renderSvg(dotSource: string, engine: EngineName): string {
|
|
|
122
124
|
export function tryRenderSvg(dotSource: string, engine: EngineName): RenderResult {
|
|
123
125
|
checkRenderArgs(dotSource, engine);
|
|
124
126
|
try {
|
|
127
|
+
// renderSvg calls resetRenderState first (AD-4).
|
|
125
128
|
return { svg: renderSvg(dotSource, engine) };
|
|
126
129
|
} catch (err: unknown) {
|
|
127
130
|
if (isUsageError(err)) throw err;
|
|
@@ -27,6 +27,7 @@ import { CLUSTER } from './rank.js';
|
|
|
27
27
|
import { makeSlots, safeOtherEdge, makeInterclustChain } from './cluster-path.js';
|
|
28
28
|
// mergeChain lives in classify.ts (circular: classify ↔ cluster — safe for function refs)
|
|
29
29
|
import { mergeChain, portsEq } from './classify.js';
|
|
30
|
+
import { agwarningf } from '../../common/agerr.js';
|
|
30
31
|
|
|
31
32
|
export { CLUSTER_EDGE } from './cluster-path.js';
|
|
32
33
|
export { mapInterclustNode } from './cluster-path.js';
|
|
@@ -297,7 +298,7 @@ export function markClusterNode(clust: Graph, n: Node, g: Graph): void {
|
|
|
297
298
|
if ((n.info.ranktype ?? 0) !== 0) {
|
|
298
299
|
// C warns with the ENCLOSING graph's name, not the cluster's.
|
|
299
300
|
// @see lib/dotgen/cluster.c:317-320
|
|
300
|
-
|
|
301
|
+
agwarningf(`${n.name} was already in a rankset, deleted from cluster ${g.name}`, 'error');
|
|
301
302
|
agDeleteFromCluster(clust, n);
|
|
302
303
|
return;
|
|
303
304
|
}
|
package/src/layout/dot/conc.ts
CHANGED
|
@@ -20,6 +20,7 @@ import { dotScanRanks } from './rank.js';
|
|
|
20
20
|
import { dotRoot, rankGet } from './mincross-utils.js';
|
|
21
21
|
import { nodesInSeq } from './decomp.js';
|
|
22
22
|
import { graphMinrank, graphMaxrank } from './position-aux.js';
|
|
23
|
+
import { agerr, agerrorf, agwarningf } from '../../common/agerr.js';
|
|
23
24
|
|
|
24
25
|
const UP = 0;
|
|
25
26
|
const DOWN = 1;
|
|
@@ -263,13 +264,13 @@ export function fillRankVlist(g: Graph, r: number, root: Graph): number {
|
|
|
263
264
|
const rankArr = g.info.rank!;
|
|
264
265
|
const lead = g.info.rankleader![r];
|
|
265
266
|
if (lead === undefined || lead === null) {
|
|
266
|
-
|
|
267
|
+
agerrorf(`rebuild_vlists: lead is null for rank ${r}`);
|
|
267
268
|
return -1;
|
|
268
269
|
}
|
|
269
270
|
const rootRank = root.info.rank![r];
|
|
270
271
|
if (rootRank.v[lead.info.order ?? 0] !== lead) {
|
|
271
|
-
|
|
272
|
-
`
|
|
272
|
+
agerrorf(
|
|
273
|
+
`rebuild_vlists: rank lead ${lead.name} not in order ` +
|
|
273
274
|
`${lead.info.order ?? 0} of rank ${r}`,
|
|
274
275
|
);
|
|
275
276
|
return -1;
|
|
@@ -292,7 +293,7 @@ export function fillRankVlist(g: Graph, r: number, root: Graph): number {
|
|
|
292
293
|
rankArr[r].v = rootRank.v;
|
|
293
294
|
rankArr[r].vStart = lead.info.order ?? 0;
|
|
294
295
|
const maxi = computeMaxi(g, r);
|
|
295
|
-
if (maxi === -1)
|
|
296
|
+
if (maxi === -1) agwarningf(`degenerate concentrated rank ${g.name},${r}`, 'error');
|
|
296
297
|
rankArr[r].n = maxi + 1;
|
|
297
298
|
return 0;
|
|
298
299
|
}
|
|
@@ -425,7 +426,7 @@ export function dotConcentrate(g: Graph): number {
|
|
|
425
426
|
const clust = g.info.clust ?? [];
|
|
426
427
|
for (let c = 0; c < nCluster; c++) {
|
|
427
428
|
if (rebuildVlists(clust[c]) !== 0) {
|
|
428
|
-
|
|
429
|
+
agerr('prev', 'concentrate=true may not work correctly.');
|
|
429
430
|
return -1;
|
|
430
431
|
}
|
|
431
432
|
}
|
package/src/layout/dot/decomp.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import type { Node } from '../../model/node.js';
|
|
4
4
|
import type { Graph } from '../../model/graph.js';
|
|
5
5
|
import type { EdgeList } from '../../model/nodeInfo.js';
|
|
6
|
+
import { registerRenderState } from '../../common/render-state.js';
|
|
6
7
|
|
|
7
8
|
// ---------------------------------------------------------------------------
|
|
8
9
|
// AGSEQ-order node iteration (agfstnode/agnxtnode mirror)
|
|
@@ -135,7 +136,9 @@ export function decompSearch(g: Graph, start: Node, cmark: number): void {
|
|
|
135
136
|
}
|
|
136
137
|
|
|
137
138
|
// Cmark as const-object property avoids module-level let that confuses Lizard.
|
|
139
|
+
/** @see lib/dotgen/decomp.c:Cmark (C static, 0 at process start) */
|
|
138
140
|
const _dc = { cmark: 0 };
|
|
141
|
+
registerRenderState(() => { _dc.cmark = 0; });
|
|
139
142
|
|
|
140
143
|
// ONE private function immediately before decompose — the acyclic.ts pattern.
|
|
141
144
|
function resolveNode(n: Node, pass: 0 | 1): Node | undefined {
|
|
@@ -12,6 +12,7 @@ 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
14
|
import { bezier } from '../../common/bezier.js';
|
|
15
|
+
import { fma } from '../../common/fma.js';
|
|
15
16
|
|
|
16
17
|
// ---------------------------------------------------------------------------
|
|
17
18
|
// De Casteljau subdivision
|
|
@@ -115,17 +116,30 @@ export function bezierClipNode(
|
|
|
115
116
|
}
|
|
116
117
|
|
|
117
118
|
/**
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
|
|
119
|
+
* DIST(p, q) = sqrt(SQR(dx) + SQR(dy)) as the oracle compiles it
|
|
120
|
+
* (libgvc 16.1 `_arrowEndClip`: `fmul dy*dy; fmadd dx, dx; fsqrt`), i.e.
|
|
121
|
+
* sqrt(fma(dx, dx, dy * dy)) -- not Math.hypot.
|
|
122
|
+
* @see lib/common/geom.h:DIST
|
|
123
|
+
*/
|
|
124
|
+
export function distFused(p: Point, q: Point): number {
|
|
125
|
+
const dx = p.x - q.x;
|
|
126
|
+
const dy = p.y - q.y;
|
|
127
|
+
return Math.sqrt(fma(dx, dx, dy * dy));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Clip the path endpoint to the arrowhead BASE (not the node boundary).
|
|
123
132
|
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
* 3
|
|
128
|
-
*
|
|
133
|
+
* Ports the bezier part of lib/common/arrows.c:arrowEndClip (:285-330); the
|
|
134
|
+
* `spl->eflag/ep` bookkeeping and the `endp -= 3` back-up (:288-296) live in
|
|
135
|
+
* the callers (compound.ts:arrowEndClipIdx). Line map (C -> here):
|
|
136
|
+
* :299-302 sp[3..0] = ps[endp..], sp[0] = spl->ep -> `sp` below
|
|
137
|
+
* :304 if (elen > 0) -> `elen > 0`
|
|
138
|
+
* :305-307 inside_context {p = &sp[0], r = &elen} -> `inside` (centre = tip)
|
|
139
|
+
* :308 bezier_clip(&ctx, inside, sp, true) -> bezierClipNode, left
|
|
140
|
+
* inside, in ABSOLUTE coordinates (centre 0,0), as C does
|
|
141
|
+
* :311-314 ps[endp..endp+3] = sp[3..0] -> returned array
|
|
142
|
+
* :281-283 inside(): DIST(p, a.p[0]) <= a.r[0] -> distFused <= elen
|
|
129
143
|
*
|
|
130
144
|
* @see lib/common/arrows.c:arrowEndClip
|
|
131
145
|
*/
|
|
@@ -134,18 +148,10 @@ export function arrowEndClip(
|
|
|
134
148
|
arrowTip: Point,
|
|
135
149
|
elen: number,
|
|
136
150
|
): Point[] {
|
|
137
|
-
if (elen <= 0) return path4;
|
|
138
|
-
// Reverse: sp[0]=tip (inside sphere), sp[1..3]=reversed last 3 path points
|
|
139
151
|
const sp: Point[] = [arrowTip, path4[2]!, path4[1]!, path4[0]!];
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const spRel: Point[] = sp.map(p => ({ x: p.x - arrowTip.x, y: p.y - arrowTip.y }));
|
|
144
|
-
const clippedRel = bezierClipLocal(spRel, insideSphere, true);
|
|
145
|
-
const clipped = clippedRel.map(p => ({ x: p.x + arrowTip.x, y: p.y + arrowTip.y }));
|
|
146
|
-
// Un-reverse: the clipped right subdivision = [arrowBase, ..., arrowTip]
|
|
147
|
-
// The path endpoint becomes arrowBase = clipped[0]
|
|
148
|
-
// Un-reverse the full clipped result; all 4 points update via de Casteljau
|
|
152
|
+
const clipped = elen > 0
|
|
153
|
+
? bezierClipNode(sp, 0, 0, (x, y) => distFused({ x, y }, arrowTip) <= elen, true)
|
|
154
|
+
: sp;
|
|
149
155
|
return [clipped[3]!, clipped[2]!, clipped[1]!, clipped[0]!];
|
|
150
156
|
}
|
|
151
157
|
|
|
@@ -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;
|