Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion fixtures/via-graph-solver/via-graph-solver01.fixture.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { GenericSolverDebugger } from "@tscircuit/solver-utils/react"
import viaTile from "assets/ViaGraphSolver/via-tile-4-regions.json"
import { ViaGraphSolver } from "lib/ViaGraphSolver/ViaGraphSolver"
import { createViaGraphWithConnections } from "lib/ViaGraphSolver/via-graph-generator/createViaGraphWithConnections"
import { generateViaTopologyRegions } from "lib/ViaGraphSolver/via-graph-generator/generateViaTopologyRegions"
import viaTile from "assets/ViaGraphSolver/via-tile-4-regions.json"

const baseGraph = generateViaTopologyRegions(viaTile, {
graphSize: 5,
Expand Down
2 changes: 1 addition & 1 deletion fixtures/via-graph-solver/via-graph-solver02.fixture.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { GenericSolverDebugger } from "@tscircuit/solver-utils/react"
import viaTile from "assets/ViaGraphSolver/via-tile-4-regions.json"
import { ViaGraphSolver } from "lib/ViaGraphSolver/ViaGraphSolver"
import { createViaGraphWithConnections } from "lib/ViaGraphSolver/via-graph-generator/createViaGraphWithConnections"
import { generateViaTopologyRegions } from "lib/ViaGraphSolver/via-graph-generator/generateViaTopologyRegions"
import viaTile from "assets/ViaGraphSolver/via-tile-4-regions.json"

const baseGraph = generateViaTopologyRegions(viaTile, {
graphSize: 5,
Expand Down
2 changes: 1 addition & 1 deletion fixtures/via-graph-solver/via-graph-solver03.fixture.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { GenericSolverDebugger } from "@tscircuit/solver-utils/react"
import viaTile from "assets/ViaGraphSolver/via-tile-4-regions.json"
import { ViaGraphSolver } from "lib/ViaGraphSolver/ViaGraphSolver"
import { createViaGraphWithConnections } from "lib/ViaGraphSolver/via-graph-generator/createViaGraphWithConnections"
import { generateViaTopologyRegions } from "lib/ViaGraphSolver/via-graph-generator/generateViaTopologyRegions"
import viaTile from "assets/ViaGraphSolver/via-tile-4-regions.json"

const baseGraph = generateViaTopologyRegions(viaTile, {
graphSize: 5,
Expand Down
2 changes: 1 addition & 1 deletion fixtures/via-graph-solver/via-graph-solver04.fixture.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { GenericSolverDebugger } from "@tscircuit/solver-utils/react"
import viaTile from "assets/ViaGraphSolver/via-tile-4-regions.json"
import { ViaGraphSolver } from "lib/ViaGraphSolver/ViaGraphSolver"
import { createViaGraphWithConnections } from "lib/ViaGraphSolver/via-graph-generator/createViaGraphWithConnections"
import { generateViaTopologyRegions } from "lib/ViaGraphSolver/via-graph-generator/generateViaTopologyRegions"
import viaTile from "assets/ViaGraphSolver/via-tile-4-regions.json"

const baseGraph = generateViaTopologyRegions(viaTile, {
graphSize: 5,
Expand Down
18 changes: 11 additions & 7 deletions fixtures/via-graph-solver/via-graph-solver05.fixture.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { GenericSolverDebugger } from "@tscircuit/solver-utils/react"
import viaTile from "assets/ViaGraphSolver/via-tile-4-regions.json"
import { createConnectionPort } from "lib/JumperGraphSolver/jumper-graph-generator/createConnectionPort"
import { createConnectionRegion } from "lib/JumperGraphSolver/jumper-graph-generator/createConnectionRegion"
import type {
Expand All @@ -11,7 +12,6 @@ import type { ViaByNet, ViaTile } from "lib/ViaGraphSolver/ViaGraphSolver"
import { ViaGraphSolver } from "lib/ViaGraphSolver/ViaGraphSolver"
import { findBoundaryRegionForPolygons } from "lib/ViaGraphSolver/via-graph-generator/findBoundaryRegionForPolygons"
import { generateViaTopologyRegions } from "lib/ViaGraphSolver/via-graph-generator/generateViaTopologyRegions"
import viaTile from "assets/ViaGraphSolver/via-tile-4-regions.json"

// ── Configuration ──────────────────────────────────────────────────────
const TILE_SIZE = 5
Expand Down Expand Up @@ -462,11 +462,11 @@ for (const xyConn of connections) {
allRegions.push(endRegion)

// Find the nearest boundary region for each endpoint
const startBoundary = findBoundaryRegionForPolygons(
start.x,
start.y,
allRegions,
)
const startBoundary = findBoundaryRegionForPolygons({
x: start.x,
y: start.y,
regions: allRegions,
})
if (startBoundary) {
const startPort = createConnectionPort(
`conn:${connectionId}:start-port`,
Expand All @@ -477,7 +477,11 @@ for (const xyConn of connections) {
allPorts.push(startPort)
}

const endBoundary = findBoundaryRegionForPolygons(end.x, end.y, allRegions)
const endBoundary = findBoundaryRegionForPolygons({
x: end.x,
y: end.y,
regions: allRegions,
})
if (endBoundary) {
const endPort = createConnectionPort(
`conn:${connectionId}:end-port`,
Expand Down
19 changes: 19 additions & 0 deletions lib/ViaGraphSolver/ViaGraphSolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,25 @@ export class ViaGraphSolver extends HyperGraphSolver<JRegion, JPort> {
return crossings * this.crossingPenalty + crossings * this.crossingPenaltySq
}

override isRipRequiredForPortUsage(
region: JRegion,
_port1: JPort,
_port2: JPort,
): boolean {
// Via regions are exclusive - if the region has any assignment from a
// different connection, using it requires ripping. This ensures the solver
// properly considers via region exclusivity during pathfinding.
if (region.d.isViaRegion) {
const assignments = region.assignments ?? []
return assignments.some(
(a) =>
a.connection.mutuallyConnectedNetworkId !==
this.currentConnection!.mutuallyConnectedNetworkId,
)
}
return false
}

override getRipsRequiredForPortUsage(
region: JRegion,
port1: JPort,
Expand Down
47 changes: 46 additions & 1 deletion lib/ViaGraphSolver/polygonPerimeterUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type Point = { x: number; y: number }
/**
* Check if two 2D line segments intersect (excluding shared endpoints).
* Uses the cross product method for robust intersection detection.
* Also detects T-intersections where one segment's endpoint lies on the other segment.
*/
function lineSegmentsIntersect(
p1: Point,
Expand Down Expand Up @@ -42,11 +43,55 @@ function lineSegmentsIntersect(
const d3 = cross(p1, p2, p3)
const d4 = cross(p1, p2, p4)

// Check if segments straddle each other
// Check if segments straddle each other (proper crossing)
if (d1 * d2 < 0 && d3 * d4 < 0) {
return true
}

// Check for T-intersections: one segment's endpoint lies ON the other segment
// This happens when one cross product is ~0 and the point is within segment bounds
const pointOnSegment = (
point: Point,
segStart: Point,
segEnd: Point,
crossProduct: number,
) => {
if (Math.abs(crossProduct) > eps) return false
// Point is on the line, check if it's within segment bounds
const minX = Math.min(segStart.x, segEnd.x) - eps
const maxX = Math.max(segStart.x, segEnd.x) + eps
const minY = Math.min(segStart.y, segEnd.y) - eps
const maxY = Math.max(segStart.y, segEnd.y) + eps
return (
point.x >= minX && point.x <= maxX && point.y >= minY && point.y <= maxY
)
}

// Check if p1 or p2 lies on segment p3-p4 (but not at endpoints, already checked)
if (pointOnSegment(p1, p3, p4, d1)) {
// p1 is on segment p3-p4, check it's not at the endpoints
if (!pointsCoincident(p1, p3) && !pointsCoincident(p1, p4)) {
return true
}
}
if (pointOnSegment(p2, p3, p4, d2)) {
if (!pointsCoincident(p2, p3) && !pointsCoincident(p2, p4)) {
return true
}
}

// Check if p3 or p4 lies on segment p1-p2 (but not at endpoints)
if (pointOnSegment(p3, p1, p2, d3)) {
if (!pointsCoincident(p3, p1) && !pointsCoincident(p3, p2)) {
return true
}
}
if (pointOnSegment(p4, p1, p2, d4)) {
if (!pointsCoincident(p4, p1) && !pointsCoincident(p4, p2)) {
return true
}
}

return false
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ export function createConvexViaGraphFromXYConnections(
const baseGraph: JumperGraph = { regions, ports }

// Add connections to the graph
// Note: findBoundaryRegionForPolygons auto-detects convex topology by checking
// for filler regions and only connects to them (avoiding tiny isolated convex regions)
const graphWithConnections = createViaGraphWithConnections(
baseGraph,
xyConnections,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ export const createViaGraphWithConnections = (
)
regions.push(endRegion)

const startBoundary = findBoundaryRegionForPolygons(
start.x,
start.y,
baseGraph.regions,
)
const startBoundary = findBoundaryRegionForPolygons({
x: start.x,
y: start.y,
regions: baseGraph.regions,
})
if (startBoundary) {
const startPort = createConnectionPort(
`conn:${connectionId}:start-port`,
Expand All @@ -61,11 +61,11 @@ export const createViaGraphWithConnections = (
ports.push(startPort)
}

const endBoundary = findBoundaryRegionForPolygons(
end.x,
end.y,
baseGraph.regions,
)
const endBoundary = findBoundaryRegionForPolygons({
x: end.x,
y: end.y,
regions: baseGraph.regions,
})
if (endBoundary) {
const endPort = createConnectionPort(
`conn:${connectionId}:end-port`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,20 @@ function closestPointOnPolygonEdge(
*
* Only considers non-pad, non-throughJumper, non-connectionRegion regions
* that have polygon data.
*
* For convex topologies (detected by presence of filler regions), only
* connects to filler regions to avoid isolated tiny convex regions inside
* the tile grid.
*/
export const findBoundaryRegionForPolygons = (
x: number,
y: number,
regions: JRegion[],
): BoundaryRegionResult | null => {
export const findBoundaryRegionForPolygons = (params: {
x: number
y: number
regions: JRegion[]
}): BoundaryRegionResult | null => {
const { x, y, regions } = params
// Check if this is a convex topology by looking for filler regions
const hasFillerRegions = regions.some((r) => r.regionId.startsWith("filler:"))

let closestRegion: JRegion | null = null
let closestDistance = Infinity
let closestPortPosition = { x, y }
Expand All @@ -67,6 +75,10 @@ export const findBoundaryRegionForPolygons = (
)
continue

// For convex topologies, only connect to filler regions to avoid
// isolated tiny convex regions inside the tile grid.
if (hasFillerRegions && !region.regionId.startsWith("filler:")) continue

const polygon = region.d.polygon
if (!polygon || polygon.length < 3) continue

Expand Down
Loading