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
29 changes: 20 additions & 9 deletions lib/components/primitive-components/CopperPour/CopperPour.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export type { CopperPourProps }

export class CopperPour extends PrimitiveComponent<typeof copperPourProps> {
isPcbPrimitive = true
pcb_copper_pour_ids: string[] = []

get config() {
return {
Expand Down Expand Up @@ -44,6 +45,9 @@ export class CopperPour extends PrimitiveComponent<typeof copperPourProps> {
}
const subcircuit = this.getSubcircuit()
const circuitJson = db.toArray()
const copperPourCircuitJson = props.unbroken
? circuitJson.filter((element) => element.type !== "pcb_trace")
: circuitJson
const sourceNet = circuitJson.find(
(elm) => elm.type === "source_net" && elm.name === net.name,
) as SourceNet | undefined
Expand All @@ -58,15 +62,18 @@ export class CopperPour extends PrimitiveComponent<typeof copperPourProps> {
""

const clearance = props.clearance ?? 0.2
const inputProblem = convertCircuitJsonToInputProblem(circuitJson, {
layer: props.layer,
pour_connectivity_key: pourConnectivityKey,
pad_margin: props.padMargin ?? clearance,
trace_margin: props.traceMargin ?? clearance,
board_edge_margin: props.boardEdgeMargin ?? clearance,
cutout_margin: props.cutoutMargin ?? clearance,
outline: props.outline,
})
const inputProblem = convertCircuitJsonToInputProblem(
copperPourCircuitJson,
{
layer: props.layer,
pour_connectivity_key: pourConnectivityKey,
pad_margin: props.padMargin ?? clearance,
trace_margin: props.traceMargin ?? clearance,
board_edge_margin: props.boardEdgeMargin ?? clearance,
cutout_margin: props.cutoutMargin ?? clearance,
outline: props.outline,
},
)

const solver = new CopperPourPipelineSolver(inputProblem)

Expand All @@ -79,6 +86,7 @@ export class CopperPour extends PrimitiveComponent<typeof copperPourProps> {
const { brep_shapes } = solver.getOutput()

const coveredWithSolderMask = props.coveredWithSolderMask ?? false
const pcbCopperPourIds: string[] = []

for (const brep_shape of brep_shapes) {
const insertedPour = db.pcb_copper_pour.insert({
Expand All @@ -89,12 +97,15 @@ export class CopperPour extends PrimitiveComponent<typeof copperPourProps> {
subcircuit_id: subcircuit?.subcircuit_id ?? undefined,
covered_with_solder_mask: coveredWithSolderMask,
} as PcbCopperPour)
pcbCopperPourIds.push(insertedPour.pcb_copper_pour_id)

markTraceSegmentsInsideCopperPour({
db,
copperPour: insertedPour,
})
}

this.pcb_copper_pour_ids = pcbCopperPourIds
})
}
}
2 changes: 2 additions & 0 deletions lib/components/primitive-components/Group/Group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,7 @@ export class Group<Props extends z.ZodType<any, any, any> = typeof groupProps>
minTraceWidth: this.props.autorouter?.minTraceWidth ?? 0.15,
nominalTraceWidth: this.props.nominalTraceWidth,
subcircuit_id: this.subcircuit_id,
selectableRoot: this.root ?? undefined,
}).simpleRouteJson,
subcircuit_id: this.subcircuit_id!,
}),
Expand Down Expand Up @@ -566,6 +567,7 @@ export class Group<Props extends z.ZodType<any, any, any> = typeof groupProps>
minTraceWidth: this.props.autorouter?.minTraceWidth ?? 0.15,
nominalTraceWidth: this.props.nominalTraceWidth,
subcircuit_id: this.subcircuit_id,
selectableRoot: this.root ?? undefined,
})

