diff --git a/lib/components/primitive-components/Group/Subcircuit/inflators/inflateFootprintComponent.ts b/lib/components/primitive-components/Group/Subcircuit/inflators/inflateFootprintComponent.ts index 7a1ea44d2..a0bc910c6 100644 --- a/lib/components/primitive-components/Group/Subcircuit/inflators/inflateFootprintComponent.ts +++ b/lib/components/primitive-components/Group/Subcircuit/inflators/inflateFootprintComponent.ts @@ -1,7 +1,6 @@ import type { PcbComponent } from "circuit-json" -import { Footprint } from "lib/components/primitive-components/Footprint" -import { extractPcbPrimitivesFromCircuitJson } from "lib/utils/extractPcbPrimitivesFromCircuitJson" import type { InflatorContext } from "../InflatorFn" +import { inflatePcbComponentPrimitives } from "./inflatePcbComponentPrimitives" /** * Inflates a Footprint component from circuit JSON by extracting all PCB primitives @@ -14,20 +13,11 @@ import type { InflatorContext } from "../InflatorFn" export const inflateFootprintComponent = ( pcbElm: PcbComponent, inflatorContext: InflatorContext, -): Footprint | null => { - const { injectionDb, normalComponent } = inflatorContext + ) => { + const { normalComponent } = inflatorContext if (!normalComponent) return null - - const primitives = extractPcbPrimitivesFromCircuitJson({ - pcbComponent: pcbElm, - db: injectionDb, + return inflatePcbComponentPrimitives(pcbElm, { componentName: normalComponent.name, + inflatorContext, }) - - if (primitives.length === 0) return null - - const footprint = new Footprint({ originalLayer: pcbElm.layer }) - footprint.addAll(primitives) - - return footprint } diff --git a/lib/components/primitive-components/Group/Subcircuit/inflators/inflatePcbComponentPrimitives.ts b/lib/components/primitive-components/Group/Subcircuit/inflators/inflatePcbComponentPrimitives.ts new file mode 100644 index 000000000..a466e201e --- /dev/null +++ b/lib/components/primitive-components/Group/Subcircuit/inflators/inflatePcbComponentPrimitives.ts @@ -0,0 +1,28 @@ +import type { PcbComponent } from "circuit-json" +import { Footprint } from "lib/components/primitive-components/Footprint" +import { extractPcbPrimitivesFromCircuitJson } from "lib/utils/extractPcbPrimitivesFromCircuitJson" +import type { InflatorContext } from "../InflatorFn" + +export const inflatePcbComponentPrimitives = ( + pcbComponent: PcbComponent, + { + componentName, + inflatorContext, + }: { + componentName: string + inflatorContext: InflatorContext + }, +): Footprint | null => { + const primitives = extractPcbPrimitivesFromCircuitJson({ + pcbComponent, + db: inflatorContext.injectionDb, + componentName, + }) + + if (primitives.length === 0) return null + + const footprint = new Footprint({ originalLayer: pcbComponent.layer }) + footprint.addAll(primitives) + + return footprint +} diff --git a/lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceFiducial.ts b/lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceFiducial.ts new file mode 100644 index 000000000..8acb8aa94 --- /dev/null +++ b/lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceFiducial.ts @@ -0,0 +1,52 @@ +import type { PcbComponent, SourceSimpleFiducial } from "circuit-json" +import { ImportedPcbComponent } from "lib/components/primitive-components/ImportedPcbComponent" +import type { InflatorContext } from "../InflatorFn" +import { inflatePcbComponentPrimitives } from "./inflatePcbComponentPrimitives" +import { getInflatedPcbPlacement } from "./getInflatedPcbPlacement" + +export function inflateSourceFiducial( + sourceElm: SourceSimpleFiducial, + inflatorContext: InflatorContext, +) { + const { injectionDb, subcircuit, groupsMap } = inflatorContext + + const pcbElm = injectionDb.pcb_component.getWhere({ + source_component_id: sourceElm.source_component_id, + }) as PcbComponent | null + + const { pcbX, pcbY } = getInflatedPcbPlacement({ + pcbComponent: pcbElm, + sourceGroupId: sourceElm.source_group_id, + inflatorContext, + }) + + const fiducial = new ImportedPcbComponent({ + height: pcbElm?.height, + name: sourceElm.name, + layer: pcbElm?.layer, + obstructsWithinBounds: pcbElm?.obstructs_within_bounds, + pcbX, + pcbY, + pcbRotation: pcbElm?.rotation, + doNotPlace: pcbElm?.do_not_place, + width: pcbElm?.width, + }) + + if (pcbElm) { + const footprint = inflatePcbComponentPrimitives(pcbElm, { + componentName: sourceElm.name, + inflatorContext, + }) + + if (footprint) { + fiducial.add(footprint) + } + } + + if (sourceElm.source_group_id && groupsMap?.has(sourceElm.source_group_id)) { + const group = groupsMap.get(sourceElm.source_group_id)! + group.add(fiducial) + } else { + subcircuit.add(fiducial) + } +} diff --git a/lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceLed.ts b/lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceLed.ts new file mode 100644 index 000000000..47bbcdb09 --- /dev/null +++ b/lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceLed.ts @@ -0,0 +1,56 @@ +import type { CadComponent, PcbComponent, SourceSimpleLed } from "circuit-json" +import { Led } from "lib/components/normal-components/Led" +import type { InflatorContext } from "../InflatorFn" +import { inflateFootprintComponent } from "./inflateFootprintComponent" +import { getInflatedPcbPlacement } from "./getInflatedPcbPlacement" + +export function inflateSourceLed( + sourceElm: SourceSimpleLed, + inflatorContext: InflatorContext, +) { + const { injectionDb, subcircuit, groupsMap } = inflatorContext + + const pcbElm = injectionDb.pcb_component.getWhere({ + source_component_id: sourceElm.source_component_id, + }) as PcbComponent | null + + const cadElm = injectionDb.cad_component.getWhere({ + source_component_id: sourceElm.source_component_id, + }) as CadComponent | null + + const { pcbX, pcbY } = getInflatedPcbPlacement({ + pcbComponent: pcbElm, + sourceGroupId: sourceElm.source_group_id, + inflatorContext, + }) + + const led = new Led({ + name: sourceElm.name, + color: sourceElm.color, + wavelength: sourceElm.wavelength, + layer: pcbElm?.layer, + pcbX, + pcbY, + pcbRotation: pcbElm?.rotation, + doNotPlace: pcbElm?.do_not_place, + obstructsWithinBounds: pcbElm?.obstructs_within_bounds, + }) + + if (pcbElm) { + const footprint = inflateFootprintComponent(pcbElm, { + ...inflatorContext, + normalComponent: led, + }) + + if (footprint) { + led.add(footprint) + } + } + + if (sourceElm.source_group_id && groupsMap?.has(sourceElm.source_group_id)) { + const group = groupsMap.get(sourceElm.source_group_id)! + group.add(led) + } else { + subcircuit.add(led) + } +} diff --git a/lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceTrace.ts b/lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceTrace.ts index ae2c63691..69e1eb1ee 100644 --- a/lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceTrace.ts +++ b/lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceTrace.ts @@ -1,14 +1,6 @@ -import type { - LayerRef, - PcbTrace, - PcbTraceRoutePoint, - SourceTrace, -} from "circuit-json" +import type { PcbTrace, PcbVia, SourceTrace } from "circuit-json" import { Trace } from "lib/components/primitive-components/Trace/Trace" -import { - type ManualPcbPathPoint, - pcbTraceRouteToPcbPath, -} from "lib/utils/pcbTraceRouteToPcbPath" +import { setImportedTracePayload } from "lib/components/primitive-components/Trace/imported-trace-payload-registry" import type { InflatorContext } from "../InflatorFn" const getSelectorPath = ( @@ -90,28 +82,37 @@ export function inflateSourceTrace( return } - const pcbTrace = injectionDb.pcb_trace.getWhere({ - source_trace_id: sourceTrace.source_trace_id, - }) - - let pcbPath: ManualPcbPathPoint[] | undefined - if (pcbTrace) { - pcbPath = pcbTraceRouteToPcbPath(pcbTrace.route) - } - - // Extract trace width from source_trace or pcb_trace route points + const pcbTraces = injectionDb.pcb_trace + .list() + .filter( + (pcbTrace) => pcbTrace.source_trace_id === sourceTrace.source_trace_id, + ) + + const inflatedPcbVias: PcbVia[] | undefined = + pcbTraces.length > 0 + ? injectionDb.pcb_via + .list() + .filter((via) => + pcbTraces.some( + (pcbTrace) => pcbTrace.pcb_trace_id === via.pcb_trace_id, + ), + ) + : undefined + + // Extract trace width from source_trace or the first imported pcb_trace route let traceWidth: number | undefined = sourceTrace.min_trace_thickness - if (!traceWidth && pcbTrace?.route) { - // Try to get width from the first wire point in the route - const wirePoint = pcbTrace.route.find((pt) => pt.route_type === "wire") - if (wirePoint && wirePoint.route_type === "wire") { - traceWidth = wirePoint.width + if (!traceWidth) { + for (const pcbTrace of pcbTraces) { + const wirePoint = pcbTrace.route.find((pt) => pt.route_type === "wire") + if (wirePoint && wirePoint.route_type === "wire") { + traceWidth = wirePoint.width + break + } } } const traceProps: { path: string[] - pcbPath?: ManualPcbPathPoint[] pcbStraightLine?: boolean thickness?: number } = { @@ -122,12 +123,8 @@ export function inflateSourceTrace( traceProps.thickness = traceWidth } - // If pcbPath has intermediate points, use manual routing - // Otherwise, use straight-line routing (simple 2-point traces) - if (pcbPath && pcbPath.length > 0) { - traceProps.pcbPath = pcbPath - } else if ( - !pcbTrace && + if ( + pcbTraces.length === 0 && sourceTrace.connected_source_port_ids.length === 2 && sourceTrace.connected_source_net_ids.length === 0 ) { @@ -137,12 +134,11 @@ export function inflateSourceTrace( } const trace = new Trace(traceProps) - trace._inflatedPcbTrace = pcbTrace ?? undefined - trace._inflatedPcbVias = pcbTrace - ? injectionDb.pcb_via - .list() - .filter((via) => via.pcb_trace_id === pcbTrace.pcb_trace_id) - : undefined + setImportedTracePayload(trace, { + importedPcbTraces: pcbTraces.length > 0 ? pcbTraces : undefined, + importedPcbVias: inflatedPcbVias, + importedSourceTrace: sourceTrace, + }) subcircuit.add(trace) } diff --git a/lib/components/primitive-components/ImportedPcbComponent.ts b/lib/components/primitive-components/ImportedPcbComponent.ts new file mode 100644 index 000000000..b9108c125 --- /dev/null +++ b/lib/components/primitive-components/ImportedPcbComponent.ts @@ -0,0 +1,65 @@ +import type { LayerRef } from "circuit-json" +import { z } from "zod" +import { PrimitiveComponent } from "../base-components/PrimitiveComponent" + +const importedPcbComponentProps = z.object({ + doNotPlace: z.boolean().optional(), + height: z.number().optional(), + layer: z.custom().optional(), + name: z.string().optional(), + obstructsWithinBounds: z.boolean().optional(), + pcbRotation: z.number().optional(), + pcbX: z.number().optional(), + pcbY: z.number().optional(), + width: z.number().optional(), +}) + +export class ImportedPcbComponent extends PrimitiveComponent< + typeof importedPcbComponentProps +> { + isPrimitiveContainer = true + + get config() { + return { + componentName: "ImportedPcbComponent", + sourceFtype: "simple_fiducial" as const, + zodProps: importedPcbComponentProps, + } + } + + protected _getPcbComponentLayer(): LayerRef | undefined { + return this._parsedProps.layer + } + + doInitialSourceRender() { + const { db } = this.root! + const sourceComponent = db.source_component.insert({ + ftype: "simple_fiducial", + name: this.name, + }) + + this.source_component_id = sourceComponent.source_component_id + } + + doInitialPcbComponentRender() { + if (this.root?.pcbDisabled) return + const { db } = this.root! + const { _parsedProps: props } = this + const { pcbX = 0, pcbY = 0 } = this.getResolvedPcbPositionProp() + + const pcbComponent = db.pcb_component.insert({ + center: { x: pcbX, y: pcbY }, + width: props.width ?? 0, + height: props.height ?? 0, + layer: props.layer ?? "top", + rotation: props.pcbRotation ?? 0, + source_component_id: this.source_component_id!, + subcircuit_id: this.getSubcircuit().subcircuit_id ?? undefined, + pcb_group_id: this.getGroup()?.pcb_group_id ?? undefined, + do_not_place: props.doNotPlace ?? false, + obstructs_within_bounds: props.obstructsWithinBounds ?? true, + }) + + this.pcb_component_id = pcbComponent.pcb_component_id + } +} diff --git a/lib/components/primitive-components/Trace/Trace.ts b/lib/components/primitive-components/Trace/Trace.ts index 66a1e0ff3..3283a676f 100644 --- a/lib/components/primitive-components/Trace/Trace.ts +++ b/lib/components/primitive-components/Trace/Trace.ts @@ -2,9 +2,7 @@ import { MultilayerIjump } from "@tscircuit/infgrid-ijump-astar" import { traceProps } from "@tscircuit/props" import { type LayerRef, - type PcbTrace, type PcbTraceRoutePoint, - type PcbVia, type RouteHintPoint, type SchematicNetLabel, type SchematicTrace, @@ -44,6 +42,7 @@ import { Trace_doInitialPcbTraceRender } from "./Trace_doInitialPcbTraceRender" import { Trace_doInitialPcbManualTraceRender } from "./Trace_doInitialPcbManualTraceRender" import { Trace__doInitialSchematicTraceRenderWithDisplayLabel } from "./Trace__doInitialSchematicTraceRenderWithDisplayLabel" import { Trace__findConnectedPorts } from "./Trace__findConnectedPorts" +import { getImportedTracePayload } from "./imported-trace-payload-registry" import { TraceConnectionError } from "../../../errors" export class Trace @@ -53,8 +52,6 @@ export class Trace source_trace_id: string | null = null pcb_trace_id: string | null = null schematic_trace_id: string | null = null - _inflatedPcbTrace?: PcbTrace - _inflatedPcbVias?: PcbVia[] _portsRoutedOnPcb: Port[] subcircuit_connectivity_map_key: string | null = null _traceConnectionHash: string | null = null @@ -232,6 +229,7 @@ export class Trace doInitialSourceTraceRender(): void { const { db } = this.root! const { _parsedProps: props, parent } = this + const subcircuit = this.getSubcircuit() if (!parent) { this.renderError("Trace has no parent") @@ -260,6 +258,8 @@ export class Trace if (!allPortsFound) return this._traceConnectionHash = this._computeTraceConnectionHash() + const nets = this._findConnectedNets().nets + const importedTracePayload = getImportedTracePayload(this) const existingTraces = db.source_trace.list() const existingTrace = existingTraces.find( @@ -274,19 +274,23 @@ export class Trace return } - const nets = this._findConnectedNets().nets const displayName = getTraceDisplayName({ ports: ports, nets: nets }) const trace = db.source_trace.insert({ connected_source_port_ids: ports.map((p) => p.port.source_port_id!), connected_source_net_ids: nets.map((n) => n.source_net_id!), - subcircuit_id: this.getSubcircuit()?.subcircuit_id!, + subcircuit_id: subcircuit?.subcircuit_id!, max_length: + importedTracePayload?.importedSourceTrace?.max_length ?? getMaxLengthFromConnectedCapacitors( ports.map((p) => p.port), { db }, - ) ?? props.maxLength, - display_name: displayName, - min_trace_thickness: this._getExplicitTraceThickness(), + ) ?? + props.maxLength, + display_name: + importedTracePayload?.importedSourceTrace?.display_name ?? displayName, + min_trace_thickness: + importedTracePayload?.importedSourceTrace?.min_trace_thickness ?? + this._getExplicitTraceThickness(), }) this.source_trace_id = trace.source_trace_id diff --git a/lib/components/primitive-components/Trace/Trace_doInitialPcbManualTraceRender.ts b/lib/components/primitive-components/Trace/Trace_doInitialPcbManualTraceRender.ts index 0ec514bb2..246f60708 100644 --- a/lib/components/primitive-components/Trace/Trace_doInitialPcbManualTraceRender.ts +++ b/lib/components/primitive-components/Trace/Trace_doInitialPcbManualTraceRender.ts @@ -1,4 +1,4 @@ -import type { LayerRef, PcbTraceRoutePoint, PcbVia } from "circuit-json" +import type { LayerRef, PcbTraceRoutePoint } from "circuit-json" import { getTraceLength } from "./trace-utils/compute-trace-length" import type { Port } from "../Port" import type { Trace } from "./Trace" @@ -9,34 +9,8 @@ import type { ManualPcbPathPoint } from "lib/utils/pcbTraceRouteToPcbPath" import { TraceConnectionError } from "lib/errors" import { getPcbSelectorErrorForTracePort } from "./getPcbSelectorErrorForTracePort" import { jlcMinTolerances } from "@tscircuit/jlcpcb-manufacturing-specs" - -const findInflatedPcbViaForPoint = ( - vias: PcbVia[] | undefined, - point: PcbTraceRoutePoint, -): PcbVia | undefined => { - if (point.route_type !== "via") return undefined - return vias?.find( - (via) => - Math.abs(via.x - point.x) < 0.0001 && - Math.abs(via.y - point.y) < 0.0001 && - (!via.from_layer || via.from_layer === point.from_layer) && - (!via.to_layer || via.to_layer === point.to_layer), - ) -} - -const getViaDiameterFromRoutePoint = (point: PcbTraceRoutePoint) => { - const viaPoint = point as PcbTraceRoutePoint & { - hole_diameter?: number - outer_diameter?: number - via_hole_diameter?: number - via_diameter?: number - } - - return { - holeDiameter: viaPoint.hole_diameter ?? viaPoint.via_hole_diameter, - outerDiameter: viaPoint.outer_diameter ?? viaPoint.via_diameter, - } -} +import { getImportedTracePayload } from "./imported-trace-payload-registry" +import { Trace_renderImportedPcbTraces } from "./Trace_renderImportedPcbTraces" export function Trace_doInitialPcbManualTraceRender(trace: Trace) { if (trace.root?.pcbDisabled) return @@ -46,9 +20,15 @@ export function Trace_doInitialPcbManualTraceRender(trace: Trace) { const hasPcbPath = props.pcbPath !== undefined const wantsStraightLine = Boolean(props.pcbStraightLine) - const inflatedPcbTrace = trace._inflatedPcbTrace + const importedTracePayload = getImportedTracePayload(trace) - if (!hasPcbPath && !wantsStraightLine && !inflatedPcbTrace) return + if ( + !hasPcbPath && + !wantsStraightLine && + !importedTracePayload?.importedPcbTraces?.length + ) { + return + } let allPortsFound: boolean let ports: Port[] @@ -118,99 +98,14 @@ export function Trace_doInitialPcbManualTraceRender(trace: Trace) { trace.getSubcircuit()._parsedProps.minTraceWidth ?? jlcMinTolerances.min_trace_width! - if (inflatedPcbTrace) { - const { maybeFlipLayer } = trace._getPcbPrimitiveFlippedHelpers() - const transform = trace._computePcbGlobalTransformBeforeLayout() - const transformedRoute = inflatedPcbTrace.route.map((point) => { - if (point.route_type === "wire") { - const { x, y, ...restOfPoint } = point - const transformedPoint = applyToPoint(transform, { x, y }) - return { - ...restOfPoint, - ...transformedPoint, - layer: maybeFlipLayer(point.layer), - } as PcbTraceRoutePoint - } - - if (point.route_type === "via") { - const { x, y, ...restOfPoint } = point - const transformedPoint = applyToPoint(transform, { x, y }) - return { - ...restOfPoint, - ...transformedPoint, - from_layer: maybeFlipLayer(point.from_layer), - to_layer: maybeFlipLayer(point.to_layer), - } as PcbTraceRoutePoint - } - - return { - ...point, - start: applyToPoint(transform, point.start), - end: applyToPoint(transform, point.end), - start_layer: maybeFlipLayer(point.start_layer), - end_layer: maybeFlipLayer(point.end_layer), - } as PcbTraceRoutePoint + if ( + importedTracePayload && + Trace_renderImportedPcbTraces({ + importedTracePayload, + ports, + trace, }) - - const pcb_trace = db.pcb_trace.insert({ - ...inflatedPcbTrace, - route: transformedRoute, - source_trace_id: trace.source_trace_id!, - subcircuit_id: subcircuit?.subcircuit_id ?? undefined, - pcb_group_id: trace.getGroup()?.pcb_group_id ?? undefined, - }) - const pcbStyle = trace.getInheritedMergedProperty("pcbStyle") - const { holeDiameter, padDiameter } = getViaDiameterDefaults(pcbStyle) - for (let index = 0; index < transformedRoute.length; index++) { - const point = transformedRoute[index] - if (point.route_type === "via") { - const originalPoint = inflatedPcbTrace.route[index] - const inflatedPcbVia = findInflatedPcbViaForPoint( - trace._inflatedPcbVias, - originalPoint, - ) - const routePointViaDiameter = getViaDiameterFromRoutePoint(point) - const fromLayer = maybeFlipLayer( - (inflatedPcbVia?.from_layer ?? point.from_layer) as LayerRef, - ) - const toLayer = maybeFlipLayer( - (inflatedPcbVia?.to_layer ?? point.to_layer) as LayerRef, - ) - const layers = ( - inflatedPcbVia?.layers ?? [ - point.from_layer as LayerRef, - point.to_layer, - ] - ).map((layer) => maybeFlipLayer(layer as LayerRef)) - - db.pcb_via.insert({ - pcb_trace_id: pcb_trace.pcb_trace_id, - x: point.x, - y: point.y, - hole_diameter: - inflatedPcbVia?.hole_diameter ?? - routePointViaDiameter.holeDiameter ?? - holeDiameter, - outer_diameter: - inflatedPcbVia?.outer_diameter ?? - routePointViaDiameter.outerDiameter ?? - padDiameter, - layers, - from_layer: fromLayer, - to_layer: toLayer, - subcircuit_id: subcircuit?.subcircuit_id ?? undefined, - pcb_group_id: trace.getGroup()?.pcb_group_id ?? undefined, - subcircuit_connectivity_map_key: - inflatedPcbVia?.subcircuit_connectivity_map_key, - net_is_assignable: inflatedPcbVia?.net_is_assignable, - net_assigned: inflatedPcbVia?.net_assigned, - is_tented: inflatedPcbVia?.is_tented, - }) - } - } - trace._portsRoutedOnPcb = ports - trace.pcb_trace_id = pcb_trace.pcb_trace_id - trace._insertErrorIfTraceIsOutsideBoard(pcb_trace.route, ports) + ) { return } diff --git a/lib/components/primitive-components/Trace/Trace_renderImportedPcbTraces.ts b/lib/components/primitive-components/Trace/Trace_renderImportedPcbTraces.ts new file mode 100644 index 000000000..89866a645 --- /dev/null +++ b/lib/components/primitive-components/Trace/Trace_renderImportedPcbTraces.ts @@ -0,0 +1,155 @@ +import type { LayerRef, PcbTraceRoutePoint, PcbVia } from "circuit-json" +import { applyToPoint } from "transformation-matrix" +import { getViaDiameterDefaults } from "../../../utils/pcbStyle/getViaDiameterDefaults" +import type { Port } from "../Port" +import type { Trace } from "./Trace" +import type { ImportedTracePayload } from "./imported-trace-payload-registry" + +const findImportedPcbViaForPoint = ( + importedPcbVias: PcbVia[] | undefined, + importedPcbTraceId: string, + point: PcbTraceRoutePoint, +): PcbVia | undefined => { + if (point.route_type !== "via") return undefined + + return importedPcbVias?.find( + (via) => + via.pcb_trace_id === importedPcbTraceId && + Math.abs(via.x - point.x) < 0.0001 && + Math.abs(via.y - point.y) < 0.0001 && + (!via.from_layer || via.from_layer === point.from_layer) && + (!via.to_layer || via.to_layer === point.to_layer), + ) +} + +const getViaDiameterFromRoutePoint = (point: PcbTraceRoutePoint) => { + const viaPoint = point as PcbTraceRoutePoint & { + hole_diameter?: number + outer_diameter?: number + via_hole_diameter?: number + via_diameter?: number + } + + return { + holeDiameter: viaPoint.hole_diameter ?? viaPoint.via_hole_diameter, + outerDiameter: viaPoint.outer_diameter ?? viaPoint.via_diameter, + } +} + +export const Trace_renderImportedPcbTraces = ({ + importedTracePayload, + ports, + trace, +}: { + importedTracePayload: ImportedTracePayload + ports: Port[] + trace: Trace +}) => { + const importedPcbTraces = importedTracePayload.importedPcbTraces + if (!importedPcbTraces?.length) return false + + const { db } = trace.root! + const subcircuit = trace.getSubcircuit() + const { maybeFlipLayer } = trace._getPcbPrimitiveFlippedHelpers() + const pcbGlobalTransform = trace._computePcbGlobalTransformBeforeLayout() + const pcbStyle = trace.getInheritedMergedProperty("pcbStyle") + const { holeDiameter, padDiameter } = getViaDiameterDefaults(pcbStyle) + + let firstPcbTraceId: string | null = null + + for (const importedPcbTrace of importedPcbTraces) { + const transformedRoute = importedPcbTrace.route.map((point) => { + if (point.route_type === "wire") { + const { x, y, ...restOfPoint } = point + const transformedPoint = applyToPoint(pcbGlobalTransform, { x, y }) + return { + ...restOfPoint, + ...transformedPoint, + layer: maybeFlipLayer(point.layer), + } as PcbTraceRoutePoint + } + + if (point.route_type === "via") { + const { x, y, ...restOfPoint } = point + const transformedPoint = applyToPoint(pcbGlobalTransform, { x, y }) + return { + ...restOfPoint, + ...transformedPoint, + from_layer: maybeFlipLayer(point.from_layer), + to_layer: maybeFlipLayer(point.to_layer), + } as PcbTraceRoutePoint + } + + return { + ...point, + start: applyToPoint(pcbGlobalTransform, point.start), + end: applyToPoint(pcbGlobalTransform, point.end), + start_layer: maybeFlipLayer(point.start_layer), + end_layer: maybeFlipLayer(point.end_layer), + } as PcbTraceRoutePoint + }) + + const pcbTrace = db.pcb_trace.insert({ + ...importedPcbTrace, + route: transformedRoute, + source_trace_id: trace.source_trace_id!, + subcircuit_id: subcircuit?.subcircuit_id ?? undefined, + pcb_group_id: trace.getGroup()?.pcb_group_id ?? undefined, + }) + + firstPcbTraceId ??= pcbTrace.pcb_trace_id + trace.pcb_trace_id = pcbTrace.pcb_trace_id + + for (let index = 0; index < transformedRoute.length; index++) { + const point = transformedRoute[index] + if (point.route_type !== "via") continue + + const originalPoint = importedPcbTrace.route[index] + const importedPcbVia = findImportedPcbViaForPoint( + importedTracePayload.importedPcbVias, + importedPcbTrace.pcb_trace_id, + originalPoint, + ) + const routePointViaDiameter = getViaDiameterFromRoutePoint(point) + const fromLayer = maybeFlipLayer( + (importedPcbVia?.from_layer ?? point.from_layer) as LayerRef, + ) + const toLayer = maybeFlipLayer( + (importedPcbVia?.to_layer ?? point.to_layer) as LayerRef, + ) + const layers = ( + importedPcbVia?.layers ?? [point.from_layer as LayerRef, point.to_layer] + ).map((layer) => maybeFlipLayer(layer as LayerRef)) + + db.pcb_via.insert({ + pcb_trace_id: pcbTrace.pcb_trace_id, + x: point.x, + y: point.y, + hole_diameter: + importedPcbVia?.hole_diameter ?? + routePointViaDiameter.holeDiameter ?? + holeDiameter, + outer_diameter: + importedPcbVia?.outer_diameter ?? + routePointViaDiameter.outerDiameter ?? + padDiameter, + layers, + from_layer: fromLayer, + to_layer: toLayer, + subcircuit_id: subcircuit?.subcircuit_id ?? undefined, + pcb_group_id: trace.getGroup()?.pcb_group_id ?? undefined, + subcircuit_connectivity_map_key: + importedPcbVia?.subcircuit_connectivity_map_key, + net_is_assignable: importedPcbVia?.net_is_assignable, + net_assigned: importedPcbVia?.net_assigned, + is_tented: importedPcbVia?.is_tented, + }) + } + + trace._insertErrorIfTraceIsOutsideBoard(pcbTrace.route, ports) + } + + trace._portsRoutedOnPcb = ports + trace.pcb_trace_id = firstPcbTraceId + return true +} diff --git a/lib/components/primitive-components/Trace/imported-trace-payload-registry.ts b/lib/components/primitive-components/Trace/imported-trace-payload-registry.ts new file mode 100644 index 000000000..5e34a42f4 --- /dev/null +++ b/lib/components/primitive-components/Trace/imported-trace-payload-registry.ts @@ -0,0 +1,21 @@ +import type { PcbTrace, PcbVia, SourceTrace } from "circuit-json" +import type { Trace } from "./Trace" + +export interface ImportedTracePayload { + importedPcbTraces?: PcbTrace[] + importedPcbVias?: PcbVia[] + importedSourceTrace?: SourceTrace +} + +const importedTracePayloadByTrace = new WeakMap() + +export const setImportedTracePayload = ( + trace: Trace, + payload: ImportedTracePayload, +) => { + importedTracePayloadByTrace.set(trace, payload) +} + +export const getImportedTracePayload = ( + trace: Trace, +): ImportedTracePayload | undefined => importedTracePayloadByTrace.get(trace) diff --git a/lib/utils/circuit-json/inflate-circuit-json.ts b/lib/utils/circuit-json/inflate-circuit-json.ts index 739c62ddd..86ee0a666 100644 --- a/lib/utils/circuit-json/inflate-circuit-json.ts +++ b/lib/utils/circuit-json/inflate-circuit-json.ts @@ -10,8 +10,10 @@ import { inflatePcbBoard } from "../../components/primitive-components/Group/Sub import { inflateSourceCapacitor } from "../../components/primitive-components/Group/Subcircuit/inflators/inflateSourceCapacitor" import { inflateSourceChip } from "../../components/primitive-components/Group/Subcircuit/inflators/inflateSourceChip" import { inflateSourceDiode } from "../../components/primitive-components/Group/Subcircuit/inflators/inflateSourceDiode" +import { inflateSourceFiducial } from "../../components/primitive-components/Group/Subcircuit/inflators/inflateSourceFiducial" import { inflateSourceGroup } from "../../components/primitive-components/Group/Subcircuit/inflators/inflateSourceGroup" import { inflateSourceInductor } from "../../components/primitive-components/Group/Subcircuit/inflators/inflateSourceInductor" +import { inflateSourceLed } from "../../components/primitive-components/Group/Subcircuit/inflators/inflateSourceLed" import { inflateSourcePort } from "../../components/primitive-components/Group/Subcircuit/inflators/inflateSourcePort" import { inflateSourcePushButton } from "../../components/primitive-components/Group/Subcircuit/inflators/inflateSourcePushButton" import { inflateSourceResistor } from "../../components/primitive-components/Group/Subcircuit/inflators/inflateSourceResistor" @@ -88,6 +90,12 @@ export const inflateCircuitJson = ( case "simple_diode": inflateSourceDiode(sourceComponent, inflationCtx) break + case "simple_fiducial": + inflateSourceFiducial(sourceComponent, inflationCtx) + break + case "simple_led": + inflateSourceLed(sourceComponent, inflationCtx) + break case "simple_chip": inflateSourceChip(sourceComponent, inflationCtx) break diff --git a/package.json b/package.json index 257494e76..5a723c5b8 100644 --- a/package.json +++ b/package.json @@ -77,8 +77,8 @@ "flatbush": "^4.5.0", "graphics-debug": "^0.0.95", "howfat": "^0.3.8", - "kicad-to-circuit-json": "^0.0.60", - "kicadts": "^0.0.35", + "kicad-to-circuit-json": "^0.0.94", + "kicadts": "^0.0.45", "live-server": "^1.2.2", "looks-same": "^9.0.1", "minicssgrid": "^0.0.9", diff --git a/tests/repros/__snapshots__/repro116-arduino-uno-reroute-center-pcb.snap.svg b/tests/repros/__snapshots__/repro116-arduino-uno-reroute-center-pcb.snap.svg index 42d3b42ef..e97d7f480 100644 --- a/tests/repros/__snapshots__/repro116-arduino-uno-reroute-center-pcb.snap.svg +++ b/tests/repros/__snapshots__/repro116-arduino-uno-reroute-center-pcb.snap.svg @@ -1 +1 @@ -Y2C1U4J8U2S1U5U1J2J9F2C2Q1LFXTAL003240BULKY2ATMEGA16U2-MUU3CSTNE16M0V530000R0Y1100nC9PPTC101LFBN-RCJ447uCD1206-S01575D222pC11100nC31kΩ@100MHzFB1100nC4ATMEGA328P-PUU4YELLOWD4100nC6100nC12100nC7USB_C_Receptacle_USB2.0_16PJ8PCB EdgeLP2985-3.3U2CGRB307-GD11uC10TS06-667-30-BK-100-G-SMT-TR22pC13PPTC061LFBN-RCJ6LMV358IDGKRU5SolderJumper_2_OpenFiducialFID1PPTC081LFBN-RCJ7NCP1117-5.0_SOT223U15pF@1MHzZ15k1R3M20-9980245J21kRN25k1R41MR2FiducialFID3PJ-102AHJ9YELLOWD510kRN122RRN310uHFB21kRN4MF-MSMF050-2F2PPTC081LFBN-RCJ51uC5FiducialFID25pF@1MHzZ21MR1CD1206-S01575D347uGREEND7M20-9980345J1100nC8FDN340PQ1M20-9980345J3YELLOWD6SolderJumper_2_OpenREROUTED CENTER 10MM \ No newline at end of file +Y2C1U4J8U2S1U5U1J2J9F2C2Q1LFXTAL003240BULKY2ATMEGA16U2-MUU3CSTNE16M0V530000R0Y1100nC9PPTC101LFBN-RCJ447uCD1206-S01575D222pC11100nC31kΩ@100MHzFB1100nC4ATMEGA328P-PUU4YELLOWD4100nC6100nC12100nC7USB_C_Receptacle_USB2.0_16PPCB EdgeLP2985-3.3U2CGRB307-GD11uC10TS06-667-30-BK-100-G-SMT-TR22pC13PPTC061LFBN-RCJ6LMV358IDGKRSolderJumper_2_OpenFiducialFID1PPTC081LFBN-RCJ7NCP1117-5.0_SOT2235pF@1MHzZ15k1R3M20-9980245J21kRN25k1R41MR2FiducialFID3PJ-102AHJ9YELLOWD510kRN122RRN310uHFB21kRN4MF-MSMF050-2PPTC081LFBN-RCJ51uC5FiducialFID25pF@1MHzZ21MR1CD1206-S01575D347uGREEND7M20-9980345J1100nC8FDN340PM20-9980345J3YELLOWD6SolderJumper_2_OpenREROUTED CENTER 10MM \ No newline at end of file diff --git a/tests/repros/__snapshots__/repro116-arduino-uno-reroute-lower-mid-pcb.snap.svg b/tests/repros/__snapshots__/repro116-arduino-uno-reroute-lower-mid-pcb.snap.svg index cca985f83..d0e10eabc 100644 --- a/tests/repros/__snapshots__/repro116-arduino-uno-reroute-lower-mid-pcb.snap.svg +++ b/tests/repros/__snapshots__/repro116-arduino-uno-reroute-lower-mid-pcb.snap.svg @@ -1 +1 @@ -Y2C1U4J8U2S1U5U1J2J9F2C2Q1LFXTAL003240BULKY2ATMEGA16U2-MUU3CSTNE16M0V530000R0Y1100nC9PPTC101LFBN-RCJ447uCD1206-S01575D222pC11100nC31kΩ@100MHzFB1100nC4ATMEGA328P-PUU4YELLOWD4100nC6100nC12100nC7USB_C_Receptacle_USB2.0_16PJ8PCB EdgeLP2985-3.3U2CGRB307-GD11uC10TS06-667-30-BK-100-G-SMT-TR22pC13PPTC061LFBN-RCJ6LMV358IDGKRU5SolderJumper_2_OpenFiducialFID1PPTC081LFBN-RCJ7NCP1117-5.0_SOT223U15pF@1MHzZ15k1R3M20-9980245J21kRN25k1R41MR2FiducialFID3PJ-102AHJ9YELLOWD510kRN122RRN310uHFB21kRN4MF-MSMF050-2F2PPTC081LFBN-RCJ51uC5FiducialFID25pF@1MHzZ21MR1CD1206-S01575D347uGREEND7M20-9980345J1100nC8FDN340PQ1M20-9980345J3YELLOWD6SolderJumper_2_OpenREROUTED LOWER MID 10MM \ No newline at end of file +Y2C1U4J8U2S1U5U1J2J9F2C2Q1LFXTAL003240BULKY2ATMEGA16U2-MUU3CSTNE16M0V530000R0Y1100nC9PPTC101LFBN-RCJ447uCD1206-S01575D222pC11100nC31kΩ@100MHzFB1100nC4ATMEGA328P-PUU4YELLOWD4100nC6100nC12100nC7USB_C_Receptacle_USB2.0_16PPCB EdgeLP2985-3.3U2CGRB307-GD11uC10TS06-667-30-BK-100-G-SMT-TR22pC13PPTC061LFBN-RCJ6LMV358IDGKRSolderJumper_2_OpenFiducialFID1PPTC081LFBN-RCJ7NCP1117-5.0_SOT2235pF@1MHzZ15k1R3M20-9980245J21kRN25k1R41MR2FiducialFID3PJ-102AHJ9YELLOWD510kRN122RRN310uHFB21kRN4MF-MSMF050-2PPTC081LFBN-RCJ51uC5FiducialFID25pF@1MHzZ21MR1CD1206-S01575D347uGREEND7M20-9980345J1100nC8FDN340PM20-9980345J3YELLOWD6SolderJumper_2_OpenREROUTED LOWER MID 10MM \ No newline at end of file diff --git a/tests/repros/__snapshots__/repro116-arduino-uno-reroute-pcb.snap.svg b/tests/repros/__snapshots__/repro116-arduino-uno-reroute-pcb.snap.svg index 5d3e1c180..55345ae0a 100644 --- a/tests/repros/__snapshots__/repro116-arduino-uno-reroute-pcb.snap.svg +++ b/tests/repros/__snapshots__/repro116-arduino-uno-reroute-pcb.snap.svg @@ -1 +1 @@ -Y2C1U4J8U2S1U5U1J2J9F2C2Q1LFXTAL003240BULKY2ATMEGA16U2-MUU3CSTNE16M0V530000R0Y1100nC9PPTC101LFBN-RCJ447uCD1206-S01575D222pC11100nC31kΩ@100MHzFB1100nC4ATMEGA328P-PUU4YELLOWD4100nC6100nC12100nC7USB_C_Receptacle_USB2.0_16PJ8PCB EdgeLP2985-3.3U2CGRB307-GD11uC10TS06-667-30-BK-100-G-SMT-TR22pC13PPTC061LFBN-RCJ6LMV358IDGKRU5SolderJumper_2_OpenFiducialFID1PPTC081LFBN-RCJ7NCP1117-5.0_SOT223U15pF@1MHzZ15k1R3M20-9980245J21kRN25k1R41MR2FiducialFID3PJ-102AHJ9YELLOWD510kRN122RRN310uHFB21kRN4MF-MSMF050-2F2PPTC081LFBN-RCJ51uC5FiducialFID25pF@1MHzZ21MR1CD1206-S01575D347uGREEND7M20-9980345J1100nC8FDN340PQ1M20-9980345J3YELLOWD6SolderJumper_2_OpenREROUTED REGION 10MM \ No newline at end of file +Y2C1U4J8U2S1U5U1J2J9F2C2Q1LFXTAL003240BULKY2ATMEGA16U2-MUU3CSTNE16M0V530000R0Y1100nC9PPTC101LFBN-RCJ447uCD1206-S01575D222pC11100nC31kΩ@100MHzFB1100nC4ATMEGA328P-PUU4YELLOWD4100nC6100nC12100nC7USB_C_Receptacle_USB2.0_16PPCB EdgeLP2985-3.3U2CGRB307-GD11uC10TS06-667-30-BK-100-G-SMT-TR22pC13PPTC061LFBN-RCJ6LMV358IDGKRSolderJumper_2_OpenFiducialFID1PPTC081LFBN-RCJ7NCP1117-5.0_SOT2235pF@1MHzZ15k1R3M20-9980245J21kRN25k1R41MR2FiducialFID3PJ-102AHJ9YELLOWD510kRN122RRN310uHFB21kRN4MF-MSMF050-2PPTC081LFBN-RCJ51uC5FiducialFID25pF@1MHzZ21MR1CD1206-S01575D347uGREEND7M20-9980345J1100nC8FDN340PM20-9980345J3YELLOWD6SolderJumper_2_OpenREROUTED REGION 10MM \ No newline at end of file diff --git a/tests/repros/__snapshots__/repro116-arduino-uno.test.tsx-after-inflation-pcb.snap.svg b/tests/repros/__snapshots__/repro116-arduino-uno.test.tsx-after-inflation-pcb.snap.svg index 4920b2ce9..98bb96e78 100644 --- a/tests/repros/__snapshots__/repro116-arduino-uno.test.tsx-after-inflation-pcb.snap.svg +++ b/tests/repros/__snapshots__/repro116-arduino-uno.test.tsx-after-inflation-pcb.snap.svg @@ -1 +1 @@ -Y2C1U4J8U2S1U5U1J2J9F2C2Q1LFXTAL003240BULKY2ATMEGA16U2-MUU3CSTNE16M0V530000R0Y1100nC9PPTC101LFBN-RCJ447uCD1206-S01575D222pC11100nC31kΩ@100MHzFB1100nC4ATMEGA328P-PUU4YELLOWD4100nC6100nC12100nC7USB_C_Receptacle_USB2.0_16PJ8PCB EdgeLP2985-3.3U2CGRB307-GD11uC10TS06-667-30-BK-100-G-SMT-TR22pC13PPTC061LFBN-RCJ6LMV358IDGKRU5SolderJumper_2_OpenFiducialFID1PPTC081LFBN-RCJ7NCP1117-5.0_SOT223U15pF@1MHzZ15k1R3M20-9980245J21kRN25k1R41MR2FiducialFID3PJ-102AHJ9YELLOWD510kRN122RRN310uHFB21kRN4MF-MSMF050-2F2PPTC081LFBN-RCJ51uC5FiducialFID25pF@1MHzZ21MR1CD1206-S01575D347uGREEND7M20-9980345J1100nC8FDN340PQ1M20-9980345J3YELLOWD6SolderJumper_2_Open \ No newline at end of file +Y2C1U4J8U2S1U5U1J2J9F2C2Q1LFXTAL003240BULKY2ATMEGA16U2-MUU3CSTNE16M0V530000R0Y1100nC9PPTC101LFBN-RCJ447uCD1206-S01575D222pC11100nC31kΩ@100MHzFB1100nC4ATMEGA328P-PUU4YELLOWD4100nC6100nC12100nC7USB_C_Receptacle_USB2.0_16PPCB EdgeLP2985-3.3U2CGRB307-GD11uC10TS06-667-30-BK-100-G-SMT-TR22pC13PPTC061LFBN-RCJ6LMV358IDGKRSolderJumper_2_OpenFiducialFID1PPTC081LFBN-RCJ7NCP1117-5.0_SOT2235pF@1MHzZ15k1R3M20-9980245J21kRN25k1R41MR2FiducialFID3PJ-102AHJ9YELLOWD510kRN122RRN310uHFB21kRN4MF-MSMF050-2PPTC081LFBN-RCJ51uC5FiducialFID25pF@1MHzZ21MR1CD1206-S01575D347uGREEND7M20-9980345J1100nC8FDN340PM20-9980345J3YELLOWD6SolderJumper_2_Open \ No newline at end of file diff --git a/tests/repros/__snapshots__/repro116-arduino-uno.test.tsx-before-inflation-pcb.snap.svg b/tests/repros/__snapshots__/repro116-arduino-uno.test.tsx-before-inflation-pcb.snap.svg index 1df8d1d3a..cafc5ee6d 100644 --- a/tests/repros/__snapshots__/repro116-arduino-uno.test.tsx-before-inflation-pcb.snap.svg +++ b/tests/repros/__snapshots__/repro116-arduino-uno.test.tsx-before-inflation-pcb.snap.svg @@ -1 +1 @@ -SCLSDAGITHUB.COM/SABOGALCUNORCY2C1U4J8U2S1U5U1J2J9F2C2Q1TXA1~11GND4RCA5~378LRX~5~925V13ONAREF~10~6VinRXANALOG INA3POWERA2GITHUB.COM/SABOGALCUNOIOREFRESET3.3VA4A0121TXRST ENGND0DIGITAL - PWM~RESETICSPLFXTAL003240BULKY2ATMEGA16U2-MUU3CSTNE16M0V530000R0Y1100nC9PPTC101LFBN-RCJ447uCD1206-S01575D222pC11100nC31kΩ@100MHzFB1100nC4ATMEGA328P-PUU4YELLOWD4100nC6100nC12100nC7USB_C_Receptacle_USB2.0_16PJ8PCB EdgeLP2985-3.3U2CGRB307-GD11uC10TS06-667-30-BK-100-G-SMT-TR22pC13PPTC061LFBN-RCJ6LMV358IDGKRU5SolderJumper_2_OpenFiducialFID1PPTC081LFBN-RCJ7NCP1117-5.0_SOT223U15pF@1MHzZ15k1R3M20-9980245J21kRN25k1R41MR2FiducialFID3PJ-102AHJ9YELLOWD510kRN122RRN310uHFB21kRN4MF-MSMF050-2F2PPTC081LFBN-RCJ51uC5FiducialFID25pF@1MHzZ21MR1CD1206-S01575D347uGREEND7M20-9980345J1100nC8FDN340PQ1M20-9980345J3YELLOWD6SolderJumper_2_Open \ No newline at end of file +SCLSDAGITHUB.COM/SABOGALCRCY2C1U4J8U2S1U5U1J2J9F2C2Q1TXA1~114RCA5~378LRX~5~925V13ONAREF~10~6VinRXA3A2GITHUB.COM/SABOGALCIOREFRESET3.3VA4A0121TXRST EN0RESETICSPLFXTAL003240BULKY2ATMEGA16U2-MUU3CSTNE16M0V530000R0Y1100nC9PPTC101LFBN-RCJ447uCD1206-S01575D222pC11100nC31kΩ@100MHzFB1100nC4ATMEGA328P-PUU4YELLOWD4100nC6100nC12100nC7USB_C_Receptacle_USB2.0_16PPCB EdgeLP2985-3.3U2CGRB307-GD11uC10TS06-667-30-BK-100-G-SMT-TR22pC13PPTC061LFBN-RCJ6LMV358IDGKRSolderJumper_2_OpenFiducialFID1PPTC081LFBN-RCJ7NCP1117-5.0_SOT2235pF@1MHzZ15k1R3M20-9980245J21kRN25k1R41MR2FiducialFID3PJ-102AHJ9YELLOWD510kRN122RRN310uHFB21kRN4MF-MSMF050-2PPTC081LFBN-RCJ51uC5FiducialFID25pF@1MHzZ21MR1CD1206-S01575D347uGREEND7M20-9980345J1100nC8FDN340PM20-9980345J3YELLOWD6SolderJumper_2_Open \ No newline at end of file diff --git a/tests/repros/repro116-arduino-uno-fiducial-inflation.test.tsx b/tests/repros/repro116-arduino-uno-fiducial-inflation.test.tsx new file mode 100644 index 000000000..bf95353af --- /dev/null +++ b/tests/repros/repro116-arduino-uno-fiducial-inflation.test.tsx @@ -0,0 +1,92 @@ +import { expect, test } from "bun:test" +import { KicadToCircuitJsonConverter } from "kicad-to-circuit-json" +import fs from "node:fs" +import type { CircuitJson, PcbSmtPad } from "circuit-json" +import { getTestFixture } from "tests/fixtures/get-test-fixture" + +const loadArduinoUnoCircuitJson = () => { + const converter = new KicadToCircuitJsonConverter() + converter.addFile( + "tests/repros/assets/arduino-uno.source.kicad_pcb", + fs.readFileSync("tests/repros/assets/arduino-uno.source.kicad_pcb", "utf8"), + ) + converter.runUntilFinished() + return converter.getOutput() as CircuitJson +} + +test("repro116: imported fiducials inflate as pcb-only artifacts", async () => { + const { circuit } = getTestFixture() + const arduinoUnoCircuitJson = loadArduinoUnoCircuitJson() + + const importedFiducialComponents = arduinoUnoCircuitJson.filter( + (element): element is Extract< + CircuitJson[number], + { type: "source_component"; ftype: "simple_fiducial" } + > => + element.type === "source_component" && element.ftype === "simple_fiducial", + ) + expect(importedFiducialComponents.length).toBeGreaterThan(0) + + const importedFiducialPcbComponents = arduinoUnoCircuitJson.filter( + (element): element is Extract => + element.type === "pcb_component" && + importedFiducialComponents.some( + (sourceComponent) => + sourceComponent.source_component_id === element.source_component_id, + ), + ) + + const importedFiducialPads = arduinoUnoCircuitJson.filter( + ( + element, + ): element is Extract => + element.type === "pcb_smtpad" && + element.shape === "circle" && + importedFiducialComponents.some((sourceComponent) => { + const pcbComponent = importedFiducialPcbComponents.find( + (candidate) => + candidate.source_component_id === sourceComponent.source_component_id, + ) + + return pcbComponent?.pcb_component_id === element.pcb_component_id + }), + ) + expect(importedFiducialPads.length).toBeGreaterThan(0) + + circuit.add( + + + , + ) + + await circuit.renderUntilSettled() + + const circuitJson = circuit.getCircuitJson() + const inflatedFiducialChips = circuitJson.filter( + (element) => + element.type === "source_component" && + element.ftype === "simple_chip" && + importedFiducialComponents.some( + (sourceComponent) => sourceComponent.name === element.name, + ), + ) + expect(inflatedFiducialChips).toHaveLength(0) + + const inflatedPads = circuitJson.filter( + ( + element, + ): element is Extract => + element.type === "pcb_smtpad" && element.shape === "circle", + ) + for (const importedPad of importedFiducialPads) { + expect( + inflatedPads.some( + (inflatedPad) => + inflatedPad.shape === importedPad.shape && + Math.abs(inflatedPad.x - importedPad.x) < 1e-6 && + Math.abs(inflatedPad.y - importedPad.y) < 1e-6 && + Math.abs((inflatedPad.radius ?? 0) - (importedPad.radius ?? 0)) < 1e-6, + ), + ).toBe(true) + } +}, 80_000) diff --git a/tests/repros/repro116-arduino-uno-reroute-center.test.tsx b/tests/repros/repro116-arduino-uno-reroute-center.test.tsx index ea25ac4be..6a4c6a07a 100644 --- a/tests/repros/repro116-arduino-uno-reroute-center.test.tsx +++ b/tests/repros/repro116-arduino-uno-reroute-center.test.tsx @@ -16,4 +16,4 @@ test("repro116: arduino uno circuit json can reroute a center imported region", rerouteRegion, snapshotName: "repro116-arduino-uno-reroute-center", }) -}, 80_000) +}, 120_000) diff --git a/tests/repros/repro116-arduino-uno-reroute-invalid-source-ids.test.tsx b/tests/repros/repro116-arduino-uno-reroute-invalid-source-ids.test.tsx index 68f47b73b..08e0d4642 100644 --- a/tests/repros/repro116-arduino-uno-reroute-invalid-source-ids.test.tsx +++ b/tests/repros/repro116-arduino-uno-reroute-invalid-source-ids.test.tsx @@ -39,4 +39,4 @@ test("repro116: rerouting imported arduino region should not create pcb traces w })) expect(tracesWithMissingSourceTrace).toHaveLength(0) -}, 100_000) +}, 180_000) diff --git a/tests/repros/repro116-arduino-uno-reroute-lower-mid.test.tsx b/tests/repros/repro116-arduino-uno-reroute-lower-mid.test.tsx index d3120a200..341ba8e89 100644 --- a/tests/repros/repro116-arduino-uno-reroute-lower-mid.test.tsx +++ b/tests/repros/repro116-arduino-uno-reroute-lower-mid.test.tsx @@ -16,4 +16,4 @@ test("repro116: arduino uno circuit json can reroute a lower middle imported reg rerouteRegion, snapshotName: "repro116-arduino-uno-reroute-lower-mid", }) -}, 80_000) +}, 120_000) diff --git a/tests/repros/repro116-arduino-uno-reroute-utils.tsx b/tests/repros/repro116-arduino-uno-reroute-utils.tsx index 8ef203744..bcde58a5e 100644 --- a/tests/repros/repro116-arduino-uno-reroute-utils.tsx +++ b/tests/repros/repro116-arduino-uno-reroute-utils.tsx @@ -240,17 +240,13 @@ export async function expectArduinoUnoRerouteRegion({ snapshotName: string }) { const resolvedDataTestId = dataTestId ?? `${snapshotName}-stack` - const { - afterRerouteCircuit, - arduinoUnoCircuitJson, - beforeRerouteCircuit, - phaseInputs, - } = await renderArduinoUnoRerouteRegion({ label, rerouteRegion }) + const { afterRerouteCircuit, beforeRerouteCircuit, phaseInputs } = + await renderArduinoUnoRerouteRegion({ label, rerouteRegion }) const originalRouteSignaturesBySourceTraceId = new Map() const originalTraceWidthBySourceTraceId = new Map() - for (const element of arduinoUnoCircuitJson) { - if (element.type !== "pcb_trace" || !element.source_trace_id) continue + for (const element of beforeRerouteCircuit.db.pcb_trace.list()) { + if (!element.source_trace_id) continue const firstWirePoint = element.route.find( (point) => point.route_type === "wire", ) @@ -263,13 +259,16 @@ export async function expectArduinoUnoRerouteRegion({ firstWirePoint.width, ) } - const routeSignatures = - originalRouteSignaturesBySourceTraceId.get(element.source_trace_id) ?? [] - routeSignatures.push(routeSignature(element.route)) - originalRouteSignaturesBySourceTraceId.set( - element.source_trace_id, - routeSignatures, - ) + if (routeTouchesRegion(element.route, rerouteRegion)) { + const routeSignatures = + originalRouteSignaturesBySourceTraceId.get(element.source_trace_id) ?? + [] + routeSignatures.push(routeSignature(element.route)) + originalRouteSignaturesBySourceTraceId.set( + element.source_trace_id, + routeSignatures, + ) + } } expect(afterRerouteCircuit.db.pcb_autorouting_error.list()).toHaveLength(0) diff --git a/tests/repros/repro116-arduino-uno-reroute.test.tsx b/tests/repros/repro116-arduino-uno-reroute.test.tsx index 8996a0bd2..1220571d5 100644 --- a/tests/repros/repro116-arduino-uno-reroute.test.tsx +++ b/tests/repros/repro116-arduino-uno-reroute.test.tsx @@ -16,4 +16,4 @@ test("repro116: arduino uno circuit json can reroute an imported region with the rerouteRegion, snapshotName: "repro116-arduino-uno-reroute-left-right", }) -}, 20_000) +}, 120_000) diff --git a/tests/repros/repro116-arduino-uno.test.tsx b/tests/repros/repro116-arduino-uno.test.tsx index 03665fcd2..5595d1c42 100644 --- a/tests/repros/repro116-arduino-uno.test.tsx +++ b/tests/repros/repro116-arduino-uno.test.tsx @@ -96,4 +96,4 @@ test("repro116: arduino uno trace and via inflation", async () => { `${import.meta.path}-before-inflation`, ) expect(circuit).toMatchPcbSnapshot(`${import.meta.path}-after-inflation`) -}, 15_000) +}, 80_000)