fix: route_pad_to_pad auto-inserts via when pads are on different copper layers
- Detects F.Cu<->B.Cu layer mismatch in route_pad_to_pad - Splits route into: trace on start layer + via at midpoint + trace on end layer - route_trace description warns: use route_pad_to_pad for cross-layer routing - route_pad_to_pad description highlights automatic via insertion
This commit is contained in:
@@ -144,40 +144,64 @@ class RoutingCommands:
|
||||
if not net:
|
||||
net = start_pad.GetNetname() or end_pad.GetNetname() or ""
|
||||
|
||||
# Delegate to route_trace
|
||||
result = self.route_trace(
|
||||
{
|
||||
"start": {
|
||||
"x": start_pos.x / scale,
|
||||
"y": start_pos.y / scale,
|
||||
"unit": "mm",
|
||||
},
|
||||
"end": {
|
||||
"x": end_pos.x / scale,
|
||||
"y": end_pos.y / scale,
|
||||
"unit": "mm",
|
||||
},
|
||||
"layer": layer,
|
||||
"width": width,
|
||||
"net": net,
|
||||
}
|
||||
# Detect if pads are on different copper layers → need via
|
||||
start_layer = start_pad.GetLayerName()
|
||||
end_layer = end_pad.GetLayerName()
|
||||
copper_layers = {"F.Cu", "B.Cu"}
|
||||
needs_via = (
|
||||
start_layer in copper_layers
|
||||
and end_layer in copper_layers
|
||||
and start_layer != end_layer
|
||||
)
|
||||
|
||||
if needs_via:
|
||||
# Place via at midpoint between the two pads
|
||||
via_x = (start_pos.x + end_pos.x) / 2 / scale
|
||||
via_y = (start_pos.y + end_pos.y) / 2 / scale
|
||||
|
||||
# Trace on start layer: start_pad → via
|
||||
r1 = self.route_trace({
|
||||
"start": {"x": start_pos.x / scale, "y": start_pos.y / scale, "unit": "mm"},
|
||||
"end": {"x": via_x, "y": via_y, "unit": "mm"},
|
||||
"layer": start_layer, "width": width, "net": net,
|
||||
})
|
||||
# Via connecting both layers
|
||||
self.add_via({
|
||||
"position": {"x": via_x, "y": via_y, "unit": "mm"},
|
||||
"net": net,
|
||||
"from_layer": start_layer,
|
||||
"to_layer": end_layer,
|
||||
})
|
||||
# Trace on end layer: via → end_pad
|
||||
r2 = self.route_trace({
|
||||
"start": {"x": via_x, "y": via_y, "unit": "mm"},
|
||||
"end": {"x": end_pos.x / scale, "y": end_pos.y / scale, "unit": "mm"},
|
||||
"layer": end_layer, "width": width, "net": net,
|
||||
})
|
||||
success = r1.get("success") and r2.get("success")
|
||||
result = {
|
||||
"success": success,
|
||||
"message": f"Routed {from_ref}.{from_pad} → via → {to_ref}.{to_pad} (net: {net}, via at {via_x:.2f},{via_y:.2f})",
|
||||
"via_added": True,
|
||||
"via_position": {"x": via_x, "y": via_y},
|
||||
}
|
||||
else:
|
||||
# Same layer — direct trace
|
||||
result = self.route_trace({
|
||||
"start": {"x": start_pos.x / scale, "y": start_pos.y / scale, "unit": "mm"},
|
||||
"end": {"x": end_pos.x / scale, "y": end_pos.y / scale, "unit": "mm"},
|
||||
"layer": layer if layer else start_layer,
|
||||
"width": width, "net": net,
|
||||
})
|
||||
|
||||
if result.get("success"):
|
||||
result["message"] = (
|
||||
f"Routed {from_ref}.{from_pad} → {to_ref}.{to_pad} (net: {net or 'none'})"
|
||||
)
|
||||
result["fromPad"] = {
|
||||
"ref": from_ref,
|
||||
"pad": from_pad,
|
||||
"x": start_pos.x / scale,
|
||||
"y": start_pos.y / scale,
|
||||
"ref": from_ref, "pad": from_pad,
|
||||
"x": start_pos.x / scale, "y": start_pos.y / scale,
|
||||
}
|
||||
result["toPad"] = {
|
||||
"ref": to_ref,
|
||||
"pad": to_pad,
|
||||
"x": end_pos.x / scale,
|
||||
"y": end_pos.y / scale,
|
||||
"ref": to_ref, "pad": to_pad,
|
||||
"x": end_pos.x / scale, "y": end_pos.y / scale,
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
@@ -33,7 +33,7 @@ export function registerRoutingTools(
|
||||
// Route trace tool
|
||||
server.tool(
|
||||
"route_trace",
|
||||
"Route a trace between two points",
|
||||
"Route a trace segment between two XY points on a fixed layer. WARNING: Does NOT handle layer changes — if start and end are on different copper layers, use route_pad_to_pad instead, which automatically inserts a via.",
|
||||
{
|
||||
start: z
|
||||
.object({
|
||||
@@ -331,7 +331,7 @@ export function registerRoutingTools(
|
||||
// Route pad to pad tool
|
||||
server.tool(
|
||||
"route_pad_to_pad",
|
||||
"Route a trace directly from one component pad to another without needing separate get_pad_position calls. Automatically looks up pad coordinates and uses the pad's net. Saves token usage compared to the 3-step get_pad_position + get_pad_position + route_trace sequence.",
|
||||
"PREFERRED tool for pad-to-pad routing. Looks up pad positions automatically, detects the net from the pad, and — critically — if the two pads are on different copper layers (e.g. J1 on F.Cu and J2 on B.Cu) automatically inserts a via at the midpoint so the connection is complete. Always use this instead of route_trace when routing between named component pads.",
|
||||
{
|
||||
fromRef: z.string().describe("Reference of the source component (e.g. 'U2')"),
|
||||
fromPad: z.union([z.string(), z.number()]).describe("Pad number on the source component (e.g. '6' or 6)"),
|
||||
|
||||
Reference in New Issue
Block a user