Skip to content
Open
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
52 changes: 30 additions & 22 deletions lib/solvers/TraceCleanupSolver/simplifyPath.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,46 @@ import {
isVertical,
} from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/collisions"

export const simplifyPath = (path: Point[]): Point[] => {
if (path.length < 3) return path
const newPath: Point[] = [path[0]]
for (let i = 1; i < path.length - 1; i++) {
const p1 = newPath[newPath.length - 1]
const p2 = path[i]
const p3 = path[i + 1]
if (
(isVertical(p1, p2) && isVertical(p2, p3)) ||
(isHorizontal(p1, p2) && isHorizontal(p2, p3))
) {
const EPS = 1e-9

const removeDuplicateConsecutivePoints = (path: Point[]): Point[] => {
if (path.length <= 1) return path
const result: Point[] = [path[0]]
for (let i = 1; i < path.length; i++) {
const prev = result[result.length - 1]
const cur = path[i]
if (Math.abs(prev.x - cur.x) < EPS && Math.abs(prev.y - cur.y) < EPS) {
continue
}
newPath.push(p2)
result.push(cur)
}
newPath.push(path[path.length - 1])
return result
}

if (newPath.length < 3) return newPath
const finalPath: Point[] = [newPath[0]]
for (let i = 1; i < newPath.length - 1; i++) {
const p1 = finalPath[finalPath.length - 1]
const p2 = newPath[i]
const p3 = newPath[i + 1]
const collapseCollinearPoints = (path: Point[]): Point[] => {
if (path.length < 3) return path
const result: Point[] = [path[0]]
for (let i = 1; i < path.length - 1; i++) {
const p1 = result[result.length - 1]
const p2 = path[i]
const p3 = path[i + 1]
if (
(isVertical(p1, p2) && isVertical(p2, p3)) ||
(isHorizontal(p1, p2) && isHorizontal(p2, p3))
) {
continue
}
finalPath.push(p2)
result.push(p2)
}
finalPath.push(newPath[newPath.length - 1])
result.push(path[path.length - 1])
return result
}

return finalPath
export const simplifyPath = (path: Point[]): Point[] => {
let current = removeDuplicateConsecutivePoints(path)
current = collapseCollinearPoints(current)
current = removeDuplicateConsecutivePoints(current)
current = collapseCollinearPoints(current)
current = removeDuplicateConsecutivePoints(current)
return current
}
119 changes: 119 additions & 0 deletions tests/solvers/TraceCleanupSolver/simplifyPath.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { expect, test, describe } from "bun:test"
import { simplifyPath } from "lib/solvers/TraceCleanupSolver/simplifyPath"

describe("simplifyPath duplicate point removal", () => {
test("removes consecutive duplicate points in the middle", () => {
const path = [
{ x: 0, y: 0 },
{ x: 1, y: 0 },
{ x: 1, y: 0 },
{ x: 2, y: 0 },
]
const result = simplifyPath(path)
expect(result).toEqual([
{ x: 0, y: 0 },
{ x: 2, y: 0 },
])
})

test("removes consecutive duplicate points at the start", () => {
const path = [
{ x: 0, y: 0 },
{ x: 0, y: 0 },
{ x: 1, y: 0 },
{ x: 1, y: 1 },
]
const result = simplifyPath(path)
expect(result).toEqual([
{ x: 0, y: 0 },
{ x: 1, y: 0 },
{ x: 1, y: 1 },
])
})

test("removes consecutive duplicate points at the end", () => {
const path = [
{ x: 0, y: 0 },
{ x: 1, y: 0 },
{ x: 1, y: 1 },
{ x: 1, y: 1 },
]
const result = simplifyPath(path)
expect(result).toEqual([
{ x: 0, y: 0 },
{ x: 1, y: 0 },
{ x: 1, y: 1 },
])
})

test("removes multiple consecutive duplicates", () => {
const path = [
{ x: 0, y: 0 },
{ x: 1, y: 0 },
{ x: 1, y: 0 },
{ x: 1, y: 0 },
{ x: 1, y: 1 },
]
const result = simplifyPath(path)
expect(result).toEqual([
{ x: 0, y: 0 },
{ x: 1, y: 0 },
{ x: 1, y: 1 },
])
})

test("handles zero-length two-point path (both points identical)", () => {
const path = [
{ x: 5, y: 5 },
{ x: 5, y: 5 },
]
const result = simplifyPath(path)
expect(result).toEqual([{ x: 5, y: 5 }])
})

test("collapses collinear horizontal points", () => {
const path = [
{ x: 0, y: 0 },
{ x: 1, y: 0 },
{ x: 2, y: 0 },
{ x: 3, y: 0 },
]
const result = simplifyPath(path)
expect(result).toEqual([
{ x: 0, y: 0 },
{ x: 3, y: 0 },
])
})

test("collapses collinear vertical points", () => {
const path = [
{ x: 0, y: 0 },
{ x: 0, y: 1 },
{ x: 0, y: 2 },
{ x: 0, y: 3 },
]
const result = simplifyPath(path)
expect(result).toEqual([
{ x: 0, y: 0 },
{ x: 0, y: 3 },
])
})

test("handles path with duplicates at direction change", () => {
const path = [
{ x: 0, y: 0 },
{ x: 1, y: 0 },
{ x: 1, y: 0 },
{ x: 1, y: 1 },
{ x: 1, y: 1 },
{ x: 2, y: 1 },
]
const result = simplifyPath(path)
expect(result).toEqual([
{ x: 0, y: 0 },
{ x: 1, y: 0 },
{ x: 1, y: 1 },
{ x: 2, y: 1 },
])
})
})
Loading