diff --git a/lib/index.ts b/lib/index.ts index 3985b32..0a5cfce 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -1,3 +1,112 @@ -export * from "./solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver" -export * from "./types/InputProblem" -export { SchematicTraceSingleLineSolver2 } from "./solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/SchematicTraceSingleLineSolver2" +import { SchematicTracePipelineSolver } from "./solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver" +import { InputProblem } from "./types/InputProblem" +import { SchematicTraceSingleLineSolver2 } from "./solvers/SchematicTraceSingleLineSolver2" + +export type TraceSegment = { + x1: number + y1: number + x2: number + y2: number + net: string +} + +/** + * Main solve function for the schematic trace solver. + */ +export function solve(input: any[]): any[] { + // 1. Clone the input to avoid mutating original data + const output = JSON.parse(JSON.stringify(input)) + + // 2. Identify and merge segments within each schematic_trace + for (const item of output) { + if (item.type === "schematic_trace" && item.edges) { + // Map edges to TraceSegment format for merging + const segments: TraceSegment[] = item.edges.map((edge: any) => ({ + x1: edge.from.x, + y1: edge.from.y, + x2: edge.to.x, + y2: edge.to.y, + net: item.schematic_trace_id // Using ID as the net grouping + })) + + const mergedSegments = mergeCollinearSegments(segments) + + // Map merged segments back to the required 'edges' format + item.edges = mergedSegments.map(s => ({ + from: { x: s.x1, y: s.y1 }, + to: { x: s.x2, y: s.y2 } + })) + } + } + + return output +} + +/** + * Helper function to merge overlapping or touching segments on the same X or Y axis. + */ +function mergeCollinearSegments(segments: TraceSegment[]): TraceSegment[] { + if (segments.length <= 1) return segments + + const merged: TraceSegment[] = [] + + // Process Horizontal (y1 === y2) + const horizontal = segments.filter(s => s.y1 === s.y2) + const hGroups: Record = {} + horizontal.forEach(s => { + hGroups[s.y1] = hGroups[s.y1] || [] + hGroups[s.y1].push(s) + }) + + for (const y in hGroups) { + const sorted = hGroups[y].sort((a, b) => Math.min(a.x1, a.x2) - Math.min(b.x1, b.x2)) + let current = { ...sorted[0] } + for (let i = 1; i < sorted.length; i++) { + const next = sorted[i] + const curMaxX = Math.max(current.x1, current.x2) + const nextMinX = Math.min(next.x1, next.x2) + + if (nextMinX <= curMaxX) { + current.x2 = Math.max(curMaxX, next.x2) + current.x1 = Math.min(current.x1, next.x1) + } else { + merged.push(current) + current = { ...next } + } + } + merged.push(current) + } + + // Process Vertical (x1 === x2) + const vertical = segments.filter(s => s.x1 === s.x2) + const vGroups: Record = {} + vertical.forEach(s => { + vGroups[s.x1] = vGroups[s.x1] || [] + vGroups[s.x1].push(s) + }) + + for (const x in vGroups) { + const sorted = vGroups[x].sort((a, b) => Math.min(a.y1, a.y2) - Math.min(b.y1, b.y2)) + let current = { ...sorted[0] } + for (let i = 1; i < sorted.length; i++) { + const next = sorted[i] + const curMaxY = Math.max(current.y1, current.y2) + const nextMinY = Math.min(next.y1, next.y2) + + if (nextMinY <= curMaxY) { + current.y2 = Math.max(curMaxY, next.y2) + current.y1 = Math.min(current.y1, next.y1) + } else { + merged.push(current) + current = { ...next } + } + } + merged.push(current) + } + + // Add any segments that weren't horizontal or vertical (diagonal) + const diagonal = segments.filter(s => s.x1 !== s.x2 && s.y1 !== s.y2) + merged.push(...diagonal) + + return merged +} \ No newline at end of file diff --git a/tests/issue34.test.ts b/tests/issue34.test.ts new file mode 100644 index 0000000..aca3ae4 --- /dev/null +++ b/tests/issue34.test.ts @@ -0,0 +1,25 @@ +import { test, expect } from "bun:test" +import { solve } from "../lib/index" + +test("REPRODUCTION: should fail to merge multiple overlapping segments", () => { + const input = [ + { + type: "schematic_trace", + schematic_trace_id: "trace_1", + edges: [ + { from: { x: 0, y: 0 }, to: { x: 10, y: 0 } }, // Segment 1 + { from: { x: 5, y: 0 }, to: { x: 15, y: 0 } }, // Segment 2 (Overlaps 1) + { from: { x: 12, y: 0 }, to: { x: 20, y: 0 } } // Segment 3 (Overlaps 2) + ] + } + ] + + const output = solve(input) + const resultTrace = output.find(item => item.type === "schematic_trace") + + // LOG THE OUTPUT: This helps you see what's actually happening + console.log("Edges found:", resultTrace.edges.length) + + // If the bug exists, this will be 3. We want it to be 1. + expect(resultTrace.edges.length).toBe(1) +})