Skip to content

Require a trace endpoint's pad to be on the same layer#166

Open
abdalraof-albarbar wants to merge 1 commit into
tscircuit:mainfrom
abdalraof-albarbar:traces-layer-fix
Open

Require a trace endpoint's pad to be on the same layer#166
abdalraof-albarbar wants to merge 1 commit into
tscircuit:mainfrom
abdalraof-albarbar:traces-layer-fix

Conversation

@abdalraof-albarbar

@abdalraof-albarbar abdalraof-albarbar commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Closes #167

Fixes the false negative from #165. checkTracesAreContiguous matched endpoints to pads by x/y only, so a top-layer wire endpoint was accepted as connected to a bottom-layer pad. Now each isPointInPad check is gated by the endpoint's layer (SMT pad → its layer, plated hole → its copper layers). Legit via routes still pass since each endpoint lands on its own pad's layer; full suite stays green.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure what i am seeing

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call — I removed that snapshot. This is a verdict-only fix (the DRC now flags a trace endpoint whose pad is on a different layer), so the board render was byte-identical on both branches and the snapshot showed nothing to compare. The layer check is covered by the numeric test instead. Mind taking another look when you get a sec? 🙏

@abdalraof-albarbar

abdalraof-albarbar commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

that snapshot wasn't showing anything useful. It just rendered the board, which is identical whether the check passes or fails (the fix changes the check's result, not the geometry), so there was genuinely nothing to see in it. Removed it. The layer bug is covered by the assertion test instead — a top-layer wire endpoint on a bottom-layer pad now returns an error. @0hmX @seveibar

@0hmX 0hmX left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the fix looks valid; i am not sure i can approve this because i am not the code owner maybe @MustafaMulla29 can take a look he last edited this file

isPointInPad({ x: lastPoint.x, y: lastPoint.y }, pad),
pads.some(
(pad) =>
isPointInPad({ x: lastPoint.x, y: lastPoint.y }, pad) &&

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i do not think you need a new function isPointInPad should also check the layer

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call — folded the layer check into isPointInPad and removed the separate isPadOnLayer.

@MustafaMulla29 MustafaMulla29 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should first try to reproduce it with a snapshot test along with "shouldDrawErrors: true".

@abdalraof-albarbar

Copy link
Copy Markdown
Contributor Author

@MustafaMulla29 added a snapshot test rendered with shouldDrawErrors: true — it shows the flagged endpoint (a top-layer wire landing on a bottom-layer pad), so the error is now visible in the snapshot. Also folded the layer check into isPointInPad per @0hmX.

@MustafaMulla29 MustafaMulla29 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Repro should be merged first and then the solution

@abdalraof-albarbar

Copy link
Copy Markdown
Contributor Author

@MustafaMulla29 restructured as suggested: the repro (#165) now carries the shouldDrawErrors snapshot test — on the unfixed code it renders the scenario with no error drawn — and this fix flips it so the error marker appears. Repro is ready to merge first, then this.


export function isPointInPad(
point: { x: number; y: number },
point: { x: number; y: number; layer?: string },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layer can be a separate param, point is represented only with x an y

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — isPointInPad(point, pad, layer?) now takes layer as a separate param; point stays { x, y }. All call sites pass the endpoint's layer through.

@MustafaMulla29 MustafaMulla29 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment and now just update the repro snapshot and remove this repro from pr.

checkTracesAreContiguous matched an endpoint to a pad by x/y only, so a
top-layer wire endpoint counted as connected to a bottom-layer pad. Gate
the match on layer: isPointInPad now takes the endpoint's layer as a
separate param and rejects a pad on a different layer (smt pad -> its
layer, plated hole -> its copper layers).

Flips the repro tests from tscircuit#165 to passing and updates the
shouldDrawErrors snapshot to show the now-flagged endpoint.

Co-authored-by: abdalrouf-AAA <236259618+technologyet31-create@users.noreply.github.com>
@abdalraof-albarbar

Copy link
Copy Markdown
Contributor Author

@MustafaMulla29 addressed both points:

  • Repro removed from this PR — rebased onto main (which now has the merged repro Add a repro test for checkTracesAreContiguous ignoring pad layer #165), so the PR no longer re-adds the test file. The only change to the test is flipping the two test.failing cases to test now that the fix makes them pass.
  • Repro snapshot updated — regenerated trace-endpoint-on-different-layer.snap.svg; it now renders the pcb_trace_error marker on the endpoint that lands on the wrong-layer pad.
  • isPointInPadlayer is now a separate param, point stays { x, y } (per your inline comment).

Diff is now just the lib fix + the snapshot update + the .failing flip. Full suite green (127 pass).

point: { x: number; y: number },
pad: PcbSmtPad | PcbPlatedHole,
layer?: string,
): boolean {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See if we have a layer type we can import from circuit-json. Otherwise looks good

const padIsOnLayer =
pad.type === "pcb_smtpad"
? pad.layer === layer
: pad.layers.some((padLayer) => padLayer === layer)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplify this, remove ternary

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

checkTracesAreContiguous accepts a trace endpoint connected to a pad on a different layer

3 participants