// Enable jumpers for auto_jumper preset
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type { Port } from "../Port"
import type { TraceHint } from "../TraceHint"
import { getTraceLength } from "./trace-utils/compute-trace-length"
import { getObstaclesFromCircuitJson } from "lib/utils/obstacles/getObstaclesFromCircuitJson"
import { getUnbrokenCopperPourIds } from "lib/utils/obstacles/getUnbrokenCopperPourIds"
import { getViaDiameterDefaults } from "lib/utils/pcbStyle/getViaDiameterDefaults"
import { TraceConnectionError } from "lib/errors"
import { getPcbSelectorErrorForTracePort } from "./getPcbSelectorErrorForTracePort"
Expand Down Expand Up @@ -253,7 +254,10 @@ export function Trace_doInitialPcbTraceRender(trace: Trace) {
// Cache the PCB obstacles, they'll be needed for each segment between
// ports/hints
const [obstacles, errGettingObstacles] = tryNow(
() => getObstaclesFromCircuitJson(trace.root!.db.toArray() as any), // Remove as any when autorouting-dataset gets updated
() =>
getObstaclesFromCircuitJson(trace.root!.db.toArray() as any, connMap, {
unbrokenCopperPourIds: getUnbrokenCopperPourIds(trace.root),
}), // Remove as any when autorouting-dataset gets updated
)

if (errGettingObstacles) {
Expand All @@ -276,7 +280,7 @@ export function Trace_doInitialPcbTraceRender(trace: Trace) {
if (connectedTo.length > 0) {
const netId = connMap.getNetConnectedToId(obstacle.connectedTo[0])
if (netId) {
obstacle.connectedTo.push(netId)
obstacle.connectedTo = Array.from(new Set([...connectedTo, netId]))
}
}
}
Expand Down
11 changes: 11 additions & 0 deletions lib/utils/autorouting/getSimpleRouteJsonFromCircuitJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,15 @@ import {
getFullConnectivityMapFromCircuitJson,
} from "circuit-json-to-connectivity-map"
import { getObstaclesFromCircuitJson } from "../obstacles/getObstaclesFromCircuitJson"
import { getUnbrokenCopperPourIds } from "../obstacles/getUnbrokenCopperPourIds"
import type { SimpleRouteConnection } from "./SimpleRouteJson"
import type { SimpleRouteJson } from "./SimpleRouteJson"
import { getDescendantSubcircuitIds } from "./getAncestorSubcircuitIds"

type SelectableRoot = {
selectAll(selector: string): unknown[]
}

/**
* This function can only be called in the PcbTraceRender phase or later
*/
Expand All @@ -19,12 +24,14 @@ export const getSimpleRouteJsonFromCircuitJson = ({
subcircuit_id,
minTraceWidth = 0.1,
nominalTraceWidth,
selectableRoot,
}: {
db?: CircuitJsonUtilObjects
circuitJson?: AnyCircuitElement[]
subcircuit_id?: string | null
minTraceWidth?: number
nominalTraceWidth?: number
selectableRoot?: SelectableRoot
}): { simpleRouteJson: SimpleRouteJson; connMap: ConnectivityMap } => {
if (!db && circuitJson) {
db = su(circuitJson)
Expand Down Expand Up @@ -81,13 +88,17 @@ export const getSimpleRouteJsonFromCircuitJson = ({
...db.pcb_plated_hole.list(),
...db.pcb_hole.list(),
...db.pcb_via.list(),
...db.pcb_copper_pour.list(),
...db.pcb_cutout.list(),
// getObstaclesFromSoup is old and doesn't support diagonal traces
// ...db.pcb_trace.list(),
].filter(
(e) => !subcircuit_id || relevantSubcircuitIds?.has(e.subcircuit_id!),
),
connMap,
{
unbrokenCopperPourIds: getUnbrokenCopperPourIds(selectableRoot),
},
)

// Add everything in the connMap to the connectedTo array of each obstacle
Expand Down
76 changes: 76 additions & 0 deletions lib/utils/obstacles/getObstaclesFromCircuitJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,77 @@ import { fillCircleWithRects } from "./fillCircleWithRects"
import type { Obstacle } from "./types"

const EVERY_LAYER = ["top", "inner1", "inner2", "bottom"]
const COPPER_POUR_RECT_HEIGHT = 0.6

const getUnbrokenCopperPourObstacles = (
element: Extract<AnyCircuitElement, { type: "pcb_copper_pour" }>,
withNetId: (ids: string[]) => string[],
unbrokenCopperPourIds: Set<string>,
): Obstacle[] => {
if (!unbrokenCopperPourIds.has(element.pcb_copper_pour_id)) return []

const connectedTo = element.source_net_id
? withNetId([element.source_net_id])
: []

if (element.shape === "rect") {
if (element.rotation) {
const approximatingRects = generateApproximatingRects({
center: element.center,
width: element.width,
height: element.height,
rotation: element.rotation,
})

return approximatingRects.map((rect) => ({
type: "rect",
layers: [element.layer],
center: rect.center,
width: rect.width,
height: rect.height,
connectedTo: [...connectedTo],
}))
}

return [
{
type: "rect",
layers: [element.layer],
center: element.center,
width: element.width,
height: element.height,
connectedTo,
},
]
}

if (element.shape === "brep") {
const outerRing = element.brep_shape.outer_ring.vertices.map((vertex) => ({
x: vertex.x,
y: vertex.y,
}))

return fillPolygonWithRects(outerRing, {
rectHeight: COPPER_POUR_RECT_HEIGHT,
}).map((rect) => ({
type: "rect",
layers: [element.layer],
center: rect.center,
width: rect.width,
height: rect.height,
connectedTo: [...connectedTo],
}))
}

return []
}

export const getObstaclesFromCircuitJson = (
soup: AnyCircuitElement[],
connMap?: ConnectivityMap,
options?: {
unbrokenCopperPourIds?: Set<string>
},
) => {
const withNetId = (idList: string[]) =>
connMap
Expand All @@ -22,6 +89,7 @@ export const getObstaclesFromCircuitJson = (
)
: idList
const obstacles: Obstacle[] = []
const unbrokenCopperPourIds = options?.unbrokenCopperPourIds ?? new Set()
for (const element of soup) {
if (element.type === "pcb_smtpad") {
if (element.shape === "circle") {
Expand Down Expand Up @@ -266,6 +334,14 @@ export const getObstaclesFromCircuitJson = (
})
}
}
} else if (element.type === "pcb_copper_pour") {
obstacles.push(
...getUnbrokenCopperPourObstacles(
element,
withNetId,
unbrokenCopperPourIds,
),
)
} else if (element.type === "pcb_trace") {
const traceObstacles = getObstaclesFromRoute(
element.route.map((rp) => ({
Expand Down
34 changes: 34 additions & 0 deletions lib/utils/obstacles/getUnbrokenCopperPourIds.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
type Selectable = {
selectAll(selector: string): unknown[]
}

type CopperPourLike = {
lowercaseComponentName?: string
_parsedProps?: {
unbroken?: boolean
}
pcb_copper_pour_ids?: string[]
}

const isCopperPourLike = (value: unknown): value is CopperPourLike =>
typeof value === "object" && value !== null

export const getUnbrokenCopperPourIds = (
selectable?: Selectable | null,
): Set<string> => {
if (!selectable) return new Set()

const unbrokenCopperPourIds = new Set<string>()

for (const component of selectable.selectAll("copperpour")) {
if (!isCopperPourLike(component)) continue
if (component.lowercaseComponentName !== "copperpour") continue
if (!component._parsedProps?.unbroken) continue

for (const pcbCopperPourId of component.pcb_copper_pour_ids ?? []) {
unbrokenCopperPourIds.add(pcbCopperPourId)
}
}

return unbrokenCopperPourIds
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"@tscircuit/math-utils": "^0.0.36",
"@tscircuit/miniflex": "^0.0.4",
"@tscircuit/ngspice-spice-engine": "^0.0.8",
"@tscircuit/props": "^0.0.502",
"@tscircuit/props": "^0.0.503",
"@tscircuit/schematic-match-adapt": "^0.0.16",
"@tscircuit/schematic-trace-solver": "^v0.0.45",
"@tscircuit/solver-utils": "^0.0.3",
Expand Down
Loading
Loading