Skip to content

Commit 86cd217

Browse files
authored
Fix Outer Channel Bugs, support for bounds prop (#6)
* wip bounds * fix channel bug, add support for bounds * fix bounds type * one test per file * format
1 parent 669a921 commit 86cd217

19 files changed

+245
-112
lines changed

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
"titleBar.inactiveForeground": "#15202b99"
1414
},
1515
"peacock.color": "#b3e3de"
16-
}
16+
}

index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
console.log("Hello via Bun!");
1+
console.log("Hello via Bun!")

lib/JumperGraphSolver/geometry/getBoundsCenter.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import type { Bounds } from "../Bounds"
22

3-
export const computeBoundsCenter = (bounds: Bounds): { x: number; y: number } => {
3+
export const computeBoundsCenter = (
4+
bounds: Bounds,
5+
): { x: number; y: number } => {
46
return {
57
x: (bounds.minX + bounds.maxX) / 2,
68
y: (bounds.minY + bounds.maxY) / 2,

lib/JumperGraphSolver/jumper-graph-generator/generateJumperX2Grid.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,11 @@ export const generateJumperX2Grid = ({
8383
})
8484

8585
// Helper to create a port at the boundary between two regions
86-
const createPort = (id: string, region1: JRegion, region2: JRegion): JPort => {
86+
const createPort = (
87+
id: string,
88+
region1: JRegion,
89+
region2: JRegion,
90+
): JPort => {
8791
const b1 = region1.d.bounds
8892
const b2 = region2.d.bounds
8993

@@ -273,7 +277,15 @@ export const generateJumperX2Grid = ({
273277
true,
274278
)
275279

276-
regions.push(pad1, pad2, pad3, pad4, underjumper, throughjumper1, throughjumper2)
280+
regions.push(
281+
pad1,
282+
pad2,
283+
pad3,
284+
pad4,
285+
underjumper,
286+
throughjumper1,
287+
throughjumper2,
288+
)
277289

278290
// Determine which frame regions to create based on grid position
279291
const isFirstRow = row === 0

lib/JumperGraphSolver/jumper-graph-generator/generateJumperX4Grid.ts

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ export const generateJumperX4Grid = ({
1313
innerColChannelPointCount = 1,
1414
innerRowChannelPointCount = 1,
1515
regionsBetweenPads = false,
16-
outerPaddingX = 0.5,
17-
outerPaddingY = 0.5,
16+
outerPaddingX: outerPaddingXParam = 0.5,
17+
outerPaddingY: outerPaddingYParam = 0.5,
1818
outerChannelXPointCount,
1919
outerChannelYPointCount,
2020
orientation = "vertical",
2121
center,
22+
bounds,
2223
}: {
2324
cols: number
2425
rows: number
@@ -33,12 +34,8 @@ export const generateJumperX4Grid = ({
3334
outerChannelYPointCount?: number
3435
orientation?: "vertical" | "horizontal"
3536
center?: { x: number; y: number }
37+
bounds?: { minX: number; maxX: number; minY: number; maxY: number }
3638
}): JumperGraph => {
37-
// Calculate outer channel points: use provided value or derive from outer padding
38-
const effectiveOuterChannelXPoints =
39-
outerChannelXPointCount ?? Math.max(1, Math.floor(outerPaddingX / 0.4))
40-
const effectiveOuterChannelYPoints =
41-
outerChannelYPointCount ?? Math.max(1, Math.floor(outerPaddingY / 0.4))
4239
const regions: JRegion[] = []
4340
const ports: JPort[] = []
4441

@@ -65,6 +62,25 @@ export const generateJumperX4Grid = ({
6562
const cellHeight = row1CenterY - row4CenterY + padHeight // total height of pads region
6663
const verticalSpacing = cellHeight + marginY
6764

65+
// Calculate outer padding from bounds if specified
66+
let outerPaddingX = outerPaddingXParam
67+
let outerPaddingY = outerPaddingYParam
68+
if (bounds) {
69+
// Content dimensions (without outer padding)
70+
const contentWidth = cols * cellWidth + (cols - 1) * marginX
71+
const contentHeight = rows * cellHeight + (rows - 1) * marginY
72+
const boundsWidth = bounds.maxX - bounds.minX
73+
const boundsHeight = bounds.maxY - bounds.minY
74+
outerPaddingX = (boundsWidth - contentWidth) / 2
75+
outerPaddingY = (boundsHeight - contentHeight) / 2
76+
}
77+
78+
// Calculate outer channel points: use provided value or derive from outer padding
79+
const effectiveOuterChannelXPoints =
80+
outerChannelXPointCount ?? Math.max(1, Math.floor(outerPaddingX / 0.4))
81+
const effectiveOuterChannelYPoints =
82+
outerChannelYPointCount ?? Math.max(1, Math.floor(outerPaddingY / 0.4))
83+
6884
// Store cells for later port connections
6985
const cells: {
7086
pad1: JRegion
@@ -566,7 +582,9 @@ export const generateJumperX4Grid = ({
566582
`${idPrefix}:T-R`,
567583
top,
568584
right,
569-
isLastCol ? effectiveOuterChannelXPoints : innerColChannelPointCount,
585+
isLastCol
586+
? effectiveOuterChannelXPoints
587+
: innerColChannelPointCount,
570588
),
571589
)
572590
// Top connects to pad1, pad8, and underjumper
@@ -613,7 +631,9 @@ export const generateJumperX4Grid = ({
613631
`${idPrefix}:B-R`,
614632
bottom,
615633
right,
616-
isLastCol ? effectiveOuterChannelXPoints : innerColChannelPointCount,
634+
isLastCol
635+
? effectiveOuterChannelXPoints
636+
: innerColChannelPointCount,
617637
),
618638
)
619639
// Bottom connects to pad4, pad5, and underjumper
@@ -817,24 +837,28 @@ export const generateJumperX4Grid = ({
817837
)
818838
}
819839
// T-T connection between horizontally adjacent cells (first row only)
840+
// This is a vertical boundary, so use Y point count for outer edge
820841
if (top && prevCell.top) {
821842
ports.push(
822843
...createMultiplePorts(
823844
`cell_${row}_${col - 1}->cell_${row}_${col}:T-T`,
824845
prevCell.top,
825846
top,
826-
innerRowChannelPointCount,
847+
effectiveOuterChannelYPoints,
827848
),
828849
)
829850
}
830851
// B-B connection between horizontally adjacent cells
852+
// This is a vertical boundary; use Y points for outer edge (last row), inner points otherwise
831853
if (bottom && prevCell.bottom) {
832854
ports.push(
833855
...createMultiplePorts(
834856
`cell_${row}_${col - 1}->cell_${row}_${col}:B-B`,
835857
prevCell.bottom,
836858
bottom,
837-
innerRowChannelPointCount,
859+
isLastRow
860+
? effectiveOuterChannelYPoints
861+
: innerRowChannelPointCount,
838862
),
839863
)
840864
}
@@ -901,7 +925,9 @@ export const generateJumperX4Grid = ({
901925
`cell_${row - 1}_${col}->cell_${row}_${col}:B-R`,
902926
aboveCell.bottom!,
903927
right,
904-
isLastCol ? effectiveOuterChannelXPoints : innerColChannelPointCount,
928+
isLastCol
929+
? effectiveOuterChannelXPoints
930+
: innerColChannelPointCount,
905931
),
906932
)
907933
}
@@ -910,11 +936,12 @@ export const generateJumperX4Grid = ({
910936

911937
let graph: JumperGraph = { regions, ports }
912938

913-
// Apply transformations based on orientation and center
939+
// Apply transformations based on orientation, center, and bounds
914940
const needsRotation = orientation === "horizontal"
915941
const needsCentering = center !== undefined
942+
const needsBoundsTransform = bounds !== undefined
916943

917-
if (needsRotation || needsCentering) {
944+
if (needsRotation || needsCentering || needsBoundsTransform) {
918945
// Calculate current graph bounds and center
919946
const currentBounds = calculateGraphBounds(graph.regions)
920947
const currentCenter = computeBoundsCenter(currentBounds)
@@ -930,8 +957,16 @@ export const generateJumperX4Grid = ({
930957
matrices.push(rotate(-Math.PI / 2))
931958
}
932959

933-
// Translate to target center (or back to current center if no center specified)
934-
const targetCenter = center ?? currentCenter
960+
// Translate to target center
961+
// Priority: explicit center > bounds center > current center
962+
let targetCenter: { x: number; y: number }
963+
if (center) {
964+
targetCenter = center
965+
} else if (bounds) {
966+
targetCenter = computeBoundsCenter(bounds)
967+
} else {
968+
targetCenter = currentCenter
969+
}
935970
matrices.push(translate(targetCenter.x, targetCenter.y))
936971

937972
const matrix = compose(...matrices)

lib/JumperGraphSolver/perimeterChordUtils.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,10 @@ function areCoincident(t1: number, t2: number, eps: number = 1e-6): boolean {
6868
*
6969
* Chords that share a coincident endpoint do NOT count as crossing.
7070
*/
71-
export function chordsCross(chord1: [number, number], chord2: [number, number]): boolean {
71+
export function chordsCross(
72+
chord1: [number, number],
73+
chord2: [number, number],
74+
): boolean {
7275
// Normalize each chord so first endpoint is smaller
7376
const [a, b] = chord1[0] < chord1[1] ? chord1 : [chord1[1], chord1[0]]
7477
const [c, d] = chord2[0] < chord2[1] ? chord2 : [chord2[1], chord2[0]]

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"type": "module",
66
"scripts": {
77
"start": "cosmos",
8+
"format": "biome format --write .",
89
"build:site": "cosmos-export",
910
"build": "tsup ./lib/index.ts --dts --format esm"
1011
},

tests/fixtures/preload.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
import "bun-match-svg"
1+
import "bun-match-svg"

tests/jumper-graph-generation/__snapshots__/jumper-graph-generation08.snap.svg

Lines changed: 1 addition & 1 deletion
Loading

tests/jumper-graph-generation/__snapshots__/jumper-graph-generation09.snap.svg

Lines changed: 1 addition & 1 deletion
Loading

0 commit comments

Comments
 (0)