@clarify/edge-router 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["freeSegmentID","fixedSegmentID","freeWeight","fixedWeight","newRoutingVertex","VertInfClass","cr"],"sources":["../src/geomtypes.ts","../src/geometry.ts","../src/makepath.ts","../src/graph.ts","../src/utilities/assert.ts","../src/edge.ts","../src/utilities/option-set.ts","../src/endpoint.ts","../src/vertex.ts","../src/obstacle.ts","../src/junction.ts","../src/scanline.ts","../src/vpsc.ts","../src/utilities/nudging-shift-segment.ts","../src/utilities/pos-vert-inf.ts","../src/utilities/breakpoint-set.ts","../src/utilities/vert-set.ts","../src/utilities/line-segment.ts","../src/utilities/segment-list-wrapper.ts","../src/orthogonal.ts","../src/hyperedgetree.ts","../src/mtst.ts","../src/hyperedge.ts","../src/router.ts"],"sourcesContent":["export const XDIM = 0;\nexport const YDIM = 1;\nexport const kUnassignedVertexNumber = 8;\nexport const kShapeConnectionPin = 9;\n\n// Direction of point c relative to directed segment a→b.\n// Returns 1 (CCW), 0 (collinear), or -1 (CW).\n// maybeZero widens the zero band for near-collinear tolerance.\nexport function vecDir(a: Point, b: Point, c: Point, maybeZero = 0): number {\n const area2 = (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y);\n if (area2 < -maybeZero) return -1;\n if (area2 > maybeZero) return 1;\n return 0;\n}\n\nexport class Point {\n x: number;\n y: number;\n // Geometric corner-index / midpoint label used by `midVertexNumber` in\n // shared-path detection. Valid values: 0..3 = rectangle corners, 4..7 =\n // edge midpoints, kUnassignedVertexNumber = not on any shape boundary.\n vn: number;\n\n constructor(x = 0, y = 0) {\n this.x = x;\n this.y = y;\n this.vn = kUnassignedVertexNumber;\n }\n\n eq(rhs: Point): boolean {\n return this.x === rhs.x && this.y === rhs.y;\n }\n\n // Index by dimension: 0=x, 1=y (read).\n at(dimension: number): number {\n return dimension === XDIM ? this.x : this.y;\n }\n\n // Index by dimension: 0=x, 1=y (write).\n setAt(dimension: number, value: number): void {\n if (dimension === XDIM) this.x = value;\n else this.y = value;\n }\n}\n\nexport class Box {\n min: Point;\n max: Point;\n\n constructor() {\n this.min = new Point();\n this.max = new Point();\n }\n\n length(dimension: number): number {\n return dimension === XDIM\n ? this.max.x - this.min.x\n : this.max.y - this.min.y;\n }\n\n width(): number {\n return this.max.x - this.min.x;\n }\n\n height(): number {\n return this.max.y - this.min.y;\n }\n}\n\nexport class Polygon {\n ps: Point[];\n // Checkpoints on the route and which segment/vertex they lie on.\n // Encoding: 2*k → on ps[k]; 2*k+1 → on segment ps[k]→ps[k+1].\n checkpointsOnRoute: Array<[number, Point]>;\n\n constructor(n?: number) {\n this.ps =\n n !== undefined ? Array.from({ length: n }, () => new Point()) : [];\n this.checkpointsOnRoute = [];\n }\n\n clone(): Polygon {\n const copy = new Polygon();\n copy.ps = this.ps.map((p) => {\n const np = new Point(p.x, p.y);\n np.vn = p.vn;\n return np;\n });\n copy.checkpointsOnRoute = this.checkpointsOnRoute.map(([n, p]) => {\n const np = new Point(p.x, p.y);\n np.vn = p.vn;\n return [n, np] as [number, Point];\n });\n return copy;\n }\n\n clear(): void {\n this.ps = [];\n }\n\n empty(): boolean {\n return this.ps.length === 0;\n }\n\n size(): number {\n return this.ps.length;\n }\n\n at(index: number): Point {\n return this.ps[index];\n }\n\n simplify(): Polygon {\n const simplified = this.clone();\n const checkpoints = simplified.checkpointsOnRoute;\n const hasCheckpointInfo = checkpoints.length > 0;\n\n let j = 2;\n while (j < simplified.ps.length) {\n if (\n vecDir(simplified.ps[j - 2], simplified.ps[j - 1], simplified.ps[j]) ===\n 0\n ) {\n simplified.ps.splice(j - 1, 1);\n\n if (hasCheckpointInfo) {\n const deletedPointValue = j - 1 - 1;\n for (const cp of checkpoints) {\n if (cp[0] === deletedPointValue) {\n cp[0] -= 1;\n } else if (cp[0] > deletedPointValue) {\n cp[0] -= 2;\n }\n }\n }\n } else {\n j++;\n }\n }\n\n return simplified;\n }\n\n checkpointsOnSegment(segmentLowerIndex: number, indexModifier = 0): Point[] {\n let lower = 2 * segmentLowerIndex;\n let upper = lower + 2;\n\n if (indexModifier > 0) lower++;\n else if (indexModifier < 0) upper--;\n\n const result: Point[] = [];\n for (const [pos, pt] of this.checkpointsOnRoute) {\n if (pos >= lower && pos <= upper) {\n result.push(pt);\n }\n }\n return result;\n }\n\n offsetBoundingBox(offset: number): Box {\n const box = new Box();\n box.min.x = Infinity;\n box.min.y = Infinity;\n box.max.x = -Infinity;\n box.max.y = -Infinity;\n\n for (let i = 0; i < this.size(); i++) {\n const pt = this.at(i);\n if (pt.x < box.min.x) box.min.x = pt.x;\n if (pt.y < box.min.y) box.min.y = pt.y;\n if (pt.x > box.max.x) box.max.x = pt.x;\n if (pt.y > box.max.y) box.max.y = pt.y;\n }\n\n box.min.x -= offset;\n box.min.y -= offset;\n box.max.x += offset;\n box.max.y += offset;\n\n return box;\n }\n}\n\nexport class Rect extends Polygon {\n private _origin: { x: number; y: number };\n private _size: { width: number; height: number };\n constructor(\n origin: { x: number; y: number },\n size: { width: number; height: number },\n ) {\n super(4);\n this._origin = origin;\n this._size = size;\n this.ps[0] = new Point(origin.x + size.width, origin.y);\n this.ps[1] = new Point(origin.x + size.width, origin.y + size.height);\n this.ps[2] = new Point(origin.x, origin.y + size.height);\n this.ps[3] = new Point(origin.x, origin.y);\n\n this.ps[0].vn = 0;\n this.ps[1].vn = 1;\n this.ps[2].vn = 2;\n this.ps[3].vn = 3;\n }\n\n offsetPolygon(bufferSpace: number) {\n return new Rect(\n {\n x: this._origin.x - bufferSpace,\n y: this._origin.y - bufferSpace,\n },\n {\n width: this._size.width + bufferSpace * 2,\n height: this._size.height + bufferSpace * 2,\n },\n );\n }\n}\n","import { vecDir, Point, type Polygon } from './geomtypes';\n\n// ─── Intersection result codes ────────────────────────────────────────────────\n\nexport const DONT_INTERSECT = 0;\nexport const DO_INTERSECT = 1;\nexport const PARALLEL = 3;\n\n// ─── Pure geometry utilities ──────────────────────────────────────────────────\n\n// Returns the Manhattan distance between points a and b.\nexport function manhattanDist(a: Point, b: Point): number {\n return Math.abs(a.x - b.x) + Math.abs(a.y - b.y);\n}\n\nexport function inBetween(a: Point, b: Point, c: Point): boolean {\n const epsilon = Number.EPSILON;\n if (Math.abs(a.x - b.x) > epsilon) {\n // Not vertical — compare x.\n return (a.x < c.x && c.x < b.x) || (b.x < c.x && c.x < a.x);\n } else {\n return (a.y < c.y && c.y < b.y) || (b.y < c.y && c.y < a.y);\n }\n}\n\n// ─── Collinearity / between-ness ─────────────────────────────────────────────\n\n// Returns true iff a, b, c are collinear within tolerance.\nexport function colinear(a: Point, b: Point, c: Point, tolerance = 0): boolean {\n if (a.eq(b)) return true;\n if (a.x === b.x) return a.x === c.x;\n if (a.y === b.y) return a.y === c.y;\n return vecDir(a, b, c, tolerance) === 0;\n}\n\n// Returns true iff c lies on the closed segment ab (inclusive of endpoints).\nexport function pointOnLine(\n a: Point,\n b: Point,\n c: Point,\n tolerance = 0,\n): boolean {\n if (a.x === b.x) {\n return (\n a.x === c.x && ((a.y < c.y && c.y < b.y) || (b.y < c.y && c.y < a.y))\n );\n }\n if (a.y === b.y) {\n return (\n a.y === c.y && ((a.x < c.x && c.x < b.x) || (b.x < c.x && c.x < a.x))\n );\n }\n return vecDir(a, b, c, tolerance) === 0 && inBetween(a, b, c);\n}\n\n// ─── Intersection tests ───────────────────────────────────────────────────────\n\n// Returns true if segment cd properly intersects segment ab (blocking\n// visibility). Endpoint-touching cases are excluded.\nexport function segmentIntersect(\n a: Point,\n b: Point,\n c: Point,\n d: Point,\n): boolean {\n const ab_c = vecDir(a, b, c);\n if (ab_c === 0) return false;\n\n const ab_d = vecDir(a, b, d);\n if (ab_d === 0) return false;\n\n const cd_a = vecDir(c, d, a);\n const cd_b = vecDir(c, d, b);\n\n return ab_c * ab_d < 0 && cd_a * cd_b < 0;\n}\n\n// Returns true if segment e1–e2 intersects shape boundary segment s1–s2,\n// blocking visibility. seenIntersectionAtEndpoint is a shared mutable box:\n// endpoint touches are allowed once, then block on the second occurrence.\nexport function segmentShapeIntersect(\n e1: Point,\n e2: Point,\n s1: Point,\n s2: Point,\n seenIntersectionAtEndpoint: { value: boolean },\n): boolean {\n if (segmentIntersect(e1, e2, s1, s2)) {\n return true;\n }\n\n const e1TouchesS = s2.eq(e1) || pointOnLine(s1, s2, e1);\n const e2TouchesS = s2.eq(e2) || pointOnLine(s1, s2, e2);\n\n if (\n (e1TouchesS && vecDir(s1, s2, e2) !== 0) ||\n (e2TouchesS && vecDir(s1, s2, e1) !== 0)\n ) {\n if (seenIntersectionAtEndpoint.value) {\n return true;\n }\n seenIntersectionAtEndpoint.value = true;\n }\n return false;\n}\n\n// ─── Point-in-polygon ─────────────────────────────────────────────────────────\n\n// Fast convex-polygon test. Returns true iff q is inside (or on the border\n// when countBorder is true) the convex polygon poly.\nexport function inPoly(poly: Polygon, q: Point, countBorder = true): boolean {\n const n = poly.size();\n const P = poly.ps;\n let onBorder = false;\n for (let i = 0; i < n; i++) {\n const prev = (i + n - 1) % n;\n const dir = vecDir(P[prev], P[i], q);\n if (dir === -1) {\n return false; // outside\n }\n onBorder = onBorder || dir === 0;\n }\n if (!countBorder && onBorder) return false;\n return true;\n}\n\n// General (non-convex) polygon test using ray-casting.\n// Returns true iff q is inside or on the boundary of poly.\nexport function inPolyGen(argpoly: Polygon, q: Point): boolean {\n let Rcross = 0;\n let Lcross = 0;\n\n // Work on a shifted copy so that q becomes the origin.\n const P = argpoly.ps.map((p) => new Point(p.x - q.x, p.y - q.y));\n const n = P.length;\n\n for (let i = 0; i < n; i++) {\n // Vertex coincides with q — count as inside.\n if (P[i].x === 0 && P[i].y === 0) return true;\n\n const i1 = (i + n - 1) % n;\n\n // Right ray: straddles x-axis with y going from ≤0 to >0 or vice versa.\n if (P[i].y > 0 !== P[i1].y > 0) {\n const x = (P[i].x * P[i1].y - P[i1].x * P[i].y) / (P[i1].y - P[i].y);\n if (x > 0) Rcross++;\n }\n\n // Left ray: straddles x-axis with y going from ≥0 to <0 or vice versa.\n if (P[i].y < 0 !== P[i1].y < 0) {\n const x = (P[i].x * P[i1].y - P[i1].x * P[i].y) / (P[i1].y - P[i].y);\n if (x < 0) Lcross++;\n }\n }\n\n // On an edge if left and right crossing parities differ.\n if (Rcross % 2 !== Lcross % 2) return true;\n\n // Inside iff odd number of crossings.\n return Rcross % 2 === 1;\n}\n\n// ─── Region / visibility helpers ─────────────────────────────────────────────\n\n// Returns the side (+1 anticlockwise / -1 clockwise) of corner c1–c2–c3\n// that point p lies on.\nexport function cornerSide(c1: Point, c2: Point, c3: Point, p: Point): number {\n const s123 = vecDir(c1, c2, c3);\n const s12p = vecDir(c1, c2, p);\n const s23p = vecDir(c2, c3, p);\n\n if (s123 === 1) {\n return s12p >= 0 && s23p >= 0 ? 1 : -1;\n }\n if (s123 === -1) {\n return s12p <= 0 && s23p <= 0 ? -1 : 1;\n }\n // c1–c2–c3 collinear: use vecDir from c1–c2.\n return s12p;\n}\n\n// ─── Intersection-point solvers ───────────────────────────────────────────────\n\nexport interface IntersectResult {\n code: typeof DONT_INTERSECT | typeof DO_INTERSECT | typeof PARALLEL;\n x: number;\n y: number;\n}\n\n// Segment-intersection with intersection-point output.\n// Based on Franklin Antonio, Graphics Gems III.\nexport function segmentIntersectPoint(\n a1: Point,\n a2: Point,\n b1: Point,\n b2: Point,\n): IntersectResult {\n const Ax = a2.x - a1.x;\n const Bx = b1.x - b2.x;\n\n // X bounding-box test.\n let x1lo: number, x1hi: number;\n if (Ax < 0) {\n x1lo = a2.x;\n x1hi = a1.x;\n } else {\n x1hi = a2.x;\n x1lo = a1.x;\n }\n\n if (Bx > 0) {\n if (x1hi < b2.x || b1.x < x1lo) return { code: DONT_INTERSECT, x: 0, y: 0 };\n } else {\n if (x1hi < b1.x || b2.x < x1lo) return { code: DONT_INTERSECT, x: 0, y: 0 };\n }\n\n const Ay = a2.y - a1.y;\n const By = b1.y - b2.y;\n\n // Y bounding-box test.\n let y1lo: number, y1hi: number;\n if (Ay < 0) {\n y1lo = a2.y;\n y1hi = a1.y;\n } else {\n y1hi = a2.y;\n y1lo = a1.y;\n }\n\n if (By > 0) {\n if (y1hi < b2.y || b1.y < y1lo) return { code: DONT_INTERSECT, x: 0, y: 0 };\n } else {\n if (y1hi < b1.y || b2.y < y1lo) return { code: DONT_INTERSECT, x: 0, y: 0 };\n }\n\n const Cx = a1.x - b1.x;\n const Cy = a1.y - b1.y;\n const d = By * Cx - Bx * Cy; // alpha numerator\n const f = Ay * Bx - Ax * By; // common denominator\n\n // Alpha tests.\n if (f > 0) {\n if (d < 0 || d > f) return { code: DONT_INTERSECT, x: 0, y: 0 };\n } else {\n if (d > 0 || d < f) return { code: DONT_INTERSECT, x: 0, y: 0 };\n }\n\n const e = Ax * Cy - Ay * Cx; // beta numerator\n\n // Beta tests.\n if (f > 0) {\n if (e < 0 || e > f) return { code: DONT_INTERSECT, x: 0, y: 0 };\n } else {\n if (e > 0 || e < f) return { code: DONT_INTERSECT, x: 0, y: 0 };\n }\n\n if (f === 0) return { code: PARALLEL, x: 0, y: 0 };\n\n const x = a1.x + (d * Ax) / f;\n const y = a1.y + (d * Ay) / f;\n return { code: DO_INTERSECT, x, y };\n}\n","// A* path search.\n//\n// Ports input/makepath.cpp. The exported entry point is `AStarPath.search()`,\n// which performs an A* search through the router's visibility graph from\n// `src` to `tar`, populating each VertInf's `pathNext` pointer to reconstruct\n// the shortest path.\n\nimport { Point, vecDir, XDIM, YDIM } from './geomtypes';\nimport { VertInf } from './vertex';\nimport { manhattanDist } from './geometry';\nimport type { EdgeInf } from './graph';\nimport {\n ConnectorCrossings,\n CROSSING_SHARES_PATH,\n CROSSING_SHARES_FIXED_SEGMENT,\n CROSSING_SHARES_PATH_AT_END,\n Edge,\n} from './edge';\nimport { Polygon } from './geomtypes';\nimport type { Router } from './router';\n\n// ─── ConnRefLike for makepath ─────────────────────────────────────────────────\n// Structural interface for the connector — we don't import `ConnRef` directly\n// to avoid a tight coupling (the AStar code lives outside ConnRef but still\n// needs to introspect a few of its fields).\n\nexport interface MakepathConnRef extends Edge {\n router: Router;\n src(): VertInf | null;\n dst(): VertInf | null;\n route(): Polygon;\n displayRoute(): Polygon;\n possibleDstPinPoints(): Point[];\n}\n\n// ─── ANode ────────────────────────────────────────────────────────────────────\n\n// Search node used in PENDING / Done lists. Stored by pointer in C++; here\n// we just allocate plain instances. Each VertInf maintains intrusive lists\n// (`aStarPendingNodes` / `aStarDoneNodes`) — see vertex.ts.\nclass ANode {\n inf: VertInf;\n g: number; // Gone (cost so far)\n h: number; // Heuristic (estimated remaining)\n f: number; // f = g + h\n prevNode: ANode | null;\n timeStamp: number;\n\n constructor(inf: VertInf, time = 0) {\n this.inf = inf;\n this.g = 0;\n this.h = 0;\n this.f = 0;\n this.prevNode = null;\n this.timeStamp = time;\n }\n}\n\n// ─── Cost-direction bitflags ──────────────────────────────────────────────────\n\nconst CostDirectionN = 1;\nconst CostDirectionE = 2;\nconst CostDirectionS = 4;\nconst CostDirectionW = 8;\nconst CostDirectionAll =\n CostDirectionN | CostDirectionE | CostDirectionS | CostDirectionW;\n\nfunction orthogonalDirectionsCount(directions: number): number {\n let count = 0;\n if (directions & CostDirectionN) count++;\n if (directions & CostDirectionE) count++;\n if (directions & CostDirectionS) count++;\n if (directions & CostDirectionW) count++;\n return count;\n}\n\n// Returns the directions of b from a, as a CostDirection bitfield.\nfunction orthogonalDirection(a: Point, b: Point): number {\n let result = 0;\n if (b.y > a.y) result |= CostDirectionS;\n else if (b.y < a.y) result |= CostDirectionN;\n if (b.x > a.x) result |= CostDirectionE;\n else if (b.x < a.x) result |= CostDirectionW;\n return result;\n}\n\nfunction dirRight(direction: number): number {\n switch (direction) {\n case CostDirectionN:\n return CostDirectionE;\n case CostDirectionE:\n return CostDirectionS;\n case CostDirectionS:\n return CostDirectionW;\n case CostDirectionW:\n return CostDirectionN;\n }\n throw new Error('dirRight: invalid direction');\n}\n\nfunction dirLeft(direction: number): number {\n switch (direction) {\n case CostDirectionN:\n return CostDirectionW;\n case CostDirectionE:\n return CostDirectionN;\n case CostDirectionS:\n return CostDirectionE;\n case CostDirectionW:\n return CostDirectionS;\n }\n throw new Error('dirLeft: invalid direction');\n}\n\nfunction dirReverse(direction: number): number {\n switch (direction) {\n case CostDirectionN:\n return CostDirectionS;\n case CostDirectionE:\n return CostDirectionW;\n case CostDirectionS:\n return CostDirectionN;\n case CostDirectionW:\n return CostDirectionE;\n }\n throw new Error('dirReverse: invalid direction');\n}\n\nfunction dimDirection(diff: number): number {\n if (diff > 0) return 1;\n if (diff < 0) return -1;\n return 0;\n}\n\n// ─── bends() ──────────────────────────────────────────────────────────────────\n\n// Given Point curr with direction currDir, returns the minimum number of bends\n// to reach `dest` with the entry direction `destDir`. Used for estimating the\n// bend penalty heuristic in orthogonal routing.\nexport function bends(\n curr: Point,\n currDir: number,\n dest: Point,\n destDir: number,\n): number {\n if (currDir === 0) {\n throw new Error('bends: currDir must be non-zero');\n }\n const currToDestDir = orthogonalDirection(curr, dest);\n const reverseDestDir = dirReverse(destDir);\n const currDirPerpendicularToDestDir =\n currDir === dirLeft(destDir) || currDir === dirRight(destDir);\n\n if (currDir === destDir && currToDestDir === currDir) return 0;\n\n if (currDirPerpendicularToDestDir && currToDestDir === (destDir | currDir))\n return 1;\n if (currDirPerpendicularToDestDir && currToDestDir === currDir) return 1;\n if (currDirPerpendicularToDestDir && currToDestDir === destDir) return 1;\n\n if (\n currDir === destDir &&\n currToDestDir !== currDir &&\n (currToDestDir & reverseDestDir) === 0\n ) {\n return 2;\n }\n if (\n currDir === reverseDestDir &&\n currToDestDir !== destDir &&\n currToDestDir !== currDir\n ) {\n return 2;\n }\n if (\n currDirPerpendicularToDestDir &&\n currToDestDir !== (destDir | currDir) &&\n currToDestDir !== currDir\n ) {\n return 3;\n }\n if (\n currDir === reverseDestDir &&\n (currToDestDir === destDir || currToDestDir === currDir)\n ) {\n return 4;\n }\n if (currDir === destDir && currToDestDir & reverseDestDir) {\n return 4;\n }\n\n // Should not be reached.\n return 0;\n}\n\n// ─── Angle helpers (for cost()) ───────────────────────────────────────────────\n\nfunction dot(l: Point, r: Point): number {\n return l.x * r.x + l.y * r.y;\n}\n\nfunction crossLength(l: Point, r: Point): number {\n return l.x * r.y - l.y * r.x;\n}\n\n// Returns the angle between line segments p1-p2 and p2-p3, in radians.\nfunction angleBetween(p1: Point, p2: Point, p3: Point): number {\n if ((p1.x === p2.x && p1.y === p2.y) || (p2.x === p3.x && p2.y === p3.y)) {\n return Math.PI;\n }\n const v1 = new Point(p1.x - p2.x, p1.y - p2.y);\n const v2 = new Point(p3.x - p2.x, p3.y - p2.y);\n return Math.abs(Math.atan2(crossLength(v1, v2), dot(v1, v2)));\n}\n\n// ─── constructPolygonPath ─────────────────────────────────────────────────────\n\n// Builds a temporary Polygon from the chain of ANode prevNodes plus the\n// pending step (inf2 → inf3). Used for cluster-crossing and crossing-penalty\n// checks inside cost(). Collinear points are eliminated.\nfunction constructPolygonPath(\n connRoute: Polygon,\n inf2: VertInf,\n inf3: VertInf,\n inf1Node: ANode | null,\n): void {\n let routeSize = 2;\n for (let curr = inf1Node; curr !== null; curr = curr.prevNode) {\n routeSize += 1;\n }\n connRoute.ps = new Array(routeSize);\n const arraySize = routeSize;\n connRoute.ps[routeSize - 1] = inf3.point;\n connRoute.ps[routeSize - 2] = inf2.point;\n routeSize -= 3;\n for (let curr = inf1Node; curr !== null; curr = curr.prevNode) {\n const isJunctionCentre = curr.inf.isJunctionCentre;\n\n if (\n curr === inf1Node ||\n vecDir(\n curr.inf.point,\n connRoute.ps[routeSize + 1],\n connRoute.ps[routeSize + 2],\n ) !== 0\n ) {\n // Earlier than the last segment and not collinear — keep it.\n connRoute.ps[routeSize] = curr.inf.point;\n routeSize -= 1;\n } else {\n // Collinear with the last segment — collapse it.\n connRoute.ps[routeSize + 1] = curr.inf.point;\n }\n\n if (isJunctionCentre) {\n // Stop at the junction — its centre vertex is the route's terminus.\n break;\n }\n }\n\n // Trim any unused front.\n const diff = routeSize + 1;\n if (diff > 0) {\n for (let i = diff; i < arraySize; ++i) {\n connRoute.ps[i - diff] = connRoute.ps[i];\n }\n connRoute.ps.length = arraySize - diff;\n }\n}\n\n// ─── cost() ──────────────────────────────────────────────────────────────────\n\n// Compute the cost of stepping from inf2 to inf3 (a segment of length `dist`,\n// preceded by inf1Node's vertex, if any). Applies angle, segment, and\n// reverse-direction penalties up front, then optionally adds cluster-crossing\n// and connector-crossing penalties.\nfunction cost(\n lineRef: MakepathConnRef,\n dist: number,\n inf2: VertInf,\n inf3: VertInf,\n inf1Node: ANode | null,\n): number {\n const inf1 = inf1Node ? inf1Node.inf : null;\n let result = dist;\n const connRoute = new Polygon();\n let routeBuilt = false;\n\n const router = lineRef.router;\n if (inf1 !== null) {\n const segmt_penalty = router.params.segmentPenalty;\n\n // Not the first segment — there's a bend between this segment and the\n // previous one. Orthogonal routing has no per-angle penalty (no acute\n // bends), so we only apply the segment penalty.\n if (segmt_penalty > 0) {\n const p1 = inf1.point;\n const p2 = inf2.point;\n const p3 = inf3.point;\n const rad = Math.PI - angleBetween(p1, p2, p3);\n\n if (rad === Math.PI) {\n // Doubling back.\n result += 2 * segmt_penalty;\n } else if (rad > 0) {\n result += segmt_penalty;\n }\n }\n }\n\n // Reverse-direction penalty.\n const reversePenalty = router.params.reverseDirectionPenalty;\n if (reversePenalty) {\n const srcVert = lineRef.src();\n const dstVert = lineRef.dst();\n if (srcVert && dstVert) {\n const xDir = dimDirection(dstVert.point.x - srcVert.point.x);\n const yDir = dimDirection(dstVert.point.y - srcVert.point.y);\n\n let doesReverse = false;\n if (xDir !== 0 && -xDir === dimDirection(inf3.point.x - inf2.point.x)) {\n doesReverse = true;\n }\n if (yDir !== 0 && -yDir === dimDirection(inf3.point.y - inf2.point.y)) {\n doesReverse = true;\n }\n if (doesReverse) {\n result += reversePenalty;\n }\n }\n }\n\n if (!router.isInCrossingPenaltyReroutingStage()) {\n // Crossing-penalty pass only runs in the rerouting stage.\n return result;\n }\n\n const crossing_penalty = router.params.crossingPenalty;\n\n const shared_path_penalty = router.params.fixedSharedPathPenalty;\n if (shared_path_penalty > 0 || crossing_penalty > 0) {\n if (!routeBuilt) {\n constructPolygonPath(connRoute, inf2, inf3, inf1Node);\n routeBuilt = true;\n }\n for (const connRef of router.connRefs) {\n if (connRef === lineRef) continue;\n const route2 = connRef.displayRoute();\n const dynamic_route2 = new Polygon();\n dynamic_route2.ps = route2.ps.slice();\n const dynamic_conn_route = new Polygon();\n dynamic_conn_route.ps = connRoute.ps.slice();\n const dstVert = lineRef.dst();\n const finalSegment = !!(dstVert && inf3.point.eq(dstVert.point));\n const cross = new ConnectorCrossings(\n dynamic_route2,\n true,\n dynamic_conn_route,\n connRef as never,\n lineRef as never,\n );\n cross.checkForBranchingSegments = true;\n cross.countForSegment(connRoute.size() - 1, finalSegment);\n\n if (\n cross.crossingFlags & CROSSING_SHARES_PATH &&\n cross.crossingFlags & CROSSING_SHARES_FIXED_SEGMENT &&\n (router.options.penaliseOrthogonalSharedPathsAtConnEnds ||\n !(cross.crossingFlags & CROSSING_SHARES_PATH_AT_END))\n ) {\n result += shared_path_penalty;\n }\n result += cross.crossingCount * crossing_penalty;\n }\n }\n\n return result;\n}\n\n// ─── estimatedCost (heuristic) ────────────────────────────────────────────────\n\n// Heuristic for A*: for polyline routing it's the straight-line distance to\n// the closest cost target; for orthogonal routing it's manhattan distance\n// plus an extra cost for unavoidable bends.\nfunction estimatedCostSpecific(\n lineRef: MakepathConnRef,\n last: Point | null,\n curr: Point,\n costTar: VertInf,\n costTarDirs: number,\n): number {\n const costTarPoint = costTar.point;\n const router = lineRef.router;\n const dist = manhattanDist(curr, costTarPoint);\n\n let bendCount = 0;\n const xmove = costTarPoint.x - curr.x;\n const ymove = costTarPoint.y - curr.y;\n if (last === null) {\n // Initial point: penalise if not inline with the target.\n if (xmove !== 0 && ymove !== 0) {\n bendCount += 1;\n }\n } else if (dist > 0) {\n const currDir = orthogonalDirection(last, curr);\n if (currDir > 0 && orthogonalDirectionsCount(currDir) === 1) {\n bendCount = 10;\n if (costTarDirs & CostDirectionN) {\n bendCount = Math.min(\n bendCount,\n bends(curr, currDir, costTarPoint, CostDirectionN),\n );\n }\n if (costTarDirs & CostDirectionE) {\n bendCount = Math.min(\n bendCount,\n bends(curr, currDir, costTarPoint, CostDirectionE),\n );\n }\n if (costTarDirs & CostDirectionS) {\n bendCount = Math.min(\n bendCount,\n bends(curr, currDir, costTarPoint, CostDirectionS),\n );\n }\n if (costTarDirs & CostDirectionW) {\n bendCount = Math.min(\n bendCount,\n bends(curr, currDir, costTarPoint, CostDirectionW),\n );\n }\n }\n }\n const penalty = bendCount * router.params.segmentPenalty;\n return dist + penalty;\n}\n\n// ─── ANodeCmp (heap ordering) ─────────────────────────────────────────────────\n\n// Returns true if `a` has *higher* priority than `b`, i.e., should pop sooner\n// from the heap. Lower f-value first; ties broken by higher timestamp (so\n// \"forward\" exploration wins over left/right turns at equal cost).\nfunction aNodeBetter(a: ANode, b: ANode): boolean {\n if (Math.abs(a.f - b.f) > 1e-7) {\n return a.f < b.f;\n }\n if (a.timeStamp !== b.timeStamp) {\n return a.timeStamp > b.timeStamp;\n }\n return false;\n}\n\n// ─── Binary heap ──────────────────────────────────────────────────────────────\n\n// Minimal binary heap keyed by aNodeBetter. We avoid pulling in a heap\n// library for portability and because the C++ uses std::make_heap directly.\nclass ANodeHeap {\n private arr: ANode[] = [];\n\n size(): number {\n return this.arr.length;\n }\n\n empty(): boolean {\n return this.arr.length === 0;\n }\n\n top(): ANode {\n return this.arr[0];\n }\n\n push(n: ANode): void {\n this.arr.push(n);\n this.bubbleUp(this.arr.length - 1);\n }\n\n pop(): ANode {\n const top = this.arr[0];\n const last = this.arr.pop()!;\n if (this.arr.length > 0) {\n this.arr[0] = last;\n this.bubbleDown(0);\n }\n return top;\n }\n\n // Rebuild the heap from scratch. Called when an existing node's g/f is\n // mutated in place (matching C++ std::make_heap after edit).\n rebuild(): void {\n for (let i = (this.arr.length >> 1) - 1; i >= 0; i--) {\n this.bubbleDown(i);\n }\n }\n\n private bubbleUp(i: number): void {\n while (i > 0) {\n const parent = (i - 1) >> 1;\n if (aNodeBetter(this.arr[i], this.arr[parent])) {\n [this.arr[i], this.arr[parent]] = [this.arr[parent], this.arr[i]];\n i = parent;\n } else {\n break;\n }\n }\n }\n\n private bubbleDown(i: number): void {\n const n = this.arr.length;\n while (true) {\n const l = i * 2 + 1;\n const r = i * 2 + 2;\n let best = i;\n if (l < n && aNodeBetter(this.arr[l], this.arr[best])) best = l;\n if (r < n && aNodeBetter(this.arr[r], this.arr[best])) best = r;\n if (best === i) break;\n [this.arr[i], this.arr[best]] = [this.arr[best], this.arr[i]];\n i = best;\n }\n }\n}\n\n// ─── AStarPath ────────────────────────────────────────────────────────────────\n\n// Returns true if `point[dim]` is collinear (along the named axis) with at\n// least one of `points`.\nfunction pointAlignedWithOneOf(\n point: Point,\n points: Point[],\n dim: number,\n): boolean {\n for (const p of points) {\n if (point.at(dim) === p.at(dim)) {\n return true;\n }\n }\n return false;\n}\n\nexport class AStarPath {\n // For orthogonal heuristic computation.\n private m_cost_targets: VertInf[] = [];\n private m_cost_targets_directions: number[] = [];\n private m_cost_targets_displacements: number[] = [];\n\n // Search entry point. Updates `tar.pathNext` chain in place; on failure,\n // `tar.pathNext` is left null.\n search(\n lineRef: MakepathConnRef,\n src: VertInf,\n tar: VertInf,\n start: VertInf | null,\n ): void {\n const router = lineRef.router;\n\n if (start === null) start = src;\n\n // ─── Cost targets ──────────────────────────────────────────────────\n this.m_cost_targets = [];\n this.m_cost_targets_directions = [];\n this.m_cost_targets_displacements = [];\n\n if (tar.isConnPoint && !tar.isConnCheckpoint) {\n const dist = manhattanDist(start.point, tar.point);\n for (const edge of tar.orthogVisList as EdgeInf[]) {\n const other = edge.otherVert(tar);\n if (other.isJunctionCentre) {\n // Junction centre vertex — descend one more level since this edge\n // is a zero-length dummy bridging the connector endpoint into the\n // junction.\n const replacementTar = other;\n for (const edge2 of replacementTar.orthogVisList as EdgeInf[]) {\n const other2 = edge2.otherVert(replacementTar);\n if (other2 === tar || other2.point.eq(tar.point)) continue;\n this.determineEndPointLocation(\n dist,\n start,\n replacementTar,\n other2,\n 2,\n );\n }\n continue;\n }\n this.determineEndPointLocation(dist, start, tar, other, 1);\n }\n }\n\n if (this.m_cost_targets.length === 0) {\n this.m_cost_targets.push(tar);\n this.m_cost_targets_directions.push(CostDirectionAll);\n this.m_cost_targets_displacements.push(0);\n }\n\n // We may turn aside only when in line with an endpoint or alongside a\n // shape.\n const endPoints: Point[] = lineRef.possibleDstPinPoints();\n endPoints.push(tar.point);\n\n // ─── Initial PENDING ───────────────────────────────────────────────\n const PENDING = new ANodeHeap();\n let exploredCount = 0;\n let bestNode: ANode | null = null;\n let timestamp = 1;\n\n if (start.pathNext) {\n // Checkpoint routing: pre-seed Done with the existing previous\n // segment so we prefer a collinear continuation.\n const dummy = new ANode(start.pathNext, timestamp++);\n dummy.inf.aStarDoneNodes.push(dummy);\n bestNode = dummy;\n exploredCount++;\n }\n\n const node = new ANode(src, timestamp++);\n node.g = 0;\n node.h = this.estimatedCost(lineRef, null, node.inf.point);\n node.f = node.g + node.h;\n node.prevNode = bestNode;\n src.aStarPendingNodes.push(node);\n PENDING.push(node);\n\n tar.pathNext = null;\n\n // ─── Main A* loop ──────────────────────────────────────────────────\n while (!PENDING.empty()) {\n bestNode = PENDING.pop();\n const bestNodeInf = bestNode.inf;\n\n // Remove this node from the vertex's pending list.\n const pIdx = bestNodeInf.aStarPendingNodes.indexOf(bestNode);\n if (pIdx !== -1) bestNodeInf.aStarPendingNodes.splice(pIdx, 1);\n\n bestNodeInf.aStarDoneNodes.push(bestNode);\n exploredCount++;\n\n const prevInf = bestNode.prevNode ? bestNode.prevNode.inf : null;\n\n if (bestNodeInf === tar) {\n // Reached the target — link pathNext.\n for (\n let curr: ANode | null = bestNode;\n curr && curr.prevNode;\n curr = curr.prevNode\n ) {\n curr.inf.pathNext = curr.prevNode.inf;\n }\n break;\n }\n\n // Expand neighbours. Sort the candidate edges by rotation away from\n // the incoming segment.\n const visList = bestNodeInf.orthogVisList as EdgeInf[];\n visList.sort((u, v) => {\n if (u.isOrthogonal() && v.isOrthogonal()) {\n return u.rotationLessThan(prevInf, v) ? -1 : 1;\n }\n // Fall back to a stable ordering for non-orthogonal edges (we use\n // object identity, akin to the C++ pointer comparison).\n return 0;\n });\n\n for (const edge of visList) {\n if (edge.isDisabled()) continue;\n\n const otherInf = edge.otherVert(bestNodeInf);\n const node = new ANode(otherInf, timestamp++);\n node.prevNode = bestNode;\n const localPrevInf = bestNode.prevNode ? bestNode.prevNode.inf : null;\n\n // Don't revisit the segment we just arrived along.\n if (localPrevInf && localPrevInf === node.inf) continue;\n\n if (node.inf.isJunctionCentre && !node.inf.isConnCheckpoint) {\n // Junction centre vertices are only valid via the src vertex's\n // dummy helper, or when they reach the dst directly.\n const lineSrc = lineRef.src();\n const lineDst = lineRef.dst();\n const allowedAtSrc =\n bestNodeInf === lineSrc && (lineSrc?.isDummyPinHelper ?? false);\n const allowedAtDst =\n lineDst &&\n node.inf.hasNeighbour(lineDst) &&\n lineDst.isDummyPinHelper;\n if (!allowedAtSrc && !allowedAtDst) continue;\n } else if (node.inf.isConnPoint) {\n // Don't traverse other connector endpoints.\n if (node.inf !== tar) continue;\n }\n\n if (!edge.isDummyConnection()) {\n // Only turn when in line with an endpoint or beside a shape\n // boundary.\n const bestPt = bestNodeInf.point;\n const nextPt = node.inf.point;\n const notInlineX =\n !!localPrevInf && localPrevInf.point.x !== bestPt.x;\n const notInlineY =\n !!localPrevInf && localPrevInf.point.y !== bestPt.y;\n\n if (\n bestPt.x === nextPt.x &&\n notInlineX &&\n !notInlineY &&\n bestPt.at(YDIM) !== src.point.at(YDIM)\n ) {\n if (nextPt.y < bestPt.y) {\n if (\n !((bestNodeInf.orthogVisPropFlags & 16) /* YL_EDGE */) &&\n !pointAlignedWithOneOf(bestPt, endPoints, XDIM)\n ) {\n continue;\n }\n } else if (nextPt.y > bestPt.y) {\n if (\n !((bestNodeInf.orthogVisPropFlags & 64) /* YH_EDGE */) &&\n !pointAlignedWithOneOf(bestPt, endPoints, XDIM)\n ) {\n continue;\n }\n }\n }\n if (\n bestPt.y === nextPt.y &&\n notInlineY &&\n !notInlineX &&\n bestPt.at(XDIM) !== src.point.at(XDIM)\n ) {\n if (nextPt.x < bestPt.x) {\n if (\n !((bestNodeInf.orthogVisPropFlags & 1) /* XL_EDGE */) &&\n !pointAlignedWithOneOf(bestPt, endPoints, YDIM)\n ) {\n continue;\n }\n } else if (nextPt.x > bestPt.x) {\n if (\n !((bestNodeInf.orthogVisPropFlags & 4) /* XH_EDGE */) &&\n !pointAlignedWithOneOf(bestPt, endPoints, YDIM)\n ) {\n continue;\n }\n }\n }\n }\n\n const edgeDist = edge.getDist();\n if (edgeDist === 0) continue;\n\n // Detect whether bestNode is itself one of the orthogonal cost\n // targets — in which case the next step to tar/pin has zero cost.\n let atCostTarget = false;\n for (const t of this.m_cost_targets) {\n if (bestNode.inf === t) {\n atCostTarget = true;\n break;\n }\n }\n\n if (atCostTarget && (node.inf.isJunctionCentre || node.inf === tar)) {\n node.g = bestNode.g;\n node.h = 0;\n } else {\n if (node.inf === tar) {\n node.h = 0;\n } else {\n node.h = this.estimatedCost(\n lineRef,\n bestNodeInf.point,\n node.inf.point,\n );\n }\n if (node.inf.isDummyPinHelper) {\n // Dummy bridging vertex — no extra cost.\n node.g = bestNode.g;\n } else {\n node.g =\n bestNode.g +\n cost(lineRef, edgeDist, bestNodeInf, node.inf, bestNode.prevNode);\n }\n }\n node.f = node.g + node.h;\n\n // Deduplicate against PENDING.\n let bNodeFound = false;\n for (const ati of node.inf.aStarPendingNodes as ANode[]) {\n if (\n node.inf === ati.inf &&\n (node.prevNode === ati.prevNode ||\n (node.prevNode &&\n ati.prevNode &&\n node.prevNode.inf === ati.prevNode.inf))\n ) {\n if (node.g < ati.g) {\n // Update in place; rebuild heap since f changed.\n ati.g = node.g;\n ati.h = node.h;\n ati.f = node.f;\n ati.prevNode = node.prevNode;\n ati.timeStamp = node.timeStamp;\n PENDING.rebuild();\n }\n bNodeFound = true;\n break;\n }\n }\n if (!bNodeFound) {\n // Then check Done.\n for (const ati of node.inf.aStarDoneNodes as ANode[]) {\n if (\n node.inf === ati.inf &&\n ati.prevNode &&\n (node.prevNode === ati.prevNode ||\n (node.prevNode && node.prevNode.inf === ati.prevNode.inf))\n ) {\n bNodeFound = true;\n break;\n }\n }\n }\n\n if (!bNodeFound) {\n node.inf.aStarPendingNodes.push(node);\n PENDING.push(node);\n }\n }\n }\n\n // Cleanup all the per-vertex node lists.\n const endVert = router.vertices.end();\n for (let k = router.vertices.connsBegin(); k !== endVert; k = k!.lstNext) {\n k!.aStarDoneNodes.length = 0;\n k!.aStarPendingNodes.length = 0;\n }\n }\n\n // Helper: record one possible target point for orthogonal cost\n // estimation (called from the orthogonal-endpoint setup).\n private determineEndPointLocation(\n _dist: number,\n _start: VertInf,\n target: VertInf,\n other: VertInf,\n _level: number,\n ): void {\n const thisDirs = orthogonalDirection(other.point, target.point);\n if (orthogonalDirectionsCount(thisDirs) === 0) return;\n const displacement = manhattanDist(other.point, target.point);\n this.m_cost_targets.push(other);\n this.m_cost_targets_directions.push(thisDirs);\n this.m_cost_targets_displacements.push(displacement);\n }\n\n // Heuristic from `curr` (with optional preceding point `last`) to whichever\n // cost target is cheapest. Polyline routing uses euclidean distance;\n // orthogonal routing uses manhattan + bend penalty.\n private estimatedCost(\n lineRef: MakepathConnRef,\n last: Point | null,\n curr: Point,\n ): number {\n if (this.m_cost_targets.length === 0) return 0;\n let estimate = Infinity;\n for (let i = 0; i < this.m_cost_targets.length; i++) {\n let iEstimate = estimatedCostSpecific(\n lineRef,\n last,\n curr,\n this.m_cost_targets[i],\n this.m_cost_targets_directions[i],\n );\n iEstimate += this.m_cost_targets_displacements[i];\n if (iEstimate < estimate) estimate = iEstimate;\n }\n return estimate;\n }\n}\n\n// ─── Test exports ─────────────────────────────────────────────────────────────\n\n// Internal helpers exported for unit-test access.\nexport const _testing = {\n ANode,\n ANodeHeap,\n CostDirectionN,\n CostDirectionE,\n CostDirectionS,\n CostDirectionW,\n CostDirectionAll,\n orthogonalDirection,\n orthogonalDirectionsCount,\n dirRight,\n dirLeft,\n dirReverse,\n dimDirection,\n angleBetween,\n constructPolygonPath,\n pointAlignedWithOneOf,\n aNodeBetter,\n cost,\n estimatedCostSpecific,\n};\n","import { vecDir, Point } from './geomtypes';\nimport type { Router } from './router';\nimport { VertInf } from './vertex';\n\n// ─── Internal helpers ─────────────────────────────────────────────────────────\n\nfunction removeFromArray<T>(arr: T[], item: T): void {\n const idx = arr.indexOf(item);\n if (idx !== -1) {\n arr.splice(idx, 1);\n }\n}\n\n// Returns a turn-order value for point c given the last segment was a→b:\n// 0 directly backwards\n// 1 left-hand 90° turn\n// 2 right-hand 90° turn\n// 3 straight ahead\n// 4 not orthogonally positioned\nfunction orthogTurnOrder(a: Point, b: Point, c: Point): number {\n if ((c.x !== b.x && c.y !== b.y) || (a.x !== b.x && a.y !== b.y)) {\n return 4;\n }\n\n const dir = vecDir(a, b, c);\n if (dir > 0) return 1; // CCW = left\n if (dir < 0) return 2; // CW = right\n\n // Collinear — check if behind or ahead.\n if (b.x === c.x) {\n if ((a.y < b.y && c.y < b.y) || (a.y > b.y && c.y > b.y)) return 0;\n } else {\n if ((a.x < b.x && c.x < b.x) || (a.x > b.x && c.x > b.x)) return 0;\n }\n return 3;\n}\n\n// ─── EdgeInf ─────────────────────────────────────────────────────────────────\n\nexport class EdgeInf {\n // Intrusive linked-list pointers for EdgeList.\n lstPrev: EdgeInf | null;\n lstNext: EdgeInf | null;\n\n private _router: Router;\n private _added: boolean;\n private _isHyperedgeSegment: boolean;\n private _disabled: boolean;\n private _vert1: VertInf;\n private _vert2: VertInf;\n\n private _dist: number;\n private _mtstDist: number;\n\n constructor(v1: VertInf, v2: VertInf, router: Router) {\n this.lstPrev = null;\n this.lstNext = null;\n\n this._router = router;\n this._added = false;\n this._isHyperedgeSegment = false;\n this._disabled = false;\n this._vert1 = v1;\n this._vert2 = v2;\n this._dist = -1;\n this._mtstDist = 0;\n }\n\n // ─── Public accessors ─────────────────────────────────────────────────────\n\n getDist(): number {\n return this._dist;\n }\n\n isOrthogonal(): boolean {\n return (\n this._vert1.point.x === this._vert2.point.x ||\n this._vert1.point.y === this._vert2.point.y\n );\n }\n\n // Returns true when this edge connects a junction centre vertex to a\n // connector endpoint vertex — a zero-length dummy edge used when a\n // connector is anchored at a junction.\n isDummyConnection(): boolean {\n return (\n (this._vert1.isJunctionCentre && this._vert2.isConnPoint) ||\n (this._vert2.isJunctionCentre && this._vert1.isConnPoint)\n );\n }\n\n isDisabled(): boolean {\n return this._disabled;\n }\n\n setDisabled(disabled: boolean): void {\n this._disabled = disabled;\n }\n\n isHyperedgeSegment(): boolean {\n return this._isHyperedgeSegment;\n }\n\n setHyperedgeSegment(hyperedge: boolean): void {\n this._isHyperedgeSegment = hyperedge;\n }\n\n mtstDist(): number {\n return this._mtstDist;\n }\n\n setMtstDist(joinCost: number): void {\n this._mtstDist = joinCost;\n }\n\n otherVert(vert: VertInf): VertInf {\n return vert === this._vert1 ? this._vert2 : this._vert1;\n }\n\n // ─── First / second endpoint accessors (used by mtst) ─────────────────────\n // Mirror C++ public `m_vert1` / `m_vert2`. The fields remain private to\n // preserve invariant control inside EdgeInf; outside callers use these.\n vert1(): VertInf {\n return this._vert1;\n }\n\n vert2(): VertInf {\n return this._vert2;\n }\n\n // ─── Visibility state ─────────────────────────────────────────────────────\n\n // Sets the visibility distance and activates this edge if it isn't already.\n setDist(dist: number): void {\n if (!this._added) {\n this.makeActive();\n }\n this._dist = dist;\n }\n\n // ─── Activation / deactivation ────────────────────────────────────────────\n\n // Adds this edge to the router's orthogonal visibility graph and both\n // vertices' edge lists.\n makeActive(): void {\n this._router.visOrthogGraph.addEdge(this);\n this._vert1.orthogVisList.unshift(this);\n this._vert1.orthogVisListSize++;\n this._vert2.orthogVisList.unshift(this);\n this._vert2.orthogVisListSize++;\n this._added = true;\n }\n\n // Removes this edge from the orthogonal visibility graph and both vertices'\n // edge lists.\n makeInactive(): void {\n this._router.visOrthogGraph.removeEdge(this);\n removeFromArray(this._vert1.orthogVisList, this);\n this._vert1.orthogVisListSize--;\n removeFromArray(this._vert2.orthogVisList, this);\n this._vert2.orthogVisListSize--;\n this._added = false;\n }\n\n // Equivalent to C++ delete: deactivates if active, then releases resources.\n destroy(): void {\n if (this._added) {\n this.makeInactive();\n }\n }\n\n // ─── Rotation ordering ────────────────────────────────────────────────────\n\n // Returns true if this edge should sort before rhs in a rotation sweep\n // starting from lastV. Both edges must share a common vertex.\n rotationLessThan(lastV: VertInf | null, rhs: EdgeInf): boolean {\n if (this._vert1 === rhs._vert1 && this._vert2 === rhs._vert2) return false;\n\n let commonV: VertInf | null = null;\n let lhsV: VertInf | null = null;\n let rhsV: VertInf | null = null;\n\n if (this._vert1 === rhs._vert1) {\n commonV = this._vert1;\n lhsV = this._vert2;\n rhsV = rhs._vert2;\n } else if (this._vert1 === rhs._vert2) {\n commonV = this._vert1;\n lhsV = this._vert2;\n rhsV = rhs._vert1;\n } else if (this._vert2 === rhs._vert1) {\n commonV = this._vert2;\n lhsV = this._vert1;\n rhsV = rhs._vert2;\n } else if (this._vert2 === rhs._vert2) {\n commonV = this._vert2;\n lhsV = this._vert1;\n rhsV = rhs._vert1;\n }\n\n const commonPt = commonV!.point;\n const lastPt = lastV ? lastV.point : new Point(commonPt.x - 10, commonPt.y);\n\n const lhsVal = orthogTurnOrder(lastPt, commonPt, lhsV!.point);\n const rhsVal = orthogTurnOrder(lastPt, commonPt, rhsV!.point);\n\n return lhsVal < rhsVal;\n }\n\n // ─── Predicates ───────────────────────────────────────────────────────────\n\n private isBetween(i: VertInf, j: VertInf): boolean {\n return (\n (this._vert1 === i && this._vert2 === j) ||\n (this._vert1 === j && this._vert2 === i)\n );\n }\n\n // ─── Static factory methods ───────────────────────────────────────────────\n\n // Finds an existing edge between i and j in the orthogonal visibility list,\n // searching the shorter list first.\n static existingEdge(i: VertInf, j: VertInf): EdgeInf | null {\n const orthSelected = i.orthogVisListSize <= j.orthogVisListSize ? i : j;\n for (const edge of orthSelected.orthogVisList as EdgeInf[]) {\n if (edge.isBetween(i, j)) return edge;\n }\n return null;\n }\n}\n\n// ─── EdgeList ─────────────────────────────────────────────────────────────────\n// Intrusive doubly-linked list of EdgeInf nodes via lstPrev/lstNext.\n\nexport class EdgeList {\n private _firstEdge: EdgeInf | null;\n private _lastEdge: EdgeInf | null;\n private _count: number;\n\n constructor() {\n this._firstEdge = null;\n this._lastEdge = null;\n this._count = 0;\n }\n\n size(): number {\n return this._count;\n }\n\n begin(): EdgeInf | null {\n return this._firstEdge;\n }\n\n end(): null {\n return null;\n }\n\n // Appends edge to the tail of the list.\n addEdge(edge: EdgeInf): void {\n if (!this._firstEdge) {\n this._firstEdge = edge;\n this._lastEdge = edge;\n edge.lstPrev = null;\n edge.lstNext = null;\n } else {\n this._lastEdge!.lstNext = edge;\n edge.lstPrev = this._lastEdge;\n this._lastEdge = edge;\n edge.lstNext = null;\n }\n this._count++;\n }\n\n // Removes edge from any position in the list.\n removeEdge(edge: EdgeInf): void {\n if (edge.lstPrev) edge.lstPrev.lstNext = edge.lstNext;\n if (edge.lstNext) edge.lstNext.lstPrev = edge.lstPrev;\n\n if (edge === this._lastEdge) {\n this._lastEdge = edge.lstPrev;\n if (edge === this._firstEdge) this._firstEdge = null;\n } else if (edge === this._firstEdge) {\n this._firstEdge = edge.lstNext;\n }\n\n edge.lstPrev = null;\n edge.lstNext = null;\n this._count--;\n }\n\n // Destroys all edges (equivalent to deleting each, which calls makeInactive).\n clear(): void {\n let edge = this._firstEdge;\n while (edge) {\n const next = edge.lstNext;\n edge.destroy();\n edge = next;\n }\n this._firstEdge = null;\n this._lastEdge = null;\n this._count = 0;\n }\n}\n","export function assert(desc: string, condition: unknown): asserts condition {\n if (!condition) {\n throw new Error(desc);\n }\n}\n","import { kUnassignedVertexNumber, Point, Polygon, vecDir } from './geomtypes';\nimport { Endpoint, ConnEndType, Checkpoint, Direction } from './endpoint';\nimport { VertInf, type VertInfRoles } from './vertex';\nimport {\n manhattanDist,\n pointOnLine,\n cornerSide,\n segmentIntersectPoint,\n DO_INTERSECT,\n} from './geometry';\nimport { AStarPath } from './makepath';\nimport { EdgeInf } from './graph';\nimport { assert } from './utilities/assert';\n\nimport type { Junction } from './junction';\nimport type { Router } from './router';\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\n// Creates a defensive copy of a junction-anchored ConnEnd. Mirrors C++ copy\n// constructor behaviour for m_src_connend / m_dst_connend. Only junctions\n// reach this code path now that shape-pin endpoints are gone.\nfunction copyPinConnEnd(src: Endpoint): Endpoint {\n if (src._type !== ConnEndType.ConnEndJunction) {\n throw new Error('copyPinConnEnd: expected a junction-anchored ConnEnd');\n }\n return new Endpoint(src._anchorObj!);\n}\n\n// Builds a fresh route Point at the vertex's position, carrying its\n// geometric corner-index / midpoint label in `pt.vn`. The label drives\n// `midVertexNumber` in the nudging code: 0..3 = rectangle corners,\n// 4..7 = edge midpoints, kUnassignedVertexNumber = not on any shape edge.\n// Connector endpoints / checkpoints aren't on a shape boundary, so the\n// Point keeps its default vn (kUnassignedVertexNumber) and `midVertexNumber`\n// short-circuits cleanly.\nfunction stampRoutePoint(v: VertInf): Point {\n const pt = new Point(v.point.x, v.point.y);\n if (!v.isConnPoint) {\n pt.vn = v.vn;\n }\n return pt;\n}\n\n// ─── ConnRef class ────────────────────────────────────────────────────────────\n\n//! @brief The ConnRef class represents a connector object.\n//!\n//! Connectors are a (possible multi-segment) line between two points.\n//! They are routed intelligently so as not to overlap any of the shape\n//! objects in the Router scene.\nexport class Edge {\n router: Router;\n /** @internal */ _id: number;\n private _needsRerouteFlag: boolean;\n private _active: boolean;\n private _hateCrossings: boolean;\n _route: Polygon;\n private _displayRoute: Polygon;\n private _srcVert: VertInf | null;\n private _dstVert: VertInf | null;\n private _startVert: VertInf | null;\n private _srcConnend: Endpoint | null;\n private _dstConnend: Endpoint | null;\n private _checkpoints: Checkpoint[];\n private _checkpointVertices: VertInf[];\n\n // ─── ConnRefLike fulfillment ─────────────────────────────────────────────\n\n get srcConnEnd(): Endpoint | null {\n return this._srcConnend;\n }\n\n get dstConnEnd(): Endpoint | null {\n return this._dstConnend;\n }\n\n // ─── Constructors ─────────────────────────────────────────────────────────\n\n constructor(router: Router, src: Endpoint, dst: Endpoint) {\n this.router = router;\n this._needsRerouteFlag = true;\n this._active = false;\n this._hateCrossings = false;\n this._srcVert = null;\n this._dstVert = null;\n this._startVert = null;\n this._srcConnend = null;\n this._dstConnend = null;\n this._checkpoints = [];\n this._checkpointVertices = [];\n this._route = new Polygon();\n this._displayRoute = new Polygon();\n\n this._id = router._assignObjectId();\n\n this.updateEndPoint('src', src);\n this.updateEndPoint('tar', dst);\n }\n\n // ─── Public API ───────────────────────────────────────────────────────────\n\n //! @brief Returns a reference to the current raw \"debug\" route for the connector.\n route(): Polygon {\n return this._route;\n }\n\n //! @brief Returns a reference to the current display version of the route.\n displayRoute(): Polygon {\n if (this._displayRoute.empty()) {\n this._displayRoute = this._route.simplify();\n }\n return this._displayRoute;\n }\n\n //! @brief Returns ConnEnds specifying what this connector is attached to.\n endpointConnEnds(): [Endpoint, Endpoint] | null {\n let source = this.getConnEndForEndpointVertex(this._srcVert);\n let destination = this.getConnEndForEndpointVertex(this._dstVert);\n if (source && destination) {\n return [source, destination];\n }\n return null;\n }\n\n //! @brief Returns the obstacle anchors (shape or junction) at each end of\n //! this connector. Either element is null when that endpoint is a\n //! free-floating point rather than attached to an anchor.\n //!\n //! Mirrors the C++ `ConnRef::endpointAnchors()` (which returns a pair of\n //! Obstacle pointers). Used by HyperedgeRerouter to walk hyperedge topology.\n endpointAnchors(): [Junction | null, Junction | null] {\n return [\n this._srcConnend ? this._srcConnend._anchorObj : null,\n this._dstConnend ? this._dstConnend._anchorObj : null,\n ];\n }\n\n //! @brief Allows the user to specify a set of checkpoints that this\n //! connector will route via.\n setRoutingCheckpoints(checkpoints: Checkpoint[]): void {\n this._checkpoints = checkpoints;\n\n // Clear previous checkpoint vertices.\n for (const vert of this._checkpointVertices) {\n vert.removeFromGraph(true);\n this.router.vertices.removeVertex(vert);\n }\n this._checkpointVertices = [];\n\n for (let i = 0; i < this._checkpoints.length; ++i) {\n const vertex = new VertInf(this._id, 2 + i, this._checkpoints[i].point, {\n isConnPoint: true,\n isConnCheckpoint: true,\n });\n this.router.vertices.addVertex(vertex);\n vertex.visDirections = Direction.all;\n this._checkpointVertices.push(vertex);\n }\n }\n\n //! @brief Returns the current set of routing checkpoints for this connector.\n routingCheckpoints(): Checkpoint[] {\n return this._checkpoints;\n }\n\n //! @brief Returns candidate destination endpoint positions used by the\n //! orthogonal-routing \"only-turn-when-aligned\" optimisation.\n //!\n //! Since shape-pin endpoints are not supported, this is just the junction\n //! position (or empty for free-floating endpoints).\n possibleDstPinPoints(): Point[] {\n if (this._dstConnend && this._dstConnend.junction()) {\n return [this._dstConnend.position()];\n }\n return [];\n }\n\n //! @brief Sets the hat-crossings flag.\n setHateCrossings(val: boolean): void {\n this._hateCrossings = val;\n }\n\n //! @brief Returns the hat-crossings flag.\n doesHateCrossings(): boolean {\n return this._hateCrossings;\n }\n\n //! @brief Sets the route directly (internal use).\n set_route(route: Polygon): void {\n this._displayRoute.ps = route.ps.slice();\n }\n\n //! @brief Generates the path for this connector.\n generatePath(): boolean {\n if (!this._needsRerouteFlag) {\n return false;\n }\n if (!this._dstVert || !this._srcVert) {\n return false;\n }\n\n this._needsRerouteFlag = false;\n this._startVert = this._srcVert;\n\n // Stub: assignConnectionPinVisibility — returns [false, false]\n // Full implementation requires visibility.ts\n const isDummyAtEnd = this.assignConnectionPinVisibility(true);\n\n const path: Point[] = [];\n const vertices: VertInf[] = [];\n if (this._checkpoints.length === 0) {\n this.generateStandardPath(path, vertices);\n } else {\n this.generateCheckpointsPath(path, vertices);\n }\n\n // Get rid of dummy bridging points at beginning and end of the path that\n // come from junction-anchored endpoints (the junction centre vertex sits\n // at the same position as the endpoint vertex).\n let pathBegin = 0;\n let pathEnd = path.length;\n if (path.length > 2 && isDummyAtEnd[0]) {\n pathBegin++;\n }\n if (path.length > 2 && isDummyAtEnd[1]) {\n pathEnd--;\n }\n const clippedPath = path.slice(pathBegin, pathEnd);\n\n // Clear visibility edges added for connection pin dummy vertices.\n this.assignConnectionPinVisibility(false);\n\n this._route.clear();\n this._displayRoute.clear();\n this._route.ps = clippedPath;\n\n return true;\n }\n\n // ─── Internal methods ─────────────────────────────────────────────────────\n\n /** @internal */\n makeActive(): void {\n this.router.connRefs.unshift(this);\n this._active = true;\n }\n\n /** @internal */\n makeInactive(): void {\n const idx = this.router.connRefs.indexOf(this);\n if (idx !== -1) {\n this.router.connRefs.splice(idx, 1);\n }\n this._active = false;\n }\n\n /** @internal */\n src(): VertInf | null {\n return this._srcVert;\n }\n\n /** @internal */\n dst(): VertInf | null {\n return this._dstVert;\n }\n\n /** @internal */\n makePathInvalid(): void {\n this._needsRerouteFlag = true;\n }\n\n /** @internal */\n updateEndPoint(type: 'src' | 'tar', connEnd: Endpoint): void {\n const point = connEnd.position();\n\n // The connEnd is a copy of a ConnEnd that will get disconnected,\n // so don't leave it looking like it is still connected.\n connEnd._connRef = null;\n\n if (!this._active) {\n this.makeActive();\n }\n\n const isSrc = type === 'src';\n const roles: VertInfRoles = {\n isConnPoint: true,\n isDummyPinHelper: connEnd.isPinConnection(),\n isSrcEndpoint: isSrc,\n isTarEndpoint: !isSrc,\n };\n // vn = 0 (src) / 1 (tar) keeps endpoint identities unique within the\n // connector so checkpoint vertices (vn = 2 + i) don't collide. Role\n // identity is read off the VertInf via isSrcEndpoint / isTarEndpoint;\n // these vn values are purely a storage detail.\n const vn = isSrc ? 0 : 1;\n\n let altered: VertInf;\n\n if (isSrc) {\n if (this._srcVert) {\n this._srcVert.resetIdAndPoint(this._id, vn, point, roles);\n } else {\n this._srcVert = new VertInf(this._id, vn, point, roles);\n this.router.vertices.addVertex(this._srcVert);\n }\n this._srcVert.visDirections = connEnd.directions;\n\n if (this._srcConnend) {\n this._srcConnend.disconnect();\n this._srcConnend = null;\n }\n if (connEnd.isPinConnection()) {\n this._srcConnend = copyPinConnEnd(connEnd);\n this._srcConnend.connect(this);\n // Don't need visibility since we won't be connecting to it.\n this._srcVert.visDirections = Direction.zero;\n }\n\n altered = this._srcVert;\n } else {\n if (this._dstVert) {\n this._dstVert.resetIdAndPoint(this._id, vn, point, roles);\n } else {\n this._dstVert = new VertInf(this._id, vn, point, roles);\n this.router.vertices.addVertex(this._dstVert);\n }\n this._dstVert.visDirections = connEnd.directions;\n\n if (this._dstConnend) {\n this._dstConnend.disconnect();\n this._dstConnend = null;\n }\n if (connEnd.isPinConnection()) {\n this._dstConnend = copyPinConnEnd(connEnd);\n this._dstConnend.connect(this);\n // Don't need visibility since we won't be connecting to it.\n this._dstVert.visDirections = Direction.zero;\n }\n\n altered = this._dstVert;\n }\n\n // Remove edges and recreate.\n const isConn = true;\n altered.removeFromGraph(isConn);\n\n this.makePathInvalid();\n }\n\n /** @internal */\n getConnEndForEndpointVertex(vertex: VertInf | null): Endpoint | null {\n if (vertex === null) {\n return null;\n }\n if (vertex === this._srcVert) {\n if (this._srcConnend) {\n return this._srcConnend;\n }\n return new Endpoint(\n new Point(this._srcVert.point.x, this._srcVert.point.y),\n this._srcVert.visDirections,\n );\n } else if (vertex === this._dstVert) {\n if (this._dstConnend) {\n return this._dstConnend;\n } else {\n return new Endpoint(\n new Point(this._dstVert.point.x, this._dstVert.point.y),\n this._dstVert.visDirections,\n );\n }\n }\n return null;\n }\n\n /** @internal */\n //\n // Wires (or unwires) the temporary zero-length edge a connector needs to\n // reach its junction-anchored endpoint.\n //\n // Each ConnRef carries its own `_srcVert` / `_dstVert` at the endpoint\n // position. When that endpoint is anchored to a JunctionRef, the vert is\n // marked `visDirections = Direction.zero`, so the scanline sweep\n // *deliberately* gives it no visibility edges — otherwise it would lure\n // unrelated connectors into routing through every junction.\n //\n // The trade-off is that A* now has no way to reach (or depart) the dummy\n // vertex unless we plug a single bridging edge to the junction's centre\n // vertex. This method is that plug:\n //\n // - On `connect = true` (called immediately before `generatePath`'s A*\n // run): drop any stale edges off the dummy vert and add a fresh\n // EdgeInf to the junction centre with cost\n // manhattanDist + max(0.001, centreConnectionCost).\n // - On `connect = false` (called after A* finishes): tear the bridging\n // edge back down so it doesn't pollute the global vis graph between\n // route() invocations.\n //\n // The return value matches the C++ signature: `[dummySrcEnd, dummyDstEnd]`\n // tells `generatePath` which path endpoints to clip after A* (the dummy\n // junction-centre hop in the raw path is a routing artefact, not a real\n // segment).\n assignConnectionPinVisibility(connect: boolean): [boolean, boolean] {\n const dummySrc = !!(this._srcConnend && this._srcConnend.isPinConnection());\n if (dummySrc && this._srcVert) {\n this._srcVert.removeFromGraph(true);\n if (connect && this._dstVert) {\n this._wirePinVisibility(this._srcConnend!, this._srcVert);\n }\n }\n\n const dummyDst = !!(this._dstConnend && this._dstConnend.isPinConnection());\n if (dummyDst && this._dstVert) {\n this._dstVert.removeFromGraph(true);\n if (connect && this._srcVert) {\n this._wirePinVisibility(this._dstConnend!, this._dstVert);\n }\n }\n\n return [dummySrc, dummyDst];\n }\n\n // Adds the single bridging edge described in\n // `assignConnectionPinVisibility`. Junction-only — shape pins were\n // dropped from this port, so every PinConnection ConnEnd is junction-\n // anchored and has exactly one pin (the junction centre vertex).\n private _wirePinVisibility(connEnd: Endpoint, dummyVert: VertInf): void {\n const junction = connEnd.junction();\n assert('pin-connection endpoint must be a Junction', junction);\n const pinVert = junction.centreVertex();\n const cost = junction.centreConnectionCost();\n const edge = new EdgeInf(dummyVert, pinVert, this.router);\n edge.setDist(\n manhattanDist(dummyVert.point, pinVert.point) + Math.max(0.001, cost),\n );\n }\n\n /** @internal */\n generateStandardPath(path: Point[], vertices: VertInf[]): void {\n if (!this._srcVert || !this._dstVert) return;\n const src = this._srcVert;\n const tar = this._dstVert;\n\n new AStarPath().search(this as never, src, tar, this._startVert);\n let pathlen = tar.pathLeadsBackTo(src);\n\n if (pathlen < 2) {\n // No valid path — degrade to a direct line so callers can continue.\n this._needsRerouteFlag = true;\n pathlen = 2;\n tar.pathNext = src;\n }\n\n path.length = pathlen;\n vertices.length = pathlen;\n let j = pathlen - 1;\n for (let i: VertInf | null = tar; i && i !== src; i = i.pathNext) {\n path[j] = stampRoutePoint(i);\n vertices[j] = i;\n j--;\n }\n path[0] = stampRoutePoint(src);\n vertices[0] = src;\n }\n\n /** @internal */\n generateCheckpointsPath(path: Point[], vertices: VertInf[]): void {\n if (!this._srcVert || !this._dstVert) return;\n const src = this._srcVert;\n const dst = this._dstVert;\n\n // Build [src, ...checkpoint verts, dst]\n const checkpoints: VertInf[] = [src, ...this._checkpointVertices, dst];\n\n path.length = 0;\n vertices.length = 0;\n path.push(src.point);\n vertices.push(src);\n\n let lastSuccessfulIndex = 0;\n for (let i = 1; i < checkpoints.length; i++) {\n const start = checkpoints[lastSuccessfulIndex];\n const end = checkpoints[i];\n\n // Apply checkpoint visibility-direction restrictions.\n if (lastSuccessfulIndex > 0) {\n const srcCP = this._checkpoints[lastSuccessfulIndex - 1];\n if (!srcCP.departureDirections.equal(Direction.all)) {\n start.setVisibleDirections(srcCP.departureDirections);\n }\n }\n if (i + 1 < checkpoints.length) {\n const dstCP = this._checkpoints[i - 1];\n if (!dstCP.arrivalDirections.equal(Direction.all)) {\n end.setVisibleDirections(dstCP.arrivalDirections);\n }\n }\n\n new AStarPath().search(this as never, start, end, null);\n\n // Restore full visibility for these vertices.\n if (lastSuccessfulIndex > 0) start.setVisibleDirections(Direction.all);\n if (i + 1 < checkpoints.length) end.setVisibleDirections(Direction.all);\n\n const pathlen = end.pathLeadsBackTo(start);\n if (pathlen >= 2) {\n const prevPathSize = path.length;\n path.length = prevPathSize + (pathlen - 1);\n vertices.length = prevPathSize + (pathlen - 1);\n let vertInf: VertInf | null = end;\n for (\n let index = path.length - 1;\n index >= prevPathSize && vertInf;\n index--\n ) {\n path[index] = stampRoutePoint(vertInf);\n vertices[index] = vertInf;\n vertInf = vertInf.pathNext;\n }\n lastSuccessfulIndex = i;\n } else if (i + 1 === checkpoints.length) {\n // Last segment failed — bail with a direct dst point.\n this._needsRerouteFlag = true;\n path.push(dst.point);\n vertices.push(dst);\n }\n // Else: skip this checkpoint and try the next.\n }\n }\n}\n\n// ─── midVertexNumber (module-private) ────────────────────────────────────────\n\n// Returns the vn for a point that lies between two shape corners p0 and p1.\nfunction midVertexNumber(p0: Point, p1: Point, c: Point): number {\n if (c.vn !== kUnassignedVertexNumber) {\n // The split point is a shape corner, so doesn't need its vertex number\n // adjusting.\n return c.vn;\n }\n if (p0.vn >= 4 && p0.vn < kUnassignedVertexNumber) {\n return p0.vn;\n }\n if (p1.vn >= 4 && p1.vn < kUnassignedVertexNumber) {\n return p1.vn;\n }\n if (p0.vn < 4 && p1.vn < 4) {\n if (p0.vn !== p1.vn) {\n return p0.vn;\n }\n // Splitting between two ordinary shape corners.\n let vn_mid = Math.min(p0.vn, p1.vn);\n if (Math.max(p0.vn, p1.vn) === 3 && vn_mid === 0) {\n vn_mid = 3; // Next vn is effectively 4.\n }\n return vn_mid + 4;\n }\n\n if (p0.vn !== kUnassignedVertexNumber) {\n if (p0.x === p1.x) {\n if (p0.vn === 2 || p0.vn === 3) {\n return 6;\n }\n return 4;\n } else {\n if (p0.vn === 0 || p0.vn === 3) {\n return 7;\n }\n return 5;\n }\n } else if (p1.vn !== kUnassignedVertexNumber) {\n if (p0.x === p1.x) {\n if (p1.vn === 2 || p1.vn === 3) {\n return 6;\n }\n return 4;\n } else {\n if (p1.vn === 0 || p1.vn === 3) {\n return 7;\n }\n return 5;\n }\n }\n\n // Shouldn't both be new (kUnassignedVertexNumber) points.\n return kUnassignedVertexNumber;\n}\n\n// ─── splitBranchingSegments ───────────────────────────────────────────────────\n\n//! @brief Break up overlapping parallel segments that are not the same edge\n//! in the visibility graph, i.e., where one segment is a subsegment\n//! of another.\nexport function splitBranchingSegments(\n poly: Polygon,\n polyIsConn: boolean,\n conn: Polygon,\n tolerance = 0,\n): void {\n // Loop over conn segments (skipping first point).\n let i = 1;\n while (i < conn.ps.length) {\n const c0 = conn.ps[i - 1];\n const c1 = conn.ps[i];\n\n let j = polyIsConn ? 1 : 0;\n while (j < poly.ps.length) {\n const poly_size = poly.ps.length;\n const p0 = j === 0 ? poly.ps[poly_size - 1] : poly.ps[j - 1];\n const p1 = poly.ps[j];\n\n // Check the first point of the first segment (c0 = conn.ps[i-1]).\n if (i === 1 && pointOnLine(p0, p1, c0, tolerance)) {\n c0.vn = midVertexNumber(p0, p1, c0);\n poly.ps.splice(j, 0, c0);\n if (j > 0) {\n j--;\n }\n continue;\n }\n // And the second point of every conn segment (c1 = conn.ps[i]).\n if (pointOnLine(p0, p1, c1, tolerance)) {\n c1.vn = midVertexNumber(p0, p1, c1);\n poly.ps.splice(j, 0, c1);\n if (j > 0) {\n j--;\n }\n continue;\n }\n\n // Check the first point of the first poly segment (p0 = poly.ps[j-1]).\n if (polyIsConn && j === 1 && pointOnLine(c0, c1, p0, tolerance)) {\n p0.vn = midVertexNumber(c0, c1, p0);\n conn.ps.splice(i, 0, p0);\n // i stays the same — we'll re-examine from the same conn segment.\n continue;\n }\n // And the second point of every poly segment (p1 = poly.ps[j]).\n if (pointOnLine(c0, c1, p1, tolerance)) {\n p1.vn = midVertexNumber(c0, c1, p1);\n conn.ps.splice(i, 0, p1);\n // i stays — re-examine (now c0..conn.ps[i] is the new sub-segment).\n }\n\n j++;\n }\n i++;\n }\n}\n\n// ─── segDir (module-private) ──────────────────────────────────────────────────\n\nfunction segDir(p1: Point, p2: Point): number {\n let result = 1;\n if (p1.x === p2.x) {\n if (p2.y > p1.y) {\n result = -1;\n }\n } else if (p1.y === p2.y) {\n if (p2.x < p1.x) {\n result = -1;\n }\n }\n return result;\n}\n\n// ─── posInlineWithConnEndSegs (module-private) ────────────────────────────────\n\nfunction posInlineWithConnEndSegs(\n pos: number,\n dim: number,\n poly: Polygon,\n conn: Polygon,\n): boolean {\n const pLast = poly.size() - 1;\n const cLast = conn.size() - 1;\n if (\n // Is inline with the beginning of the \"poly\" line\n ((pos === poly.ps[0].at(dim) && pos === poly.ps[1].at(dim)) ||\n // Is inline with the end of the \"poly\" line\n (pos === poly.ps[pLast].at(dim) && pos === poly.ps[pLast - 1].at(dim))) &&\n // Is inline with the beginning of the \"conn\" line\n ((pos === conn.ps[0].at(dim) && pos === conn.ps[1].at(dim)) ||\n // Is inline with the end of the \"conn\" line\n (pos === conn.ps[cLast].at(dim) && pos === conn.ps[cLast - 1].at(dim)))\n ) {\n return true;\n }\n return false;\n}\n\n// ─── Constants ───────────────────────────────────────────────────────────────\n\nexport const CROSSING_NONE = 0;\nconst CROSSING_TOUCHES = 1;\nexport const CROSSING_SHARES_PATH = 2;\nexport const CROSSING_SHARES_PATH_AT_END = 4;\nexport const CROSSING_SHARES_FIXED_SEGMENT = 8;\n\n// ─── PtOrder ─────────────────────────────────────────────────────────────────\n\nexport type PtConnPtrPair = [Point, Edge];\nexport type PointRepVector = PtConnPtrPair[];\n\nexport class PtOrder {\n private sorted: [boolean, boolean] = [false, false];\n private nodes: [PointRepVector, PointRepVector] = [[], []];\n private links: [Array<[number, number]>, Array<[number, number]>] = [[], []];\n private sortedConnVector: [PointRepVector, PointRepVector] = [[], []];\n\n addPoints(dim: number, arg1: PtConnPtrPair, arg2: PtConnPtrPair): void {\n this.insertPoint(dim, arg1);\n this.insertPoint(dim, arg2);\n }\n\n addOrderedPoints(\n dim: number,\n inner: PtConnPtrPair,\n outer: PtConnPtrPair,\n swapped: boolean,\n ): void {\n const actualInner = swapped ? outer : inner;\n const actualOuter = swapped ? inner : outer;\n\n const innerIndex = this.insertPoint(dim, actualInner);\n const outerIndex = this.insertPoint(dim, actualOuter);\n\n // Edge: outerIndex -> innerIndex (outer comes first in sorted order).\n this.links[dim].push([outerIndex, innerIndex]);\n }\n\n positionFor(dim: number, conn: Edge): number {\n if (!this.sorted[dim]) {\n this.sort(dim);\n }\n const sv = this.sortedConnVector[dim];\n for (let i = 0; i < sv.length; ++i) {\n if (sv[i][1] === conn) {\n return i;\n }\n }\n return -1;\n }\n\n sortedPoints(dim: number): PointRepVector {\n if (!this.sorted[dim]) {\n this.sort(dim);\n }\n return this.sortedConnVector[dim];\n }\n\n private insertPoint(dim: number, point: PtConnPtrPair): number {\n // Is this connector's bendpoint already inserted?\n const n = this.nodes[dim];\n for (let i = 0; i < n.length; ++i) {\n if (n[i][1] === point[1]) {\n return i;\n }\n }\n // Not found — insert.\n n.push(point);\n return n.length - 1;\n }\n\n private sort(dim: number): void {\n // Topological sort of the points using the edge/dependency info.\n this.sorted[dim] = true;\n\n const n = this.nodes[dim].length;\n if (n === 0) {\n this.sortedConnVector[dim] = [];\n return;\n }\n\n // Build adjacency matrix.\n const adjacencyMatrix: boolean[][] = Array.from({ length: n }, () =>\n new Array<boolean>(n).fill(false),\n );\n for (const [from, to] of this.links[dim]) {\n adjacencyMatrix[from][to] = true;\n }\n\n // Build incoming-degree counts.\n const incomingDegree: number[] = new Array<number>(n).fill(0);\n for (let i = 0; i < n; ++i) {\n for (let j = 0; j < n; ++j) {\n if (adjacencyMatrix[j][i]) {\n incomingDegree[i]++;\n }\n }\n }\n\n // Seed queue with nodes that have no incoming edges.\n const queue: number[] = [];\n for (let i = 0; i < n; ++i) {\n if (incomingDegree[i] === 0) {\n queue.push(i);\n }\n }\n\n const result: PointRepVector = [];\n while (queue.length > 0) {\n const k = queue.shift()!;\n result.push(this.nodes[dim][k]);\n\n for (let i = 0; i < n; ++i) {\n if (adjacencyMatrix[k][i]) {\n adjacencyMatrix[k][i] = false;\n incomingDegree[i]--;\n if (incomingDegree[i] === 0) {\n queue.push(i);\n }\n }\n }\n }\n\n this.sortedConnVector[dim] = result;\n }\n}\n\n// ─── ConnectorCrossings ───────────────────────────────────────────────────────\n\nexport type PointSet = Set<Point>;\nexport type PtOrderMap = Map<Point, PtOrder>;\n\nexport class ConnectorCrossings {\n poly: Polygon;\n polyIsConn: boolean;\n conn: Polygon;\n checkForBranchingSegments: boolean;\n polyConnRef: Edge | null;\n connConnRef: Edge | null;\n\n crossingCount: number;\n crossingFlags: number;\n crossingPoints: PointSet | null;\n pointOrders: PtOrderMap | null;\n sharedPaths: Point[][] | null;\n\n firstSharedPathAtEndLength: number;\n secondSharedPathAtEndLength: number;\n\n constructor(\n poly: Polygon,\n polyIsConn: boolean,\n conn: Polygon,\n polyConnRef: Edge | null = null,\n connConnRef: Edge | null = null,\n ) {\n this.poly = poly;\n this.polyIsConn = polyIsConn;\n this.conn = conn;\n this.checkForBranchingSegments = false;\n this.polyConnRef = polyConnRef;\n this.connConnRef = connConnRef;\n this.crossingCount = 0;\n this.crossingFlags = CROSSING_NONE;\n this.crossingPoints = null;\n this.pointOrders = null;\n this.sharedPaths = null;\n this.firstSharedPathAtEndLength = Number.MAX_VALUE;\n this.secondSharedPathAtEndLength = Number.MAX_VALUE;\n }\n\n clear(): void {\n this.crossingCount = 0;\n this.crossingFlags = CROSSING_NONE;\n this.firstSharedPathAtEndLength = Number.MAX_VALUE;\n this.secondSharedPathAtEndLength = Number.MAX_VALUE;\n }\n\n // Works out if the segment conn[cIndex-1]--conn[cIndex] really crosses poly.\n // This does not count non-crossing shared paths as crossings.\n // poly can be either a connector (polyIsConn = true) or a cluster\n // boundary (polyIsConn = false).\n countForSegment(cIndex: number, finalSegment: boolean): void {\n this.clear();\n\n // All connectors are orthogonal in this port — true iff the ConnRef\n // exists. Kept as locals so the downstream checks read clearly.\n const polyIsOrthogonal = this.polyConnRef !== null;\n const connIsOrthogonal = this.connConnRef !== null;\n\n // We need to split apart connectors at potential crossing points if\n // either has a fixed route or it is a polyline connector.\n if (\n this.checkForBranchingSegments ||\n !polyIsOrthogonal ||\n !connIsOrthogonal\n ) {\n const epsilon = Number.EPSILON;\n const conn_pn = this.conn.size();\n const tolerance = !this.polyIsConn ? epsilon : 0.0;\n splitBranchingSegments(this.poly, this.polyIsConn, this.conn, tolerance);\n // cIndex is going to be the last, so take into account added points.\n cIndex += this.conn.size() - conn_pn;\n }\n\n const poly_size = this.poly.size();\n\n // c_path and p_path are index arrays into conn.ps and poly.ps.\n const max_path_size = Math.min(poly_size, this.conn.size());\n const c_path: number[] = new Array(max_path_size);\n const p_path: number[] = new Array(max_path_size);\n let size = 0;\n\n const a1 = this.conn.ps[cIndex - 1];\n const a2 = this.conn.ps[cIndex];\n\n for (let j = this.polyIsConn ? 1 : 0; j < poly_size; ++j) {\n const b1_idx = (j - 1 + poly_size) % poly_size;\n const b2_idx = j;\n const b1 = this.poly.ps[b1_idx];\n const b2 = this.poly.ps[b2_idx];\n\n size = 0;\n\n let converging = false;\n\n const a1_eq_b1 = a1.eq(b1);\n const a2_eq_b1 = a2.eq(b1);\n const a2_eq_b2 = a2.eq(b2);\n const a1_eq_b2 = a1.eq(b2);\n\n if ((a1_eq_b1 && a2_eq_b2) || (a2_eq_b1 && a1_eq_b2)) {\n if (finalSegment) {\n converging = true;\n } else {\n // Route along same segment: no penalty. We detect crossovers when\n // we see the segments diverge.\n continue;\n }\n } else if (a2_eq_b1 || a2_eq_b2 || a1_eq_b2) {\n // Each crossing that is at a vertex in the visibility graph gets\n // noticed four times. We ignore three of these cases.\n continue;\n }\n\n if (a1_eq_b1 || converging) {\n if (!converging) {\n if (this.polyIsConn && j === 1) {\n // Can't be the end of a shared path or crossing path since the\n // common point is the first point of the connector path.\n continue;\n }\n\n const b0_idx = (j - 2 + poly_size) % poly_size;\n const b0 = this.poly.ps[b0_idx];\n if (a2.eq(b0)) {\n // a2 is not a split, continue.\n continue;\n }\n }\n\n let shared_path = false;\n let p_dir_back = false;\n let p_dir = 0;\n let trace_c = 0;\n let trace_p = 0;\n\n if (converging) {\n p_dir_back = a2_eq_b2;\n p_dir = p_dir_back ? -1 : 1;\n trace_c = cIndex;\n trace_p = j;\n if (!p_dir_back) {\n if (finalSegment) {\n trace_p--;\n } else {\n trace_c--;\n }\n }\n shared_path = true;\n } else if (cIndex >= 2) {\n const b0_idx = (j - 2 + poly_size) % poly_size;\n const b0 = this.poly.ps[b0_idx];\n const a0 = this.conn.ps[cIndex - 2];\n\n if (a0.eq(b2) || a0.eq(b0)) {\n p_dir_back = a0.eq(b0);\n p_dir = p_dir_back ? -1 : 1;\n trace_c = cIndex;\n trace_p = p_dir_back ? j : j - 2;\n shared_path = true;\n }\n }\n\n if (shared_path) {\n this.crossingFlags |= CROSSING_SHARES_PATH;\n\n // Build the shared path, including the diverging points at each end.\n while (\n trace_c >= 0 &&\n (!this.polyIsConn || (trace_p >= 0 && trace_p < poly_size))\n ) {\n const index_p = ((trace_p % poly_size) + poly_size) % poly_size;\n const index_c = trace_c;\n c_path[size] = index_c;\n p_path[size] = index_p;\n ++size;\n if (size > 1 && !this.conn.ps[index_c].eq(this.poly.ps[index_p])) {\n // Points don't match, so break out of loop.\n break;\n }\n trace_c--;\n trace_p += p_dir;\n }\n\n const front_same = this.conn.ps[c_path[0]].eq(\n this.poly.ps[p_path[0]],\n );\n const back_same = this.conn.ps[c_path[size - 1]].eq(\n this.poly.ps[p_path[size - 1]],\n );\n\n // Determine if the shared path originates at a junction.\n let terminatesAtJunction = false;\n if (\n this.polyConnRef &&\n this.connConnRef &&\n (front_same || back_same)\n ) {\n const connEnds = this.connConnRef.endpointConnEnds();\n const polyEnds = this.polyConnRef.endpointConnEnds();\n if (connEnds && polyEnds) {\n const connJunction = front_same\n ? connEnds[1].junction()\n : connEnds[0].junction();\n let use_first = back_same;\n if (p_dir_back) {\n use_first = !use_first;\n }\n const polyJunction = use_first\n ? polyEnds[1].junction()\n : polyEnds[0].junction();\n\n terminatesAtJunction = !!(\n connJunction && connJunction === polyJunction\n );\n }\n }\n\n if (this.sharedPaths) {\n const start = front_same ? 0 : 1;\n const limit = size - (back_same ? 0 : 1);\n const sPath: Point[] = [];\n for (let pi = start; pi < limit; ++pi) {\n sPath.push(this.conn.ps[c_path[pi]]);\n }\n this.sharedPaths.push(sPath);\n }\n\n // Check to see if these share a fixed segment.\n if (polyIsOrthogonal && connIsOrthogonal) {\n const startPt = front_same ? 0 : 1;\n const endPt = size - (back_same ? 1 : 2);\n for (let dim = 0; dim < 2; ++dim) {\n if (\n this.conn.ps[c_path[startPt]].at(dim) ===\n this.conn.ps[c_path[endPt]].at(dim)\n ) {\n const pos = this.conn.ps[c_path[startPt]].at(dim);\n if (\n (pos === this.poly.ps[0].at(dim) ||\n pos === this.poly.ps[poly_size - 1].at(dim)) &&\n (pos === this.conn.ps[0].at(dim) ||\n pos === this.conn.ps[cIndex].at(dim)) &&\n !terminatesAtJunction\n ) {\n this.crossingFlags |= CROSSING_SHARES_FIXED_SEGMENT;\n }\n }\n }\n\n if (!front_same && !back_same) {\n for (let dim = 0; dim < 2; ++dim) {\n const end = size - 1;\n const altDim = (dim + 1) % 2;\n if (\n this.conn.ps[c_path[1]].at(altDim) ===\n this.conn.ps[c_path[end - 1]].at(altDim)\n ) {\n const posBeg = this.conn.ps[c_path[1]].at(dim);\n const posEnd = this.conn.ps[c_path[end - 1]].at(dim);\n if (\n posBeg === this.conn.ps[c_path[0]].at(dim) &&\n posBeg === this.poly.ps[p_path[0]].at(dim) &&\n posEnd === this.conn.ps[c_path[end]].at(dim) &&\n posEnd === this.poly.ps[p_path[end]].at(dim)\n ) {\n if (\n posInlineWithConnEndSegs(\n posBeg,\n dim,\n this.conn,\n this.poly,\n ) &&\n posInlineWithConnEndSegs(\n posEnd,\n dim,\n this.conn,\n this.poly,\n )\n ) {\n this.crossingFlags |= CROSSING_SHARES_FIXED_SEGMENT;\n }\n }\n }\n }\n }\n }\n\n // Determine corner sides at start/end of shared path.\n let startCornerSide = 1;\n let endCornerSide = 1;\n\n if (!front_same) {\n startCornerSide = cornerSide(\n this.conn.ps[c_path[0]],\n this.conn.ps[c_path[1]],\n this.conn.ps[c_path[2]],\n this.poly.ps[p_path[0]],\n );\n }\n if (!back_same) {\n endCornerSide = cornerSide(\n this.conn.ps[c_path[size - 3]],\n this.conn.ps[c_path[size - 2]],\n this.conn.ps[c_path[size - 1]],\n this.poly.ps[p_path[size - 1]],\n );\n } else {\n endCornerSide = startCornerSide;\n }\n if (front_same) {\n startCornerSide = endCornerSide;\n }\n\n if (endCornerSide !== startCornerSide) {\n this.crossingCount += 1;\n if (this.crossingPoints) {\n this.crossingPoints.add(this.conn.ps[c_path[1]]);\n }\n }\n\n if (front_same || back_same) {\n this.crossingFlags |= CROSSING_SHARES_PATH_AT_END;\n\n const straightModifier = 200;\n this.firstSharedPathAtEndLength = this.secondSharedPathAtEndLength =\n pathLengthFromIndices(this.conn, this.poly, c_path, p_path, size);\n\n if (back_same && size > 2) {\n if (\n vecDir(\n this.poly.ps[p_path[0]],\n this.poly.ps[p_path[1]],\n this.poly.ps[p_path[2]],\n ) === 0\n ) {\n this.firstSharedPathAtEndLength -= straightModifier;\n }\n if (\n vecDir(\n this.conn.ps[c_path[0]],\n this.conn.ps[c_path[1]],\n this.conn.ps[c_path[2]],\n ) === 0\n ) {\n this.secondSharedPathAtEndLength -= straightModifier;\n }\n } else if (front_same && size > 2) {\n if (\n vecDir(\n this.poly.ps[p_path[size - 3]],\n this.poly.ps[p_path[size - 2]],\n this.poly.ps[p_path[size - 1]],\n ) === 0\n ) {\n this.firstSharedPathAtEndLength -= straightModifier;\n }\n if (\n vecDir(\n this.conn.ps[c_path[size - 3]],\n this.conn.ps[c_path[size - 2]],\n this.conn.ps[c_path[size - 1]],\n ) === 0\n ) {\n this.secondSharedPathAtEndLength -= straightModifier;\n }\n }\n } else if (polyIsOrthogonal && connIsOrthogonal) {\n const cStartDir = vecDir(\n this.conn.ps[c_path[0]],\n this.conn.ps[c_path[1]],\n this.conn.ps[c_path[2]],\n );\n const pStartDir = vecDir(\n this.poly.ps[p_path[0]],\n this.poly.ps[p_path[1]],\n this.poly.ps[p_path[2]],\n );\n if (cStartDir !== 0 && cStartDir === -pStartDir) {\n startCornerSide = -cStartDir;\n } else {\n const cEndDir = vecDir(\n this.conn.ps[c_path[size - 3]],\n this.conn.ps[c_path[size - 2]],\n this.conn.ps[c_path[size - 1]],\n );\n const pEndDir = vecDir(\n this.poly.ps[p_path[size - 3]],\n this.poly.ps[p_path[size - 2]],\n this.poly.ps[p_path[size - 1]],\n );\n if (cEndDir !== 0 && cEndDir === -pEndDir) {\n startCornerSide = -cEndDir;\n }\n }\n }\n\n if (this.pointOrders) {\n let reversed = false;\n const startPt = front_same ? 0 : 1;\n\n if (startCornerSide > 0) {\n reversed = !reversed;\n }\n\n let prevDir = 0;\n const adj_size = size - (back_same ? 0 : 1);\n for (let pi = startPt; pi < adj_size; ++pi) {\n const an = this.conn.ps[c_path[pi]];\n const bn = this.poly.ps[p_path[pi]];\n\n if (pi > startPt) {\n const ap = this.conn.ps[c_path[pi - 1]];\n const bp = this.poly.ps[p_path[pi - 1]];\n\n const thisDir = segDir(ap, an);\n if (prevDir === 0) {\n if (thisDir > 0) {\n reversed = !reversed;\n }\n } else if (thisDir !== prevDir) {\n reversed = !reversed;\n }\n\n const orientation = ap.x === an.x ? 0 : 1;\n\n // Get or create PtOrder for an.\n let ptOrderAn = this.pointOrders.get(an);\n if (!ptOrderAn) {\n ptOrderAn = new PtOrder();\n this.pointOrders.set(an, ptOrderAn);\n }\n ptOrderAn.addOrderedPoints(\n orientation,\n [bn, this.polyConnRef!],\n [an, this.connConnRef!],\n reversed,\n );\n\n let ptOrderAp = this.pointOrders.get(ap);\n if (!ptOrderAp) {\n ptOrderAp = new PtOrder();\n this.pointOrders.set(ap, ptOrderAp);\n }\n ptOrderAp.addOrderedPoints(\n orientation,\n [bp, this.polyConnRef!],\n [ap, this.connConnRef!],\n reversed,\n );\n\n prevDir = thisDir;\n }\n }\n }\n\n this.crossingFlags |= CROSSING_TOUCHES;\n } else if (cIndex >= 2) {\n // The connectors cross or touch at this point.\n const b0_idx = (j - 2 + poly_size) % poly_size;\n const b0 = this.poly.ps[b0_idx];\n const a0 = this.conn.ps[cIndex - 2];\n\n const side1 = cornerSide(a0, a1, a2, b0);\n const side2 = cornerSide(a0, a1, a2, b2);\n if (side1 !== side2) {\n this.crossingCount += 1;\n if (this.crossingPoints) {\n this.crossingPoints.add(a1);\n }\n }\n\n this.crossingFlags |= CROSSING_TOUCHES;\n\n if (this.pointOrders) {\n if (polyIsOrthogonal && connIsOrthogonal) {\n const reversedX = a0.x < a1.x || a2.x < a1.x;\n const reversedY = a0.y < a1.y || a2.y < a1.y;\n let ptOrderB1 = this.pointOrders.get(b1);\n if (!ptOrderB1) {\n ptOrderB1 = new PtOrder();\n this.pointOrders.set(b1, ptOrderB1);\n }\n ptOrderB1.addOrderedPoints(\n 0,\n [b1, this.polyConnRef!],\n [a1, this.connConnRef!],\n !reversedX,\n );\n ptOrderB1.addOrderedPoints(\n 1,\n [b1, this.polyConnRef!],\n [a1, this.connConnRef!],\n !reversedY,\n );\n }\n }\n }\n } else {\n // No endpoint is shared between these two line segments,\n // so just calculate normal segment intersection.\n\n if (polyIsOrthogonal && connIsOrthogonal) {\n // All crossings in orthogonal connectors will be at a vertex in\n // the visibility graph, so we need not bother doing normal line\n // intersection.\n continue;\n }\n\n const result = segmentIntersectPoint(a1, a2, b1, b2);\n\n if (result.code === DO_INTERSECT) {\n const cPt = new Point(result.x, result.y);\n if (\n !this.polyIsConn &&\n (a1.eq(cPt) || a2.eq(cPt) || b1.eq(cPt) || b2.eq(cPt))\n ) {\n continue;\n }\n this.crossingCount += 1;\n if (this.crossingPoints) {\n this.crossingPoints.add(cPt);\n }\n }\n }\n }\n }\n}\n\n// ─── pathLengthFromIndices (module-private) ──────────────────────────────────\n\n// Computes the *shared* length of two shared paths.\n// Uses index arrays into conn.ps and poly.ps.\nfunction pathLengthFromIndices(\n conn: Polygon,\n poly: Polygon,\n c_path: number[],\n p_path: number[],\n size: number,\n): number {\n let length = 0;\n\n for (let ind = 1; ind < size; ++ind) {\n if (\n conn.ps[c_path[ind - 1]].eq(poly.ps[p_path[ind - 1]]) &&\n conn.ps[c_path[ind]].eq(poly.ps[p_path[ind]])\n ) {\n // This segment is shared by both paths.\n // Use Manhattan distance since this is for orthogonal paths.\n length += manhattanDist(conn.ps[c_path[ind - 1]], conn.ps[c_path[ind]]);\n }\n }\n\n return length;\n}\n","export class OptionSet {\n private rawValue: number;\n constructor(value: number | OptionSet[]) {\n if (typeof value === 'number') {\n this.rawValue = value;\n } else {\n this.rawValue = value.reduce(\n (oldValue, newValue) => oldValue | newValue.rawValue,\n 0,\n );\n }\n }\n\n has(value: OptionSet) {\n return (this.rawValue & value.rawValue) === value.rawValue;\n }\n\n add(value: typeof this): typeof this {\n let constructor = <typeof OptionSet>this.constructor;\n return new constructor(this.rawValue | value.rawValue) as typeof this;\n }\n\n equal(other: typeof this): boolean {\n return this.rawValue === other.rawValue;\n }\n\n static zero = new OptionSet(0);\n}\n","import { Edge } from './edge.ts';\nimport { Point } from './geomtypes.ts';\nimport type { Junction } from './junction.ts';\nimport { assert } from './utilities/assert.ts';\nimport { OptionSet } from './utilities/option-set.ts';\n\n// ─── Enums ───────────────────────────────────────────────────────────────────\n\nexport class Direction extends OptionSet {\n static blockStart = new Direction(1);\n static blockEnd = new Direction(2);\n static block = new Direction([Direction.blockStart, Direction.blockEnd]);\n\n static inlineStart = new Direction(4);\n static inlineEnd = new Direction(8);\n static inline = new Direction([Direction.inlineStart, Direction.inlineEnd]);\n\n static all = new Direction([Direction.block, Direction.inline]);\n}\n\nexport enum ConnEndType {\n ConnEndPoint,\n ConnEndJunction,\n}\n\n// ─── Checkpoint ──────────────────────────────────────────────────────────────\n\n//! A point that a connector route must visit, with optional arrival/departure\n//! direction constraints.\nexport class Checkpoint {\n point: Point;\n arrivalDirections: Direction;\n departureDirections: Direction;\n\n constructor(\n point: Point,\n arrivalDirections = Direction.all,\n departureDirections = Direction.all,\n ) {\n this.point = point;\n this.arrivalDirections = arrivalDirections;\n this.departureDirections = departureDirections;\n }\n}\n\n// ─── ConnEnd ─────────────────────────────────────────────────────────────────\n\n//! Represents one endpoint of a connector — either a free-floating point or\n//! a junction anchor. Shape-pin endpoints are not supported in this port.\nexport class Endpoint {\n /** @internal */ _type: ConnEndType;\n /** @internal */ _point: Point;\n directions: Direction;\n\n _anchorObj: Junction | null;\n /** @internal */ _connRef: Edge | null;\n\n // ─── Constructors ─────────────────────────────────────────────────────────\n\n constructor(point: Point);\n constructor(point: Point, visDirs: Direction);\n constructor(junctionRef: Junction);\n constructor(\n pointOrAnchor: Point | Junction,\n visDirsOrIsJunction?: Direction,\n ) {\n this._anchorObj = null;\n this._connRef = null;\n\n if (pointOrAnchor instanceof Point) {\n this._type = ConnEndType.ConnEndPoint;\n this._point = pointOrAnchor;\n this.directions = visDirsOrIsJunction ?? Direction.all;\n } else {\n this._anchorObj = pointOrAnchor;\n this._point = pointOrAnchor.position();\n this._type = ConnEndType.ConnEndJunction;\n this.directions = Direction.all;\n }\n }\n\n // ─── Public API ───────────────────────────────────────────────────────────\n\n type(): ConnEndType {\n return this._type;\n }\n\n position(): Point {\n if (this._anchorObj) {\n return this._anchorObj.position();\n }\n return this._point;\n }\n\n junction(): Junction | null {\n return this._type === ConnEndType.ConnEndJunction\n ? (this._anchorObj as Junction)\n : null;\n }\n\n // ─── Internal methods ─────────────────────────────────────────────────────\n\n /** @internal */\n isPinConnection(): boolean {\n return this._type === ConnEndType.ConnEndJunction;\n }\n\n /** @internal */\n endpointType(): 'src' | 'tar' {\n return this._connRef?.dstConnEnd === this ? 'tar' : 'src';\n }\n\n /** @internal */\n connect(conn: Edge): void {\n let junction = this.junction();\n assert('ConnEnd#connection must be called on junction connector', junction);\n junction.addFollowingConnEnd(this);\n this._connRef = conn;\n }\n\n /** @internal */\n disconnect(shapeDeleted = false): void {\n if (this._connRef === null) {\n return;\n }\n\n let junction = this.junction();\n assert('ConnEnd#disconnect must be called on junction connector', junction);\n\n this._point = this.position();\n junction.removeFollowingConnEnd(this);\n this._connRef = null;\n\n if (shapeDeleted) {\n this._point = this.position();\n this._anchorObj = null;\n this._type = ConnEndType.ConnEndPoint;\n }\n }\n}\n","import { Direction } from './endpoint.ts';\nimport { Point } from './geomtypes.ts';\nimport type { EdgeInf } from './graph.ts';\n\n// Forward reference for ANode (defined in makepath.ts).\nexport interface ANode {}\n\n// ─── Orthogonal visibility property flags ────────────────────────────────────\n\nexport const XL_EDGE = 1;\nexport const XL_CONN = 2;\nexport const XH_EDGE = 4;\nexport const XH_CONN = 8;\nexport const YL_EDGE = 16;\nexport const YL_CONN = 32;\nexport const YH_EDGE = 64;\nexport const YH_CONN = 128;\n\n// Role-flag bag passed to `VertInf`'s constructor and `resetIdAndPoint(…)`.\n// Omitted fields default to `false`.\nexport interface VertInfRoles {\n isConnPoint?: boolean;\n isOrthShapeEdge?: boolean;\n isJunctionCentre?: boolean;\n isConnCheckpoint?: boolean;\n isDummyPinHelper?: boolean;\n // Stage 3 of the VertID overhaul: connector endpoints carry src/tar\n // identity as named flags instead of overloading `vn = 1` / `vn = 2`. The\n // vn values themselves are now 0 / 1, with no collision-prone meaning.\n isSrcEndpoint?: boolean;\n isTarEndpoint?: boolean;\n // Stage 5 of the VertID overhaul: synthetic vertex MTST creates to model\n // the bend penalty between horizontal/vertical routing layers.\n isDimensionChangePartner?: boolean;\n}\n\n// Monotonic counter used to stamp each `VertInf` with a unique `_seq` at\n// construction. Drives the deterministic tie-break ordering used by MTST\n// (when two tree roots compare equal on point coordinates we still need a\n// stable winner). Replaces the C++ `VertID::lt` ordering.\nlet _vertInfSeqCounter = 0;\n\n// ─── VertInf ──────────────────────────────────────────────────────────────────\n\nexport class VertInf {\n // ─── Identity ──────────────────────────────────────────────────────────────\n // `objID` is the owner's `_id` (Obstacle / ConnRef) — or 0 for synthetic\n // vertices that aren't owned by any obstacle. `vn` is shape-corner index\n // (for shape vertices) or a connector-internal disambiguator (0 = src,\n // 1 = tar, 2 + i = i-th checkpoint). Stage 5 of the VertID overhaul\n // hoisted these out of the now-deleted `VertID` class.\n objID: number;\n vn: number;\n\n // Monotonically increasing creation sequence — guarantees a stable\n // deterministic ordering between any two VertInfs, used by MTST and the\n // scanline's `PosVertInf.lt` tie-break. Replaces the C++ `VertID::lt`.\n readonly _seq: number;\n\n point: Point;\n\n // ─── Role flags ────────────────────────────────────────────────────────────\n // Named role bits, owned directly by the vertex. Callers pass the\n // applicable flags via the fourth constructor / `resetIdAndPoint` argument.\n // (TS can't see that `applyRoles` populates these from inside the\n // constructor, so the `!` definite-assignment assertions are required.)\n isConnPoint!: boolean;\n isOrthShapeEdge!: boolean;\n isJunctionCentre!: boolean;\n isConnCheckpoint!: boolean;\n isDummyPinHelper!: boolean;\n isSrcEndpoint!: boolean;\n isTarEndpoint!: boolean;\n isDimensionChangePartner!: boolean;\n\n // Doubly-linked list pointers within VertInfList.\n lstPrev: VertInf | null;\n lstNext: VertInf | null;\n // Linked list pointers within a shape's own vertex ring.\n shPrev: VertInf | null;\n shNext: VertInf | null;\n\n // Orthogonal visibility graph edge list.\n orthogVisList: EdgeInf[];\n orthogVisListSize: number;\n\n // A* pathfinding.\n pathNext: VertInf | null;\n aStarDoneNodes: ANode[];\n aStarPendingNodes: ANode[];\n\n // Orthogonal partner used when building the orthogonal visibility graph.\n orthogonalPartner: VertInf | null;\n\n // MTST tree root — a shared mutable box so multiple vertices can track the\n // same root through a single reference. Replaces the C++ VertInf** hack.\n _treeRootBox: { value: VertInf | null } | null;\n\n // SPTF (shortest-path tree from source) root — stored separately because\n // the C++ reuses the m_treeRoot field with an unsafe cast; we keep them\n // distinct for clarity.\n _sptfRoot: VertInf | null;\n\n sptfDist: number;\n\n visDirections: Direction;\n\n // Flags encoding which sides of this vertex border shape edges or\n // connection points (used by orthogonal routing).\n orthogVisPropFlags: number;\n\n constructor(\n objID: number,\n vn: number,\n point: Point,\n roles: VertInfRoles = {},\n ) {\n this.objID = objID;\n this.vn = vn;\n this._seq = ++_vertInfSeqCounter;\n\n this.point = new Point(point.x, point.y);\n this.point.vn = vn;\n\n this.applyRoles(roles);\n\n this.lstPrev = null;\n this.lstNext = null;\n this.shPrev = null;\n this.shNext = null;\n\n this.orthogVisList = [];\n this.orthogVisListSize = 0;\n\n this.pathNext = null;\n this.aStarDoneNodes = [];\n this.aStarPendingNodes = [];\n\n this.orthogonalPartner = null;\n this._treeRootBox = null;\n this._sptfRoot = null;\n this.sptfDist = 0;\n\n this.visDirections = Direction.zero;\n this.orthogVisPropFlags = 0;\n }\n\n private applyRoles(roles: VertInfRoles): void {\n this.isConnPoint = roles.isConnPoint ?? false;\n this.isOrthShapeEdge = roles.isOrthShapeEdge ?? false;\n this.isJunctionCentre = roles.isJunctionCentre ?? false;\n this.isConnCheckpoint = roles.isConnCheckpoint ?? false;\n this.isDummyPinHelper = roles.isDummyPinHelper ?? false;\n this.isSrcEndpoint = roles.isSrcEndpoint ?? false;\n this.isTarEndpoint = roles.isTarEndpoint ?? false;\n this.isDimensionChangePartner = roles.isDimensionChangePartner ?? false;\n }\n\n //! Replace identity (objID + vn), position, and optionally role flags.\n //! Use `resetPoint` if only the position needs updating (e.g. when a\n //! shape moves but keeps the same corner indices).\n resetIdAndPoint(\n objID: number,\n vn: number,\n point: Point,\n roles?: VertInfRoles,\n ): void {\n this.objID = objID;\n this.vn = vn;\n this.point = new Point(point.x, point.y);\n this.point.vn = vn;\n if (roles) {\n this.applyRoles(roles);\n }\n }\n\n //! Update position only; identity (objID + vn) and roles are preserved.\n resetPoint(point: Point): void {\n this.point = new Point(point.x, point.y);\n this.point.vn = this.vn;\n }\n\n // Removes all edges from this vertex, alerting connected connectors.\n removeFromGraph(_isConnVert = true): void {\n while (this.orthogVisList.length > 0) {\n const edge = this.orthogVisList[0];\n edge.destroy();\n }\n }\n\n // Returns the direction flags of this vertex relative to other.\n // Uses a small epsilon to avoid floating-point noise.\n directionFrom(other: VertInf): Direction {\n const epsilon = 0.000001;\n let diff = new Point(\n this.point.x - other.point.x,\n this.point.y - other.point.y,\n );\n let directions = Direction.zero;\n\n if (diff.y > epsilon) {\n directions = directions.add(Direction.blockStart);\n }\n if (diff.y < -epsilon) {\n directions = directions.add(Direction.blockEnd);\n }\n if (diff.x > epsilon) {\n directions = directions.add(Direction.inlineEnd);\n }\n if (diff.x < -epsilon) {\n directions = directions.add(Direction.inlineStart);\n }\n return directions;\n }\n\n // Disables visibility edges whose direction is not in the given set.\n setVisibleDirections(directions: Direction): void {\n for (const edge of this.orthogVisList) {\n if (directions.equal(Direction.all)) {\n edge.setDisabled(false);\n } else {\n const other = edge.otherVert(this);\n const dir = other.directionFrom(this);\n edge.setDisabled(!dir.has(directions)); // (dir & directions) === 0\n }\n }\n }\n\n // Returns the number of steps from this vertex back to start along\n // pathNext links, or 0 if no such path exists.\n pathLeadsBackTo(start: VertInf): number {\n let pathlen = 1;\n for (let i: VertInf | null = this; i !== start; i = i.pathNext) {\n if (pathlen > 1 && i === this) return 0; // circular\n pathlen++;\n if (i === null) return 0; // not found\n }\n return pathlen;\n }\n\n // Returns an edge to target in the appropriate visibility list, or null.\n hasNeighbour(target: VertInf): EdgeInf | null {\n for (const edge of this.orthogVisList) {\n if (edge.otherVert(this) === target) return edge;\n }\n return null;\n }\n\n // ─── MTST tree root ───────────────────────────────────────────────────────\n // The C++ uses a malloc'd VertInf** so multiple vertices can share one root\n // cell. We model this as a shared { value } box.\n\n makeTreeRootPointer(root: VertInf): { value: VertInf | null } {\n this._treeRootBox = { value: root };\n return this._treeRootBox;\n }\n\n treeRoot(): VertInf | null {\n return this._treeRootBox ? this._treeRootBox.value : null;\n }\n\n treeRootPointer(): { value: VertInf | null } | null {\n return this._treeRootBox;\n }\n\n setTreeRootPointer(pointer: { value: VertInf | null } | null): void {\n this._treeRootBox = pointer;\n }\n\n clearTreeRootPointer(): void {\n this._treeRootBox = null;\n }\n\n // ─── SPTF root ────────────────────────────────────────────────────────────\n // Separate from the MTST box; the C++ reused m_treeRoot with an unsafe cast.\n\n setSPTFRoot(root: VertInf): void {\n this._sptfRoot = root;\n }\n\n sptfRoot(): VertInf | null {\n return this._sptfRoot;\n }\n}\n\n// ─── VertInfList ─────────────────────────────────────────────────────────────\n// A split linked list that keeps connector vertices before shape vertices.\n// Invariants (matching the C++ checkVertInfListConditions macro):\n// - connector vertices occupy the head of the list\n// - shape vertices follow immediately after\n// - _lastConnVert->lstNext === _firstShapeVert (or null when no shapes)\n// - _lastShapeVert->lstNext === null\n\nexport class VertInfList {\n private _firstShapeVert: VertInf | null;\n private _firstConnVert: VertInf | null;\n private _lastShapeVert: VertInf | null;\n private _lastConnVert: VertInf | null;\n private _shapeVertices: number;\n private _connVertices: number;\n\n constructor() {\n this._firstShapeVert = null;\n this._firstConnVert = null;\n this._lastShapeVert = null;\n this._lastConnVert = null;\n this._shapeVertices = 0;\n this._connVertices = 0;\n }\n\n addVertex(vert: VertInf): void {\n if (vert.isConnPoint) {\n if (this._firstConnVert) {\n vert.lstNext = this._firstConnVert;\n this._firstConnVert.lstPrev = vert;\n this._firstConnVert = vert;\n } else {\n this._firstConnVert = vert;\n this._lastConnVert = vert;\n vert.lstNext = this._firstShapeVert;\n }\n this._connVertices++;\n } else {\n if (this._lastShapeVert) {\n vert.lstPrev = this._lastShapeVert;\n this._lastShapeVert.lstNext = vert;\n this._lastShapeVert = vert;\n } else {\n this._firstShapeVert = vert;\n this._lastShapeVert = vert;\n if (this._lastConnVert) {\n this._lastConnVert.lstNext = vert;\n }\n }\n this._shapeVertices++;\n }\n }\n\n // Removes vert from the list and returns the successor.\n removeVertex(vert: VertInf | null): VertInf | null {\n if (vert === null) return null;\n\n const following = vert.lstNext;\n\n if (vert.isConnPoint) {\n if (vert === this._firstConnVert) {\n if (vert === this._lastConnVert) {\n this._firstConnVert = null;\n this._lastConnVert = null;\n } else {\n this._firstConnVert = this._firstConnVert!.lstNext;\n if (this._firstConnVert) {\n this._firstConnVert.lstPrev = null;\n }\n }\n } else if (vert === this._lastConnVert) {\n this._lastConnVert = this._lastConnVert!.lstPrev;\n this._lastConnVert!.lstNext = this._firstShapeVert;\n } else {\n vert.lstNext!.lstPrev = vert.lstPrev;\n vert.lstPrev!.lstNext = vert.lstNext;\n }\n this._connVertices--;\n } else {\n if (vert === this._lastShapeVert) {\n this._lastShapeVert = this._lastShapeVert!.lstPrev;\n\n if (vert === this._firstShapeVert) {\n this._firstShapeVert = null;\n if (this._lastConnVert) {\n this._lastConnVert.lstNext = null;\n }\n }\n\n if (this._lastShapeVert) {\n this._lastShapeVert.lstNext = null;\n }\n } else if (vert === this._firstShapeVert) {\n this._firstShapeVert = this._firstShapeVert!.lstNext;\n\n if (this._lastConnVert) {\n this._lastConnVert.lstNext = this._firstShapeVert;\n }\n\n if (this._firstShapeVert) {\n this._firstShapeVert.lstPrev = null;\n }\n } else {\n vert.lstNext!.lstPrev = vert.lstPrev;\n vert.lstPrev!.lstNext = vert.lstNext;\n }\n this._shapeVertices--;\n }\n\n vert.lstPrev = null;\n vert.lstNext = null;\n\n return following;\n }\n\n // Searches shape vertices for an exact position match.\n getVertexByPos(p: Point): VertInf | null {\n for (let curr = this.shapesBegin(); curr !== null; curr = curr.lstNext) {\n if (curr.point.eq(p)) return curr;\n }\n return null;\n }\n\n shapesBegin(): VertInf | null {\n return this._firstShapeVert;\n }\n\n // Returns the first connector vertex, falling back to the first shape\n // vertex when there are no connectors.\n connsBegin(): VertInf | null {\n return this._firstConnVert ?? this._firstShapeVert;\n }\n\n // Sentinel: iteration ends when lstNext returns null.\n end(): null {\n return null;\n }\n\n connsSize(): number {\n return this._connVertices;\n }\n\n shapesSize(): number {\n return this._shapeVertices;\n }\n}\n","import { VertInf } from './vertex';\nimport type { Box, Rect } from './geomtypes';\nimport type { Router } from './router';\nimport { assert } from './utilities/assert';\n\n// ─── Obstacle ─────────────────────────────────────────────────────────────────\n\n// Abstract base class for ShapeRef and JunctionRef.\nexport class Obstacle {\n readonly router: Router;\n readonly polygon: Rect;\n\n _active: boolean;\n _firstVert: VertInf;\n _lastVert: VertInf;\n\n constructor(router: Router, poly: Rect) {\n this.router = router;\n this.polygon = poly;\n this._active = false;\n\n // Build the ring of VertInf nodes for the routing polygon. Each corner\n // gets vn = pt_i (0..N-1), used by `midVertexNumber` to identify which\n // edge of a rectangle a route midpoint sits on.\n\n const bufferSpace = this.router.params.shapeBufferDistance;\n const routingPoly = this.routingPolygon(bufferSpace);\n let lastVertex: VertInf | null = null;\n let firstVertex: VertInf | null = null;\n\n let id = router._assignObjectId();\n for (let [index, point] of routingPoly.ps.entries()) {\n const node = new VertInf(id, index, point);\n // Not added to the router's vertex list yet — that happens in\n // makeActive() so we don't pollute the graph for inactive obstacles.\n\n if (!firstVertex) {\n firstVertex = node;\n } else {\n node.shPrev = lastVertex;\n lastVertex!.shNext = node;\n }\n lastVertex = node;\n }\n\n assert('has first and last vertext', firstVertex && lastVertex);\n\n this._lastVert = lastVertex;\n this._firstVert = firstVertex;\n this._lastVert.shNext = firstVertex;\n this._firstVert.shPrev = lastVertex;\n }\n\n // ─── Public API ─────────────────────────────────────────────────────────────\n\n //! Returns the anchor's centre vertex if it has one — junctions do, shapes\n //! do not. Used by HyperedgeRerouter to resolve a junction-anchored\n //! endpoint into a routable vertex. Default implementation returns null\n //! (suitable for ShapeRef); JunctionRef overrides.\n centreVertex(): VertInf | null {\n return null;\n }\n\n // True if this obstacle is a non-fixed junction. Free junctions are not\n // treated as obstacles during scanline / orthogonal nudging because they\n // can be moved. Shapes return false; JunctionRef overrides.\n isFreeJunction(): boolean {\n return false;\n }\n\n firstVert(): VertInf | null {\n return this._firstVert;\n }\n\n lastVert(): VertInf | null {\n return this._lastVert;\n }\n\n // Returns the expanded bounding box used for routing around this obstacle.\n routingBox(): Box {\n const bufferSpace = this.router.params.shapeBufferDistance;\n return this.polygon.offsetBoundingBox(bufferSpace);\n }\n\n // Returns the expanded routing polygon (Minkowski sum with a square buffer).\n routingPolygon(bufferSpace: number): Rect {\n return this.polygon.offsetPolygon(bufferSpace);\n }\n\n // ─── Internal methods ────────────────────────────────────────────────────────\n\n /** @internal */\n isActive(): boolean {\n return this._active;\n }\n\n /** @internal */\n makeActive(): void {\n this.router.addObstacle(this);\n\n // Add all shape vertices to the router's vertex list.\n let it = this._firstVert!;\n do {\n const tmp = it;\n it = it.shNext!;\n this.router.vertices.addVertex(tmp);\n } while (it !== this._firstVert);\n\n this._active = true;\n }\n\n /** @internal */\n makeInactive(): void {\n this.router.removeObstacle(this);\n\n // Remove all shape vertices from the router's vertex list.\n let it = this._firstVert!;\n do {\n const tmp = it;\n it = it.shNext!;\n this.router.vertices.removeVertex(tmp);\n } while (it !== this._firstVert);\n\n this._active = false;\n }\n\n /** @internal */\n removeFromGraph(): void {\n const last = this._lastVert!.lstNext;\n for (let iter: VertInf | null = this._firstVert; iter !== last; ) {\n const tmp = iter!;\n iter = iter!.lstNext;\n tmp.removeFromGraph(false);\n }\n }\n}\n","import { XDIM, YDIM, Point, kShapeConnectionPin, Rect } from './geomtypes';\nimport { Endpoint, Direction } from './endpoint';\nimport { Obstacle } from './obstacle';\nimport { VertInf } from './vertex';\nimport { Router } from './router';\nimport { Edge } from './edge';\n\n// ─── JunctionRef ──────────────────────────────────────────────────────────────\n\n//! Represents a fixed or free-floating junction between connectors.\nexport class Junction extends Obstacle {\n followingConns = new Set<Endpoint>();\n private _position: Point;\n private _positionFixed: boolean;\n\n // Single centre vertex; lives outside the Obstacle's polygon vertex ring.\n // Visibility is `Direction.all` — connectors routing through the junction\n // can approach from any side. (Previously wrapped in a JunctionCentrePin\n // helper class; merged in since it carried no state of its own beyond\n // these two fields.)\n readonly _centreVertex: VertInf;\n _centreConnectionCost: number = 0;\n\n constructor(router: Router, position: Point) {\n super(router, Junction.makeRectangle(router, position));\n this._position = new Point(position.x, position.y);\n this._positionFixed = false;\n\n this._centreVertex = new VertInf(\n router._assignObjectId(),\n kShapeConnectionPin,\n position,\n { isConnPoint: true, isJunctionCentre: true },\n );\n router.vertices.addVertex(this._centreVertex);\n this._centreVertex.visDirections = Direction.all;\n }\n\n // ─── Public API ─────────────────────────────────────────────────────────────\n\n // Returns the position of this junction.\n position(): Point {\n return this._position;\n }\n\n // Returns the centre vertex used for connector routing into/out of this\n // junction. Satisfies the `ConnEndAnchor.centreVertex` contract.\n override centreVertex(): VertInf {\n return this._centreVertex;\n }\n\n // Routing-cost added to the dummy bridging edge a ConnRef builds between\n // its endpoint vertex and this junction's centre vertex (see\n // ConnRef.assignConnectionPinVisibility). Mirrors the C++ pin-cost path —\n // currently always 0 unless `preferOrthogonalDimension` has stamped a small\n // perpendicular-dimension penalty.\n /** @internal */\n centreConnectionCost(): number {\n return this._centreConnectionCost;\n }\n\n // Sets whether the junction has a fixed position.\n setPositionFixed(fixed: boolean): void {\n this._positionFixed = fixed;\n }\n\n // Returns whether the junction position is fixed.\n positionFixed(): boolean {\n return this._positionFixed;\n }\n\n // Override: a non-fixed junction is \"free\" — scanline / nudging should not\n // treat it as a static obstacle.\n override isFreeJunction(): boolean {\n return !this._positionFixed;\n }\n\n // Creates a small Rectangle centred on position, used as the obstacle polygon.\n static makeRectangle(router: Router, position: Point): Rect {\n const nudgeDist = Math.min(1.0, router.params.idealNudgingDistance);\n const low = new Point(position.x - nudgeDist, position.y - nudgeDist);\n return new Rect(\n { x: low.x, y: low.y },\n {\n width: nudgeDist * 2,\n height: nudgeDist * 2,\n },\n );\n }\n\n // Applies a small penalty to the centre vertex when the routing dimension\n // is orthogonal to its preferred direction. Because the centre vertex\n // always has `Direction.all` visibility, both XDIM and YDIM call sites\n // unconditionally apply the penalty — the parameter is kept for parity\n // with the C++ API where per-pin direction filtering used to live.\n preferOrthogonalDimension(dim: number): void {\n const smallPenalty = 1.0;\n if (dim === XDIM || dim === YDIM) {\n this._centreConnectionCost = smallPenalty;\n }\n }\n\n override makeInactive(): void {\n super.makeInactive();\n // Convert attached ConnEnds into free-floating points.\n // Verify this…\n for (let connEnd of this.followingConns.values()) {\n connEnd.disconnect(true);\n }\n // while (this.followingConns.size > 0) {\n // const connEnd = this.followingConns.values().next().value as ConnEnd;\n // connEnd.disconnect(true);\n // }\n }\n\n addFollowingConnEnd(connEnd: Endpoint): void {\n this.followingConns.add(connEnd);\n }\n\n removeFollowingConnEnd(connEnd: Endpoint): void {\n this.followingConns.delete(connEnd);\n }\n\n // Returns all ConnRefs attached to this obstacle via following ConnEnds.\n attachedConnectors(): Edge[] {\n const result: Edge[] = [];\n for (const connEnd of this.followingConns) {\n if (connEnd._connRef !== null) {\n result.push(connEnd._connRef);\n }\n }\n return result;\n }\n}\n","// Scanline sweep for orthogonal-routing channel building.\n//\n// Ports input/scanline.cpp. Three exports drive the algorithm:\n// - buildOrthogonalChannelInfo: orthogonal nudging's space-determination\n// - buildConnectorRouteCheckpointCache: marks segments touched by\n// routing checkpoints\n// - clearConnectorRouteCheckpointCache: clears those caches\n//\n// The scanline maintains a sorted set of Node objects (by `pos`, with\n// insertion-order tiebreak). Each insertion records firstAbove/firstBelow\n// neighbour pointers so the Node can later inspect its environment without\n// re-querying the set. ShiftSegments and Obstacles meet through the same\n// Node abstraction.\n//\n// The ShiftSegment interface is left abstract; concrete subclasses come from\n// orthogonal.ts (not yet ported).\n\nimport { type Point, XDIM, YDIM } from './geomtypes';\nimport { type VertInf } from './vertex';\nimport { pointOnLine } from './geometry';\nimport type { Router } from './router';\nimport type { Obstacle } from './obstacle';\n\n// ─── Constants ────────────────────────────────────────────────────────────────\n\nexport const CHANNEL_MAX = 1e8;\n\n// ─── ShiftSegment ─────────────────────────────────────────────────────────────\n\n// Abstract interface for a shiftable segment in the orthogonal nudger.\n// Concrete implementations (NudgingShiftSegment, etc.) live in orthogonal.ts.\n//\n// `dimension` is the axis the segment is shifted *along* (perpendicular to\n// the segment direction). `lowPoint`/`highPoint` return endpoints; the order\n// follows lower → higher in `1 - dimension` (the segment's own axis).\nexport interface ShiftSegment {\n dimension: number;\n minSpaceLimit: number;\n maxSpaceLimit: number;\n\n lowPoint(): Point;\n highPoint(): Point;\n overlapsWith(rhs: ShiftSegment, dim: number): boolean;\n immovable(): boolean;\n}\n\n// ─── Node ─────────────────────────────────────────────────────────────────────\n//\n// A Node represents one of three kinds of scanline element:\n// - An obstacle (`v` set) — the centre of a shape/junction's range\n// - A connector endpoint (`c` set) — a single point\n// - A shift segment (`ss` set) — a candidate shiftable segment\n//\n// `min[dim]`/`max[dim]` is the extent of this Node in dimension `dim`. The\n// scanline sorts Nodes by `pos`; tiebreaking is by insertion order so behaviour\n// stays deterministic.\n\nlet _nodeCounter = 0;\n\nexport class Node {\n v: Obstacle | null;\n c: VertInf | null;\n ss: ShiftSegment | null;\n pos: number;\n min: [number, number];\n max: [number, number];\n firstAbove: Node | null;\n firstBelow: Node | null;\n // Insertion-order id used as a deterministic tiebreaker. Replaces the C++\n // pointer comparison in CmpNodePos.\n readonly id: number;\n\n // ─── Factories (one per kind) ─────────────────────────────────────────────\n\n static forObstacle(v: Obstacle, pos: number): Node {\n const node = new Node(pos);\n node.v = v;\n const bb = v.routingBox();\n node.min[XDIM] = bb.min.x;\n node.min[YDIM] = bb.min.y;\n node.max[XDIM] = bb.max.x;\n node.max[YDIM] = bb.max.y;\n return node;\n }\n\n static forVertex(c: VertInf, pos: number): Node {\n const node = new Node(pos);\n node.c = c;\n node.min[XDIM] = node.max[XDIM] = c.point.x;\n node.min[YDIM] = node.max[YDIM] = c.point.y;\n return node;\n }\n\n static forShiftSegment(ss: ShiftSegment, pos: number): Node {\n const node = new Node(pos);\n node.ss = ss;\n // min/max never read for shift-segment nodes.\n return node;\n }\n\n private constructor(pos: number) {\n this.v = null;\n this.c = null;\n this.ss = null;\n this.pos = pos;\n this.min = [0, 0];\n this.max = [0, 0];\n this.firstAbove = null;\n this.firstBelow = null;\n this.id = ++_nodeCounter;\n }\n\n // ─── Queries ──────────────────────────────────────────────────────────────\n\n // Returns the position of the first shape edge above (in scanline order)\n // that has not just been opened or closed at this position. Returns\n // -Number.MAX_VALUE if no such edge exists.\n firstObstacleAbove(dim: number): number {\n let curr = this.firstAbove;\n while (curr && (curr.ss !== null || curr.max[dim] > this.pos)) {\n curr = curr.firstAbove;\n }\n return curr ? curr.max[dim] : -Number.MAX_VALUE;\n }\n\n // Same as firstObstacleAbove but in the \"below\" direction.\n firstObstacleBelow(dim: number): number {\n let curr = this.firstBelow;\n while (curr && (curr.ss !== null || curr.min[dim] < this.pos)) {\n curr = curr.firstBelow;\n }\n return curr ? curr.min[dim] : Number.MAX_VALUE;\n }\n\n // Walk above and mark every connector segment whose space is bounded by\n // this obstacle's near edge.\n markShiftSegmentsAbove(dim: number): void {\n let curr = this.firstAbove;\n while (curr && (curr.ss !== null || curr.pos > this.min[dim])) {\n if (curr.ss !== null && curr.pos <= this.min[dim]) {\n curr.ss.maxSpaceLimit = Math.min(this.min[dim], curr.ss.maxSpaceLimit);\n }\n curr = curr.firstAbove;\n }\n }\n\n // Same but in the \"below\" direction.\n markShiftSegmentsBelow(dim: number): void {\n let curr = this.firstBelow;\n while (curr && (curr.ss !== null || curr.pos < this.max[dim])) {\n if (curr.ss !== null && curr.pos >= this.max[dim]) {\n curr.ss.minSpaceLimit = Math.max(this.max[dim], curr.ss.minSpaceLimit);\n }\n curr = curr.firstBelow;\n }\n }\n\n // Used by orthogonal nudging: enumerate first/last shape limits above and\n // below for the line at `linePos` (the perpendicular axis).\n findFirstPointAboveAndBelow(\n dim: number,\n linePos: number,\n ): {\n firstAbove: number;\n firstBelow: number;\n lastAbove: number;\n lastBelow: number;\n } {\n let firstAbove = -Number.MAX_VALUE;\n let firstBelow = Number.MAX_VALUE;\n // Start from the obstacle's own edges; we relax these as we walk.\n let lastAbove = this.max[dim];\n let lastBelow = this.min[dim];\n\n const altDim = 1 - dim;\n\n for (let direction = 0; direction < 2; direction++) {\n let curr = direction === 0 ? this.firstAbove : this.firstBelow;\n while (curr) {\n // True if both events share their begin or end position along altDim.\n // Such pairs do not block visibility.\n const eventsAtSamePos =\n (linePos === this.max[altDim] && linePos === curr.max[altDim]) ||\n (linePos === this.min[altDim] && linePos === curr.min[altDim]);\n\n if (curr.max[dim] <= this.min[dim]) {\n // curr is entirely to the \"above\" side of `this`; its right edge\n // bounds firstAbove from above.\n firstAbove = Math.max(curr.max[dim], firstAbove);\n } else if (curr.min[dim] >= this.max[dim]) {\n // curr is entirely \"below\"; its left edge bounds firstBelow.\n firstBelow = Math.min(curr.min[dim], firstBelow);\n } else if (!eventsAtSamePos) {\n // Overlap: shrink lastAbove/lastBelow accordingly.\n lastAbove = Math.min(curr.min[dim], lastAbove);\n lastBelow = Math.max(curr.max[dim], lastBelow);\n }\n curr = direction === 0 ? curr.firstAbove : curr.firstBelow;\n }\n }\n\n return { firstAbove, firstBelow, lastAbove, lastBelow };\n }\n\n // Walk above looking for the closest obstacle whose edge is not in line\n // with this Node's `altDim` edge (i.e. visibility along edges is allowed).\n firstPointAbove(dim: number): number {\n const altDim = 1 - dim;\n let result = -Number.MAX_VALUE;\n for (let curr = this.firstAbove; curr; curr = curr.firstAbove) {\n const inLineWithEdge =\n this.min[altDim] === curr.min[altDim] ||\n this.min[altDim] === curr.max[altDim];\n if (!inLineWithEdge && curr.max[dim] <= this.pos) {\n result = Math.max(curr.max[dim], result);\n }\n }\n return result;\n }\n\n // Same, but looking below.\n firstPointBelow(dim: number): number {\n const altDim = 1 - dim;\n let result = Number.MAX_VALUE;\n for (let curr = this.firstBelow; curr; curr = curr.firstBelow) {\n const inLineWithEdge =\n this.min[altDim] === curr.min[altDim] ||\n this.min[altDim] === curr.max[altDim];\n if (!inLineWithEdge && curr.min[dim] >= this.pos) {\n result = Math.min(curr.min[dim], result);\n }\n }\n return result;\n }\n\n // True if this point's `pos` falls strictly inside any neighbour shape's\n // extent in `dimension`.\n isInsideShape(dimension: number): boolean {\n for (let curr = this.firstBelow; curr; curr = curr.firstBelow) {\n if (curr.min[dimension] < this.pos && this.pos < curr.max[dimension]) {\n return true;\n }\n }\n for (let curr = this.firstAbove; curr; curr = curr.firstAbove) {\n if (curr.min[dimension] < this.pos && this.pos < curr.max[dimension]) {\n return true;\n }\n }\n return false;\n }\n}\n\n// ─── EventType / Event ────────────────────────────────────────────────────────\n\n// Note: Open must come first. The integer ordering determines tie-breaking\n// when multiple events share the same scanline position — Opens fire before\n// Closes at the same line.\nexport const EventType = {\n Open: 1,\n SegOpen: 2,\n ConnPoint: 3,\n SegClose: 4,\n Close: 5,\n} as const;\nexport type EventTypeKind = (typeof EventType)[keyof typeof EventType];\n\nlet _eventCounter = 0;\n\nexport class Event {\n type: EventTypeKind;\n v: Node;\n pos: number;\n // Insertion-order id for deterministic tiebreaks (replaces C++ pointer cmp).\n readonly id: number;\n\n constructor(type: EventTypeKind, v: Node, pos: number) {\n this.type = type;\n this.v = v;\n this.pos = pos;\n this.id = ++_eventCounter;\n }\n}\n\n// ─── Comparators ──────────────────────────────────────────────────────────────\n\n// CmpNodePos: sort key for the scanline. Primary by `pos`, ties broken by\n// Node insertion order (deterministic; C++ uses pointer order).\nexport function cmpNodePos(u: Node, v: Node): number {\n if (u.pos !== v.pos) return u.pos < v.pos ? -1 : 1;\n return u.id - v.id;\n}\n\n// compareEvents: sort key for the event queue. Primary by `pos`, then by\n// `type` (Opens before Closes), then by insertion order.\nexport function compareEvents(a: Event, b: Event): number {\n if (a.pos !== b.pos) return a.pos < b.pos ? -1 : 1;\n if (a.type !== b.type) return a.type - b.type;\n return a.id - b.id;\n}\n\n// ─── NodeSet ──────────────────────────────────────────────────────────────────\n// A sorted set of Nodes, kept as a sorted array. Tests rely on small inputs\n// (a few hundred obstacles at most) where O(n) inserts are perfectly fine.\n\nexport class NodeSet {\n private nodes: Node[] = [];\n\n size(): number {\n return this.nodes.length;\n }\n\n // Returns the index where `node` is (or would be) inserted.\n private lowerBound(node: Node): number {\n let lo = 0,\n hi = this.nodes.length;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (cmpNodePos(this.nodes[mid], node) < 0) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n }\n\n // Inserts `node`, returns the inserted index. Throws if already present.\n insert(node: Node): number {\n const idx = this.lowerBound(node);\n if (idx < this.nodes.length && this.nodes[idx] === node) {\n throw new Error('NodeSet.insert: node already present');\n }\n this.nodes.splice(idx, 0, node);\n return idx;\n }\n\n // Removes `node`; returns true if it was present.\n erase(node: Node): boolean {\n const idx = this.lowerBound(node);\n if (idx >= this.nodes.length || this.nodes[idx] !== node) return false;\n this.nodes.splice(idx, 1);\n return true;\n }\n\n // Returns the Node sorted just before `node` (or null if at the start).\n prev(node: Node): Node | null {\n const idx = this.lowerBound(node);\n return idx > 0 ? this.nodes[idx - 1] : null;\n }\n\n // Returns the Node sorted just after `node` (or null if at the end).\n next(node: Node): Node | null {\n const idx = this.lowerBound(node);\n if (idx >= this.nodes.length || this.nodes[idx] !== node) return null;\n return idx + 1 < this.nodes.length ? this.nodes[idx + 1] : null;\n }\n\n // Iteration helper for tests.\n toArray(): Node[] {\n return this.nodes.slice();\n }\n}\n\n// ─── processShiftEvent ────────────────────────────────────────────────────────\n\n// Processes a single sweep event in one of four passes:\n// pass 1: SegClose / Close — record limits while neighbours are still here\n// pass 2: SegClose / Close — remove from scanline\n// pass 3: Open / SegOpen — insert into scanline & link neighbours\n// pass 4: Open / SegOpen — record limits with neighbours now in place\nfunction processShiftEvent(\n scanline: NodeSet,\n e: Event,\n dim: number,\n pass: number,\n): void {\n const v = e.v;\n\n if (\n pass === 3 &&\n (e.type === EventType.Open || e.type === EventType.SegOpen)\n ) {\n scanline.insert(v);\n\n // Wire up the neighbours by querying the set.\n const above = scanline.prev(v);\n if (above) {\n v.firstAbove = above;\n above.firstBelow = v;\n }\n const below = scanline.next(v);\n if (below) {\n v.firstBelow = below;\n below.firstAbove = v;\n }\n }\n\n if (\n (pass === 4 &&\n (e.type === EventType.Open || e.type === EventType.SegOpen)) ||\n (pass === 1 &&\n (e.type === EventType.SegClose || e.type === EventType.Close))\n ) {\n if (v.ss !== null) {\n // As far as we can see in both directions.\n const minLimit = v.firstObstacleAbove(dim);\n const maxLimit = v.firstObstacleBelow(dim);\n v.ss.minSpaceLimit = Math.max(minLimit, v.ss.minSpaceLimit);\n v.ss.maxSpaceLimit = Math.min(maxLimit, v.ss.maxSpaceLimit);\n } else {\n v.markShiftSegmentsAbove(dim);\n v.markShiftSegmentsBelow(dim);\n }\n }\n\n if (\n pass === 2 &&\n (e.type === EventType.SegClose || e.type === EventType.Close)\n ) {\n // Unlink the doubly-linked neighbour pointers and remove from the set.\n const l = v.firstAbove;\n const r = v.firstBelow;\n if (l !== null) l.firstBelow = v.firstBelow;\n if (r !== null) r.firstAbove = v.firstAbove;\n\n const removed = scanline.erase(v);\n if (!removed) {\n throw new Error('processShiftEvent: failed to erase Node from scanline');\n }\n }\n}\n\n// ─── buildOrthogonalChannelInfo ───────────────────────────────────────────────\n\n//! @brief Determines the spatial limits for each shift segment in the given\n//! dimension. Mirrors the C++ `buildOrthogonalChannelInfo`.\n//!\n//! For each event scan line we run four passes:\n//! 1) Close handlers (limits from current neighbours)\n//! 2) Remove closing events from the scanline\n//! 3) Add opening events to the scanline\n//! 4) Open handlers (limits from new neighbours)\nexport function buildOrthogonalChannelInfo(\n router: Router,\n dim: number,\n segmentList: ShiftSegment[],\n): void {\n if (segmentList.length === 0) return;\n\n const altDim = 1 - dim;\n const events: Event[] = [];\n\n for (const obstacle of router.m_obstacles) {\n if (obstacle.isFreeJunction()) {\n // Free junctions can move — don't treat them as obstacles here.\n continue;\n }\n const bb = obstacle.routingBox();\n const minPt = bb.min;\n const maxPt = bb.max;\n const mid = minPt.at(dim) + (maxPt.at(dim) - minPt.at(dim)) / 2;\n const node = Node.forObstacle(obstacle, mid);\n events.push(new Event(EventType.Open, node, minPt.at(altDim)));\n events.push(new Event(EventType.Close, node, maxPt.at(altDim)));\n }\n\n for (const ss of segmentList) {\n const lowPt = ss.lowPoint();\n const highPt = ss.highPoint();\n // Sanity: segment is along `altDim` at fixed `dim`.\n if (lowPt.at(dim) !== highPt.at(dim)) {\n throw new Error('ShiftSegment endpoints disagree on `dim`');\n }\n if (lowPt.at(altDim) >= highPt.at(altDim)) {\n throw new Error('ShiftSegment endpoints out of order in `altDim`');\n }\n const node = Node.forShiftSegment(ss, lowPt.at(dim));\n events.push(new Event(EventType.SegOpen, node, lowPt.at(altDim)));\n events.push(new Event(EventType.SegClose, node, highPt.at(altDim)));\n }\n\n events.sort(compareEvents);\n\n // Sweep:\n // - Pass 1 is interleaved as we walk through events for the current line.\n // - Passes 2..4 are batched once we reach the next line position.\n const scanline = new NodeSet();\n const total = events.length;\n let thisPos = total > 0 ? events[0].pos : 0;\n let posStart = 0;\n let i = 0;\n for (; i <= total; i++) {\n if (i === total || events[i].pos !== thisPos) {\n const posFinish = i;\n for (let pass = 2; pass <= 4; pass++) {\n for (let j = posStart; j < posFinish; j++) {\n processShiftEvent(scanline, events[j], dim, pass);\n }\n }\n if (i === total) break;\n thisPos = events[i].pos;\n posStart = i;\n }\n processShiftEvent(scanline, events[i], dim, 1);\n }\n\n if (scanline.size() !== 0) {\n throw new Error(\n 'buildOrthogonalChannelInfo: scanline non-empty after sweep',\n );\n }\n}\n\n// ─── Connector route checkpoint cache ─────────────────────────────────────────\n\n//! @brief For each orthogonal connector, mark every (segment, point) pair\n//! where a routing checkpoint lies on the route. Each match is\n//! appended to displayRoute.checkpointsOnRoute as [segmentIndex, pt].\n//!\n//! The `segmentIndex` is `ind * 2` for a checkpoint that lands on a bendpoint\n//! and `(ind * 2) - 1` for one that lies along a segment.\nexport function buildConnectorRouteCheckpointCache(router: Router): void {\n for (const conn of router.connRefs) {\n const displayRoute = conn.displayRoute();\n const checkpoints = conn.routingCheckpoints();\n displayRoute.checkpointsOnRoute = [];\n\n for (let ind = 0; ind < displayRoute.size(); ind++) {\n if (ind > 0) {\n for (const cp of checkpoints) {\n if (\n pointOnLine(\n displayRoute.ps[ind - 1],\n displayRoute.ps[ind],\n cp.point,\n )\n ) {\n displayRoute.checkpointsOnRoute.push([ind * 2 - 1, cp.point]);\n }\n }\n }\n for (const cp of checkpoints) {\n if (displayRoute.ps[ind].eq(cp.point)) {\n displayRoute.checkpointsOnRoute.push([ind * 2, cp.point]);\n }\n }\n }\n }\n}\n\n//! @brief Clear the per-route checkpoint cache built by\n//! buildConnectorRouteCheckpointCache.\nexport function clearConnectorRouteCheckpointCache(router: Router): void {\n for (const conn of router.connRefs) {\n conn.displayRoute().checkpointsOnRoute = [];\n }\n}\n\n// ─── Internal exports for tests ───────────────────────────────────────────────\n\nexport const _testing = {\n processShiftEvent,\n};\n","const ZERO_UPPERBOUND = -1e-10;\nconst LAGRANGIAN_TOLERANCE = -1e-4;\n\n// ─── Errors ──────────────────────────────────────────────────────────────────\n\n//! Thrown when satisfy() cannot resolve the constraint set (e.g. an equality\n//! cycle). `path` is the active path of constraints that caused the failure.\nexport class UnsatisfiableError extends Error {\n path: Constraint[];\n\n constructor(path: Constraint[] = []) {\n super('VPSC: unsatisfiable constraint system');\n this.name = 'UnsatisfiableError';\n this.path = path;\n }\n}\n\n// ─── PositionStats ───────────────────────────────────────────────────────────\n\n// Sufficient statistics for the unconstrained optimum of a block. When a\n// variable v with scale s_v, offset o_v, weight w_v, desired d_v is added,\n// the block's optimal position posn satisfies posn = (AD - AB) / A2 where\n// a_i = scale/s_v, b_i = o_v/s_v.\nclass PositionStats {\n scale = 0;\n AB = 0;\n AD = 0;\n A2 = 0;\n\n addVariable(v: Variable): void {\n const ai = this.scale / v.scale;\n const bi = v.offset / v.scale;\n const wi = v.weight;\n this.AB += wi * ai * bi;\n this.AD += wi * ai * v.desiredPosition;\n this.A2 += wi * ai * ai;\n }\n}\n\n// ─── Variable ────────────────────────────────────────────────────────────────\n\n//! A variable to be positioned, with a desired position and a weight that\n//! controls how strongly it resists being moved away from that position.\nexport class Variable {\n id: number;\n desiredPosition: number;\n finalPosition = 0;\n weight: number;\n scale: number;\n offset = 0;\n /** @internal */ block: Block | null = null;\n /** @internal */ visited = false;\n fixedDesiredPosition = false;\n /** @internal */ in: Constraint[] = [];\n /** @internal */ out: Constraint[] = [];\n\n constructor(id: number, desiredPos = -1.0, weight = 1.0, scale = 1.0) {\n this.id = id;\n this.desiredPosition = desiredPos;\n this.weight = weight;\n this.scale = scale;\n }\n\n //! Derivative of the local cost wrt this variable's position.\n dfdv(): number {\n return 2 * this.weight * (this.position() - this.desiredPosition);\n }\n\n /** @internal */\n position(): number {\n const b = this.block!;\n return (b.ps.scale * b.posn + this.offset) / this.scale;\n }\n\n /** @internal */\n unscaledPosition(): number {\n const b = this.block!;\n if (b.ps.scale !== 1)\n throw new Error('VPSC: unscaledPosition requires block scale == 1');\n if (this.scale !== 1)\n throw new Error('VPSC: unscaledPosition requires variable scale == 1');\n return b.posn + this.offset;\n }\n}\n\n// ─── Constraint ──────────────────────────────────────────────────────────────\n\n//! A separation (or equality) constraint between two Variables of the form\n//! `right.position - left.position >= gap` (or `==` when equality is true).\nexport class Constraint {\n left: Variable;\n right: Variable;\n gap: number;\n lm = 0;\n /** @internal */ timeStamp = 0;\n /** @internal */ active = false;\n readonly equality: boolean;\n unsatisfiable = false;\n needsScaling = true;\n\n constructor(left: Variable, right: Variable, gap: number, equality = false) {\n this.left = left;\n this.right = right;\n this.gap = gap;\n this.equality = equality;\n }\n\n //! How much slack the constraint has, i.e. `right - left - gap`. Negative\n //! values mean the constraint is violated. Returns Number.MAX_VALUE when\n //! the constraint has been flagged unsatisfiable.\n slack(): number {\n if (this.unsatisfiable) {\n return Number.MAX_VALUE;\n }\n if (this.needsScaling) {\n return (\n this.right.scale * this.right.position() -\n this.gap -\n this.left.scale * this.left.position()\n );\n }\n if (this.left.scale !== 1 || this.right.scale !== 1) {\n throw new Error('VPSC: unscaled slack requires scale == 1');\n }\n return (\n this.right.unscaledPosition() - this.gap - this.left.unscaledPosition()\n );\n }\n\n toString(): string {\n const sign = this.gap < 0 ? `- ${-this.gap}` : `+ ${this.gap}`;\n const rel = this.equality ? '==' : '<=';\n return `Constraint: var(${this.left.id}) ${sign} ${rel} var(${this.right.id})`;\n }\n}\n\n// ─── ConstraintHeap ──────────────────────────────────────────────────────────\n\n// CompareConstraints from the C++ source. Constraints with out-of-date\n// timestamps or both endpoints in the same block are treated as having\n// `-Infinity` slack so they bubble to the top of the heap (where they will be\n// popped and discarded by findMinIn/OutConstraint). Smaller slack wins.\nfunction constraintLessThan(l: Constraint, r: Constraint): boolean {\n const sl =\n l.left.block!.timeStamp > l.timeStamp || l.left.block === l.right.block\n ? -Number.MAX_VALUE\n : l.slack();\n const sr =\n r.left.block!.timeStamp > r.timeStamp || r.left.block === r.right.block\n ? -Number.MAX_VALUE\n : r.slack();\n if (sl === sr) {\n // Deterministic tiebreak by variable ids.\n if (l.left.id === r.left.id) {\n return l.right.id < r.right.id;\n }\n return l.left.id < r.left.id;\n }\n return sl > sr;\n}\n\n// Min-heap on constraint slack (smaller slack = higher priority). Same shape\n// as ANodeHeap in makepath.ts.\nclass ConstraintHeap {\n private arr: Constraint[] = [];\n\n size(): number {\n return this.arr.length;\n }\n\n empty(): boolean {\n return this.arr.length === 0;\n }\n\n top(): Constraint {\n return this.arr[0];\n }\n\n push(c: Constraint): void {\n this.arr.push(c);\n this.bubbleUp(this.arr.length - 1);\n }\n\n pop(): Constraint {\n const top = this.arr[0];\n const last = this.arr.pop()!;\n if (this.arr.length > 0) {\n this.arr[0] = last;\n this.bubbleDown(0);\n }\n return top;\n }\n\n private bubbleUp(i: number): void {\n while (i > 0) {\n const parent = (i - 1) >> 1;\n if (constraintLessThan(this.arr[i], this.arr[parent])) {\n [this.arr[i], this.arr[parent]] = [this.arr[parent], this.arr[i]];\n i = parent;\n } else {\n break;\n }\n }\n }\n\n private bubbleDown(i: number): void {\n const n = this.arr.length;\n while (true) {\n const l = i * 2 + 1;\n const r = i * 2 + 2;\n let best = i;\n if (l < n && constraintLessThan(this.arr[l], this.arr[best])) best = l;\n if (r < n && constraintLessThan(this.arr[r], this.arr[best])) best = r;\n if (best === i) break;\n [this.arr[i], this.arr[best]] = [this.arr[best], this.arr[i]];\n i = best;\n }\n }\n}\n\n// ─── Block ────────────────────────────────────────────────────────────────────\n\n//! A connected component of variables linked by active constraints. Inside a\n//! block all variables move together; the block's `posn` is the optimum of\n//! the unconstrained sub-problem for those variables.\nexport class Block {\n vars: Variable[] = [];\n posn = 0;\n ps = new PositionStats();\n deleted = false;\n timeStamp = 0;\n in: ConstraintHeap | null = null;\n out: ConstraintHeap | null = null;\n /** @internal */ blocks: Blocks;\n\n constructor(blocks: Blocks, v: Variable | null = null) {\n this.blocks = blocks;\n if (v !== null) {\n v.offset = 0;\n this.addVariable(v);\n }\n }\n\n /** @internal */\n addVariable(v: Variable): void {\n v.block = this;\n this.vars.push(v);\n if (this.ps.A2 === 0) this.ps.scale = v.scale;\n this.ps.addVariable(v);\n this.posn = (this.ps.AD - this.ps.AB) / this.ps.A2;\n if (Number.isNaN(this.posn)) throw new Error('VPSC: Block.posn became NaN');\n }\n\n //! Recompute posn from the current variable offsets (called after a merge\n //! or moveBlocks pass).\n updateWeightedPosition(): void {\n this.ps.AB = 0;\n this.ps.AD = 0;\n this.ps.A2 = 0;\n for (const v of this.vars) this.ps.addVariable(v);\n this.posn = (this.ps.AD - this.ps.AB) / this.ps.A2;\n if (Number.isNaN(this.posn)) throw new Error('VPSC: Block.posn became NaN');\n }\n\n setUpInConstraints(): void {\n this.in = this.setUpConstraintHeap(true);\n }\n\n setUpOutConstraints(): void {\n this.out = this.setUpConstraintHeap(false);\n }\n\n private setUpConstraintHeap(isIn: boolean): ConstraintHeap {\n const h = new ConstraintHeap();\n for (const v of this.vars) {\n const cs = isIn ? v.in : v.out;\n for (const c of cs) {\n c.timeStamp = this.blocks.blockTimeCtr;\n if (\n (c.left.block !== this && isIn) ||\n (c.right.block !== this && !isIn)\n ) {\n h.push(c);\n }\n }\n }\n return h;\n }\n\n //! Merge two blocks across constraint c (selecting which side is `this`\n //! and which is the merged-in block by size, to keep the operation\n //! amortised cheap).\n mergeWith(b: Block, c: Constraint): Block {\n const dist = c.right.offset - c.left.offset - c.gap;\n const l = c.left.block!;\n const r = c.right.block!;\n if (l.vars.length < r.vars.length) {\n r.mergeInto(l, c, dist);\n } else {\n l.mergeInto(r, c, -dist);\n }\n return b.deleted ? this : b;\n }\n\n //! Merge b into this block across c. All variables of b are shifted by\n //! `dist` so that c is satisfied as an equality.\n /** @internal */\n mergeInto(b: Block, c: Constraint, dist: number): void {\n c.active = true;\n for (const v of b.vars) {\n v.offset += dist;\n this.addVariable(v);\n }\n this.posn = (this.ps.AD - this.ps.AB) / this.ps.A2;\n if (Number.isNaN(this.posn)) throw new Error('VPSC: Block.posn became NaN');\n b.deleted = true;\n }\n\n //! Move the contents of b's in-heap into this block's in-heap.\n mergeIn(b: Block): void {\n this.findMinInConstraint();\n b.findMinInConstraint();\n while (!b.in!.empty()) {\n this.in!.push(b.in!.pop());\n }\n }\n\n mergeOut(b: Block): void {\n this.findMinOutConstraint();\n b.findMinOutConstraint();\n while (!b.out!.empty()) {\n this.out!.push(b.out!.pop());\n }\n }\n\n findMinInConstraint(): Constraint | null {\n let v: Constraint | null = null;\n const outOfDate: Constraint[] = [];\n const heap = this.in!;\n while (!heap.empty()) {\n v = heap.top();\n const lb = v.left.block!;\n const rb = v.right.block!;\n if (lb === rb) {\n heap.pop();\n } else if (v.timeStamp < lb.timeStamp) {\n heap.pop();\n outOfDate.push(v);\n } else {\n break;\n }\n }\n for (const c of outOfDate) {\n c.timeStamp = this.blocks.blockTimeCtr;\n heap.push(c);\n }\n if (heap.empty()) return null;\n return heap.top();\n }\n\n findMinOutConstraint(): Constraint | null {\n const heap = this.out!;\n if (heap.empty()) return null;\n let v = heap.top();\n while (v.left.block === v.right.block) {\n heap.pop();\n if (heap.empty()) return null;\n v = heap.top();\n }\n return v;\n }\n\n deleteMinInConstraint(): void {\n this.in!.pop();\n }\n\n deleteMinOutConstraint(): void {\n this.out!.pop();\n }\n\n private canFollowLeft(c: Constraint, last: Variable | null): boolean {\n return c.left.block === this && c.active && last !== c.left;\n }\n\n private canFollowRight(c: Constraint, last: Variable | null): boolean {\n return c.right.block === this && c.active && last !== c.right;\n }\n\n // Computes df/dv at v in the active-constraint tree, treating constraint\n // lm values as the recursive sums. Does not back-track over u. When\n // `minLm` is supplied, the constraint with the smallest lm so far is\n // tracked through the holder.\n private compute_dfdv(\n v: Variable,\n u: Variable | null,\n minLm: { c: Constraint | null } | null,\n ): number {\n let dfdv = v.dfdv();\n for (const c of v.out) {\n if (this.canFollowRight(c, u)) {\n c.lm = this.compute_dfdv(c.right, v, minLm);\n dfdv += c.lm * c.left.scale;\n if (minLm && !c.equality && (minLm.c === null || c.lm < minLm.c.lm)) {\n minLm.c = c;\n }\n }\n }\n for (const c of v.in) {\n if (this.canFollowLeft(c, u)) {\n c.lm = -this.compute_dfdv(c.left, v, minLm);\n dfdv -= c.lm * c.right.scale;\n if (minLm && !c.equality && (minLm.c === null || c.lm < minLm.c.lm)) {\n minLm.c = c;\n }\n }\n }\n return dfdv / v.scale;\n }\n\n // Search the active-constraint tree from v outward (not back-tracking\n // over u) for the lm-minimum constraint that lies on the path to r. Only\n // left-to-right traversals contribute candidates, to avoid creating new\n // violations. `desperation` mirrors a (currently unused) C++ flag.\n private split_path(\n r: Variable,\n v: Variable,\n u: Variable | null,\n minLm: { c: Constraint | null },\n desperation = false,\n ): boolean {\n for (const c of v.in) {\n if (this.canFollowLeft(c, u)) {\n if (c.left === r) {\n if (desperation && !c.equality) minLm.c = c;\n return true;\n } else {\n if (this.split_path(r, c.left, v, minLm)) {\n if (desperation && !c.equality && (!minLm.c || c.lm < minLm.c.lm)) {\n minLm.c = c;\n }\n return true;\n }\n }\n }\n }\n for (const c of v.out) {\n if (this.canFollowRight(c, u)) {\n if (c.right === r) {\n if (!c.equality) minLm.c = c;\n return true;\n } else {\n if (this.split_path(r, c.right, v, minLm)) {\n if (!c.equality && (!minLm.c || c.lm < minLm.c.lm)) {\n minLm.c = c;\n }\n return true;\n }\n }\n }\n }\n return false;\n }\n\n // Zero the lm value on every active constraint reachable from v (without\n // back-tracking over u).\n private reset_active_lm(v: Variable, u: Variable | null): void {\n for (const c of v.out) {\n if (this.canFollowRight(c, u)) {\n c.lm = 0;\n this.reset_active_lm(c.right, v);\n }\n }\n for (const c of v.in) {\n if (this.canFollowLeft(c, u)) {\n c.lm = 0;\n this.reset_active_lm(c.left, v);\n }\n }\n }\n\n //! Find the constraint with the smallest Lagrange multiplier — the one\n //! most \"wanting\" to split.\n findMinLM(): Constraint | null {\n const holder: { c: Constraint | null } = { c: null };\n this.reset_active_lm(this.vars[0], null);\n this.compute_dfdv(this.vars[0], null, holder);\n return holder.c;\n }\n\n //! Like findMinLM but restricted to the active path between two specific\n //! variables. Throws UnsatisfiableError when no such path exists.\n findMinLMBetween(lv: Variable, rv: Variable): Constraint {\n this.reset_active_lm(this.vars[0], null);\n this.compute_dfdv(this.vars[0], null, null);\n const holder: { c: Constraint | null } = { c: null };\n this.split_path(rv, lv, null, holder);\n if (holder.c === null) {\n const path: Constraint[] = [];\n this.getActivePathBetween(path, lv, rv, null);\n throw new UnsatisfiableError(path);\n }\n return holder.c;\n }\n\n // Populates block b by traversing the active-constraint tree starting at v,\n // not back-tracking over u.\n private populateSplitBlock(b: Block, v: Variable, u: Variable | null): void {\n b.addVariable(v);\n for (const c of v.in) {\n if (this.canFollowLeft(c, u)) {\n this.populateSplitBlock(b, c.left, v);\n }\n }\n for (const c of v.out) {\n if (this.canFollowRight(c, u)) {\n this.populateSplitBlock(b, c.right, v);\n }\n }\n }\n\n //! Active path between u and v in the block's active-constraint tree.\n //! Result is pushed into `path` (in reverse order; matches C++).\n getActivePathBetween(\n path: Constraint[],\n u: Variable,\n v: Variable,\n w: Variable | null,\n ): boolean {\n if (u === v) return true;\n for (const c of u.in) {\n if (this.canFollowLeft(c, w)) {\n if (this.getActivePathBetween(path, c.left, v, u)) {\n path.push(c);\n return true;\n }\n }\n }\n for (const c of u.out) {\n if (this.canFollowRight(c, w)) {\n if (this.getActivePathBetween(path, c.right, v, u)) {\n path.push(c);\n return true;\n }\n }\n }\n return false;\n }\n\n //! Search the active tree from u for a directed path of `right` traversals\n //! to v.\n isActiveDirectedPathBetween(u: Variable, v: Variable): boolean {\n if (u === v) return true;\n for (const c of u.out) {\n if (this.canFollowRight(c, null)) {\n if (this.isActiveDirectedPathBetween(c.right, v)) return true;\n }\n }\n return false;\n }\n\n getActiveDirectedPathBetween(\n path: Constraint[],\n u: Variable,\n v: Variable,\n ): boolean {\n if (u === v) return true;\n for (const c of u.out) {\n if (this.canFollowRight(c, null)) {\n if (this.getActiveDirectedPathBetween(path, c.right, v)) {\n path.push(c);\n return true;\n }\n }\n }\n return false;\n }\n\n //! Split this block across the violated path between vl and vr. Sets `lb`\n //! and `rb` (returned via a 2-tuple) and marks this block as deleted.\n splitBetween(\n vl: Variable,\n vr: Variable,\n ): { c: Constraint | null; l: Block; r: Block } {\n const c = this.findMinLMBetween(vl, vr);\n const { l, r } = this.split(c);\n this.deleted = true;\n return { c, l, r };\n }\n\n //! Split into two new blocks across c (which becomes inactive).\n split(c: Constraint): { l: Block; r: Block } {\n c.active = false;\n const l = new Block(this.blocks);\n this.populateSplitBlock(l, c.left, c.right);\n const r = new Block(this.blocks);\n this.populateSplitBlock(r, c.right, c.left);\n return { l, r };\n }\n\n //! Sum of squared distances from desired positions, weighted.\n cost(): number {\n let c = 0;\n for (const v of this.vars) {\n const diff = v.position() - v.desiredPosition;\n c += v.weight * diff * diff;\n }\n return c;\n }\n}\n\n// ─── Blocks ───────────────────────────────────────────────────────────────────\n\n//! Container for all current Blocks. Owns the timestamp counter used by the\n//! priority queues to detect out-of-date heap entries.\nexport class Blocks {\n blockTimeCtr = 0;\n private m_blocks: Block[] = [];\n private vs: Variable[];\n private nvs: number;\n\n constructor(vs: Variable[]) {\n this.vs = vs;\n this.nvs = vs.length;\n for (let i = 0; i < this.nvs; i++) {\n this.m_blocks.push(new Block(this, vs[i]));\n }\n }\n\n size(): number {\n return this.m_blocks.length;\n }\n\n at(i: number): Block {\n return this.m_blocks[i];\n }\n\n insert(block: Block): void {\n this.m_blocks.push(block);\n }\n\n //! Topological order on variables derived from the constraint DAG.\n totalOrder(): Variable[] {\n const order: Variable[] = [];\n for (const v of this.vs) v.visited = false;\n for (const v of this.vs) {\n if (v.in.length === 0) this.dfsVisit(v, order);\n }\n // C++ pushes to the front of a list; we replicate that by appending and\n // reversing at the end.\n return order.reverse();\n }\n\n private dfsVisit(v: Variable, order: Variable[]): void {\n v.visited = true;\n for (const c of v.out) {\n if (!c.right.visited) this.dfsVisit(c.right, order);\n }\n order.push(v);\n }\n\n //! Process incoming constraints, most violated to least, merging with\n //! left-neighbour blocks until no more violated in-constraints remain.\n mergeLeft(r: Block): void {\n r.timeStamp = ++this.blockTimeCtr;\n r.setUpInConstraints();\n let c = r.findMinInConstraint();\n while (c !== null && c.slack() < 0) {\n r.deleteMinInConstraint();\n let l = c.left.block!;\n if (l.in === null) l.setUpInConstraints();\n let dist = c.right.offset - c.left.offset - c.gap;\n if (r.vars.length < l.vars.length) {\n dist = -dist;\n const tmp = l;\n l = r;\n r = tmp;\n }\n this.blockTimeCtr++;\n r.mergeInto(l, c, dist);\n r.mergeIn(l);\n r.timeStamp = this.blockTimeCtr;\n this.removeBlock(l);\n c = r.findMinInConstraint();\n }\n }\n\n mergeRight(l: Block): void {\n l.setUpOutConstraints();\n let c = l.findMinOutConstraint();\n while (c !== null && c.slack() < 0) {\n l.deleteMinOutConstraint();\n let r = c.right.block!;\n r.setUpOutConstraints();\n let dist = c.left.offset + c.gap - c.right.offset;\n if (l.vars.length > r.vars.length) {\n dist = -dist;\n const tmp = l;\n l = r;\n r = tmp;\n }\n l.mergeInto(r, c, dist);\n l.mergeOut(r);\n this.removeBlock(r);\n c = l.findMinOutConstraint();\n }\n }\n\n private removeBlock(doomed: Block): void {\n doomed.deleted = true;\n }\n\n //! Drop deleted blocks from the live list.\n cleanup(): void {\n let i = 0;\n for (let j = 0; j < this.m_blocks.length; j++) {\n if (this.m_blocks[j].deleted) continue;\n if (j > i) this.m_blocks[i] = this.m_blocks[j];\n i++;\n }\n this.m_blocks.length = i;\n }\n\n //! Split block b across c, then run mergeLeft / mergeRight to consume any\n //! violations created by the split. Returns the two surviving blocks (but\n //! note: they may have been further merged during the rebalance).\n split(b: Block, c: Constraint): { l: Block; r: Block } {\n const { l, r } = b.split(c);\n this.m_blocks.push(l);\n this.m_blocks.push(r);\n r.posn = b.posn;\n this.mergeLeft(l);\n // r may have been merged in the meantime — re-fetch through the\n // constraint's right block.\n const rPrime = c.right.block!;\n rPrime.updateWeightedPosition();\n this.mergeRight(rPrime);\n this.removeBlock(b);\n if (Number.isNaN(l.posn)) throw new Error('VPSC: split produced NaN posn');\n if (Number.isNaN(rPrime.posn))\n throw new Error('VPSC: split produced NaN posn');\n return { l, r: rPrime };\n }\n\n //! Total squared cost across all blocks.\n cost(): number {\n let c = 0;\n for (const b of this.m_blocks) c += b.cost();\n return c;\n }\n}\n\n// ─── IncSolver ────────────────────────────────────────────────────────────────\n\n//! Incremental VPSC solver. Construct with the variable and constraint\n//! lists, then call `satisfy()` to find a feasible solution or `solve()` to\n//! drive cost to a local minimum.\nexport class IncSolver {\n splitCnt = 0;\n protected bs: Blocks;\n protected m: number;\n protected cs: Constraint[];\n protected n: number;\n protected vs: Variable[];\n protected needsScaling: boolean;\n private inactive: Constraint[];\n\n constructor(vs: Variable[], cs: Constraint[]) {\n this.vs = vs;\n this.cs = cs;\n this.n = vs.length;\n this.m = cs.length;\n this.needsScaling = false;\n for (const v of vs) {\n v.in = [];\n v.out = [];\n if (v.scale !== 1) this.needsScaling = true;\n }\n for (const c of cs) {\n c.left.out.push(c);\n c.right.in.push(c);\n c.needsScaling = this.needsScaling;\n }\n this.bs = new Blocks(vs);\n this.inactive = cs.slice();\n for (const c of this.inactive) c.active = false;\n }\n\n //! Returns the current Blocks container (mainly for tests / debugging).\n getBlocks(): Blocks {\n return this.bs;\n }\n\n //! Returns the variable list (read-only by convention).\n getVariables(): Variable[] {\n return this.vs;\n }\n\n addConstraint(c: Constraint): void {\n this.m++;\n c.active = false;\n this.inactive.push(c);\n c.left.out.push(c);\n c.right.in.push(c);\n c.needsScaling = this.needsScaling;\n }\n\n // Stores the relative positions of variables in their finalPosition field.\n private copyResult(): void {\n for (const v of this.vs) {\n v.finalPosition = v.position();\n if (Number.isNaN(v.finalPosition))\n throw new Error('VPSC: variable finalPosition NaN');\n }\n }\n\n //! Drive cost(): satisfy() + while-cost-decreases-loop. Returns true if\n //! any blocks remain merged at the end (the C++ contract).\n solve(): boolean {\n this.satisfy();\n let lastCost = Number.MAX_VALUE;\n let cost = this.bs.cost();\n while (Math.abs(lastCost - cost) > 0.0001) {\n this.satisfy();\n lastCost = cost;\n cost = this.bs.cost();\n }\n this.copyResult();\n return this.bs.size() !== this.n;\n }\n\n // Incremental satisfaction:\n // - move blocks to new positions\n // - repeatedly merge across the most violated constraint until none\n // remain\n // Special case: if the most violated constraint lies between two variables\n // in the same block, split that block at its lm-minimum active constraint.\n satisfy(): boolean {\n this.splitBlocks();\n let v: Constraint | null;\n while (\n (v = this.mostViolated(this.inactive)) !== null &&\n (v.equality || (v.slack() < ZERO_UPPERBOUND && !v.active))\n ) {\n if (v.active)\n throw new Error('VPSC: invariant — most violated should be inactive');\n let lb = v.left.block!;\n let rb = v.right.block!;\n if (lb !== rb) {\n lb.mergeWith(rb, v);\n } else {\n if (lb.isActiveDirectedPathBetween(v.right, v.left)) {\n // Cycle: relax this violated constraint.\n v.unsatisfiable = true;\n continue;\n }\n // Constraint is within the block: split first.\n try {\n const split = lb.splitBetween(v.left, v.right);\n if (split.c !== null) {\n if (split.c.active)\n throw new Error('VPSC: split constraint should be inactive');\n this.inactive.push(split.c);\n lb = split.l;\n rb = split.r;\n } else {\n v.unsatisfiable = true;\n continue;\n }\n } catch (e) {\n if (e instanceof UnsatisfiableError) {\n e.path.push(v);\n v.unsatisfiable = true;\n continue;\n }\n throw e;\n }\n if (v.slack() >= 0) {\n if (v.active) throw new Error('VPSC: invariant');\n // The split was enough to satisfy v.\n this.inactive.push(v);\n this.bs.insert(lb);\n this.bs.insert(rb);\n } else {\n this.bs.insert(lb.mergeWith(rb, v));\n // Original lb (now deleted) is GC-managed; no manual delete.\n }\n }\n }\n this.bs.cleanup();\n let activeConstraints = false;\n for (const c of this.cs) {\n if (c.active) activeConstraints = true;\n if (c.slack() < ZERO_UPPERBOUND) {\n throw new Error(`VPSC: Unsatisfied constraint: ${c.toString()}`);\n }\n }\n this.copyResult();\n return activeConstraints;\n }\n\n moveBlocks(): void {\n const length = this.bs.size();\n for (let i = 0; i < length; i++) {\n this.bs.at(i).updateWeightedPosition();\n }\n }\n\n splitBlocks(): void {\n this.moveBlocks();\n this.splitCnt = 0;\n const length = this.bs.size();\n for (let i = 0; i < length; i++) {\n const block = this.bs.at(i);\n const v = block.findMinLM();\n if (v !== null && v.lm < LAGRANGIAN_TOLERANCE) {\n if (v.equality) throw new Error('VPSC: cannot split on an equality');\n this.splitCnt++;\n const b = v.left.block!;\n if (v.left.block !== v.right.block)\n throw new Error('VPSC: split invariant');\n const { l, r } = b.split(v);\n l.updateWeightedPosition();\n r.updateWeightedPosition();\n this.bs.insert(l);\n this.bs.insert(r);\n b.deleted = true;\n if (v.active)\n throw new Error('VPSC: split constraint should be inactive');\n this.inactive.push(v);\n }\n }\n this.bs.cleanup();\n }\n\n // Scan constraint list for the most violated constraint, or the first\n // equality constraint encountered. The chosen constraint is swapped to\n // the end and popped, matching the C++ \"swap-and-shrink\" idiom.\n private mostViolated(l: Constraint[]): Constraint | null {\n let slackForMostViolated = Number.MAX_VALUE;\n let mostViolated: Constraint | null = null;\n let deleteIndex = l.length;\n for (let i = 0; i < l.length; i++) {\n const c = l[i];\n const s = c.slack();\n if (c.equality || s < slackForMostViolated) {\n slackForMostViolated = s;\n mostViolated = c;\n deleteIndex = i;\n if (c.equality) break;\n }\n }\n if (\n deleteIndex < l.length &&\n mostViolated !== null &&\n ((slackForMostViolated < ZERO_UPPERBOUND && !mostViolated.active) ||\n mostViolated.equality)\n ) {\n l[deleteIndex] = l[l.length - 1];\n l.length--;\n }\n return mostViolated;\n }\n}\n","import { Variable } from '../vpsc';\nimport { Edge } from '../edge';\nimport { CHANNEL_MAX, type ShiftSegment } from '../scanline.ts';\nimport { Point } from '../geomtypes';\nimport { CmpIndexes } from '../orthogonal';\n\n// ─── Constants ───────────────────────────────────────────────────────────────\n\n// Variable IDs used by the VPSC solver (passed as `Variable.id`). The\n// channel-edge IDs let us recognise unsatisfied channel boundaries later.\nconst freeSegmentID = 0;\nconst fixedSegmentID = 1;\n\n// Weights for the four kinds of variable.\nconst freeWeight = 0.00001;\nconst strongWeight = 0.001;\nconst strongerWeight = 1.0;\nconst fixedWeight = 100000;\n\n//! The concrete ShiftSegment implementation used during orthogonal nudging.\n//!\n//! Each instance represents a segment of a connector's display route that\n//! may be shifted along `dimension`. Construction takes the low and high\n//! route-index of the segment endpoints; the actual coordinates are read\n//! lazily from `connRef.displayRoute().ps`.\nexport class NudgingShiftSegment implements ShiftSegment {\n connRef: Edge;\n /** @internal */ variable: Variable | null;\n indexes: number[];\n fixed: boolean;\n finalSegment: boolean;\n endsInShape: boolean;\n singleConnectedSegment: boolean;\n checkpoints: Point[];\n\n // ShiftSegment interface fields.\n dimension: number;\n minSpaceLimit: number;\n maxSpaceLimit: number;\n\n // Private bend flags.\n private _sBend: boolean;\n private _zBend: boolean;\n\n // ─── Construction ─────────────────────────────────────────────────────────\n //\n // Two constructor forms in the C++ source; modelled here as `makeShiftable`\n // and `makeFixed` static factories. The public constructor accepts the\n // shiftable shape.\n\n // Shiftable segment.\n constructor(\n conn: Edge,\n low: number,\n high: number,\n isSBend: boolean,\n isZBend: boolean,\n dim: number,\n minLim: number,\n maxLim: number,\n );\n // Fixed segment.\n constructor(conn: Edge, low: number, high: number, dim: number);\n constructor(\n conn: Edge,\n low: number,\n high: number,\n isSBendOrDim: boolean | number,\n isZBend?: boolean,\n dim?: number,\n minLim?: number,\n maxLim?: number,\n ) {\n this.connRef = conn;\n this.variable = null;\n this.indexes = [low, high];\n this.finalSegment = false;\n this.endsInShape = false;\n this.singleConnectedSegment = false;\n this.checkpoints = [];\n\n if (typeof isSBendOrDim === 'number') {\n // Fixed-segment overload.\n this.dimension = isSBendOrDim;\n this.fixed = true;\n this._sBend = false;\n this._zBend = false;\n // This has no space to shift.\n const pos = this.lowPoint().at(this.dimension);\n this.minSpaceLimit = pos;\n this.maxSpaceLimit = pos;\n } else {\n // Shiftable overload.\n this.dimension = dim!;\n this.fixed = false;\n this._sBend = isSBendOrDim;\n this._zBend = isZBend!;\n this.minSpaceLimit = minLim!;\n this.maxSpaceLimit = maxLim!;\n }\n }\n\n // ─── Endpoint accessors ───────────────────────────────────────────────────\n\n lowPoint(): Point {\n return this.connRef.displayRoute().ps[this.indexes[0]];\n }\n\n highPoint(): Point {\n return this.connRef.displayRoute().ps[\n this.indexes[this.indexes.length - 1]\n ];\n }\n\n // ─── Predicates ───────────────────────────────────────────────────────────\n\n nudgeDistance(): number {\n return this.connRef.router.params.idealNudgingDistance;\n }\n\n // Returns true when this segment is fixed in place by topology / direction\n // (i.e., not an s- or z-bend the nudger is allowed to slide).\n immovable(): boolean {\n return !this.zigzag();\n }\n\n zigzag(): boolean {\n return this._sBend || this._zBend;\n }\n\n get sBend(): boolean {\n return this._sBend;\n }\n get zBend(): boolean {\n return this._zBend;\n }\n\n // ─── Solver variable management ───────────────────────────────────────────\n\n //! Assign a VPSC Variable describing this segment's desired position and\n //! how strongly it resists moving. The `justUnifying` flag distinguishes\n //! the unifying preprocessing pass from the main nudging pass — see\n //! ImproveOrthogonalRoutes.execute.\n createSolverVariable(justUnifying: boolean): void {\n const router = this.connRef.router;\n const nudgeFinalSegments =\n router.options.nudgeOrthogonalSegmentsConnectedToShapes;\n\n let varID = freeSegmentID;\n let varPos = this.lowPoint().at(this.dimension);\n let weight = freeWeight;\n\n if (nudgeFinalSegments && this.finalSegment) {\n weight = strongWeight;\n if (this.singleConnectedSegment && !justUnifying) {\n // Single-segment connector spanning two shapes — keep it centred.\n weight = strongerWeight;\n }\n } else if (this.checkpoints.length > 0) {\n weight = strongWeight;\n } else if (this.zigzag()) {\n if (!(this.minSpaceLimit > -CHANNEL_MAX)) {\n throw new Error('orthogonal: zigzag segment without left channel');\n }\n if (!(this.maxSpaceLimit < CHANNEL_MAX)) {\n throw new Error('orthogonal: zigzag segment without right channel');\n }\n // For zigzag bends, take the middle as ideal.\n varPos =\n this.minSpaceLimit + (this.maxSpaceLimit - this.minSpaceLimit) / 2;\n } else if (this.fixed) {\n weight = fixedWeight;\n varID = fixedSegmentID;\n } else if (!this.finalSegment) {\n // Set a higher weight for c-bends to stop them sometimes getting pushed\n // out into channels by more-free connectors to the \"inner\" side.\n weight = strongWeight;\n }\n\n this.variable = new Variable(varID, varPos, weight);\n }\n\n //! Push the solver's chosen position back into the route.\n updatePositionsFromSolver(_justUnifying: boolean): void {\n if (this.fixed) return;\n let newPos = this.variable!.finalPosition;\n\n // The solver can sometimes cause variables to be outside their limits by a\n // tiny amount, since all variables are held by weights. Clamp.\n newPos = Math.max(newPos, this.minSpaceLimit);\n newPos = Math.min(newPos, this.maxSpaceLimit);\n\n const route = this.connRef.displayRoute();\n for (const index of this.indexes) {\n route.ps[index].setAt(this.dimension, newPos);\n }\n }\n\n // Returns 0 when the segment is fixed or pinned at both limits, +1 when\n // limited only at the min side, -1 when limited only at the max side.\n fixedOrder(): { order: number; isFixed: boolean } {\n const nudgeDist = this.nudgeDistance();\n const pos = this.lowPoint().at(this.dimension);\n const minLimited = pos - this.minSpaceLimit < nudgeDist;\n const maxLimited = this.maxSpaceLimit - pos < nudgeDist;\n\n if (this.fixed || (minLimited && maxLimited)) {\n return { order: 0, isFixed: true };\n }\n if (minLimited) return { order: 1, isFixed: false };\n if (maxLimited) return { order: -1, isFixed: false };\n return { order: 0, isFixed: false };\n }\n\n order(): number {\n if (this._lowC()) return -1;\n if (this._highC()) return 1;\n return 0;\n }\n\n //! Returns true if `rhs` shares an overlap with this segment such that the\n //! two need to be constrained against each other in the nudger. Counts\n //! collinear-sharing-endpoint pairs as overlapping so they can be nudged\n //! apart where possible.\n overlapsWith(rhsSuper: ShiftSegment, dim: number): boolean {\n const rhs = rhsSuper as NudgingShiftSegment;\n const altDim = (dim + 1) % 2;\n const lowPt = this.lowPoint();\n const highPt = this.highPoint();\n const rhsLowPt = rhs.lowPoint();\n const rhsHighPt = rhs.highPoint();\n\n if (\n lowPt.at(altDim) < rhsHighPt.at(altDim) &&\n rhsLowPt.at(altDim) < highPt.at(altDim)\n ) {\n // The segments overlap.\n if (\n this.minSpaceLimit <= rhs.maxSpaceLimit &&\n rhs.minSpaceLimit <= this.maxSpaceLimit\n ) {\n return true;\n }\n } else if (\n lowPt.at(altDim) === rhsHighPt.at(altDim) ||\n rhsLowPt.at(altDim) === highPt.at(altDim)\n ) {\n const router = this.connRef.router;\n const nudgeColinearSegments =\n router.options.nudgeOrthogonalTouchingColinearSegments;\n\n if (\n this.minSpaceLimit <= rhs.maxSpaceLimit &&\n rhs.minSpaceLimit <= this.maxSpaceLimit\n ) {\n if (router.params.fixedSharedPathPenalty > 0) {\n return true;\n }\n if ((rhs._sBend && this._sBend) || (rhs._zBend && this._zBend)) {\n return nudgeColinearSegments;\n }\n if (\n rhs.finalSegment &&\n this.finalSegment &&\n rhs.connRef === this.connRef\n ) {\n return nudgeColinearSegments;\n }\n }\n }\n return false;\n }\n\n // True if these two end-segments can drift together along `dimension`.\n canAlignWith(rhs: NudgingShiftSegment, _dim: number): boolean {\n if (this.connRef !== rhs.connRef) return false;\n // If either has checkpoints we want to maintain the path through them.\n if (this.checkpoints.length > 0 || rhs.checkpoints.length > 0) return false;\n return true;\n }\n\n // True if these two end-segments should actively align with each other in\n // the nudger.\n shouldAlignWith(rhsSuper: ShiftSegment, dim: number): boolean {\n const rhs = rhsSuper as NudgingShiftSegment;\n if (\n this.connRef === rhs.connRef &&\n this.finalSegment &&\n rhs.finalSegment &&\n this.overlapsWith(rhs, dim)\n ) {\n if (\n (this.endsInShape && rhs.endsInShape) ||\n Math.abs(this.lowPoint().at(dim) - rhs.lowPoint().at(dim)) < 10\n ) {\n return true;\n }\n } else if (\n this.connRef === rhs.connRef &&\n // Not both final\n !(this.finalSegment && rhs.finalSegment)\n ) {\n const hasCheckpoints = this.checkpoints.length > 0;\n const rhsHasCheckpoints = rhs.checkpoints.length > 0;\n if (hasCheckpoints !== rhsHasCheckpoints) {\n const altDim = (dim + 1) % 2;\n const space = Math.abs(\n this.lowPoint().at(dim) - rhs.lowPoint().at(dim),\n );\n let touchPos = 0;\n let couldTouch = false;\n if (this.lowPoint().at(altDim) === rhs.highPoint().at(altDim)) {\n couldTouch = true;\n touchPos = this.lowPoint().at(altDim);\n } else if (this.highPoint().at(altDim) === rhs.lowPoint().at(altDim)) {\n couldTouch = true;\n touchPos = this.highPoint().at(altDim);\n }\n return (\n couldTouch &&\n space <= 10 &&\n !this.hasCheckpointAtPosition(touchPos, altDim) &&\n !rhs.hasCheckpointAtPosition(touchPos, altDim)\n );\n }\n }\n return false;\n }\n\n // Merge an end-segment from the same connector into this one.\n mergeWith(rhsSuper: ShiftSegment, dim: number): void {\n // Adjust limits.\n this.minSpaceLimit = Math.max(this.minSpaceLimit, rhsSuper.minSpaceLimit);\n this.maxSpaceLimit = Math.min(this.maxSpaceLimit, rhsSuper.maxSpaceLimit);\n\n // New position is the midpoint of the two originals, clamped by the\n // merged limits.\n let segmentPos = this.lowPoint().at(this.dimension);\n const segment2Pos = rhsSuper.lowPoint().at(this.dimension);\n if (segment2Pos < segmentPos) {\n segmentPos -= (segmentPos - segment2Pos) / 2.0;\n } else if (segment2Pos > segmentPos) {\n segmentPos += (segment2Pos - segmentPos) / 2.0;\n }\n segmentPos = Math.max(this.minSpaceLimit, segmentPos);\n segmentPos = Math.min(this.maxSpaceLimit, segmentPos);\n\n // Merge the index lists and sort by altDim position.\n const rhs = rhsSuper as NudgingShiftSegment;\n this.indexes.push(...rhs.indexes);\n const altDim = (dim + 1) % 2;\n const cmp = new CmpIndexes(this.connRef, altDim);\n this.indexes.sort((a, b) => cmp.compare(a, b));\n\n // Apply the new position to all points.\n const route = this.connRef.displayRoute();\n for (const index of this.indexes) {\n route.ps[index].setAt(this.dimension, segmentPos);\n }\n }\n\n hasCheckpointAtPosition(position: number, dim: number): boolean {\n for (const cp of this.checkpoints) {\n if (cp.at(dim) === position) return true;\n }\n return false;\n }\n\n // ─── Private c-bend detection ─────────────────────────────────────────────\n\n private _lowC(): boolean {\n return (\n !this.finalSegment &&\n !this.zigzag() &&\n !this.fixed &&\n this.minSpaceLimit === this.lowPoint().at(this.dimension)\n );\n }\n\n private _highC(): boolean {\n return (\n !this.finalSegment &&\n !this.zigzag() &&\n !this.fixed &&\n this.maxSpaceLimit === this.lowPoint().at(this.dimension)\n );\n }\n}\n","//! A breakpoint along a candidate visibility segment — a position on the\n//! perpendicular axis combined with the vertex (which may be a shape corner,\n//! a connection point, or a dummy lattice vertex) at that position.\n\nimport { VisDirNone } from \"../orthogonal\";\nimport { VertInf } from \"../vertex\";\n\n// Two VertInfs share the same identity tag when both `objID` and `vn` match.\n// (Pre-Stage-5 this was the `VertID.eq` method.)\nfunction sameId(a: VertInf, b: VertInf): boolean {\n return a.objID === b.objID && a.vn === b.vn;\n}\n\n// True when the vertex is a synthesised lattice vertex with no owning\n// obstacle or connector — the scanline can produce multiple of these at the\n// same point (e.g. for junctions sitting outside any shape), and the\n// ordering treats them as interchangeable. (Pre-Stage-5 this matched\n// `dummyOrthogID` = `VertID(0, 0)`.)\nfunction isAnonymousDummy(v: VertInf): boolean {\n return v.objID === 0 && v.vn === 0;\n}\n\nexport class PosVertInf {\n pos: number;\n vert: VertInf;\n dirs: number;\n\n constructor(pos: number, vert: VertInf, dirs = VisDirNone) {\n this.pos = pos;\n this.vert = vert;\n this.dirs = dirs;\n }\n\n // Strict less-than ordering matching the C++ operator<.\n lt(rhs: PosVertInf): boolean {\n if (this.pos !== rhs.pos) return this.pos < rhs.pos;\n if (sameId(this.vert, rhs.vert) && isAnonymousDummy(this.vert)) {\n // Multiple anonymous dummy vertices at the same point are\n // interchangeable; report neither as less than the other.\n return false;\n }\n if (!sameId(this.vert, rhs.vert)) {\n // Lexicographic (objID, vn) order — stable across runs.\n if (this.vert.objID !== rhs.vert.objID) {\n return this.vert.objID < rhs.vert.objID;\n }\n return this.vert.vn < rhs.vert.vn;\n }\n return this.dirs < rhs.dirs;\n }\n\n eq(rhs: PosVertInf): boolean {\n if (this.pos !== rhs.pos) return false;\n if (sameId(this.vert, rhs.vert) && isAnonymousDummy(this.vert)) {\n return true;\n }\n if (!sameId(this.vert, rhs.vert)) return false;\n return this.dirs === rhs.dirs;\n }\n}\n","import { PosVertInf } from \"./pos-vert-inf\";\n\n// Used as the C++ BreakpointSet.\nexport class BreakpointSet {\n private _items: PosVertInf[] = [];\n\n size(): number {\n return this._items.length;\n }\n isEmpty(): boolean {\n return this._items.length === 0;\n }\n values(): PosVertInf[] {\n return this._items;\n }\n first(): PosVertInf {\n return this._items[0];\n }\n last(): PosVertInf {\n return this._items[this._items.length - 1];\n }\n\n insert(p: PosVertInf): void {\n const lo = this._lowerBound(p);\n if (lo < this._items.length && this._items[lo].eq(p)) {\n // Already present — set semantics.\n return;\n }\n this._items.splice(lo, 0, p);\n }\n\n private _lowerBound(p: PosVertInf): number {\n let lo = 0,\n hi = this._items.length;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (this._items[mid].lt(p)) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n }\n}\n","import { VertInf } from \"../vertex\";\n\n// id. All members in any one set are assumed to share an X or Y coordinate.\nexport class VertSet {\n private _items: VertInf[] = [];\n\n size(): number {\n return this._items.length;\n }\n isEmpty(): boolean {\n return this._items.length === 0;\n }\n values(): VertInf[] {\n return this._items;\n }\n\n insert(v: VertInf): void {\n const lo = this._lowerBound(v);\n if (lo < this._items.length && this._items[lo] === v) return;\n this._items.splice(lo, 0, v);\n }\n\n insertAll(others: VertInf[]): void {\n for (const v of others) this.insert(v);\n }\n\n begin(): VertInf | undefined {\n return this._items[0];\n }\n\n rbegin(): VertInf | undefined {\n return this._items[this._items.length - 1];\n }\n\n // Erase the prefix [0, end), modifying in place.\n eraseFront(end: number): void {\n this._items.splice(0, end);\n }\n\n // Find the first index whose vertex satisfies the predicate; -1 otherwise.\n findIndex(pred: (v: VertInf) => boolean): number {\n for (let i = 0; i < this._items.length; i++) {\n if (pred(this._items[i])) return i;\n }\n return -1;\n }\n\n private _lowerBound(v: VertInf): number {\n let lo = 0,\n hi = this._items.length;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (this._cmp(this._items[mid], v) < 0) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n }\n\n private _cmp(u: VertInf, v: VertInf): number {\n if (u.point.x !== v.point.x) return u.point.x < v.point.x ? -1 : 1;\n if (u.point.y !== v.point.y) return u.point.y < v.point.y ? -1 : 1;\n // Stable tiebreak — both points equal, use identity.\n if (u === v) return 0;\n // Use orthogonalPartner / object identity for deterministic ordering.\n // Falling back to never-equal so the set still contains duplicates by\n // identity.\n return 0;\n }\n}\n","import {\n VertInf,\n XH_CONN,\n XH_EDGE,\n XL_CONN,\n XL_EDGE,\n YH_CONN,\n YH_EDGE,\n YL_CONN,\n YL_EDGE,\n} from '../vertex';\nimport type { Router } from '../router';\nimport { BreakpointSet } from './breakpoint-set';\nimport { VertSet } from './vert-set';\nimport { Point, XDIM, YDIM } from '../geomtypes';\nimport { VisDirDown, VisDirNone, VisDirUp } from '../orthogonal';\nimport { EdgeInf } from '../graph';\nimport { Direction } from '../endpoint';\nimport { PosVertInf } from './pos-vert-inf';\n\n// Module-private helper: construct an anonymous routing-graph vertex\n// (objID=0, vn=0) and register it with the router's vertex list.\nfunction newRoutingVertex(router: Router, point: Point): VertInf {\n const v = new VertInf(0, 0, point);\n router.vertices.addVertex(v);\n return v;\n}\n\n// Returns a bitfield describing which scanline directions are visible from v\n// in dimension `dim`. Translates user-facing Direction visibility (left /\n// right / up / down) into scanline-orientation directions (which differ for\n// the Y axis because our Y points downward).\nexport function getPosVertInfDirections(v: VertInf, dim: number): number {\n if (dim === XDIM) {\n if (v.visDirections.has(Direction.inline)) {\n return VisDirDown | VisDirUp;\n }\n if (v.visDirections.has(Direction.inlineStart)) return VisDirDown;\n if (v.visDirections.has(Direction.inlineEnd)) return VisDirUp;\n } else if (dim === YDIM) {\n if (v.visDirections.has(Direction.block)) {\n return VisDirDown | VisDirUp;\n }\n // Ours Y points downwards: user \"down\" visibility means scanline\n // visibility to higher positions, and vice versa.\n if (v.visDirections.has(Direction.blockEnd)) {\n return VisDirUp;\n }\n if (v.visDirections.has(Direction.blockStart)) {\n return VisDirDown;\n }\n }\n return VisDirNone;\n}\n\n//! A candidate horizontal/vertical visibility segment produced during sweep.\n//! Stores its extent along the segment axis (`begin`..`finish`) and its\n//! perpendicular position (`pos`), plus a sorted set of vertices that lie on\n//! it (`vertInfs`) and intersection break-points discovered during the cross\n//! sweep (`breakPoints`).\nexport class LineSegment {\n begin: number;\n finish: number;\n pos: number;\n shapeSide: boolean;\n vertInfs: VertSet;\n breakPoints: BreakpointSet;\n\n // Two construction shapes (segment with explicit begin..finish, and point\n // segment with begin==finish). We model them as a single signature.\n\n constructor(\n b: number,\n f: number,\n p: number,\n ss?: boolean,\n bvi?: VertInf | null,\n fvi?: VertInf | null,\n );\n constructor(bf: number, p: number, bfvi?: VertInf | null);\n constructor(\n b: number,\n fOrP: number,\n pOrBfvi?: number | VertInf | null,\n ss?: boolean,\n bvi?: VertInf | null,\n fvi?: VertInf | null,\n ) {\n this.vertInfs = new VertSet();\n this.breakPoints = new BreakpointSet();\n\n if (typeof pOrBfvi === 'number') {\n // Three-number form.\n this.begin = b;\n this.finish = fOrP;\n this.pos = pOrBfvi;\n this.shapeSide = ss ?? false;\n if (this.begin >= this.finish) {\n throw new Error('orthogonal: LineSegment requires begin < finish');\n }\n if (bvi) this.vertInfs.insert(bvi);\n if (fvi) this.vertInfs.insert(fvi);\n } else {\n // Two-number form (point segment).\n this.begin = b;\n this.finish = b;\n this.pos = fOrP;\n this.shapeSide = false;\n if (pOrBfvi) this.vertInfs.insert(pOrBfvi);\n }\n }\n\n // Sort key: by begin, pos, finish.\n static compare(lhs: LineSegment, rhs: LineSegment): number {\n if (lhs.begin !== rhs.begin) return lhs.begin < rhs.begin ? -1 : 1;\n if (lhs.pos !== rhs.pos) return lhs.pos < rhs.pos ? -1 : 1;\n if (lhs.finish !== rhs.finish) return lhs.finish < rhs.finish ? -1 : 1;\n return 0;\n }\n\n overlaps(rhs: LineSegment): boolean {\n if (\n this.begin === rhs.begin &&\n this.pos === rhs.pos &&\n this.finish === rhs.finish\n ) {\n return true;\n }\n if (this.pos === rhs.pos) {\n if (\n (this.begin >= rhs.begin && this.begin <= rhs.finish) ||\n (rhs.begin >= this.begin && rhs.begin <= this.finish)\n ) {\n return true;\n }\n }\n return false;\n }\n\n mergeVertInfs(segment: LineSegment): void {\n this.begin = Math.min(this.begin, segment.begin);\n this.finish = Math.max(this.finish, segment.finish);\n this.vertInfs.insertAll(segment.vertInfs.values());\n }\n\n beginVertInf(): VertInf | null {\n const inf = this.vertInfs.begin();\n if (!inf) return null;\n if (\n (inf.point.y === this.begin && inf.point.x === this.pos) ||\n (inf.point.x === this.begin && inf.point.y === this.pos)\n ) {\n return inf;\n }\n return null;\n }\n\n finishVertInf(): VertInf | null {\n const inf = this.vertInfs.rbegin();\n if (!inf) return null;\n if (\n (inf.point.y === this.finish && inf.point.x === this.pos) ||\n (inf.point.x === this.finish && inf.point.y === this.pos)\n ) {\n return inf;\n }\n return null;\n }\n\n commitPositionX(router: Router, posX: number): VertInf {\n for (const v of this.vertInfs.values()) {\n if (v.point.x === posX) return v;\n }\n const found = newRoutingVertex(router, new Point(posX, this.pos));\n this.vertInfs.insert(found);\n return found;\n }\n\n // For horizontal lines: commit the begin endpoint vertex if none assigned.\n horiCommitBegin(router: Router, vert: VertInf | null = null): void {\n if (vert) this.vertInfs.insert(vert);\n const first = this.vertInfs.begin();\n if (!first || first.point.x !== this.begin) {\n if (this.begin !== -Number.MAX_VALUE) {\n this.vertInfs.insert(\n newRoutingVertex(router, new Point(this.begin, this.pos)),\n );\n }\n }\n }\n\n horiCommitFinish(router: Router, vert: VertInf | null = null): void {\n if (vert) this.vertInfs.insert(vert);\n const last = this.vertInfs.rbegin();\n if (!last || last.point.x !== this.finish) {\n if (this.finish !== Number.MAX_VALUE) {\n this.vertInfs.insert(\n newRoutingVertex(router, new Point(this.finish, this.pos)),\n );\n }\n }\n }\n\n // Walk the vertices of this line up to `finishPos`, registering each as a\n // breakpoint. Returns the index of the first intersection point at\n // `finishPos` (or vertInfs.size() if none).\n addSegmentsUpTo(finishPos: number): number {\n let firstIntersection = this.vertInfs.size();\n const verts = this.vertInfs.values();\n for (let i = 0; i < verts.length; i++) {\n const v = verts[i];\n if (v.point.x > finishPos) break;\n this.breakPoints.insert(\n new PosVertInf(v.point.x, v, getPosVertInfDirections(v, XDIM)),\n );\n if (\n firstIntersection === this.vertInfs.size() &&\n v.point.x === finishPos\n ) {\n firstIntersection = i;\n }\n }\n return firstIntersection;\n }\n\n addEdgeHorizontal(router: Router): void {\n this.horiCommitBegin(router);\n this.horiCommitFinish(router);\n this.addSegmentsUpTo(this.finish);\n }\n\n // Walk through breakPoints, setting the orthog-vis property flags for each\n // vertex according to whether it has seen a conn-point or shape-edge so far\n // in either direction.\n setLongRangeVisibilityFlags(dim: number): void {\n const pts = this.breakPoints.values();\n\n // Forward pass.\n let seenConnPt = false;\n let seenShapeEdge = false;\n for (const nvert of pts) {\n let mask = 0;\n if (dim === XDIM) {\n if (seenConnPt) mask |= XL_CONN;\n if (seenShapeEdge) mask |= XL_EDGE;\n } else {\n if (seenConnPt) mask |= YL_CONN;\n if (seenShapeEdge) mask |= YL_EDGE;\n }\n nvert.vert.orthogVisPropFlags |= mask;\n if (nvert.vert.isConnPoint) seenConnPt = true;\n if (nvert.vert.isOrthShapeEdge) seenShapeEdge = true;\n }\n\n // Reverse pass.\n seenConnPt = false;\n seenShapeEdge = false;\n for (let i = pts.length - 1; i >= 0; i--) {\n const rvert = pts[i];\n let mask = 0;\n if (dim === XDIM) {\n if (seenConnPt) mask |= XH_CONN;\n if (seenShapeEdge) mask |= XH_EDGE;\n } else {\n if (seenConnPt) mask |= YH_CONN;\n if (seenShapeEdge) mask |= YH_EDGE;\n }\n rvert.vert.orthogVisPropFlags |= mask;\n if (rvert.vert.isConnPoint) seenConnPt = true;\n if (rvert.vert.isOrthShapeEdge) seenShapeEdge = true;\n }\n }\n\n // Add visibility edges for this segment up until an intersection with\n // `vertLine`. After return, this segment has been advanced past the\n // intersection so subsequent calls deal with the remainder. Returns the\n // intersection-point vertices.\n addEdgeHorizontalTillIntersection(\n router: Router,\n vertLine: LineSegment,\n ): VertInf[] {\n const intersectionSet: VertInf[] = [];\n\n this.horiCommitBegin(router);\n\n // Does a vertex already exist for this point?\n this.commitPositionX(router, vertLine.pos);\n\n // Generate segments and find the first index at the intersection position.\n const restBegin = this.addSegmentsUpTo(vertLine.pos);\n\n // Capture all intersection points at vertLine.pos.\n const verts = this.vertInfs.values();\n let restEnd = restBegin;\n while (restEnd < verts.length && verts[restEnd].point.x === vertLine.pos) {\n intersectionSet.push(verts[restEnd]);\n restEnd++;\n }\n\n // Adjust segment to remove processed portion.\n this.begin = vertLine.pos;\n this.vertInfs.eraseFront(restBegin);\n\n return intersectionSet;\n }\n\n insertBreakpointsBegin(router: Router, vertLine: LineSegment): void {\n let vert: VertInf | null = null;\n if (this.pos === vertLine.begin && vertLine.beginVertInf()) {\n vert = vertLine.beginVertInf();\n } else if (this.pos === vertLine.finish && vertLine.finishVertInf()) {\n vert = vertLine.finishVertInf();\n }\n this.horiCommitBegin(router, vert);\n for (const v of this.vertInfs.values()) {\n if (v.point.x === this.begin) {\n vertLine.breakPoints.insert(\n new PosVertInf(this.pos, v, getPosVertInfDirections(v, YDIM)),\n );\n }\n }\n }\n\n insertBreakpointsFinish(router: Router, vertLine: LineSegment): void {\n let vert: VertInf | null = null;\n if (this.pos === vertLine.begin && vertLine.beginVertInf()) {\n vert = vertLine.beginVertInf();\n } else if (this.pos === vertLine.finish && vertLine.finishVertInf()) {\n vert = vertLine.finishVertInf();\n }\n this.horiCommitFinish(router, vert);\n for (const v of this.vertInfs.values()) {\n if (v.point.x === this.finish) {\n vertLine.breakPoints.insert(\n new PosVertInf(this.pos, v, getPosVertInfDirections(v, YDIM)),\n );\n }\n }\n }\n\n generateVisibilityEdgesFromBreakpointSet(router: Router, dim: number): void {\n if (\n this.breakPoints.isEmpty() ||\n this.breakPoints.first().pos > this.begin\n ) {\n // Add a begin point if there was not already an intersection at that\n // point. Skip if the line goes to -infinity — nothing to connect to.\n if (this.begin === -Number.MAX_VALUE) {\n if (this.breakPoints.isEmpty()) {\n throw new Error('orthogonal: breakPoints empty at -∞ begin');\n }\n this.begin = this.breakPoints.first().pos;\n } else {\n const point = new Point(this.pos, this.pos);\n point.setAt(dim, this.begin);\n const vert = newRoutingVertex(router, point);\n this.breakPoints.insert(new PosVertInf(this.begin, vert));\n }\n }\n if (\n this.breakPoints.isEmpty() ||\n this.breakPoints.last().pos < this.finish\n ) {\n if (this.finish === Number.MAX_VALUE) {\n this.finish = this.breakPoints.last().pos;\n } else {\n const point = new Point(this.pos, this.pos);\n point.setAt(dim, this.finish);\n const vert = newRoutingVertex(router, point);\n this.breakPoints.insert(new PosVertInf(this.finish, vert));\n }\n }\n\n // Set flags for orthogonal routing optimisation.\n this.setLongRangeVisibilityFlags(dim);\n\n const pts = this.breakPoints.values();\n let vert = 0;\n let last = 0;\n while (vert < pts.length) {\n const firstPrev = last;\n while (pts[last].vert.point.at(dim) !== pts[vert].vert.point.at(dim)) {\n // Pair of two endpoints both inside a shape.\n if (pts[vert].vert.isConnPoint && pts[last].vert.isConnPoint) {\n // Give vert visibility back to the first non-connector vertex.\n let side = last;\n while (pts[side].vert.isConnPoint) {\n if (side === 0) break;\n side--;\n }\n const canSeeDown = (pts[vert].dirs & VisDirDown) !== 0;\n if (canSeeDown && !pts[side].vert.isConnPoint) {\n const edge = new EdgeInf(pts[side].vert, pts[vert].vert, router);\n edge.setDist(\n pts[vert].vert.point.at(dim) - pts[side].vert.point.at(dim),\n );\n }\n\n // Give last visibility forward.\n let side2 = vert;\n while (side2 < pts.length && pts[side2].vert.isConnPoint) {\n side2++;\n }\n const canSeeUp = (pts[last].dirs & VisDirUp) !== 0;\n if (canSeeUp && side2 < pts.length) {\n const edge = new EdgeInf(pts[last].vert, pts[side2].vert, router);\n edge.setDist(\n pts[side2].vert.point.at(dim) - pts[last].vert.point.at(dim),\n );\n }\n }\n\n // The normal case.\n let generateEdge = true;\n if (pts[last].vert.isConnPoint && !(pts[last].dirs & VisDirUp)) {\n generateEdge = false;\n } else if (\n pts[vert].vert.isConnPoint &&\n !(pts[vert].dirs & VisDirDown)\n ) {\n generateEdge = false;\n }\n if (generateEdge) {\n const edge = new EdgeInf(pts[last].vert, pts[vert].vert, router);\n edge.setDist(\n pts[vert].vert.point.at(dim) - pts[last].vert.point.at(dim),\n );\n }\n last++;\n }\n\n vert++;\n\n if (\n vert < pts.length &&\n pts[last].vert.point.at(dim) === pts[vert].vert.point.at(dim)\n ) {\n // Still looking at same pair, just reset prev pointer.\n last = firstPrev;\n }\n // else: vert has moved to a new position; last is in the right place.\n }\n }\n}\n","import { LineSegment } from \"./line-segment\";\n\n//! A list of LineSegments with overlap-merging insertion. The list keeps the\n//! invariant that no two segments overlap; on insertion a new segment that\n//! overlaps existing ones is merged into the first overlap, and subsequent\n//! overlapping segments are merged into the first and removed.\nexport class SegmentListWrapper {\n /** @internal */ _list: LineSegment[] = [];\n\n insert(segment: LineSegment): LineSegment {\n let foundIdx = -1;\n let i = 0;\n while (i < this._list.length) {\n const curr = this._list[i];\n if (curr.overlaps(segment)) {\n if (foundIdx !== -1) {\n // Already found one; merge that one into curr, remove the previous.\n curr.mergeVertInfs(this._list[foundIdx]);\n this._list.splice(foundIdx, 1);\n if (foundIdx < i) i--;\n foundIdx = i;\n } else {\n // First overlap — merge new segment into curr.\n curr.mergeVertInfs(segment);\n foundIdx = i;\n }\n }\n i++;\n }\n\n if (foundIdx === -1) {\n this._list.push(segment);\n return this._list[this._list.length - 1];\n }\n return this._list[foundIdx];\n }\n\n list(): LineSegment[] {\n return this._list;\n }\n\n sort(): void {\n this._list.sort(LineSegment.compare);\n }\n\n clear(): void {\n this._list.length = 0;\n }\n}\n","// Orthogonal routing — static visibility graph build and post-route nudging.\n//\n// Ports input/orthogonal.cpp and input/orthogonal.h. The two public entry\n// points are:\n//\n// - generateStaticOrthogonalVisGraph(router): runs two sweepline passes (one\n// per dimension) over every obstacle corner, junction corner, and\n// connector endpoint, producing the lattice of horizontal/vertical\n// visibility edges that orthogonal A* searches over. Each edge stores\n// XL_EDGE / XH_EDGE / YL_EDGE / YH_EDGE flags so makepath can know which\n// edges hug shape boundaries.\n//\n// - improveOrthogonalRoutes(router): runs the post-route nudging pipeline.\n// Walks every orthogonal connector, builds NudgingShiftSegments, runs an\n// optional \"unifying\" VPSC preprocessing pass to centre free segments in\n// overlapping channels, then per-dimension nudges the segments via VPSC\n// with PotentialSegmentConstraints.\n//\n// Deviations from the C++ source:\n// - C++ raw pointers become TypeScript class instances; rely on GC.\n// - C++ output reference params (`Variable*&`, `LineSegment*&`) return\n// `{ ... }` records or are written via mutable fields on returned objects.\n// - `std::set<T, Cmp>` with custom comparators are modelled as sorted arrays\n// with binary insertion (see SortedSet helper) or sort-on-finalise.\n// - DBL_MAX → Number.MAX_VALUE / -Number.MAX_VALUE.\n// - All NUDGE_DEBUG / DEBUG_JUST_UNIFY / LIBVPSC_LOGGING /\n// MAJOR_HYPEREDGE_IMPROVEMENT_DEBUG blocks are dropped.\n// - operator<< printers, fprintf and SVG output are dropped.\n// - DebugHandler / debug callbacks and setDebuggingOutput are dropped.\n// - performContinuationCheck / TransactionPhase reporting is dropped\n// (transactions are not modelled in this port).\n// - improveOrthogonalTopology is dropped — the libtopology hook is not\n// ported.\n// - COLA_ASSERT becomes explicit invariant checks via Error throws for the\n// ones that matter and is dropped for pure-debug assertions.\n\nimport { Point, XDIM, YDIM, type Box, Polygon } from './geomtypes';\nimport { VertInf as VertInfClass, type VertInfRoles } from './vertex';\n\nimport { Junction } from './junction';\nimport { Direction } from './endpoint';\nimport {\n type Edge,\n ConnectorCrossings,\n CROSSING_SHARES_PATH_AT_END,\n splitBranchingSegments,\n type PtOrderMap,\n} from './edge';\nimport {\n type ShiftSegment,\n CHANNEL_MAX,\n Node,\n Event,\n EventType,\n NodeSet,\n compareEvents,\n buildOrthogonalChannelInfo,\n buildConnectorRouteCheckpointCache,\n clearConnectorRouteCheckpointCache,\n} from './scanline';\nimport { Variable, Constraint, IncSolver } from './vpsc';\nimport { Router } from './router';\nimport { NudgingShiftSegment } from './utilities/nudging-shift-segment';\nimport { getPosVertInfDirections, LineSegment } from './utilities/line-segment';\nimport { PosVertInf } from './utilities/pos-vert-inf';\nimport { SegmentListWrapper } from './utilities/segment-list-wrapper';\n\n// Module-private helper: construct a routing-graph vertex (with no owning\n// obstacle: objID=0, vn=0) and register it with the router's vertex list.\nfunction newRoutingVertex(\n router: Router,\n point: Point,\n roles: VertInfRoles = {},\n): VertInfClass {\n const v = new VertInfClass(0, 0, point, roles);\n router.vertices.addVertex(v);\n return v;\n}\n\n// Convenience wrapper for the dominant case in this file: a synthesised\n// shape-edge breakpoint discovered by the scanline.\nfunction newShapeEdgeVertex(router: Router, point: Point): VertInfClass {\n return newRoutingVertex(router, point, { isOrthShapeEdge: true });\n}\n\n// ─── Constants ───────────────────────────────────────────────────────────────\n\n// Variable IDs used by the VPSC solver (passed as `Variable.id`). The\n// channel-edge IDs let us recognise unsatisfied channel boundaries later.\nconst freeSegmentID = 0;\nconst fixedSegmentID = 1;\nconst channelLeftID = 2;\nconst channelRightID = 3;\n\n// Weights for the four kinds of variable.\nconst freeWeight = 0.00001;\nconst strongWeight = 0.001;\nconst strongerWeight = 1.0;\nconst fixedWeight = 100000;\n\n// ─── UnsignedPair ─────────────────────────────────────────────────────────────\n\n//! A pair of unsigned values that can be compared and used as keys. The\n//! smaller index is stored first so {a,b} and {b,a} compare equal.\nexport class UnsignedPair {\n readonly _index1: number;\n readonly _index2: number;\n\n constructor(ind1: number, ind2: number) {\n if (ind1 === ind2) {\n throw new Error('orthogonal: UnsignedPair indices must differ');\n }\n this._index1 = ind1 < ind2 ? ind1 : ind2;\n this._index2 = ind1 > ind2 ? ind1 : ind2;\n }\n\n // Strict less-than ordering, primary by _index1, then _index2.\n lt(rhs: UnsignedPair): boolean {\n if (this._index1 !== rhs._index1) return this._index1 < rhs._index1;\n return this._index2 < rhs._index2;\n }\n\n eq(rhs: UnsignedPair): boolean {\n return this._index1 === rhs._index1 && this._index2 === rhs._index2;\n }\n\n // String key for use with Set / Map.\n key(): string {\n return `${this._index1}:${this._index2}`;\n }\n}\n\n// A set-of-pairs backed by a string-keyed Set, preserving the C++ semantics.\nclass UnsignedPairSet {\n private _items = new Set<string>();\n\n insert(p: UnsignedPair): void {\n this._items.add(p.key());\n }\n\n has(p: UnsignedPair): boolean {\n return this._items.has(p.key());\n }\n\n clear(): void {\n this._items.clear();\n }\n\n size(): number {\n return this._items.size;\n }\n}\n\n// ─── CmpIndexes ───────────────────────────────────────────────────────────────\n\n//! Comparator used when merging NudgingShiftSegments — sorts route indexes by\n//! point position in `dimension`.\nexport class CmpIndexes {\n connRef: Edge;\n dimension: number;\n\n constructor(connRef: Edge, dimension: number) {\n this.connRef = connRef;\n this.dimension = dimension;\n }\n\n // Returns negative if lhs < rhs, positive if lhs > rhs, 0 if equal. Suits\n // Array.prototype.sort callbacks.\n compare(lhs: number, rhs: number): number {\n const a = this.connRef.displayRoute().ps[lhs].at(this.dimension);\n const b = this.connRef.displayRoute().ps[rhs].at(this.dimension);\n return a < b ? -1 : a > b ? 1 : 0;\n }\n}\n\n// ─── ScanVisDir / PosVertInf ──────────────────────────────────────────────────\nexport const VisDirNone = 0;\nexport const VisDirUp = 1; // higher position values\nexport const VisDirDown = 2; // lower position values\n\n// ─── intersectSegments ────────────────────────────────────────────────────────\n\n//! Given a router and a list of possible horizontal segments, plus a possible\n//! vertical visibility segment, compute and add edges to the orthogonal\n//! visibility graph for all visibility edges.\n//!\n//! Modifies `segments` in place — segments whose finish position is behind\n//! the vertical line are committed and removed.\nexport function intersectSegments(\n router: Router,\n segments: LineSegment[],\n vertLine: LineSegment,\n): void {\n if (segments.length === 0) {\n // C++ asserts; we tolerate empty since callers may legitimately pass empty.\n vertLine.generateVisibilityEdgesFromBreakpointSet(router, YDIM);\n return;\n }\n\n let i = 0;\n while (i < segments.length) {\n const horiLine = segments[i];\n const inVertSegRegion =\n vertLine.begin <= horiLine.pos && vertLine.finish >= horiLine.pos;\n\n if (vertLine.pos < horiLine.begin) {\n // Yet to reach this segment in the sweep, ignore.\n i++;\n continue;\n } else if (vertLine.pos === horiLine.begin) {\n if (inVertSegRegion) {\n horiLine.insertBreakpointsBegin(router, vertLine);\n }\n } else if (vertLine.pos === horiLine.finish) {\n if (inVertSegRegion) {\n horiLine.addEdgeHorizontal(router);\n horiLine.insertBreakpointsFinish(router, vertLine);\n horiLine.generateVisibilityEdgesFromBreakpointSet(router, XDIM);\n segments.splice(i, 1);\n continue;\n }\n } else if (vertLine.pos > horiLine.finish) {\n horiLine.addEdgeHorizontal(router);\n horiLine.generateVisibilityEdgesFromBreakpointSet(router, XDIM);\n segments.splice(i, 1);\n continue;\n } else {\n // vertLine.pos strictly between horiLine.begin and horiLine.finish.\n if (inVertSegRegion) {\n const intersectionVerts = horiLine.addEdgeHorizontalTillIntersection(\n router,\n vertLine,\n );\n for (const v of intersectionVerts) {\n vertLine.breakPoints.insert(\n new PosVertInf(horiLine.pos, v, getPosVertInfDirections(v, YDIM)),\n );\n }\n }\n }\n i++;\n }\n\n vertLine.generateVisibilityEdgesFromBreakpointSet(router, YDIM);\n}\n\n// ─── Sweep event processing ───────────────────────────────────────────────────\n\n// Pass-1: insert into scanline & link neighbours.\n// Pass-2: process the event.\n// Pass-3: remove from scanline.\n\nfunction processEventVert(\n router: Router,\n scanline: NodeSet,\n segments: SegmentListWrapper,\n e: Event,\n pass: number,\n): void {\n const v = e.v;\n\n if (\n (pass === 1 && e.type === EventType.Open) ||\n (pass === 2 && e.type === EventType.ConnPoint)\n ) {\n scanline.insert(v);\n const above = scanline.prev(v);\n if (above) {\n v.firstAbove = above;\n above.firstBelow = v;\n }\n const below = scanline.next(v);\n if (below) {\n v.firstBelow = below;\n below.firstAbove = v;\n }\n }\n\n if (pass === 2) {\n if (e.type === EventType.Open || e.type === EventType.Close) {\n // Only difference between Open and Close: which side of the shape we\n // emit segments on.\n const lineY = e.type === EventType.Open ? v.min[YDIM] : v.max[YDIM];\n\n const minShape = v.min[XDIM];\n const maxShape = v.max[XDIM];\n const limits = v.findFirstPointAboveAndBelow(XDIM, lineY);\n const minLimit = limits.firstAbove;\n const maxLimit = limits.firstBelow;\n const minLimitMax = limits.lastAbove;\n const maxLimitMin = limits.lastBelow;\n\n if (minLimitMax >= maxLimitMin) {\n // Shape corners (these are real shape-edge vertices).\n const vI1 = newShapeEdgeVertex(router, new Point(minShape, lineY));\n const vI2 = newShapeEdgeVertex(router, new Point(maxShape, lineY));\n\n // No overlapping shapes, full visibility.\n if (minLimit < minShape) {\n segments.insert(\n new LineSegment(minLimit, minShape, lineY, true, null, vI1),\n );\n }\n segments.insert(\n new LineSegment(minShape, maxShape, lineY, true, vI1, vI2),\n );\n if (maxShape < maxLimit) {\n segments.insert(\n new LineSegment(maxShape, maxLimit, lineY, true, vI2, null),\n );\n }\n } else {\n // Overlapping shapes along this shape edge.\n if (minLimitMax > minLimit && minLimitMax >= minShape) {\n const line = segments.insert(\n new LineSegment(minLimit, minLimitMax, lineY, true),\n );\n const vI1 = newShapeEdgeVertex(router, new Point(minShape, lineY));\n line.vertInfs.insert(vI1);\n }\n if (maxLimitMin < maxLimit && maxLimitMin <= maxShape) {\n const line = segments.insert(\n new LineSegment(maxLimitMin, maxLimit, lineY, true),\n );\n const vI2 = newShapeEdgeVertex(router, new Point(maxShape, lineY));\n line.vertInfs.insert(vI2);\n }\n }\n } else if (e.type === EventType.ConnPoint) {\n const centreVert = e.v.c!;\n const cp = centreVert.point;\n const minLimit = v.firstPointAbove(XDIM);\n const maxLimit = v.firstPointBelow(XDIM);\n const inShape = v.isInsideShape(XDIM);\n\n let line1: LineSegment | null = null;\n let line2: LineSegment | null = null;\n if (\n centreVert.visDirections.has(Direction.inlineStart) &&\n minLimit < cp.x\n ) {\n line1 = segments.insert(\n new LineSegment(minLimit, cp.x, e.pos, true, null, centreVert),\n );\n }\n if (\n centreVert.visDirections.has(Direction.inlineEnd) &&\n cp.x < maxLimit\n ) {\n line2 = segments.insert(\n new LineSegment(cp.x, maxLimit, e.pos, true, centreVert, null),\n );\n // If there was a line1, it was just merged with this one — invalidate.\n line1 = null;\n }\n if (!line1 && !line2) {\n // Point segment for the centre point.\n segments.insert(new LineSegment(cp.x, e.pos, centreVert));\n }\n\n if (!inShape) {\n // Add a dummy lattice vertex at the centre too.\n if (line1 || line2) {\n const cent = newRoutingVertex(router, cp);\n if (line1) line1.vertInfs.insert(cent);\n if (line2) line2.vertInfs.insert(cent);\n }\n }\n }\n }\n\n if (\n (pass === 3 && e.type === EventType.Close) ||\n (pass === 2 && e.type === EventType.ConnPoint)\n ) {\n const l = v.firstAbove;\n const r = v.firstBelow;\n if (l !== null) l.firstBelow = v.firstBelow;\n if (r !== null) r.firstAbove = v.firstAbove;\n if (!scanline.erase(v)) {\n throw new Error('orthogonal: failed to erase Node from scanline');\n }\n }\n}\n\nfunction processEventHori(\n router: Router,\n scanline: NodeSet,\n segments: SegmentListWrapper,\n e: Event,\n pass: number,\n): void {\n const v = e.v;\n\n if (\n (pass === 1 && e.type === EventType.Open) ||\n (pass === 2 && e.type === EventType.ConnPoint)\n ) {\n scanline.insert(v);\n const above = scanline.prev(v);\n if (above) {\n v.firstAbove = above;\n above.firstBelow = v;\n }\n const below = scanline.next(v);\n if (below) {\n v.firstBelow = below;\n below.firstAbove = v;\n }\n }\n\n if (pass === 2) {\n if (e.type === EventType.Open || e.type === EventType.Close) {\n const lineX = e.type === EventType.Open ? v.min[XDIM] : v.max[XDIM];\n const minShape = v.min[YDIM];\n const maxShape = v.max[YDIM];\n const limits = v.findFirstPointAboveAndBelow(YDIM, lineX);\n const minLimit = limits.firstAbove;\n const maxLimit = limits.firstBelow;\n const minLimitMax = limits.lastAbove;\n const maxLimitMin = limits.lastBelow;\n\n if (minLimitMax >= maxLimitMin) {\n const line = segments.insert(\n new LineSegment(minLimit, maxLimit, lineX),\n );\n const vI1 = newShapeEdgeVertex(router, new Point(lineX, minShape));\n const vI2 = newShapeEdgeVertex(router, new Point(lineX, maxShape));\n line.vertInfs.insert(vI1);\n line.vertInfs.insert(vI2);\n } else {\n if (minLimitMax > minLimit && minLimitMax >= minShape) {\n const line = segments.insert(\n new LineSegment(minLimit, minLimitMax, lineX),\n );\n const vI1 = newShapeEdgeVertex(router, new Point(lineX, minShape));\n line.vertInfs.insert(vI1);\n }\n if (maxLimitMin < maxLimit && maxLimitMin <= maxShape) {\n const line = segments.insert(\n new LineSegment(maxLimitMin, maxLimit, lineX),\n );\n const vI2 = newShapeEdgeVertex(router, new Point(lineX, maxShape));\n line.vertInfs.insert(vI2);\n }\n }\n } else if (e.type === EventType.ConnPoint) {\n const centreVert = e.v.c!;\n const cp = centreVert.point;\n const minLimit = v.firstPointAbove(YDIM);\n const maxLimit = v.firstPointBelow(YDIM);\n if (\n centreVert.visDirections.has(Direction.blockStart) &&\n minLimit < cp.y\n ) {\n segments.insert(new LineSegment(minLimit, cp.y, e.pos));\n }\n if (centreVert.visDirections.has(Direction.blockEnd) && cp.y < maxLimit) {\n segments.insert(new LineSegment(cp.y, maxLimit, e.pos));\n }\n }\n }\n\n if (\n (pass === 3 && e.type === EventType.Close) ||\n (pass === 2 && e.type === EventType.ConnPoint)\n ) {\n const l = v.firstAbove;\n const r = v.firstBelow;\n if (l !== null) l.firstBelow = v.firstBelow;\n if (r !== null) r.firstAbove = v.firstAbove;\n if (!scanline.erase(v)) {\n throw new Error('orthogonal: failed to erase Node from scanline');\n }\n }\n}\n\n// ─── fixConnectionPointVisibilityOnOutsideOfVisibilityGraph ───────────────────\n\n//! Pins or connector endpoints sitting on the leading/trailing edge of the\n//! visibility graph may only have visibility in the outward direction (away\n//! from the graph). Add the supplied visibility flags so they can still be\n//! reached.\nfunction fixConnectionPointVisibilityOnOutsideOfVisibilityGraph(\n events: Event[],\n addedVisibility: Direction,\n): void {\n const totalEvents = events.length;\n if (totalEvents === 0) return;\n\n const firstPos = events[0].pos;\n let index = 0;\n while (index < totalEvents) {\n if (events[index].pos > firstPos) break;\n if (events[index].v.c) {\n events[index].v.c!.visDirections =\n events[index].v.c!.visDirections.add(addedVisibility);\n }\n index++;\n }\n const lastPos = events[totalEvents - 1].pos;\n for (let k = 0; k < totalEvents; k++) {\n const revIndex = totalEvents - 1 - k;\n if (events[revIndex].pos < lastPos) break;\n if (events[revIndex].v.c) {\n events[revIndex].v.c!.visDirections =\n events[revIndex].v.c!.visDirections.add(addedVisibility);\n }\n }\n}\n\n// ─── generateStaticOrthogonalVisGraph ─────────────────────────────────────────\n\n//! @brief Build the static orthogonal visibility graph for the router.\n//!\n//! Runs two sweepline passes (one per dimension) over every obstacle corner,\n//! junction corner (when fixed), and connector endpoint, populating\n//! `router.visOrthogGraph` with the lattice of horizontal/vertical visibility\n//! edges and tagging every vertex with XL_*/XH_*/YL_*/YH_* property flags.\nexport function generateStaticOrthogonalVisGraph(router: Router): void {\n // ── Vertical sweep (events sorted by Y; produces horizontal segments) ──\n\n let events: Event[] = [];\n for (const obstacle of router.m_obstacles) {\n if (obstacle instanceof Junction && !obstacle.positionFixed()) {\n // Junctions free to move are not treated as obstacles.\n continue;\n }\n const bbox: Box = obstacle.routingBox();\n const midX = bbox.min.x + (bbox.max.x - bbox.min.x) / 2;\n const node = Node.forObstacle(obstacle, midX);\n events.push(new Event(EventType.Open, node, bbox.min.y));\n events.push(new Event(EventType.Close, node, bbox.max.y));\n }\n\n // Connector endpoints.\n for (\n let curr = router.vertices.connsBegin();\n curr !== null && curr !== router.vertices.shapesBegin();\n curr = curr.lstNext\n ) {\n if (curr.visDirections.equal(Direction.zero)) {\n // Connector endpoint attached to a shape's connection pin — no\n // visibility needed.\n continue;\n }\n const point = curr.point;\n const node = Node.forVertex(curr, point.x);\n events.push(new Event(EventType.ConnPoint, node, point.y));\n }\n\n events.sort(compareEvents);\n\n fixConnectionPointVisibilityOnOutsideOfVisibilityGraph(\n events,\n Direction.inline,\n );\n\n // Process the vertical sweep — adds candidate horizontal edges.\n const segments = new SegmentListWrapper();\n const scanline = new NodeSet();\n {\n const totalEvents = events.length;\n let thisPos = totalEvents > 0 ? events[0].pos : 0;\n let posStartIndex = 0;\n for (let i = 0; i <= totalEvents; i++) {\n if (i === totalEvents || events[i].pos !== thisPos) {\n const posFinishIndex = i;\n for (let pass = 2; pass <= 3; pass++) {\n for (let j = posStartIndex; j < posFinishIndex; j++) {\n processEventVert(router, scanline, segments, events[j], pass);\n }\n }\n if (i === totalEvents) break;\n thisPos = events[i].pos;\n posStartIndex = i;\n }\n processEventVert(router, scanline, segments, events[i], 1);\n }\n }\n if (scanline.size() !== 0) {\n throw new Error('orthogonal: scanline non-empty after vertical sweep');\n }\n\n // Sort the segment list before the horizontal sweep so intersection\n // testing is deterministic.\n segments.sort();\n\n // ── Horizontal sweep (events sorted by X; produces vertical segments) ──\n\n events = [];\n for (const obstacle of router.m_obstacles) {\n if (obstacle instanceof Junction && !obstacle.positionFixed()) {\n continue;\n }\n const bbox: Box = obstacle.routingBox();\n const midY = bbox.min.y + (bbox.max.y - bbox.min.y) / 2;\n const node = Node.forObstacle(obstacle, midY);\n events.push(new Event(EventType.Open, node, bbox.min.x));\n events.push(new Event(EventType.Close, node, bbox.max.x));\n }\n for (\n let curr = router.vertices.connsBegin();\n curr !== null && curr !== router.vertices.shapesBegin();\n curr = curr.lstNext\n ) {\n if (curr.visDirections.equal(Direction.zero)) {\n continue;\n }\n const point = curr.point;\n const node = Node.forVertex(curr, point.y);\n events.push(new Event(EventType.ConnPoint, node, point.x));\n }\n events.sort(compareEvents);\n\n fixConnectionPointVisibilityOnOutsideOfVisibilityGraph(\n events,\n Direction.block,\n );\n\n // Horizontal sweep — vertical edges.\n {\n const vertSegments = new SegmentListWrapper();\n const totalEvents = events.length;\n let thisPos = totalEvents > 0 ? events[0].pos : 0;\n let posStartIndex = 0;\n for (let i = 0; i <= totalEvents; i++) {\n if (i === totalEvents || events[i].pos !== thisPos) {\n const posFinishIndex = i;\n for (let pass = 2; pass <= 3; pass++) {\n for (let j = posStartIndex; j < posFinishIndex; j++) {\n processEventHori(router, scanline, vertSegments, events[j], pass);\n }\n }\n\n // Process the merged line segments — for each vertical segment, run\n // intersect against the horizontal-segment set produced by the\n // vertical sweep.\n vertSegments.sort();\n for (const curr of vertSegments.list()) {\n intersectSegments(router, segments.list(), curr);\n }\n vertSegments.clear();\n\n if (i === totalEvents) break;\n thisPos = events[i].pos;\n posStartIndex = i;\n }\n processEventHori(router, scanline, vertSegments, events[i], 1);\n }\n }\n if (scanline.size() !== 0) {\n throw new Error('orthogonal: scanline non-empty after horizontal sweep');\n }\n\n // Commit any horizontal segments still in the list (they extend past the\n // final vertical sweep position we considered).\n for (const horiLine of segments.list()) {\n horiLine.addEdgeHorizontal(router);\n horiLine.generateVisibilityEdgesFromBreakpointSet(router, XDIM);\n }\n segments.clear();\n}\n\n// ─── insideRectBounds ─────────────────────────────────────────────────────────\n\ntype RectBounds = [Point, Point];\n\nfunction insideRectBounds(point: Point, rectBounds: RectBounds): boolean {\n // Invalid sentinel: zero/zero bounds.\n if (\n rectBounds[0].x === 0 &&\n rectBounds[0].y === 0 &&\n rectBounds[1].x === 0 &&\n rectBounds[1].y === 0\n ) {\n return false;\n }\n for (let i = 0; i < 2; i++) {\n if (point.at(i) < rectBounds[0].at(i)) return false;\n if (point.at(i) > rectBounds[1].at(i)) return false;\n }\n return true;\n}\n\n// ─── buildOrthogonalNudgingSegments ───────────────────────────────────────────\n\n// Walks each orthogonal connector and produces a NudgingShiftSegment for every\n// segment in `dim`. Segments at route endpoints are made fixed (or shiftable\n// with constrained limits if `nudgeOrthogonalSegmentsConnectedToShapes` is\n// enabled).\nfunction buildOrthogonalNudgingSegments(\n router: Router,\n dim: number,\n segmentList: NudgingShiftSegment[],\n): void {\n if (router.params.segmentPenalty === 0) {\n // The nudging code assumes routes are pretty optimal. Only true with a\n // segment penalty.\n return;\n }\n const nudgeFinalSegments =\n router.options.nudgeOrthogonalSegmentsConnectedToShapes;\n // Cache shape rectangles so we don't rebuild them per-segment.\n let shapeLimits: RectBounds[] = [];\n if (nudgeFinalSegments) {\n shapeLimits = new Array(router.m_obstacles.length)\n .fill(null)\n .map(() => [new Point(0, 0), new Point(0, 0)] as RectBounds);\n\n const zeroBufferDist = 0.0;\n for (let i = 0; i < router.m_obstacles.length; i++) {\n const o = router.m_obstacles[i];\n if (o instanceof Junction) {\n const pos = o.position();\n shapeLimits[i] = [new Point(pos.x, pos.y), new Point(pos.x, pos.y)];\n } else {\n // Shape.\n const bBox = o.polygon.offsetBoundingBox(zeroBufferDist);\n shapeLimits[i] = [\n new Point(bBox.min.x, bBox.min.y),\n new Point(bBox.max.x, bBox.max.y),\n ];\n void zeroBufferDist;\n }\n }\n }\n\n const altDim = (dim + 1) % 2;\n\n for (const conn of router.connRefs) {\n const displayRoute = conn.displayRoute();\n\n for (let i = 1; i < displayRoute.size(); i++) {\n if (displayRoute.ps[i - 1].at(dim) !== displayRoute.ps[i].at(dim))\n continue;\n\n // Segment in our dimension.\n let indexLow = i - 1;\n let indexHigh = i;\n if (displayRoute.ps[i - 1].at(altDim) === displayRoute.ps[i].at(altDim)) {\n // Zero-length, skip.\n continue;\n }\n if (displayRoute.ps[i - 1].at(altDim) > displayRoute.ps[i].at(altDim)) {\n indexLow = i;\n indexHigh = i - 1;\n }\n\n const checkpoints = displayRoute.checkpointsOnSegment(i - 1);\n const prevCheckpoints = displayRoute.checkpointsOnSegment(i - 2, -1);\n const nextCheckpoints = displayRoute.checkpointsOnSegment(i, +1);\n\n const hasCheckpoints = checkpoints.length > 0;\n if (hasCheckpoints && !nudgeFinalSegments) {\n segmentList.push(\n new NudgingShiftSegment(conn, indexLow, indexHigh, dim),\n );\n continue;\n }\n\n const thisPos = displayRoute.ps[i].at(dim);\n\n if (i === 1 || i + 1 === displayRoute.size()) {\n // First or last segment.\n if (nudgeFinalSegments) {\n let minLim = -CHANNEL_MAX;\n let maxLim = CHANNEL_MAX;\n let endsInShapes = 0;\n for (let k = 0; k < shapeLimits.length; k++) {\n const shapeMin = shapeLimits[k][0].at(dim);\n const shapeMax = shapeLimits[k][1].at(dim);\n if (insideRectBounds(displayRoute.ps[i - 1], shapeLimits[k])) {\n minLim = Math.max(minLim, shapeMin);\n maxLim = Math.min(maxLim, shapeMax);\n endsInShapes |= 0x01;\n }\n if (insideRectBounds(displayRoute.ps[i], shapeLimits[k])) {\n minLim = Math.max(minLim, shapeMin);\n maxLim = Math.min(maxLim, shapeMax);\n endsInShapes |= 0x10;\n }\n }\n if (endsInShapes === 0) {\n const pos = displayRoute.ps[i - 1].at(dim);\n const freeConnBuffer = 15;\n minLim = Math.max(minLim, pos - freeConnBuffer);\n maxLim = Math.min(maxLim, pos + freeConnBuffer);\n }\n if (minLim === maxLim) {\n segmentList.push(\n new NudgingShiftSegment(conn, indexLow, indexHigh, dim),\n );\n } else {\n const seg = new NudgingShiftSegment(\n conn,\n indexLow,\n indexHigh,\n false,\n false,\n dim,\n minLim,\n maxLim,\n );\n seg.finalSegment = true;\n seg.endsInShape = endsInShapes > 0;\n if (displayRoute.size() === 2 && endsInShapes === 0x11) {\n seg.singleConnectedSegment = true;\n }\n segmentList.push(seg);\n }\n } else {\n segmentList.push(\n new NudgingShiftSegment(conn, indexLow, indexHigh, dim),\n );\n }\n continue;\n }\n\n // Inner segment with shifting headroom.\n let minLim = -CHANNEL_MAX;\n let maxLim = CHANNEL_MAX;\n\n for (const cp of nextCheckpoints) {\n if (cp.at(dim) < thisPos) minLim = Math.max(minLim, cp.at(dim));\n else if (cp.at(dim) > thisPos) maxLim = Math.min(maxLim, cp.at(dim));\n }\n for (const cp of prevCheckpoints) {\n if (cp.at(dim) < thisPos) minLim = Math.max(minLim, cp.at(dim));\n else if (cp.at(dim) > thisPos) maxLim = Math.min(maxLim, cp.at(dim));\n }\n\n let isSBend = false;\n let isZBend = false;\n\n if (checkpoints.length === 0) {\n const prevPos = displayRoute.ps[i - 2].at(dim);\n const nextPos = displayRoute.ps[i + 1].at(dim);\n if (\n (prevPos < thisPos && nextPos > thisPos) ||\n (prevPos > thisPos && nextPos < thisPos)\n ) {\n if (prevPos < thisPos && nextPos > thisPos) {\n minLim = Math.max(minLim, prevPos);\n maxLim = Math.min(maxLim, nextPos);\n isZBend = true;\n } else {\n minLim = Math.max(minLim, nextPos);\n maxLim = Math.min(maxLim, prevPos);\n isSBend = true;\n }\n }\n }\n\n const nss = new NudgingShiftSegment(\n conn,\n indexLow,\n indexHigh,\n isSBend,\n isZBend,\n dim,\n minLim,\n maxLim,\n );\n nss.checkpoints = checkpoints.slice();\n segmentList.push(nss);\n }\n }\n}\n\n// ─── CmpLineOrder ─────────────────────────────────────────────────────────────\n\n//! Comparator for the line-order sort used during nudging. Orders segments\n//! that share a position by their PtOrder map ranking, falling back to\n//! fixedOrder / c-bend order for fixed and c-bend segments.\nexport class CmpLineOrder {\n orders: PtOrderMap;\n dimension: number;\n\n constructor(orders: PtOrderMap, dimension: number) {\n this.orders = orders;\n this.dimension = dimension;\n }\n\n //! Returns `{ lessThan, comparable }`. `comparable` is false when the two\n //! segments can't be ordered against each other.\n compare(\n lhsSuper: ShiftSegment,\n rhsSuper: ShiftSegment,\n ): { lessThan: boolean; comparable: boolean } {\n const lhs = lhsSuper as NudgingShiftSegment;\n const rhs = rhsSuper as NudgingShiftSegment;\n let comparable = true;\n const lhsLow = lhs.lowPoint();\n const rhsLow = rhs.lowPoint();\n const altDim = (this.dimension + 1) % 2;\n\n if (lhsLow.at(this.dimension) !== rhsLow.at(this.dimension)) {\n return {\n lessThan: lhsLow.at(this.dimension) < rhsLow.at(this.dimension),\n comparable,\n };\n }\n\n const lhsFixed = lhs.fixedOrder();\n const rhsFixed = rhs.fixedOrder();\n const oneIsFixed = lhsFixed.isFixed || rhsFixed.isFixed;\n if (oneIsFixed && lhsFixed.order !== rhsFixed.order) {\n return { lessThan: lhsFixed.order < rhsFixed.order, comparable };\n }\n\n const lhsOrder = lhs.order();\n const rhsOrder = rhs.order();\n if (lhsOrder !== rhsOrder) {\n return { lessThan: lhsOrder < rhsOrder, comparable };\n }\n\n // Index into the PtOrder map using the original (un-shifted) point of the\n // one whose altDim is greater.\n const unchanged = lhsLow.at(altDim) > rhsLow.at(altDim) ? lhsLow : rhsLow;\n const lowOrder = this.orders.get(unchanged);\n if (!lowOrder) {\n // No order recorded for this point — fall back to altDim comparison.\n comparable = false;\n return { lessThan: lhsLow.at(altDim) < rhsLow.at(altDim), comparable };\n }\n const lhsPos = lowOrder.positionFor(this.dimension, lhs.connRef);\n const rhsPos = lowOrder.positionFor(this.dimension, rhs.connRef);\n if (lhsPos === -1 || rhsPos === -1) {\n comparable = false;\n return { lessThan: lhsLow.at(altDim) < rhsLow.at(altDim), comparable };\n }\n return { lessThan: lhsPos < rhsPos, comparable };\n }\n}\n\n// ─── linesort ─────────────────────────────────────────────────────────────────\n\n// Insertion-sort variant that tolerates partially-ordered comparisons.\n// Mirrors the C++ algorithm: segments that aren't comparable to anything in\n// the result list are deferred and retried later.\nfunction linesort(\n nudgeFinalSegments: boolean,\n origList: NudgingShiftSegment[],\n comparison: CmpLineOrder,\n): NudgingShiftSegment[] {\n // Merge end-segments of the same connector that should align.\n if (nudgeFinalSegments) {\n for (let i = 0; i < origList.length; i++) {\n for (let j = i + 1; j < origList.length; ) {\n const currSeg = origList[i];\n const otherSeg = origList[j];\n if (currSeg.shouldAlignWith(otherSeg, comparison.dimension)) {\n currSeg.mergeWith(otherSeg, comparison.dimension);\n origList.splice(j, 1);\n } else {\n j++;\n }\n }\n }\n }\n\n const resultList: NudgingShiftSegment[] = [];\n let origListSize = origList.length;\n let deferredN = 0;\n\n while (origList.length > 0) {\n const segment = origList.shift()!;\n\n // Find the insertion point.\n let allComparable = true;\n let insertIdx = resultList.length;\n for (let k = 0; k < resultList.length; k++) {\n const cmp = comparison.compare(segment, resultList[k]);\n allComparable = allComparable && cmp.comparable;\n if (cmp.comparable && cmp.lessThan) {\n insertIdx = k;\n break;\n }\n }\n\n if (resultList.length === 0 || allComparable || deferredN >= origListSize) {\n resultList.splice(insertIdx, 0, segment);\n deferredN = 0;\n origListSize = origList.length;\n } else {\n origList.push(segment);\n deferredN++;\n }\n }\n\n return resultList;\n}\n\n// ─── PotentialSegmentConstraint ───────────────────────────────────────────────\n\n//! A pair of variable indices marking a candidate \"potential\" equality\n//! constraint between two free segments. Used in the unifying pass to\n//! greedily glue free segments to the same position.\nexport class PotentialSegmentConstraint {\n index1: number;\n index2: number;\n vs: Variable[];\n\n constructor(index1: number, index2: number, vs: Variable[]) {\n this.index1 = index1;\n this.index2 = index2;\n this.vs = vs;\n }\n\n sepDistance(): number {\n if (!this.stillValid()) return 0;\n return Math.abs(\n this.vs[this.index1].finalPosition - this.vs[this.index2].finalPosition,\n );\n }\n\n stillValid(): boolean {\n return this.index1 !== this.index2;\n }\n\n rewriteIndex(oldIndex: number, newIndex: number): void {\n if (this.index1 === oldIndex) this.index1 = newIndex;\n if (this.index2 === oldIndex) this.index2 = newIndex;\n }\n\n // Comparator for sorting (smallest separation distance first).\n static compare(\n a: PotentialSegmentConstraint,\n b: PotentialSegmentConstraint,\n ): number {\n const da = a.sepDistance();\n const db = b.sepDistance();\n return da < db ? -1 : da > db ? 1 : 0;\n }\n}\n\n// ─── ImproveOrthogonalRoutes ──────────────────────────────────────────────────\n\nexport class ImproveOrthogonalRoutes {\n private m_router: Router;\n private m_point_orders: PtOrderMap;\n private m_shared_path_connectors_with_common_endpoints: UnsignedPairSet;\n private m_segment_list: NudgingShiftSegment[];\n\n constructor(router: Router) {\n this.m_router = router;\n this.m_point_orders = new Map();\n this.m_shared_path_connectors_with_common_endpoints = new UnsignedPairSet();\n this.m_segment_list = [];\n }\n\n execute() {\n this.m_shared_path_connectors_with_common_endpoints.clear();\n\n this.simplifyOrthogonalRoutes();\n\n // Build the connector-route checkpoint cache so we can check whether a\n // certain segment contains a checkpoint after route mutations.\n buildConnectorRouteCheckpointCache(this.m_router);\n\n // Unifying preprocessing — greedy free-segment co-position.\n if (\n this.m_router.options.performUnifyingNudgingPreprocessingStep &&\n this.m_router.params.fixedSharedPathPenalty === 0\n ) {\n for (let dimension = 0; dimension < 2; dimension++) {\n const justUnifying = true;\n this.m_segment_list = [];\n buildOrthogonalNudgingSegments(\n this.m_router,\n dimension,\n this.m_segment_list,\n );\n buildOrthogonalChannelInfo(\n this.m_router,\n dimension,\n this.m_segment_list,\n );\n this.nudgeOrthogonalRoutes(dimension, justUnifying);\n }\n }\n\n for (let dimension = 0; dimension < 2; dimension++) {\n this.m_point_orders = new Map();\n this.buildOrthogonalNudgingOrderInfo();\n this.m_segment_list = [];\n buildOrthogonalNudgingSegments(\n this.m_router,\n dimension,\n this.m_segment_list,\n );\n buildOrthogonalChannelInfo(\n this.m_router as never,\n dimension,\n this.m_segment_list,\n );\n this.nudgeOrthogonalRoutes(dimension);\n }\n\n this.simplifyOrthogonalRoutes();\n\n // C++ calls m_router->improveOrthogonalTopology() here — dropped (topology\n // hook not ported).\n clearConnectorRouteCheckpointCache(this.m_router);\n }\n\n private simplifyOrthogonalRoutes(): void {\n for (const conn of this.m_router.connRefs) {\n conn.set_route(conn.displayRoute().simplify());\n }\n }\n\n // Detects crossings between every pair of orthogonal connectors and\n // populates `m_point_orders` and (optionally)\n // `m_shared_path_connectors_with_common_endpoints`.\n private buildOrthogonalNudgingOrderInfo(): void {\n this.simplifyOrthogonalRoutes();\n\n // The C++ source tallies a `crossingsN` counter for debug printing; we\n // drop it but still need to walk every connector pair for the side\n // effects on m_point_orders and the shared-path set.\n const buildSharedPathInfo =\n !this.m_router.options.nudgeSharedPathsWithCommonEndPoint &&\n this.m_shared_path_connectors_with_common_endpoints.size() === 0;\n\n const connRefs = this.m_router.connRefs.slice();\n // Clone the routes — splitBranchingSegments mutates the polygons, but the\n // C++ `connRoutes[ind] = connRefs[ind]->displayRoute()` makes a copy via\n // Polygon copy-assignment, so we do the same here.\n const connRoutes: Polygon[] = connRefs.map((c) => c.displayRoute().clone());\n\n // Segment splitting.\n for (let i1 = 0; i1 < connRefs.length; i1++) {\n for (let i2 = 0; i2 < connRefs.length; i2++) {\n if (i1 === i2) continue;\n const route = connRoutes[i1];\n const route2 = connRoutes[i2];\n splitBranchingSegments(route2, true, route);\n }\n }\n\n // Crossing detection.\n for (let i1 = 0; i1 < connRefs.length; i1++) {\n const conn = connRefs[i1];\n for (let i2 = i1 + 1; i2 < connRefs.length; i2++) {\n const conn2 = connRefs[i2];\n const route = connRoutes[i1];\n const route2 = connRoutes[i2];\n let crossingFlags = 0;\n const cross = new ConnectorCrossings(route2, true, route, conn2, conn);\n cross.pointOrders = this.m_point_orders;\n for (let i = 1; i < route.size(); i++) {\n const finalSegment = i + 1 === route.size();\n cross.countForSegment(i, finalSegment);\n crossingFlags |= cross.crossingFlags;\n }\n if (\n buildSharedPathInfo &&\n crossingFlags & CROSSING_SHARES_PATH_AT_END\n ) {\n this.m_shared_path_connectors_with_common_endpoints.insert(\n new UnsignedPair(conn._id, conn2._id),\n );\n }\n }\n }\n }\n\n // Main nudging pass for one dimension.\n private nudgeOrthogonalRoutes(dimension: number, justUnifying = false): void {\n const nudgeFinalSegments =\n this.m_router.options.nudgeOrthogonalSegmentsConnectedToShapes;\n const nudgeSharedPathsWithCommonEnd =\n this.m_router.options.nudgeSharedPathsWithCommonEndPoint;\n const baseSepDist = this.m_router.params.idealNudgingDistance;\n if (baseSepDist < 0) {\n throw new Error('orthogonal: baseSepDist must be >= 0');\n }\n const reductionSteps = 10.0;\n\n while (this.m_segment_list.length > 0) {\n const currentSegment = this.m_segment_list[0];\n const currentRegion: NudgingShiftSegment[] = [currentSegment];\n this.m_segment_list.splice(0, 1);\n\n // Greedy region expansion — find every segment overlapping anyone\n // already in the region, restart from the beginning each time.\n let kIndex = 0;\n while (kIndex < this.m_segment_list.length) {\n let overlaps = false;\n for (const inRegion of currentRegion) {\n if (this.m_segment_list[kIndex].overlapsWith(inRegion, dimension)) {\n overlaps = true;\n break;\n }\n }\n if (overlaps) {\n currentRegion.push(this.m_segment_list[kIndex]);\n this.m_segment_list.splice(kIndex, 1);\n kIndex = 0;\n } else {\n kIndex++;\n }\n }\n\n let sortedRegion = currentRegion;\n if (!justUnifying) {\n const cmp = new CmpLineOrder(this.m_point_orders, dimension);\n sortedRegion = linesort(nudgeFinalSegments, currentRegion.slice(), cmp);\n }\n\n if (sortedRegion.length === 1) {\n if (sortedRegion[0].immovable() || justUnifying) {\n continue;\n }\n }\n\n // Build VPSC variables/constraints.\n const freeIndexes: number[] = [];\n const vs: Variable[] = [];\n const cs: Constraint[] = [];\n const gapcs: Constraint[] = [];\n const prevVars: NudgingShiftSegment[] = [];\n let sepDist = baseSepDist;\n\n for (const currSegment of sortedRegion) {\n currSegment.createSolverVariable(justUnifying);\n vs.push(currSegment.variable!);\n const index = vs.length - 1;\n\n if (justUnifying) {\n if (currSegment.variable!.weight === freeWeight) {\n freeIndexes.push(index);\n }\n prevVars.push(currSegment);\n continue;\n }\n\n // Channel boundary left.\n if (!currSegment.fixed) {\n if (currSegment.minSpaceLimit > -CHANNEL_MAX) {\n vs.push(\n new Variable(\n channelLeftID,\n currSegment.minSpaceLimit,\n fixedWeight,\n ),\n );\n cs.push(new Constraint(vs[vs.length - 1], vs[index], 0.0));\n }\n }\n\n // Constrain against previously-seen segments.\n for (const prevSeg of prevVars) {\n const prevVar = prevSeg.variable!;\n if (\n currSegment.overlapsWith(prevSeg, dimension) &&\n !(currSegment.fixed && prevSeg.fixed)\n ) {\n let thisSepDist = sepDist;\n let equality = false;\n if (currSegment.shouldAlignWith(prevSeg, dimension)) {\n thisSepDist = 0;\n equality = true;\n } else if (currSegment.canAlignWith(prevSeg, dimension)) {\n thisSepDist = 0;\n } else if (\n !nudgeSharedPathsWithCommonEnd &&\n this.m_shared_path_connectors_with_common_endpoints.has(\n new UnsignedPair(currSegment.connRef._id, prevSeg.connRef._id),\n )\n ) {\n thisSepDist = 0;\n equality = true;\n }\n const constraint = new Constraint(\n prevVar,\n vs[index],\n thisSepDist,\n equality,\n );\n cs.push(constraint);\n if (thisSepDist) gapcs.push(constraint);\n }\n }\n\n // Channel boundary right.\n if (!currSegment.fixed) {\n if (currSegment.maxSpaceLimit < CHANNEL_MAX) {\n vs.push(\n new Variable(\n channelRightID,\n currSegment.maxSpaceLimit,\n fixedWeight,\n ),\n );\n cs.push(new Constraint(vs[index], vs[vs.length - 1], 0.0));\n }\n }\n\n prevVars.push(currSegment);\n }\n\n // Potential constraints between free indexes (unifying pass only).\n const potentialConstraints: PotentialSegmentConstraint[] = [];\n if (justUnifying) {\n for (let p = 0; p < freeIndexes.length; p++) {\n for (let q = p + 1; q < freeIndexes.length; q++) {\n potentialConstraints.push(\n new PotentialSegmentConstraint(\n freeIndexes[p],\n freeIndexes[q],\n vs,\n ),\n );\n }\n }\n }\n\n // Solve repeatedly, either greedy-add (unifying) or reduce-separation\n // (nudging) until the constraint set is satisfied.\n let justAddedConstraint = false;\n let satisfied = false;\n\n type UnsatRange = [number, number];\n let unsatisfiedRanges: UnsatRange[] = [];\n\n // Defensive iteration cap — should never trigger but prevents pathological\n // input from infinite-looping.\n let iter = 0;\n const ITER_CAP = 200;\n\n do {\n iter++;\n if (iter > ITER_CAP) break;\n\n try {\n const f = new IncSolver(vs, cs);\n f.solve();\n } catch {\n // VPSC unsatisfiable — bail out of this region.\n break;\n }\n\n unsatisfiedRanges = [];\n satisfied = true;\n for (let i = 0; i < vs.length; i++) {\n if (vs[i].id === freeSegmentID) continue;\n if (Math.abs(vs[i].finalPosition - vs[i].desiredPosition) <= 0.0001)\n continue;\n satisfied = false;\n if (vs[i].id === channelLeftID) {\n if (\n unsatisfiedRanges.length === 0 ||\n unsatisfiedRanges[unsatisfiedRanges.length - 1][0] !==\n unsatisfiedRanges[unsatisfiedRanges.length - 1][1]\n ) {\n unsatisfiedRanges.push([i, i + 1]);\n }\n } else if (vs[i].id === channelRightID) {\n if (unsatisfiedRanges.length === 0) {\n if (i === 0 || vs[i - 1].id !== channelLeftID) {\n throw new Error('orthogonal: channelRight without channelLeft');\n }\n unsatisfiedRanges.push([i - 1, i]);\n } else {\n unsatisfiedRanges[unsatisfiedRanges.length - 1][1] = i;\n }\n } else if (vs[i].id === fixedSegmentID) {\n if (unsatisfiedRanges.length === 0) {\n unsatisfiedRanges.push([i, i]);\n } else {\n unsatisfiedRanges[unsatisfiedRanges.length - 1][1] = i;\n }\n }\n }\n\n if (justUnifying) {\n if (justAddedConstraint) {\n if (potentialConstraints.length === 0) {\n throw new Error('orthogonal: lost potentialConstraints front');\n }\n if (!satisfied) {\n // Roll back the just-added constraint.\n potentialConstraints.shift();\n cs.pop();\n } else {\n const pc = potentialConstraints[0]!;\n for (const it of potentialConstraints) {\n it.rewriteIndex(pc.index1, pc.index2);\n }\n potentialConstraints.shift();\n }\n }\n potentialConstraints.sort(PotentialSegmentConstraint.compare);\n justAddedConstraint = false;\n while (\n potentialConstraints.length > 0 &&\n !potentialConstraints[0].stillValid()\n ) {\n potentialConstraints.shift();\n }\n if (potentialConstraints.length > 0) {\n const pc = potentialConstraints[0];\n if (pc.index1 === pc.index2) {\n throw new Error('orthogonal: pc invariant');\n }\n cs.push(new Constraint(vs[pc.index1], vs[pc.index2], 0, true));\n satisfied = false;\n justAddedConstraint = true;\n }\n } else if (!satisfied) {\n if (unsatisfiedRanges.length === 0) {\n // Shouldn't happen; bail to avoid loop.\n break;\n }\n sepDist -= baseSepDist / reductionSteps;\n let withinUnsatisfied = false;\n let rangeIdx = 0;\n for (const constraint of cs) {\n if (rangeIdx >= unsatisfiedRanges.length) break;\n const range = unsatisfiedRanges[rangeIdx];\n if (constraint.left === vs[range[0]]) withinUnsatisfied = true;\n if (withinUnsatisfied && constraint.gap > 0) {\n constraint.gap = sepDist;\n }\n if (constraint.right === vs[range[1]]) {\n withinUnsatisfied = false;\n rangeIdx++;\n }\n }\n }\n } while (!satisfied && sepDist > 0.0001);\n\n if (satisfied) {\n for (const seg of sortedRegion) {\n seg.updatePositionsFromSolver(justUnifying);\n }\n }\n }\n }\n}\n\n// ─── Internal testing exports ─────────────────────────────────────────────────\n\nexport const _testing = {\n UnsignedPair,\n UnsignedPairSet,\n CmpIndexes,\n LineSegment,\n CmpLineOrder,\n PotentialSegmentConstraint,\n SegmentListWrapper,\n PosVertInf,\n intersectSegments,\n insideRectBounds,\n linesort,\n freeSegmentID,\n fixedSegmentID,\n channelLeftID,\n channelRightID,\n freeWeight,\n strongWeight,\n fixedWeight,\n VisDirNone,\n VisDirUp,\n VisDirDown,\n};\n","// Hyperedge represented as a tree of nodes and edges.\n//\n// Ports input/hyperedgetree.cpp and input/hyperedgetree.h. The C++ uses a\n// tree of `HyperedgeTreeNode` records linked together by `HyperedgeTreeEdge`\n// records. Hyperedge improvement transformations (shifting segments,\n// removing redundant junctions, rewriting connector endpoints) are applied\n// over this tree representation since it is far easier to manipulate than\n// a list of polylines.\n//\n// Each node carries a Point, an optional JunctionRef (when the node is a\n// junction between multiple segments), and a few flags used during route\n// reconstruction. Each edge tracks the ConnRef the segment will become and\n// whether the original connector route was fixed by the caller.\n//\n// Deviations from C++:\n// - Raw pointers become TS class instances; GC reclaims dropped subtrees.\n// - `std::list<HyperedgeTreeEdge *>` is a plain array; insertion order is\n// preserved by `push` / `splice`.\n// - Debug helpers (`outputEdgesExcept`, `outputNodesExcept`, `validateHyperedge`,\n// `setDebuggingOutput`) are dropped — they emit SVG/stderr only.\n// - `friend`-style access is modelled via `/** @internal */` comments rather\n// than visibility hacks.\n// - C++ output parameters (e.g. `JunctionRefList&`) are expressed by passing\n// in arrays the caller owns, matching the C++ usage exactly.\n//\n// Several structural interfaces are exported so callers can plug in their own\n// ConnRef / JunctionRef / Router types without an actual `import` cycle.\n\nimport { Edge } from './edge';\nimport { Point } from './geomtypes';\nimport { Junction } from './junction';\nimport type { Router } from './router';\nimport type { VertInf } from './vertex';\n\n// ─── Structural interfaces ───────────────────────────────────────────────────\n// We keep these as structural interfaces so hyperedgetree.ts can live\n// dependency-free of connector.ts / junction.ts / router.ts. The concrete\n// classes (ConnRef, JunctionRef, Router) all satisfy these by default.\n\n// ─── Type aliases ────────────────────────────────────────────────────────────\n\n//! Map from a junction to the tree node that represents it.\nexport type JunctionHyperedgeTreeNodeMap = Map<Junction, HyperedgeTreeNode>;\n\n//! Map from a VertInf to the tree node it became.\nexport type VertexNodeMap = Map<VertInf, HyperedgeTreeNode>;\n\n// ─── HyperedgeTreeNode ───────────────────────────────────────────────────────\n\n//! @brief A node in the hyperedge tree.\n//!\n//! Carries a position, optional junction, optional VertInf marker (used to\n//! identify terminals), and the list of edges incident on this node.\nexport class HyperedgeTreeNode {\n edges: HyperedgeTreeEdge[];\n junction: Junction | null;\n point: Point;\n //! VertInf representing the original endpoint of a connector that landed\n //! at this node. Used by buildHyperedgeTreeToRoot to remember terminals.\n finalVertex: VertInf | null;\n //! True if this terminal node is the source of its connector (vs target).\n isConnectorSource: boolean;\n //! True if this node is the extra dummy endpoint used for connection-pin\n //! routing — removed from the final route when present.\n isPinDummyEndpoint: boolean;\n //! Used during recursive traversals to detect cycles.\n visited: boolean;\n\n constructor() {\n this.edges = [];\n this.junction = null;\n this.point = new Point(0, 0);\n this.finalVertex = null;\n this.isConnectorSource = false;\n this.isPinDummyEndpoint = false;\n this.visited = false;\n }\n\n //! Traverses the tree and writes each branch's path back to its connector's\n //! display route. `pass === 0` clears each connector's route; `pass === 1`\n //! actually writes the points.\n writeEdgesToConns(\n ignored: HyperedgeTreeEdge | null,\n pass: number,\n setRouteOps?: {\n clearDisplayRoute: (conn: Edge) => void;\n pushPoint: (conn: Edge, point: Point) => void;\n reverseRoute: (conn: Edge) => void;\n popPoint: (conn: Edge) => void;\n routeIsEmpty: (conn: Edge) => boolean;\n destinationJunction: (conn: Edge) => Junction | null;\n },\n ): void {\n for (const curr of this.edges) {\n if (curr !== ignored) {\n curr.writeEdgesToConns(this, pass, setRouteOps);\n }\n }\n }\n\n //! Traverses the tree from a junction outwards, creating fresh ConnRefs\n //! for each branch. Each new connector's src endpoint is the junction\n //! we started at; tar endpoint is set when we reach the next junction or\n //! a terminal.\n //!\n //! The caller supplies a `connFactory` that creates a fresh connector\n //! attached to the supplied junction; this keeps hyperedgetree.ts free of\n //! a real ConnRef dependency.\n addConns(\n ignored: HyperedgeTreeEdge | null,\n router: Router,\n oldConns: Edge[],\n conn: Edge | null,\n connFactory: (junction: Junction) => Edge,\n setConnEndAtTerminal: (\n conn: Edge,\n finalVertex: VertInf,\n oldConns: Edge[],\n ) => void,\n setConnEndAtJunction: (conn: Edge, junction: Junction) => void,\n ): void {\n // If no connector is set, then we must be starting off at a junction.\n if (!conn && !this.junction) {\n throw new Error('HyperedgeTreeNode.addConns: conn or junction required');\n }\n\n for (const curr of this.edges) {\n if (curr !== ignored) {\n let currConn = conn;\n if (this.junction) {\n // Starting along a fresh connector from this junction.\n currConn = connFactory(this.junction);\n }\n // Set the connector for this edge.\n curr.conn = currConn;\n // Recurse.\n curr.addConns(\n this,\n router,\n oldConns,\n connFactory,\n setConnEndAtTerminal,\n setConnEndAtJunction,\n );\n }\n }\n }\n\n //! Traverses the tree and rewrites connector ConnEnds whose junction\n //! may have changed during hyperedge improvement. `forward` tracks the\n //! traversal direction relative to a connector's src/tar orientation.\n //!\n //! The caller supplies `getEnds`, `getEndJunction`, and\n //! `setEndToJunction` callbacks so we don't depend on ConnRef directly.\n updateConnEnds(\n ignored: HyperedgeTreeEdge | null,\n forward: boolean,\n changedConns: Edge[],\n getEnds: (conn: Edge) => {\n srcJunction: Junction | null;\n tarJunction: Junction | null;\n srcIsEndpointOrEmpty: boolean;\n tarIsEndpointOrEmpty: boolean;\n },\n setEndToJunction: (conn: Edge, isSrc: boolean, junction: Junction) => void,\n ): void {\n for (const edge of this.edges) {\n if (edge === ignored) continue;\n let next = forward;\n if (this.junction && edge.conn) {\n // Starting traversal along a fresh connector at this junction.\n next = travellingForwardOnConnector(edge.conn, this.junction, getEnds);\n const ends = getEnds(edge.conn);\n const existingEndJunction = next ? ends.srcJunction : ends.tarJunction;\n if (existingEndJunction !== this.junction) {\n setEndToJunction(edge.conn, next, this.junction);\n changedConns.push(edge.conn);\n }\n }\n edge.updateConnEnds(this, next, changedConns, getEnds, setEndToJunction);\n }\n }\n\n //! Traverses the tree and accumulates the JunctionRefs and ConnRefs that\n //! make up the hyperedge. Used by HyperedgeImprover to know what objects\n //! are affected by a re-route.\n listJunctionsAndConnectors(\n ignored: HyperedgeTreeEdge | null,\n junctions: Junction[],\n connectors: Edge[],\n ): void {\n if (this.junction) {\n junctions.push(this.junction);\n }\n for (const curr of this.edges) {\n if (curr !== ignored) {\n curr.listJunctionsAndConnectors(this, junctions, connectors);\n }\n }\n }\n\n //! Returns true if this node cannot be moved during hyperedge improvement.\n //! Conditions: it has only one edge (a terminal), its junction is fixed.\n isImmovable(): boolean {\n if (\n this.edges.length === 1 ||\n (this.junction && this.junction.positionFixed())\n ) {\n return true;\n }\n return false;\n }\n\n //! Recursively deletes the subtree on the other side of every edge\n //! except `ignored`. Used to tear down a hyperedge tree. TS doesn't\n //! need to free anything; we simply detach edges so GC can collect them.\n deleteEdgesExcept(ignored: HyperedgeTreeEdge | null): void {\n for (const curr of this.edges) {\n if (curr !== ignored) {\n curr.deleteNodesExcept(this);\n }\n }\n this.edges = [];\n }\n\n //! Removes a specific edge from this node's edge list (all occurrences).\n disconnectEdge(edge: HyperedgeTreeEdge): void {\n for (let i = this.edges.length - 1; i >= 0; i--) {\n if (this.edges[i] === edge) {\n this.edges.splice(i, 1);\n }\n }\n }\n\n //! Moves every edge attached to `oldNode` to be attached to this node\n //! instead. Used when collapsing two coincident nodes into one.\n spliceEdgesFrom(oldNode: HyperedgeTreeNode): void {\n if (oldNode === this) {\n throw new Error(\n 'HyperedgeTreeNode.spliceEdgesFrom: cannot splice from self',\n );\n }\n while (oldNode.edges.length > 0) {\n // replaceNode mutates oldNode.edges, so we always look at index 0.\n oldNode.edges[0].replaceNode(oldNode, this);\n }\n }\n}\n\n// ─── HyperedgeTreeEdge ───────────────────────────────────────────────────────\n\n//! @brief An edge in the hyperedge tree. Connects exactly two nodes\n//! and tracks the connector this segment will become.\nexport class HyperedgeTreeEdge {\n //! Pair of endpoint nodes; conventionally `first` is the \"from\" side\n //! when traversing. Either can be null briefly during disconnect.\n ends: [HyperedgeTreeNode | null, HyperedgeTreeNode | null];\n conn: Edge | null;\n\n constructor(\n node1: HyperedgeTreeNode,\n node2: HyperedgeTreeNode,\n conn: Edge | null,\n ) {\n this.ends = [node1, node2];\n this.conn = conn;\n node1.edges.push(this);\n node2.edges.push(this);\n }\n\n //! Returns the node at the other end from `from`.\n followFrom(from: HyperedgeTreeNode): HyperedgeTreeNode {\n if (this.ends[0] === from) {\n return this.ends[1]!;\n }\n return this.ends[0]!;\n }\n\n //! True when both endpoints share the same position.\n zeroLength(): boolean {\n return this.ends[0]!.point.eq(this.ends[1]!.point);\n }\n\n //! True when both endpoints have the same coordinate along `dimension`\n //! (i.e. the edge is axis-aligned in that dimension).\n hasOrientation(dimension: number): boolean {\n return (\n this.ends[0]!.point.at(dimension) === this.ends[1]!.point.at(dimension)\n );\n }\n\n //! Replaces `oldNode` with `newNode` on whichever side it appears.\n //! `oldNode` is detached and `newNode` gains the edge in its list.\n replaceNode(oldNode: HyperedgeTreeNode, newNode: HyperedgeTreeNode): void {\n if (this.ends[0] === oldNode) {\n oldNode.disconnectEdge(this);\n newNode.edges.push(this);\n this.ends[0] = newNode;\n } else if (this.ends[1] === oldNode) {\n oldNode.disconnectEdge(this);\n newNode.edges.push(this);\n this.ends[1] = newNode;\n }\n }\n\n //! Traverses outward from `ignored`, writing the segment between this\n //! edge's two endpoints into the appropriate connector's display route.\n //!\n //! `pass === 0` clears each connector's route; `pass === 1` writes points.\n //! `setRouteOps` provides connector-side primitives.\n writeEdgesToConns(\n ignored: HyperedgeTreeNode,\n pass: number,\n setRouteOps?: {\n clearDisplayRoute: (conn: Edge) => void;\n pushPoint: (conn: Edge, point: Point) => void;\n reverseRoute: (conn: Edge) => void;\n popPoint: (conn: Edge) => void;\n routeIsEmpty: (conn: Edge) => boolean;\n destinationJunction: (conn: Edge) => Junction | null;\n },\n ): void {\n if (this.ends[0] === null || this.ends[1] === null) {\n throw new Error(\n 'HyperedgeTreeEdge.writeEdgesToConns: edge has null endpoint',\n );\n }\n if (this.conn === null) {\n throw new Error('HyperedgeTreeEdge.writeEdgesToConns: missing conn');\n }\n\n const prevNode = ignored === this.ends[0] ? this.ends[0] : this.ends[1];\n const nextNode = ignored === this.ends[0] ? this.ends[1] : this.ends[0];\n\n if (setRouteOps) {\n if (pass === 0) {\n setRouteOps.clearDisplayRoute(this.conn);\n } else if (pass === 1) {\n if (setRouteOps.routeIsEmpty(this.conn)) {\n setRouteOps.pushPoint(this.conn, prevNode.point);\n }\n setRouteOps.pushPoint(this.conn, nextNode.point);\n\n const nextEdgeCount = nextNode.edges.length;\n if (nextEdgeCount !== 2) {\n // Done writing this connector.\n let shouldReverse = false;\n if (nextEdgeCount === 1) {\n // Terminal.\n if (nextNode.isConnectorSource) shouldReverse = true;\n if (nextNode.isPinDummyEndpoint) {\n // Hyperedge has an extra segment leading into the dummy\n // pin used for connection-pin routing — strip it.\n setRouteOps.popPoint(this.conn);\n if (prevNode.point.eq(nextNode.point)) {\n // Duplicated dummy point: remove the second one too.\n setRouteOps.popPoint(this.conn);\n }\n }\n } else {\n // nextEdgeCount > 2 — between two junctions.\n const correctEnd = setRouteOps.destinationJunction(this.conn);\n if (nextNode.junction !== correctEnd) shouldReverse = true;\n }\n if (shouldReverse) setRouteOps.reverseRoute(this.conn);\n }\n }\n }\n\n nextNode.writeEdgesToConns(this, pass, setRouteOps);\n }\n\n //! Traverses outwards through this edge, creating connectors as the\n //! traversal crosses junctions and terminals. See\n //! HyperedgeTreeNode.addConns for the callback shape.\n addConns(\n ignored: HyperedgeTreeNode,\n router: Router,\n oldConns: Edge[],\n connFactory: (junction: Junction) => Edge,\n setConnEndAtTerminal: (\n conn: Edge,\n finalVertex: VertInf,\n oldConns: Edge[],\n ) => void,\n setConnEndAtJunction: (conn: Edge, junction: Junction) => void,\n ): void {\n if (this.conn === null) {\n throw new Error('HyperedgeTreeEdge.addConns: missing conn');\n }\n\n let endNode: HyperedgeTreeNode | null = null;\n if (this.ends[0] && this.ends[0] !== ignored) {\n endNode = this.ends[0];\n this.ends[0].addConns(\n this,\n router,\n oldConns,\n this.conn,\n connFactory,\n setConnEndAtTerminal,\n setConnEndAtJunction,\n );\n }\n if (this.ends[1] && this.ends[1] !== ignored) {\n endNode = this.ends[1];\n this.ends[1].addConns(\n this,\n router,\n oldConns,\n this.conn,\n connFactory,\n setConnEndAtTerminal,\n setConnEndAtJunction,\n );\n }\n\n if (endNode && endNode.finalVertex) {\n // Reached a terminal — let the caller wire the ConnEnd.\n setConnEndAtTerminal(this.conn, endNode.finalVertex, oldConns);\n } else if (endNode && endNode.junction) {\n // Reached the next junction.\n setConnEndAtJunction(this.conn, endNode.junction);\n }\n }\n\n //! Traverses outwards, rewriting connector ConnEnds whose junction\n //! has been adjusted by hyperedge improvement. See\n //! HyperedgeTreeNode.updateConnEnds for callback semantics.\n updateConnEnds(\n ignored: HyperedgeTreeNode,\n forward: boolean,\n changedConns: Edge[],\n getEnds: (conn: Edge) => {\n srcJunction: Junction | null;\n tarJunction: Junction | null;\n srcIsEndpointOrEmpty: boolean;\n tarIsEndpointOrEmpty: boolean;\n },\n setEndToJunction: (conn: Edge, isSrc: boolean, junction: Junction) => void,\n ): void {\n let endNode: HyperedgeTreeNode | null = null;\n if (this.ends[0] && this.ends[0] !== ignored) {\n endNode = this.ends[0];\n this.ends[0].updateConnEnds(\n this,\n forward,\n changedConns,\n getEnds,\n setEndToJunction,\n );\n }\n if (this.ends[1] && this.ends[1] !== ignored) {\n endNode = this.ends[1];\n this.ends[1].updateConnEnds(\n this,\n forward,\n changedConns,\n getEnds,\n setEndToJunction,\n );\n }\n\n if (endNode && endNode.junction && this.conn) {\n // Reached a junction at the end of this connector that isn't the\n // hyperedge endpoint. Rewrite the tar/src ConnEnd as needed.\n const ends = getEnds(this.conn);\n const existingEndJunction = forward ? ends.tarJunction : ends.srcJunction;\n if (existingEndJunction !== endNode.junction) {\n setEndToJunction(this.conn, !forward, endNode.junction);\n if (\n changedConns.length === 0 ||\n changedConns[changedConns.length - 1] !== this.conn\n ) {\n changedConns.push(this.conn);\n }\n }\n }\n }\n\n //! Traverses outwards, accumulating the JunctionRefs and ConnRefs in\n //! the hyperedge. Records the connector once per traversal.\n listJunctionsAndConnectors(\n ignored: HyperedgeTreeNode,\n junctions: Junction[],\n connectors: Edge[],\n ): void {\n if (this.conn && !connectors.includes(this.conn)) {\n connectors.push(this.conn);\n }\n if (this.ends[0] !== ignored && this.ends[0]) {\n this.ends[0].listJunctionsAndConnectors(this, junctions, connectors);\n } else if (this.ends[1] !== ignored && this.ends[1]) {\n this.ends[1].listJunctionsAndConnectors(this, junctions, connectors);\n }\n }\n\n //! Splits this edge by inserting a fresh node at `point`. The existing\n //! edge stays attached to `source` on one side and to the new node on\n //! the other; a fresh edge connects the new node to the original target.\n //!\n //! Returns the newly created node so callers can position more edges off\n //! it (the C++ creates the new HyperedgeTreeEdge purely for its side\n //! effect — the constructor wires itself into both endpoint lists).\n splitFromNodeAtPoint(\n source: HyperedgeTreeNode,\n point: Point,\n ): HyperedgeTreeNode {\n // Make `source` the first of the two nodes.\n if (this.ends[1] === source) {\n const tmp = this.ends[0];\n this.ends[0] = this.ends[1];\n this.ends[1] = tmp;\n }\n if (this.ends[0] !== source) {\n throw new Error(\n 'HyperedgeTreeEdge.splitFromNodeAtPoint: source is not an endpoint',\n );\n }\n\n const target = this.ends[1]!;\n\n // Create the new node at the split point.\n const split = new HyperedgeTreeNode();\n split.point = new Point(point.x, point.y);\n\n // New edge between split and the original target.\n new HyperedgeTreeEdge(split, target, this.conn);\n\n // Detach the current edge from target and reattach it to split.\n target.disconnectEdge(this);\n this.ends[1] = split;\n split.edges.push(this);\n\n return split;\n }\n\n //! Detaches this edge from both endpoints and clears its `ends` array.\n disconnectEdge(): void {\n if (this.ends[0] === null || this.ends[1] === null) {\n throw new Error(\n 'HyperedgeTreeEdge.disconnectEdge: edge already disconnected',\n );\n }\n this.ends[0].disconnectEdge(this);\n this.ends[1].disconnectEdge(this);\n this.ends[0] = null;\n this.ends[1] = null;\n }\n\n //! Recursively detaches nodes on the other side of this edge (except\n //! `ignored`). TS doesn't need to free anything; we null out the\n //! pointers so GC reclaims the detached subtree.\n deleteNodesExcept(ignored: HyperedgeTreeNode | null): void {\n if (this.ends[0] && this.ends[0] !== ignored) {\n this.ends[0].deleteEdgesExcept(this);\n }\n this.ends[0] = null;\n if (this.ends[1] && this.ends[1] !== ignored) {\n this.ends[1].deleteEdgesExcept(this);\n }\n this.ends[1] = null;\n }\n}\n\n// ─── travellingForwardOnConnector ─────────────────────────────────────────────\n// Helper used by updateConnEnds to determine whether traversal aligns with the\n// connector's natural src→tar direction. C++ logic preserved.\n\nfunction travellingForwardOnConnector(\n conn: Edge,\n junction: Junction,\n getEnds: (conn: Edge) => {\n srcJunction: Junction | null;\n tarJunction: Junction | null;\n srcIsEndpointOrEmpty: boolean;\n tarIsEndpointOrEmpty: boolean;\n },\n): boolean {\n const ends = getEnds(conn);\n if (ends.srcJunction === junction) return true;\n if (ends.tarJunction === junction) return false;\n if (!ends.srcIsEndpointOrEmpty) return false;\n if (!ends.tarIsEndpointOrEmpty) return true;\n return true;\n}\n","// Minimum Terminal Spanning Tree construction for hyperedge routing.\n//\n// Ports input/mtst.cpp and input/mtst.h. The algorithm builds a Steiner-like\n// tree spanning a set of terminal vertices using:\n// - An *extended Dijkstra* phase that grows a shortest-path forest from\n// each terminal in parallel; and\n// - An *extended Kruskal* phase that bridges trees together via the\n// cheapest cross-tree edges.\n//\n// Two construction modes are exposed:\n// - `constructInterleaved` (heuristic 2 from the EBOARST paper) — preferred.\n// - `constructSequential` (heuristic 1 from the EBOARST paper).\n//\n// The constructed tree is returned as a HyperedgeTreeNode rooted at\n// `rootJunction()`.\n//\n// Deviations from C++:\n// - Raw `VertInf **` root pointers become shared `{ value }` boxes;\n// `VertInf.makeTreeRootPointer` already provides this on the TS side.\n// - `std::priority_queue` becomes a small intrusive binary heap; mtst.cpp\n// calls `std::make_heap` after in-place edits, which we mirror with a\n// `rebuild()` helper.\n// - `std::list` becomes a TS array.\n// - `DBL_MAX` becomes `Number.MAX_VALUE`.\n// - All debug-only blocks (`DEBUGHANDLER`, `MAJOR_HYPEREDGE_IMPROVEMENT_DEBUG`)\n// and timing macros (`TIMER_START`/`TIMER_STOP`) are dropped.\n// - `drawForest` and other diagnostic SVG outputs are dropped.\n// - The destructor (which deletes the tree) is *not* automatic in TS — call\n// `dispose()` if you want eager cleanup, otherwise rely on GC.\n//\n// The Router is modelled as a small structural interface (MtstRouter) so the\n// module doesn't pull in router.ts. Likewise a JunctionRef and ConnRef are\n// only referenced as opaque structural types via hyperedgetree.ts.\n\nimport { Point } from './geomtypes';\nimport { VertInf } from './vertex';\nimport { EdgeInf } from './graph';\nimport { colinear } from './geometry';\nimport {\n HyperedgeTreeEdge,\n HyperedgeTreeNode,\n type JunctionHyperedgeTreeNodeMap,\n type VertexNodeMap,\n} from './hyperedgetree';\nimport type { Router } from './router';\nimport { Junction } from './junction';\n\n// ─── Type aliases ────────────────────────────────────────────────────────────\n\nexport type VertexSet = Set<VertInf>;\nexport type VertexSetList = VertexSet[];\nexport type VertexPair = [VertInf, VertInf];\n\n// (Edge, partner) pair used by the orthogonal-edge traversal in heuristic 2.\ntype LayeredOrthogonalEdge = [EdgeInf, VertInf];\ntype LayeredOrthogonalEdgeList = LayeredOrthogonalEdge[];\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\n// Hyperedge tree's tree-root pointer is a shared { value: VertInf | null }\n// box. This is the TS analogue of `VertInf **` from C++.\ntype RootPointer = { value: VertInf | null };\n\n// ─── Binary heap for vertex / edge priority queues ───────────────────────────\n\nclass BinaryHeap<T> {\n arr: T[] = [];\n private less: (a: T, b: T) => boolean;\n\n // `less(a, b) === true` means `a` outranks `b` (closer to the top).\n constructor(less: (a: T, b: T) => boolean) {\n this.less = less;\n }\n\n size(): number {\n return this.arr.length;\n }\n\n empty(): boolean {\n return this.arr.length === 0;\n }\n\n front(): T {\n return this.arr[0];\n }\n\n push(v: T): void {\n this.arr.push(v);\n this.bubbleUp(this.arr.length - 1);\n }\n\n pop(): T {\n const top = this.arr[0];\n const last = this.arr.pop()!;\n if (this.arr.length > 0) {\n this.arr[0] = last;\n this.bubbleDown(0);\n }\n return top;\n }\n\n // Rebuild from arbitrary array contents (std::make_heap equivalent).\n rebuild(): void {\n for (let i = (this.arr.length >> 1) - 1; i >= 0; i--) {\n this.bubbleDown(i);\n }\n }\n\n // Replace the underlying array (and re-heapify).\n replaceWith(items: T[]): void {\n this.arr = items;\n this.rebuild();\n }\n\n contains(v: T): boolean {\n return this.arr.includes(v);\n }\n\n private bubbleUp(i: number): void {\n while (i > 0) {\n const parent = (i - 1) >> 1;\n if (this.less(this.arr[i], this.arr[parent])) {\n const tmp = this.arr[i];\n this.arr[i] = this.arr[parent];\n this.arr[parent] = tmp;\n i = parent;\n } else break;\n }\n }\n\n private bubbleDown(i: number): void {\n const n = this.arr.length;\n while (true) {\n const l = i * 2 + 1;\n const r = i * 2 + 2;\n let best = i;\n if (l < n && this.less(this.arr[l], this.arr[best])) best = l;\n if (r < n && this.less(this.arr[r], this.arr[best])) best = r;\n if (best === i) break;\n const tmp = this.arr[i];\n this.arr[i] = this.arr[best];\n this.arr[best] = tmp;\n i = best;\n }\n }\n}\n\n// Heap comparators (C++ priority queues are max-heaps; \"lower\" cost wins by\n// reversing the comparison, matching `a > b` returns from `HeapCmpVertInf`).\nfunction vertHeapLess(a: VertInf, b: VertInf): boolean {\n return a.sptfDist < b.sptfDist;\n}\n\nfunction edgeHeapLess(a: EdgeInf, b: EdgeInf): boolean {\n return a.mtstDist() < b.mtstDist();\n}\n\n// ─── MinimumTerminalSpanningTree ─────────────────────────────────────────────\n\n//! @brief Builds a minimum terminal spanning tree for a set of terminal\n//! vertices.\nexport class MinimumTerminalSpanningTree {\n private router: Router;\n private terminals: VertexSet;\n private origTerminals: VertexSet;\n private hyperedgeTreeJunctions: JunctionHyperedgeTreeNodeMap | null;\n\n private nodes: VertexNodeMap;\n private m_rootJunction: HyperedgeTreeNode | null;\n private bendPenalty: number;\n private allsets: VertexSetList;\n private extraVertices: VertInf[];\n private rootVertexPointers: RootPointer[];\n\n // Heaps used by extended Dijkstra (vHeap) and extended Kruskal (beHeap).\n private vHeap: BinaryHeap<VertInf>;\n private beHeap: BinaryHeap<EdgeInf>;\n\n constructor(\n router: Router,\n terminals: VertexSet,\n hyperedgeTreeJunctions: JunctionHyperedgeTreeNodeMap | null = null,\n ) {\n this.router = router;\n this.terminals = new Set(terminals);\n this.origTerminals = new Set();\n this.hyperedgeTreeJunctions = hyperedgeTreeJunctions;\n\n this.nodes = new Map();\n this.m_rootJunction = null;\n this.bendPenalty = 2000;\n this.allsets = [];\n this.extraVertices = [];\n this.rootVertexPointers = [];\n\n this.vHeap = new BinaryHeap(vertHeapLess);\n this.beHeap = new BinaryHeap(edgeHeapLess);\n }\n\n //! Returns the root junction node of the constructed tree (null until\n //! construct{Sequential,Interleaved}() runs).\n rootJunction(): HyperedgeTreeNode | null {\n return this.m_rootJunction;\n }\n\n //! Tears down the constructed hyperedge tree subtree (callers may instead\n //! rely on GC; this exists to mirror the C++ destructor).\n dispose(): void {\n if (this.m_rootJunction) {\n this.m_rootJunction.deleteEdgesExcept(null);\n this.m_rootJunction = null;\n }\n }\n\n // ─── Disjoint-set bookkeeping ──────────────────────────────────────────────\n\n private makeSet(vertex: VertInf): void {\n const newSet: VertexSet = new Set();\n newSet.add(vertex);\n this.allsets.push(newSet);\n }\n\n private findSet(vertex: VertInf): number {\n for (let i = 0; i < this.allsets.length; i++) {\n if (this.allsets[i].has(vertex)) return i;\n }\n return -1;\n }\n\n private unionSets(i1: number, i2: number): void {\n const s1 = this.allsets[i1];\n const s2 = this.allsets[i2];\n const merged: VertexSet = new Set(s1);\n for (const v of s2) merged.add(v);\n // Erase higher index first so the lower stays valid.\n const hi = Math.max(i1, i2);\n const lo = Math.min(i1, i2);\n this.allsets.splice(hi, 1);\n this.allsets.splice(lo, 1);\n this.allsets.push(merged);\n }\n\n // ─── HyperedgeTreeNode bookkeeping ─────────────────────────────────────────\n\n //! Returns the HyperedgeTreeNode for a given vertex, creating it if needed.\n //! When two vertices end up at the same node, that node becomes a junction.\n //! Also wires a fresh HyperedgeTreeEdge to `prevNode` if supplied.\n private addNode(\n vertex: VertInf,\n prevNode: HyperedgeTreeNode | null,\n ): HyperedgeTreeNode {\n let node: HyperedgeTreeNode;\n const existing = this.nodes.get(vertex);\n if (!existing) {\n const newNode = new HyperedgeTreeNode();\n newNode.point = new Point(vertex.point.x, vertex.point.y);\n this.nodes.set(vertex, newNode);\n node = newNode;\n } else {\n const junctionNode = existing;\n if (junctionNode.junction === null) {\n // Promote this node into a junction.\n let junction = new Junction(\n this.router,\n new Point(vertex.point.x, vertex.point.y),\n );\n this.router.addJunction(junction);\n junctionNode.junction = junction;\n\n if (this.m_rootJunction === null) {\n // Remember the first junction node, used to traverse the tree\n // when adding connectors and ConnEnds later.\n this.m_rootJunction = junctionNode;\n }\n }\n node = junctionNode;\n }\n\n if (prevNode) {\n // Wire prevNode → node. HyperedgeTreeEdge's constructor self-attaches.\n new HyperedgeTreeEdge(prevNode, node, null);\n }\n\n return node;\n }\n\n //! Walks backwards along pathNext links, materialising HyperedgeTreeNodes\n //! and edges as it goes. Stops when it reaches a junction or terminal.\n private buildHyperedgeTreeToRoot(\n currVert: VertInf | null,\n prevNode: HyperedgeTreeNode | null,\n prevVert: VertInf,\n markEdges = false,\n ): void {\n if (prevNode && prevNode.junction) {\n // Reached a junction; stop.\n return;\n }\n // If currVert is null on entry (terminal had no pathNext), the loop\n // simply doesn't run — mirroring the C++ COLA_ASSERT-less release path.\n\n while (currVert) {\n const currentNode = this.addNode(currVert, prevNode);\n\n if (markEdges) {\n let edge = prevVert.hasNeighbour(currVert) as EdgeInf | null;\n if (edge === null && currVert.isDimensionChangePartner) {\n const modCurr = currVert.isDimensionChangePartner\n ? (currVert.orthogonalPartner ?? currVert)\n : currVert;\n const modPrev = prevVert.isDimensionChangePartner\n ? (prevVert.orthogonalPartner ?? prevVert)\n : prevVert;\n edge = modPrev.hasNeighbour(modCurr) as EdgeInf | null;\n }\n if (edge) {\n edge.setHyperedgeSegment(true);\n }\n }\n\n if (currentNode.junction) {\n // Reached a junction; stop.\n break;\n }\n\n if (currVert.pathNext === null) {\n // Hyperedge terminal — record the vertex so we can later wire a\n // proper ConnEnd for the connector.\n currentNode.finalVertex = currVert;\n }\n\n if (currVert.isDummyPinHelper) {\n currentNode.isPinDummyEndpoint = true;\n }\n\n prevNode = currentNode;\n prevVert = currVert;\n currVert = currVert.pathNext;\n }\n }\n\n //! Resets sptfDist and treeRootPointer for every vertex on the pathNext\n //! chain starting at `currVert`. Returns the old tree-root pointer for\n //! the first vertex that already had sptfDist === 0.\n private resetDistsForPath(\n currVert: VertInf,\n newRootVertPtr: RootPointer,\n ): RootPointer | null {\n if (!currVert) {\n throw new Error('resetDistsForPath: currVert must not be null');\n }\n\n let cv: VertInf | null = currVert;\n while (cv) {\n if (cv.sptfDist === 0) {\n const oldTreeRootPtr = cv.treeRootPointer();\n this.rewriteRestOfHyperedge(cv, newRootVertPtr);\n return oldTreeRootPtr;\n }\n cv.sptfDist = 0;\n cv.setTreeRootPointer(newRootVertPtr);\n this.terminals.add(cv);\n cv = cv.pathNext;\n }\n throw new Error('resetDistsForPath: walked off the end');\n }\n\n //! Recursively marks the rest of an existing hyperedge with the new root\n //! pointer so all vertices on a freshly-committed branch share one root.\n private rewriteRestOfHyperedge(\n vert: VertInf,\n newTreeRootPtr: RootPointer,\n ): void {\n vert.setTreeRootPointer(newTreeRootPtr);\n\n const edgeList = this.getOrthogonalEdgesFromVertex(vert, null);\n for (const [, v] of edgeList) {\n if (v.treeRootPointer() === newTreeRootPtr) continue;\n if (v.sptfDist === 0) {\n this.rewriteRestOfHyperedge(v, newTreeRootPtr);\n }\n }\n }\n\n // ─── Orthogonal partner & edge enumeration ─────────────────────────────────\n\n //! Creates (if necessary) and returns the dummy orthogonal partner for a\n //! given vertex. The partner sits at the same point but is on a different\n //! \"layer\" — turning between the two layers costs `penalty` (default\n //! bendPenalty). This models the rectilinear bend cost.\n private orthogonalPartner(vert: VertInf, penalty = 0): VertInf {\n if (penalty === 0) penalty = this.bendPenalty;\n if (vert.orthogonalPartner === null) {\n // Synthetic partner; objID=0 / vn=0 is the conventional \"no owner\"\n // identity. The `isDimensionChangePartner` flag is what downstream\n // checks (was `id.eq(dimensionChangeVertexID)` in the pre-Stage-5\n // code). Not added to the router's vertex list — this is a transient\n // bookkeeping vertex used only inside the MTST construction.\n const partner = new VertInf(0, 0, vert.point, {\n isDimensionChangePartner: true,\n });\n vert.orthogonalPartner = partner;\n partner.orthogonalPartner = vert;\n this.extraVertices.push(partner);\n const extraEdge = new EdgeInf(partner, vert, this.router);\n extraEdge.setDist(penalty);\n }\n return vert.orthogonalPartner;\n }\n\n //! Removes bridging edges from `beHeap` whose endpoints no longer connect\n //! distinct trees or whose roots have been pruned.\n private removeInvalidBridgingEdges(): void {\n const valid: EdgeInf[] = [];\n for (const e of this.beHeap.arr) {\n const ends = this.realVerticesCountingPartners(e);\n const r1 = ends[0].treeRoot();\n const r2 = ends[1].treeRoot();\n const ok =\n r1 !== r2 &&\n r1 !== null &&\n r2 !== null &&\n this.origTerminals.has(r1) &&\n this.origTerminals.has(r2);\n if (ok) valid.push(e);\n }\n this.beHeap.replaceWith(valid);\n }\n\n //! Returns every orthogonal edge incident on `vert`, paired with the\n //! \"partner\" vertex on the other side (which may be `vert`'s real\n //! neighbour or its orthogonal partner depending on layer). Pre-computes\n //! the orthogonal partner if not present.\n private getOrthogonalEdgesFromVertex(\n vert: VertInf,\n prev: VertInf | null,\n ): LayeredOrthogonalEdgeList {\n const edgeList: LayeredOrthogonalEdgeList = [];\n if (!vert) throw new Error('getOrthogonalEdgesFromVertex: vert required');\n\n const penalty = prev === null ? 0.1 : 0;\n this.orthogonalPartner(vert, penalty);\n\n const isRealVert = !vert.isDimensionChangePartner;\n const realVert = isRealVert ? vert : this.orthogonalPartner(vert);\n\n for (const edgeLike of realVert.orthogVisList) {\n const edge = edgeLike as EdgeInf;\n const other = edge.otherVert(realVert);\n\n if (other === this.orthogonalPartner(realVert)) {\n const partner = isRealVert ? other : this.orthogonalPartner(other);\n if (partner !== prev) {\n edgeList.push([edge, partner]);\n }\n continue;\n }\n\n const partner = isRealVert ? other : this.orthogonalPartner(other);\n\n if (other.point.y === realVert.point.y) {\n if (isRealVert && prev !== partner) {\n edgeList.push([edge, partner]);\n }\n } else if (other.point.x === realVert.point.x) {\n if (!isRealVert && prev !== partner) {\n edgeList.push([edge, partner]);\n }\n } else {\n // Non-orthogonal edge — keep but record.\n edgeList.push([edge, other]);\n }\n }\n\n return edgeList;\n }\n\n // ─── Sequential construction (heuristic 1) ─────────────────────────────────\n\n //! Builds the MTST using sequential (Dijkstra-then-Kruskal) construction.\n //! Slower / weaker than the interleaved variant, kept for parity.\n constructSequential(): void {\n // Local heap shadows — the sequential variant uses fresh heaps each call.\n const vHeap = new BinaryHeap<VertInf>(vertHeapLess);\n const beHeap = new BinaryHeap<EdgeInf>(edgeHeapLess);\n const extraVertices: VertInf[] = [];\n\n // Initialisation: clear distances on every vertex.\n const endVert = this.router.vertices.end();\n for (\n let k = this.router.vertices.connsBegin();\n k !== endVert;\n k = k!.lstNext\n ) {\n k!.sptfDist = Number.MAX_VALUE;\n k!.pathNext = null;\n k!.setSPTFRoot(k!);\n }\n for (const t of this.terminals) {\n t.sptfDist = 0;\n this.makeSet(t);\n vHeap.push(t);\n }\n vHeap.rebuild();\n\n // Shortest-path terminal forest construction.\n while (!vHeap.empty()) {\n const u = vHeap.pop();\n\n let extraVertex: VertInf | null = null;\n for (const edgeLike of u.orthogVisList) {\n const edge = edgeLike as EdgeInf;\n const v = edge.otherVert(u);\n let edgeDist = edge.getDist();\n\n if (v.isDummyPinHelper || u.isDummyPinHelper) {\n edgeDist = 1;\n }\n\n // Skip edges back to where we came from.\n if (u.pathNext === v || (u.pathNext && u.pathNext.pathNext === v)) {\n continue;\n }\n\n // Ignore intra-tree edges.\n if (u.sptfRoot() === v.sptfRoot()) {\n continue;\n }\n\n const newCost = u.sptfDist + edgeDist;\n const freeConnection = this.connectsWithoutBend(u, v);\n\n if (!freeConnection) {\n // Add a dummy node with a bend penalty.\n if (extraVertex === null) {\n extraVertex = new VertInf(0, 0, u.point, {\n isDimensionChangePartner: true,\n });\n // Transient — not added to the router's vertex list.\n extraVertices.push(extraVertex);\n extraVertex.sptfDist = this.bendPenalty + u.sptfDist;\n extraVertex.pathNext = u;\n extraVertex.setSPTFRoot(u.sptfRoot()!);\n vHeap.push(extraVertex);\n }\n const extraEdge = new EdgeInf(extraVertex, v, this.router);\n extraEdge.setDist(edgeDist);\n continue;\n }\n\n if (newCost < v.sptfDist && v.sptfRoot() === v) {\n v.sptfDist = newCost;\n v.pathNext = u;\n v.setSPTFRoot(u.sptfRoot()!);\n vHeap.push(v);\n } else {\n const secondJoinCost = this.connectsWithoutBend(v, u)\n ? 0\n : this.bendPenalty;\n const cost =\n edge.vert1().sptfDist +\n edge.vert2().sptfDist +\n secondJoinCost +\n edge.getDist();\n edge.setMtstDist(cost);\n beHeap.arr.push(edge);\n }\n }\n }\n beHeap.rebuild();\n\n // Extended Kruskal phase.\n while (!beHeap.empty()) {\n const e = beHeap.pop();\n const r1 = e.vert1().sptfRoot();\n const r2 = e.vert2().sptfRoot();\n if (r1 === null || r2 === null) continue;\n const s1 = this.findSet(r1);\n const s2 = this.findSet(r2);\n if (s1 === -1 || s2 === -1) continue;\n\n if (s1 !== s2) {\n this.unionSets(s1, s2);\n\n let node1: HyperedgeTreeNode | null = null;\n let node2: HyperedgeTreeNode | null = null;\n if (this.hyperedgeTreeJunctions) {\n node1 = this.addNode(e.vert1(), null);\n node2 = this.addNode(e.vert2(), node1);\n }\n this.buildHyperedgeTreeToRoot(e.vert1().pathNext, node1, e.vert1());\n this.buildHyperedgeTreeToRoot(e.vert2().pathNext, node2, e.vert2());\n }\n }\n\n // Free dummy vertices.\n for (const v of extraVertices) {\n v.removeFromGraph(false);\n }\n extraVertices.length = 0;\n this.nodes.clear();\n this.allsets.length = 0;\n }\n\n // ─── Interleaved construction (heuristic 2) ────────────────────────────────\n\n //! Builds the MTST using interleaved Dijkstra/Kruskal construction —\n //! preferred over the sequential variant.\n constructInterleaved(): void {\n this.origTerminals = new Set(this.terminals);\n\n // Initialisation: clear every connector vertex's distance and partner.\n const endVert = this.router.vertices.end();\n for (\n let k = this.router.vertices.connsBegin();\n k !== endVert;\n k = k!.lstNext\n ) {\n k!.sptfDist = Number.MAX_VALUE;\n k!.pathNext = null;\n k!.setTreeRootPointer(null);\n k!.orthogonalPartner = null;\n }\n\n if (this.rootVertexPointers.length !== 0) {\n throw new Error('constructInterleaved: rootVertexPointers must be empty');\n }\n for (const t of this.terminals) {\n t.sptfDist = 0;\n this.rootVertexPointers.push(t.makeTreeRootPointer(t));\n this.vHeap.arr.push(t);\n }\n // Reset hyperedge-segment flags on every orthogonal edge.\n for (\n let t = this.router.visOrthogGraph.begin();\n t !== this.router.visOrthogGraph.end();\n t = t!.lstNext\n ) {\n (t as EdgeInf).setHyperedgeSegment(false);\n }\n\n this.vHeap.rebuild();\n\n // Main loop — interleaves forest growth with bridging-edge commits.\n while (!this.vHeap.empty()) {\n const u = this.vHeap.front();\n\n if (u.treeRoot() === null) {\n throw new Error('constructInterleaved: orphaned vertex on heap');\n }\n if (u.pathNext === null && u.sptfDist !== 0) {\n throw new Error('constructInterleaved: non-terminal without pathNext');\n }\n\n if (\n !this.beHeap.empty() &&\n u.sptfDist >= 0.5 * this.beHeap.front().mtstDist()\n ) {\n // Commit to the cheapest bridging edge.\n const e = this.beHeap.pop();\n this.commitToBridgingEdge(e);\n\n if (this.origTerminals.size === 1) {\n break;\n }\n\n this.removeInvalidBridgingEdges();\n // Don't pop u — re-loop.\n continue;\n }\n\n this.vHeap.pop();\n\n const edgeList = this.getOrthogonalEdgesFromVertex(u, u.pathNext);\n for (const [e, v] of edgeList) {\n let edgeDist = e.getDist();\n if (v.isDummyPinHelper || u.isDummyPinHelper) {\n edgeDist = 1;\n }\n\n // Skip intra-tree edges.\n if (u.treeRoot() === v.treeRoot()) {\n continue;\n }\n\n if (v.treeRoot() === null) {\n // Unexplored vertex — attach to u's tree.\n const newCost = u.sptfDist + edgeDist;\n v.sptfDist = newCost;\n v.pathNext = u;\n v.setTreeRootPointer(u.treeRootPointer());\n this.vHeap.arr.push(v);\n this.vHeap.rebuild();\n } else {\n // Bridging candidate.\n const cost = v.sptfDist + u.sptfDist + e.getDist();\n const found = this.beHeap.contains(e);\n if (!found) {\n e.setMtstDist(cost);\n this.beHeap.push(e);\n } else if (cost < e.mtstDist()) {\n e.setMtstDist(cost);\n this.beHeap.rebuild();\n }\n }\n }\n }\n\n // The C++ asserts origTerminals.size() == 1. In TS we tolerate\n // disconnected inputs (e.g. a terminal stranded in an isolated cluster\n // of orthogonal visibility) since tests may exercise such cases.\n\n // Drop the malloc'd root pointers (TS just lets them GC).\n this.rootVertexPointers.length = 0;\n\n // Detach dummy vertices.\n for (const v of this.extraVertices) {\n v.removeFromGraph(false);\n }\n this.extraVertices.length = 0;\n }\n\n // ─── Misc helpers ──────────────────────────────────────────────────────────\n\n //! Returns true if a new leaf can join an old leaf without introducing a\n //! bend. The exact rules depend on whether the old leaf is itself a\n //! terminal (sptfDist === 0) or a propagated vertex.\n private connectsWithoutBend(oldLeaf: VertInf, newLeaf: VertInf): boolean {\n if (oldLeaf.sptfDist === 0) {\n let hyperedgeConnection = false;\n for (const edgeLike of oldLeaf.orthogVisList) {\n const edge = edgeLike as EdgeInf;\n const other = edge.otherVert(oldLeaf);\n if (other === newLeaf) continue;\n if (other.point.eq(oldLeaf.point)) continue;\n if (edge.isHyperedgeSegment()) {\n hyperedgeConnection = true;\n if (colinear(other.point, oldLeaf.point, newLeaf.point)) return true;\n }\n }\n return !hyperedgeConnection;\n }\n\n if (oldLeaf.pathNext) {\n return colinear(oldLeaf.pathNext.point, oldLeaf.point, newLeaf.point);\n }\n return true;\n }\n\n //! Returns the real vertices of a bridging edge, swapping in orthogonal\n //! partners when needed to make orientation comparisons meaningful.\n private realVerticesCountingPartners(edge: EdgeInf): VertexPair {\n const v1 = edge.vert1();\n const v2 = edge.vert2();\n let r1 = v1;\n let r2 = v2;\n\n if (\n !v1.isDimensionChangePartner &&\n !v2.isDimensionChangePartner &&\n !v1.point.eq(v2.point) &&\n v1.point.x === v2.point.x\n ) {\n if (v1.orthogonalPartner) r1 = v1.orthogonalPartner;\n if (v2.orthogonalPartner) r2 = v2.orthogonalPartner;\n }\n return [r1, r2];\n }\n\n //! Commits to a particular bridging edge — merges the two terminal trees,\n //! materialises the path on the HyperedgeTree, and rewrites root pointers\n //! so all vertices on the committed branch share a single tree root.\n private commitToBridgingEdge(e: EdgeInf): void {\n const ends = this.realVerticesCountingPartners(e);\n const r1 = ends[0].treeRoot()!;\n const r2 = ends[1].treeRoot()!;\n // Stable tie-break by VertInf creation order — TS has no inherent\n // pointer ordering, and we need the choice to be deterministic.\n const r1Less = r1._seq < r2._seq;\n const newRoot = r1Less ? r1 : r2;\n const oldRoot = r1Less ? r2 : r1;\n\n let node1: HyperedgeTreeNode | null = null;\n let node2: HyperedgeTreeNode | null = null;\n const vert1 = ends[0];\n const vert2 = ends[1];\n if (this.hyperedgeTreeJunctions) {\n node1 = this.addNode(vert1, null);\n node2 = this.addNode(vert2, node1);\n e.setHyperedgeSegment(true);\n }\n\n this.buildHyperedgeTreeToRoot(vert1.pathNext, node1, vert1, true);\n this.buildHyperedgeTreeToRoot(vert2.pathNext, node2, vert2, true);\n\n // Re-root every vertex on the committed path to a fresh shared box.\n const oldTreeRootPtr1 = vert1.treeRootPointer();\n const oldTreeRootPtr2 = vert2.treeRootPointer();\n this.origTerminals.delete(oldRoot);\n const newTreeRootPtr = vert1.makeTreeRootPointer(newRoot);\n this.rootVertexPointers.push(newTreeRootPtr);\n vert2.setTreeRootPointer(newTreeRootPtr);\n\n if (newRoot === null) {\n throw new Error('commitToBridgingEdge: newRoot must not be null');\n }\n this.resetDistsForPath(vert1, newTreeRootPtr);\n this.resetDistsForPath(vert2, newTreeRootPtr);\n\n if (!oldTreeRootPtr1 || !oldTreeRootPtr2) {\n throw new Error('commitToBridgingEdge: oldTreeRootPtrs must be set');\n }\n oldTreeRootPtr1.value = null;\n oldTreeRootPtr2.value = null;\n\n if (this.origTerminals.size === 1) return;\n\n // Drop orphaned vertices from the vertex heap.\n const next: VertInf[] = [];\n for (const v of this.vHeap.arr) {\n if (v.treeRoot() === null) continue;\n next.push(v);\n }\n // Reset all (current) terminals back to the heap with sptfDist === 0.\n for (const t of this.terminals) {\n if (t.sptfDist !== 0) {\n throw new Error('commitToBridgingEdge: terminal sptfDist not 0');\n }\n next.push(t);\n }\n this.vHeap.replaceWith(next);\n }\n}\n","// Hyperedge rerouting — convenience API to fully reroute a set of\n// junction-joined connectors with fresh junction positions.\n//\n// Ports input/hyperedge.cpp and input/hyperedge.h. Unlike hyperedgeimprover\n// (which preserves topology and only nudges segments), `HyperedgeRerouter`\n// throws away the existing routing and builds a fresh Minimum Terminal\n// Spanning Tree over the endpoint vertices. The old junctions and connectors\n// are deleted; new ones are created.\n//\n// Workflow:\n// 1. Caller acquires `router.hyperedgeRerouter()`.\n// 2. Caller registers each hyperedge to be rerouted via\n// `registerHyperedgeForRerouting(junction)` or\n// `registerHyperedgeForRerouting(terminals: ConnEnd[])`. The returned\n// index lets the caller fetch per-hyperedge results later.\n// 3. The next call to `router.route()` invokes `performRerouting()`.\n// 4. Caller reads `newAndDeletedObjectLists(index)` per registered hyperedge.\n//\n// Deviations from C++:\n// - `assignConnectionPinVisibility` is still a stub in connector.ts; the\n// calls are preserved here for API parity but currently do nothing\n// interesting. When the visibility-graph pin work lands, this will start\n// to matter.\n// - Debug helpers (`outputInstanceToSVG`, `DEBUGHANDLER` blocks) dropped.\n// - Cyclic-hyperedge warnings are silent (matches the functional behaviour).\n\nimport { kUnassignedVertexNumber, Point } from './geomtypes';\nimport { Endpoint } from './endpoint';\nimport { VertInf } from './vertex';\nimport { Edge } from './edge';\nimport type { Junction } from './junction';\nimport type { JunctionHyperedgeTreeNodeMap } from './hyperedgetree';\nimport { MinimumTerminalSpanningTree, type VertexSet } from './mtst';\nimport type { Router } from './router';\n\n// ─── HyperedgeNewAndDeletedObjectLists ───────────────────────────────────────\n//\n// Canonical home for the result type. Both HyperedgeImprover (which mutates\n// in place) and HyperedgeRerouter (which rebuilds from scratch) use this\n// shape. hyperedgeimprover.ts re-exports it for source-level compatibility.\n\n//! Lists of junctions and connectors created, deleted, and changed during\n//! a hyperedge rerouting or improvement pass.\n//!\n//! `changedConnectorList` is only populated by HyperedgeImprover — for the\n//! rerouter it always stays empty.\nexport interface HyperedgeNewAndDeletedObjectLists {\n //! A list of newly created junctions.\n newJunctionList: Junction[];\n //! A list of newly created connectors.\n newConnectorList: Edge[];\n //! A list of deleted junctions.\n deletedJunctionList: Junction[];\n //! A list of deleted connectors.\n deletedConnectorList: Edge[];\n //! A list of changed connectors (HyperedgeImprover only — always empty for\n //! HyperedgeRerouter results).\n changedConnectorList: Edge[];\n}\n\nexport type Hyperedge =\n | { type: 'terminals'; connEnds: Endpoint[] }\n | {\n type: 'junction';\n junction: Junction;\n }\n | { type: 'invalid' };\n\n// ─── Internal helpers ────────────────────────────────────────────────────────\n\n// Equivalent of C++ `ConnEnd::getHyperedgeVertex(router)`. Returns the\n// `VertInf` that represents this endpoint inside the visibility graph — either\n// an existing pin vertex or a freshly created one. When a new vertex is\n// created, `addedVertex` is true so the caller can clean it up later.\n//\n// The C++ version also calls `vertexVisibility(vertex, null, true, true)` when\n// poly-line routing is enabled; we skip that — this port is orthogonal-only.\nfunction getHyperedgeVertex(\n end: Endpoint,\n router: Router,\n): { addedVertex: boolean; vertex: VertInf } {\n if (end._anchorObj !== null) {\n // Junction-anchored endpoint — return the junction's centre vertex.\n const centre = end._anchorObj.centreVertex();\n if (centre === null) {\n throw new Error('HyperedgeRerouter: anchor has no centre vertex');\n }\n return { addedVertex: false, vertex: centre as VertInf };\n }\n\n // Free-floating endpoint. If some existing connector already has an\n // endpoint vertex at this exact position+direction, reuse it — that vertex\n // is already in the orthogonal visibility graph (built at the top of\n // `route()`), so MTST can expand from it without forcing a graph rebuild.\n // Synthesising a fresh duplicate vertex would land in `router.vertices`\n // mid-`route()`, miss the graph, and leave MTST with an empty visList.\n for (\n let curr = router.vertices.connsBegin();\n curr !== null;\n curr = curr.lstNext\n ) {\n if (\n curr.isConnPoint &&\n curr.point.eq(end._point) &&\n curr.visDirections.equal(end.directions)\n ) {\n return { addedVertex: false, vertex: curr };\n }\n }\n\n // No existing vertex matched — synthesise a fresh one. This vertex won't\n // have visibility edges (the static graph is already built), so the caller\n // is responsible for regenerating the graph before MTST runs.\n const vertex = new VertInf(0, kUnassignedVertexNumber, end._point, {\n isConnPoint: true,\n });\n router.vertices.addVertex(vertex);\n vertex.visDirections = end.directions;\n return { addedVertex: true, vertex };\n}\n\n// ─── HyperedgeRerouter ───────────────────────────────────────────────────────\n\n//! @brief The HyperedgeRerouter class is a convenience object used to\n//! register hyperedges for full rerouting.\n//!\n//! To work with this class, get a reference via `Router.hyperedgeRerouter()`.\n//!\n//! Registering a hyperedge stages it for rerouting — the rerouting itself\n//! happens the next time `Router.route()` is called, just before connector\n//! routes are generated. After `route()` returns, the caller can read\n//! `newAndDeletedObjectLists(index)` to learn what junctions and connectors\n//! were created and deleted for that hyperedge.\nexport class HyperedgeRerouter {\n router: Router;\n hyperedges: Hyperedge[];\n // Registered hyperedges. Each one is either a list of endpoint ConnEnds or\n // a root junction (with the other vector entry empty).\n // private m_terminals_vector: ConnEnd[][] = [];\n // private m_root_junction_vector: (JunctionRef | null)[] = [];\n\n // Populated by performRerouting(). Indexed by registration order.\n private m_new_junctions_vector: Junction[][] = [];\n private m_deleted_junctions_vector: Junction[][] = [];\n private m_new_connectors_vector: Edge[][] = [];\n private m_deleted_connectors_vector: Edge[][] = [];\n private m_terminal_vertices_vector: VertexSet[] = [];\n private m_added_vertices: VertInf[] = [];\n\n //! How many fresh `VertInf`s `calcHyperedgeConnectors` injected into\n //! `router.vertices` (free-floating terminals whose position+direction\n //! didn't match any existing connector endpoint). Used by `Router.route()`\n //! to decide whether the static vis graph needs rebuilding before MTST\n //! runs: zero added → existing visibility is fine, MTST can start.\n /** @internal */\n addedVertexCount(): number {\n return this.m_added_vertices.length;\n }\n\n constructor(router: Router, hyperedges: Hyperedge[]) {\n this.hyperedges = hyperedges;\n this.router = router;\n }\n\n //! @brief The number of hyperedges that have been registered.\n count(): number {\n return this.hyperedges.length;\n }\n\n //! @brief Returns the new/deleted objects for the hyperedge registered at\n //! `index`. Call this after `Router.route()` has run.\n newAndDeletedObjectLists(index: number): HyperedgeNewAndDeletedObjectLists {\n if (index > this.count()) {\n throw new Error(\n `HyperedgeRerouter: index ${index} out of range (count=${this.count()})`,\n );\n }\n return {\n newJunctionList: this.m_new_junctions_vector[index] ?? [],\n newConnectorList: this.m_new_connectors_vector[index] ?? [],\n deletedJunctionList: this.m_deleted_junctions_vector[index] ?? [],\n deletedConnectorList: this.m_deleted_connectors_vector[index] ?? [],\n changedConnectorList: [],\n };\n }\n\n // ─── Internal: invoked from Router ────────────────────────────────────────\n\n /** @internal */\n // Recurse from a connector to find every junction and connector that\n // belongs to its hyperedge. Adds found objects to the deleted-list for\n // this index. Returns true if at least one traversed junction had three+\n // connectors (a precondition for the topology being a true hyperedge).\n private findAttachedFromConnector(\n index: number,\n connector: Edge,\n ignore: Junction | null,\n hyperedgeConns: Set<Edge>,\n ): boolean {\n let valid = false;\n // Mark pin visibility (stubbed in connector.ts; preserved for API parity).\n connector.assignConnectionPinVisibility(true);\n\n this.m_deleted_connectors_vector[index].push(connector);\n hyperedgeConns.add(connector);\n\n const [jA, jB] = connector.endpointAnchors();\n\n if (jA !== null) {\n if (jA !== ignore) {\n valid =\n this.findAttachedFromJunction(index, jA, connector, hyperedgeConns) ||\n valid;\n }\n } else {\n // Endpoint — record the source vertex.\n const src = connector.src();\n if (src) this.m_terminal_vertices_vector[index].add(src);\n }\n\n if (jB !== null) {\n if (jB !== ignore) {\n valid =\n this.findAttachedFromJunction(index, jB, connector, hyperedgeConns) ||\n valid;\n }\n } else {\n const dst = connector.dst();\n if (dst) this.m_terminal_vertices_vector[index].add(dst);\n }\n\n return valid;\n }\n\n /** @internal */\n // Recurse from a junction to find every connector / junction belonging to\n // the hyperedge.\n private findAttachedFromJunction(\n index: number,\n junction: Junction,\n ignore: Edge | null,\n hyperedgeConns: Set<Edge>,\n ): boolean {\n let valid = false;\n this.m_deleted_junctions_vector[index].push(junction);\n\n const connectors = junction.attachedConnectors();\n if (connectors.length > 2) {\n // Real hyperedges have at least one junction with 3+ connectors.\n valid = true;\n }\n for (const connRef of connectors) {\n if (connRef === ignore) continue;\n if (!(connRef instanceof Edge)) continue;\n valid =\n this.findAttachedFromConnector(\n index,\n connRef,\n junction,\n hyperedgeConns,\n ) || valid;\n }\n return valid;\n }\n\n /** @internal */\n // Populate the deleted-object vectors and terminal-vertex sets for every\n // registered hyperedge. Returns the set of connectors that belong to a\n // registered hyperedge (so Router.route() can skip them — the rerouter will\n // throw them away).\n calcHyperedgeConnectors(): Set<Edge> {\n if (this.router === null) {\n throw new Error('HyperedgeRerouter: router not set');\n }\n\n const allRegistered = new Set<Edge>();\n\n // Reset per-hyperedge state.\n this.m_deleted_junctions_vector = Array.from(\n { length: this.count() },\n () => [],\n );\n this.m_deleted_connectors_vector = Array.from(\n { length: this.count() },\n () => [],\n );\n this.m_terminal_vertices_vector = Array.from(\n { length: this.count() },\n () => new Set<VertInf>(),\n );\n this.m_added_vertices = [];\n\n for (let [index, hyperedge] of this.hyperedges.entries()) {\n if (hyperedge.type === 'junction') {\n const valid = this.findAttachedFromJunction(\n index,\n hyperedge.junction,\n null,\n allRegistered,\n );\n if (!valid) {\n // Not a true hyperedge — clear and ignore.\n this.hyperedges[index] = { type: 'invalid' };\n this.m_terminal_vertices_vector[index] = new Set();\n this.m_deleted_junctions_vector[index] = [];\n this.m_deleted_connectors_vector[index] = [];\n }\n } else if (hyperedge.type === 'terminals') {\n for (let connEnd of hyperedge.connEnds) {\n const { addedVertex, vertex } = getHyperedgeVertex(\n connEnd,\n this.router,\n );\n this.m_terminal_vertices_vector[index].add(vertex);\n if (addedVertex) {\n this.m_added_vertices.push(vertex);\n }\n }\n // Any existing connector whose *both* endpoints sit at registered\n // terminal positions+directions is implicitly part of the user's\n // intended hyperedge — the rerouter will spit out a fresh tree\n // spanning these terminals, so leaving the old connectors alive\n // would leave two parallel routings on the diagram. Mark them for\n // deletion and tell the connector loop in `Router.route()` to skip\n // them (via `allRegistered`).\n //\n // The \"both endpoints\" rule is conservative: a connector that only\n // shares one endpoint with the hyperedge is still doing its own\n // independent job and shouldn't be deleted.\n this.findExistingConnectorsForTerminals(\n index,\n hyperedge.connEnds,\n allRegistered,\n );\n }\n }\n return allRegistered;\n }\n\n /** @internal */\n // Walks `router.connRefs` and marks for deletion any connector whose\n // src AND dst both match a registered terminal (by position + direction).\n // See the `terminals` branch in `calcHyperedgeConnectors` for the\n // rationale.\n private findExistingConnectorsForTerminals(\n index: number,\n connEnds: Endpoint[],\n allRegistered: Set<Edge>,\n ): void {\n const matchesAnyTerminal = (vert: VertInf | null): boolean => {\n if (vert === null) return false;\n for (const ce of connEnds) {\n if (\n vert.point.eq(ce._point) &&\n vert.visDirections.equal(ce.directions)\n ) {\n return true;\n }\n }\n return false;\n };\n\n for (const conn of this.router.connRefs) {\n if (allRegistered.has(conn)) continue;\n if (matchesAnyTerminal(conn.src()) && matchesAnyTerminal(conn.dst())) {\n this.m_deleted_connectors_vector[index].push(conn);\n allRegistered.add(conn);\n }\n }\n }\n\n /** @internal */\n //! Perform the actual rerouting. Called from `Router.route()` before\n //! individual connector routing. Builds an MTST per registered hyperedge,\n //! writes the tree back to fresh ConnRef objects, then deletes the old\n //! junctions and connectors.\n performRerouting(): void {\n this.m_new_junctions_vector = Array.from(\n { length: this.count() },\n () => [],\n );\n this.m_new_connectors_vector = Array.from(\n { length: this.count() },\n () => [],\n );\n\n for (let i = 0; i < this.count(); i++) {\n const terminals = this.m_terminal_vertices_vector[i];\n if (terminals.size === 0) continue; // Invalid hyperedge.\n\n // Build the MTST and grab its hyperedge tree root.\n const hyperedgeTreeJunctions: JunctionHyperedgeTreeNodeMap = new Map();\n const mtst = new MinimumTerminalSpanningTree(\n this.router,\n terminals,\n hyperedgeTreeJunctions,\n );\n mtst.constructInterleaved();\n const treeRoot = mtst.rootJunction();\n if (treeRoot === null) {\n // No junction was created — can't form a hyperedge. Skip.\n continue;\n }\n\n // Wire fresh ConnRefs onto the tree via the routeOps callbacks that\n // hyperedgetree.ts expects. See hyperedgeimprover.ts for the parallel\n // setup.\n const deletedConns = this.m_deleted_connectors_vector[i];\n treeRoot.addConns(\n null,\n this.router,\n deletedConns,\n null,\n // connFactory: create a fresh ConnRef attached at `junction`.\n (junction) => {\n let srcEnd = new Endpoint(junction);\n let destination = new Endpoint(new Point(0, 0));\n let conn = new Edge(this.router, srcEnd, destination);\n return conn;\n },\n // setConnEndAtTerminal: wire the tar endpoint to a terminal anchor.\n (conn, finalVertex, _oldConns) => {\n const cr = conn as unknown as Edge;\n setConnEndAtTerminal(cr, finalVertex, deletedConns);\n },\n // setConnEndAtJunction: wire the tar endpoint to another junction.\n (conn, junction) => {\n const tarEnd = new Endpoint(junction);\n conn.updateEndPoint('tar', tarEnd);\n },\n );\n\n // Collect new objects.\n treeRoot.listJunctionsAndConnectors(\n null,\n this.m_new_junctions_vector[i],\n this.m_new_connectors_vector[i],\n );\n\n // Two-pass write of segments → connector routes.\n const setRouteOps = makeSetRouteOps();\n for (let pass = 0; pass < 2; pass++) {\n treeRoot.writeEdgesToConns(null, pass, setRouteOps);\n }\n\n // Delete the old objects.\n for (const conn of this.m_deleted_connectors_vector[i]) {\n conn.assignConnectionPinVisibility(false);\n this.router.deleteConnector(conn);\n }\n\n for (const junction of this.m_deleted_junctions_vector[i]) {\n this.router.deleteJunction(junction);\n }\n }\n\n // Clear the registration so subsequent route() calls don't re-process.\n this.hyperedges = [];\n\n // Free temporary endpoint vertices.\n for (const v of this.m_added_vertices) {\n v.removeFromGraph();\n this.router.vertices.removeVertex(v);\n }\n this.m_added_vertices = [];\n }\n}\n\n// ─── Tree-traversal glue (matches hyperedgeimprover.ts pattern) ─────────────\n\n// Wires a freshly-created connector's tar endpoint to the terminal vertex\n// as a free-floating point. Shape-pin endpoints are not supported, so the\n// terminal is always represented as a Point ConnEnd.\n//\n// Carries the original terminal vertex's `visDirections` across to the new\n// ConnEnd — otherwise the new endpoint would default to `Direction.all`,\n// which lets the orthogonal vis graph grant omnidirectional visibility from\n// the endpoint. When the endpoint sits on (or inside) a shape's buffer\n// zone, that omnidirectional visibility lets A* discover paths that cut\n// through neighbouring buffers; preserving the user's direction keeps the\n// approach constrained the way the original ConnEnd intended.\nfunction setConnEndAtTerminal(\n conn: Edge,\n finalVertex: VertInf,\n _deletedConns: Edge[],\n): void {\n const tarEnd = new Endpoint(\n new Point(finalVertex.point.x, finalVertex.point.y),\n finalVertex.visDirections,\n );\n conn.updateEndPoint('tar', tarEnd);\n}\n\n// Builds the setRouteOps record that `HyperedgeTreeEdge.writeEdgesToConns`\n// expects. Same shape as in hyperedgeimprover.ts.\nfunction makeSetRouteOps(): {\n clearDisplayRoute: (conn: Edge) => void;\n pushPoint: (conn: Edge, point: Point) => void;\n reverseRoute: (conn: Edge) => void;\n popPoint: (conn: Edge) => void;\n routeIsEmpty: (conn: Edge) => boolean;\n destinationJunction: (conn: Edge) => Junction | null;\n} {\n return {\n clearDisplayRoute(conn) {\n (conn as unknown as Edge).displayRoute().ps.length = 0;\n },\n pushPoint(conn, point) {\n (conn as unknown as Edge)\n .displayRoute()\n .ps.push(new Point(point.x, point.y));\n },\n reverseRoute(conn) {\n (conn as unknown as Edge).displayRoute().ps.reverse();\n },\n popPoint(conn) {\n (conn as unknown as Edge).displayRoute().ps.pop();\n },\n routeIsEmpty(conn) {\n return (conn as unknown as Edge).displayRoute().ps.length === 0;\n },\n destinationJunction(conn) {\n const cr = conn as unknown as Edge;\n const dst = cr.dstConnEnd;\n if (dst !== null && dst instanceof Endpoint) {\n return dst.junction();\n }\n return null;\n },\n };\n}\n","import { VertInfList } from './vertex.ts';\nimport { EdgeList } from './graph';\nimport { Obstacle } from './obstacle';\nimport {\n generateStaticOrthogonalVisGraph,\n ImproveOrthogonalRoutes,\n} from './orthogonal';\nimport { type Hyperedge, HyperedgeRerouter } from './hyperedge';\n\nimport type { Junction } from './junction.ts';\nimport type { Edge } from './edge.ts';\nimport type { Rect } from './geomtypes.ts';\n\nexport type RoutingParams = {\n segmentPenalty: number;\n crossingPenalty: number;\n fixedSharedPathPenalty: number;\n portDirectionPenalty: number;\n shapeBufferDistance: number;\n idealNudgingDistance: number;\n reverseDirectionPenalty: number;\n};\n\nexport type RoutingOptions = {\n nudgeOrthogonalSegmentsConnectedToShapes: boolean;\n improveHyperedgeRoutesMovingJunctions: boolean;\n penaliseOrthogonalSharedPathsAtConnEnds: boolean;\n nudgeOrthogonalTouchingColinearSegments: boolean;\n performUnifyingNudgingPreprocessingStep: boolean;\n improveHyperedgeRoutesMovingAddingAndDeletingJunctions: boolean;\n nudgeSharedPathsWithCommonEndPoint: boolean;\n};\n\nexport class Router {\n // ─── Public data members (mirrors C++ public fields) ─────────────────────\n //\n // These are public so other modules can introspect them; the structural\n // router interfaces require them to be readable as fields.\n\n //! Canonical list of every obstacle (shapes + junctions) known to the\n //! router.\n m_obstacles: Obstacle[];\n connRefs: Edge[];\n visOrthogGraph: EdgeList;\n vertices: VertInfList;\n\n // General routing options:\n\n params: RoutingParams;\n options: RoutingOptions;\n hyperedgesForRerouting: Hyperedge[] = [];\n\n private _nextObjectId: number;\n private m_in_crossing_rerouting_stage: boolean;\n\n constructor(\n params: Partial<RoutingParams> = {},\n options: Partial<RoutingOptions> = {},\n ) {\n this.params = Object.assign(\n {\n segmentPenalty: 10,\n idealNudgingDistance: 4,\n crossingPenalty: 0, // Sensable default: 200,\n fixedSharedPathPenalty: 0, // Sensable default: 110,\n portDirectionPenalty: 0, // Sensable default: 100,\n shapeBufferDistance: 0, // Sensable default: 50,\n reverseDirectionPenalty: 0, // Sensable default: 50,\n },\n params,\n );\n\n this.options = Object.assign(\n {\n nudgeOrthogonalSegmentsConnectedToShapes: false,\n improveHyperedgeRoutesMovingJunctions: true,\n penaliseOrthogonalSharedPathsAtConnEnds: false,\n nudgeOrthogonalTouchingColinearSegments: false,\n performUnifyingNudgingPreprocessingStep: true,\n improveHyperedgeRoutesMovingAddingAndDeletingJunctions: false,\n nudgeSharedPathsWithCommonEndPoint: true,\n },\n options,\n );\n\n this.m_obstacles = [];\n this.connRefs = [];\n this.visOrthogGraph = new EdgeList();\n this.vertices = new VertInfList();\n\n this._nextObjectId = 1;\n this.m_in_crossing_rerouting_stage = false;\n }\n\n // ─── Internal object-id assignment ────────────────────────────────────────\n\n //! @brief Returns the next unused internal object id and advances the\n //! counter. Used by `Obstacle` and `ConnRef` to tag their owning\n //! `VertInf.objID` and cache keys. Not part of the public API.\n /** @internal */\n _assignObjectId(): number {\n return this._nextObjectId++;\n }\n\n // ─── Obstacle / shape / junction registration ─────────────────────────────\n\n createObstacle(rect: Rect) {\n let obstable = new Obstacle(this, rect);\n obstable.makeActive();\n return obstable;\n }\n\n //! @brief Registers a generic obstacle in the router's obstacle list.\n //! Called by Obstacle.makeActive — not part of the public API.\n /** @internal */\n addObstacle(obstacle: Obstacle): void {\n this.m_obstacles.push(obstacle);\n }\n\n //! @brief Removes a generic obstacle. Called by Obstacle.makeInactive.\n /** @internal */\n removeObstacle(obstacle: Obstacle): void {\n const idx = this.m_obstacles.indexOf(obstacle);\n if (idx !== -1) {\n this.m_obstacles.splice(idx, 1);\n }\n }\n\n //! @brief Adds a junction to the router scene. Called from the\n //! JunctionRef constructor.\n addJunction(junction: Junction): void {\n junction.makeActive();\n }\n\n //! @brief Remove a connector from the router scene.\n //!\n //! Called from JunctionRef.removeJunctionAndMergeConnectors — applications\n //! that want to remove a connector should use this method (instead of the\n //! C++ deleteConnector → ActionInfo dance).\n deleteConnector(connector: Edge) {\n connector.makeInactive();\n }\n\n //! @brief Remove a junction from the router scene.\n //!\n //! Called from JunctionRef.removeJunctionAndMergeConnectors — applications\n //! can also call it directly.\n deleteJunction(junction: Junction): void {\n if (junction.isActive()) {\n junction.removeFromGraph();\n junction.makeInactive();\n }\n }\n\n // ─── Flag setters / state readers ─────────────────────────────────────────\n //! @brief Returns whether the router is currently in the crossing-penalty\n //! rerouting stage. Used by makepath to suppress some penalties\n //! during the first routing pass.\n isInCrossingPenaltyReroutingStage(): boolean {\n return this.m_in_crossing_rerouting_stage;\n }\n\n // ─── Static graph build / nudging stubs ───────────────────────────────────\n //\n // These are no-ops until orthogonal.ts and the orthogonal-graph builder\n // are ported. They preserve the pipeline shape so the route() entry point\n // can be written end-to-end.\n\n //! @brief Rebuild the static orthogonal visibility graph if it's been\n //! invalidated. See orthogonal.ts.\n regenerateStaticBuiltGraph() {\n this.visOrthogGraph.clear();\n generateStaticOrthogonalVisGraph(this);\n }\n\n registerHyperedgeForRerouting(hyperedge: Hyperedge): number {\n switch (hyperedge.type) {\n case 'terminals':\n this.hyperedgesForRerouting.push({\n type: 'terminals',\n connEnds: [...hyperedge.connEnds],\n });\n break;\n case 'junction':\n this.hyperedgesForRerouting.push(hyperedge);\n break;\n }\n return this.hyperedgesForRerouting.length - 1;\n }\n\n // ─── route() — the routing pipeline entry point ───────────────────────────\n\n //! @brief Run the orthogonal routing pipeline over every active connector.\n //!\n //! Replaces the C++ `processTransaction` minus the action-replay machinery.\n //! Pipeline:\n //! 1. Rebuild the static orthogonal visibility graph (stub — TODO(orthogonal)).\n //! 2. Walk connRefs and call generatePath() on each. Connectors whose\n //! `_needsRerouteFlag` / `_falsePath` is false are no-ops, so this is\n //! safe to call after each individual mutation.\n //! 3. Nudge orthogonal routes (stub — TODO(orthogonal)).\n //! 4. Improve hyperedge routes (stub — TODO(hyperedgeimprover)).\n //!\n //! @return true if any connector had its route updated.\n route() {\n this.regenerateStaticBuiltGraph();\n\n // Hyperedge rerouting — registered hyperedges get full rebuilds via MTST\n // before any individual connector routing. Connectors that belong to a\n // rerouted hyperedge are skipped below since the rerouter has already\n // wired their replacements.\n let rerouted: Set<Edge> = new Set();\n\n let hyperedgeRerouter: HyperedgeRerouter | null = null;\n if (this.hyperedgesForRerouting.length) {\n hyperedgeRerouter = new HyperedgeRerouter(\n this,\n this.hyperedgesForRerouting,\n );\n rerouted = hyperedgeRerouter.calcHyperedgeConnectors();\n // `calcHyperedgeConnectors` may inject fresh terminal vertices into\n // `router.vertices` for `type: 'terminals'` hyperedges (one per free-\n // floating ConnEnd whose position+direction didn't match any existing\n // connector endpoint). Those synthesised vertices have no visibility\n // edges in the graph we built at the top of `route()` — without a\n // rebuild MTST sees empty visLists for them, finds no bridging edges,\n // and produces no tree. Skip the rebuild when none were added (the\n // common case once `getHyperedgeVertex` finds an existing match).\n if (hyperedgeRerouter.addedVertexCount() > 0) {\n this.regenerateStaticBuiltGraph();\n }\n\n hyperedgeRerouter.performRerouting();\n // performRerouting() creates fresh JunctionRefs (at the Steiner points\n // chosen by MTST) and fresh ConnRefs — their centre vertices and\n // endpoint vertices land in `router.vertices`, but the orthogonal vis\n // graph was built before any of that existed. Rebuild so the newly\n // added vertices have visibility edges; otherwise generatePath()\n // below can't route any of the new connectors and falls back to\n // 2-point direct lines.\n this.regenerateStaticBuiltGraph();\n }\n\n let anyChange = false;\n // Iterate over a snapshot — generatePath() can theoretically mutate the\n // connRefs list (e.g. via hyperedge splitting)\n const snapshot = this.connRefs.slice();\n for (const conn of snapshot) {\n if (rerouted.has(conn)) {\n continue;\n }\n\n if (conn.generatePath()) {\n anyChange = true;\n }\n }\n\n const improver = new ImproveOrthogonalRoutes(this);\n improver.execute();\n\n this.hyperedgesForRerouting = [];\n\n return {\n anyChange,\n hyperedgeRerouter,\n };\n }\n}\n"],"mappings":"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"}