Skip to content
Draft
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
19 changes: 17 additions & 2 deletions src/gerber/convert-soup-to-gerber-commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -644,9 +644,24 @@ export const convertSoupToGerberCommands = (
aperture_number: 10,
})
if (outline && outline.length > 2) {
gerberBuild.add("move_operation", outline[0])
const firstPoint = outline[0]
gerberBuild.add("move_operation", {
x: firstPoint.x,
y: mfy(firstPoint.y),
})
for (let i = 1; i < outline.length; i++) {
gerberBuild.add("plot_operation", outline[i])
gerberBuild.add("plot_operation", {
x: outline[i].x,
y: mfy(outline[i].y),
})
}

const lastPoint = outline[outline.length - 1]
if (lastPoint.x !== firstPoint.x || lastPoint.y !== firstPoint.y) {
gerberBuild.add("plot_operation", {
x: firstPoint.x,
y: mfy(firstPoint.y),
})
}
} else {
gerberBuild
Expand Down
7 changes: 7 additions & 0 deletions tests/gerber/__snapshots__/outline-closure-bottom.snap.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions tests/gerber/__snapshots__/outline-closure-top.snap.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
54 changes: 54 additions & 0 deletions tests/gerber/generate-board-outline-closure.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Circuit } from "@tscircuit/core"
import { expect, test } from "bun:test"
import { convertSoupToGerberCommands } from "src/gerber/convert-soup-to-gerber-commands"
import { stringifyGerberCommandLayers } from "src/gerber/stringify-gerber"

// Regression test: outlines should be closed in the Edge_Cuts layer
// even if the provided outline path does not repeat the starting point.
test("board outline paths are closed and flipped when required", async () => {
const circuit = new Circuit()
circuit.add(
<board
width={10}
height={10}
outline={[
{ x: 0, y: 0 },
{ x: 10, y: 0 },
{ x: 10, y: 5 },
{ x: 0, y: 5 },
]}
/>, // outline intentionally does not repeat the starting point
)

const soup = circuit.getCircuitJson()
const edgeCuts = convertSoupToGerberCommands(soup as any, {
flip_y_axis: true,
}).Edge_Cuts

const outlineCommands = edgeCuts.filter(
(cmd) => cmd.command_code === "D02" || cmd.command_code === "D01",
)

expect(
outlineCommands.map(({ command_code, x, y }) => ({
command_code,
x,
y: Object.is(y, -0) ? 0 : y,
})),
).toEqual([
{ command_code: "D02", x: 0, y: 0 },
{ command_code: "D01", x: 10, y: 0 },
{ command_code: "D01", x: 10, y: -5 },
{ command_code: "D01", x: 0, y: -5 },
{ command_code: "D01", x: 0, y: 0 },
])

const gerberOutput = stringifyGerberCommandLayers(
convertSoupToGerberCommands(soup as any, { flip_y_axis: true }),
)

await expect(gerberOutput).toMatchGerberSnapshot(
import.meta.path,
"outline-closure",
)
})
Loading