Skip to content

Commit

Permalink
Merge pull request #15 from tscircuit/layout-and-extras
Browse files Browse the repository at this point in the history
Jumper Support, pinLabels fix, Resistor.pullup, Capacitor.decoupling, Silkscreen drawings
  • Loading branch information
seveibar authored Sep 1, 2024
2 parents 8453184 + 3757ecb commit 9bf1da9
Show file tree
Hide file tree
Showing 23 changed files with 313 additions and 278 deletions.
Binary file modified bun.lockb
Binary file not shown.
2 changes: 2 additions & 0 deletions bunfig.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[test]
preload = ["./tests/fixtures/preload.ts"]
29 changes: 29 additions & 0 deletions lib/Project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export class Project {
children: PrimitiveComponent[]
db: SoupUtilObjects

_hasRenderedAtleastOnce = false

constructor() {
this.children = []
this.db = su([])
Expand Down Expand Up @@ -64,16 +66,43 @@ export class Project {
rootComponent.setProject(this)

rootComponent.runRenderCycle()
this._hasRenderedAtleastOnce = true
}

getSoup(): AnySoupElement[] {
if (!this._hasRenderedAtleastOnce) this.render()
return this.db.toArray()
}

getCircuitJson(): AnySoupElement[] {
return this.getSoup()
}

async getSvg(options: { view: "pcb"; layer?: string }): Promise<string> {
const circuitToSvg = await import("circuit-to-svg").catch((e) => {
throw new Error(
`To use project.getSvg, you must install the "circuit-to-svg" package.\n\n"${e.message}"`,
)
})

return circuitToSvg.circuitJsonToPcbSvg(this.getSoup())
}

async preview(
previewNameOrOpts:
| string
| {
previewName: string
tscircuitApiKey?: string
},
) {
const previewOpts =
typeof previewNameOrOpts === "object"
? previewNameOrOpts
: { previewName: previewNameOrOpts }
throw new Error("project.preview is not yet implemented")
}

computeGlobalSchematicTransform(): Matrix {
return identity()
}
Expand Down
16 changes: 16 additions & 0 deletions lib/components/base-components/NormalComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,22 @@ export class NormalComponent<
const portsFromFootprint = this.getPortsFromFootprint()

this.addAll(portsFromFootprint)

const pinLabels: Record<string, string> | undefined =
this._parsedProps.pinLabels
if (pinLabels) {
for (let [pinNumber, label] of Object.entries(pinLabels)) {
pinNumber = pinNumber.replace("pin", "")
const port = this.selectOne(`port[pinNumber='${pinNumber}']`)
if (!port) {
throw new Error(
`Could not find port for pin number ${pinNumber} in chip ${this.getString()}`,
)
}
port.externallyAddedAliases.push(label)
port.props.name = label
}
}
}

_addChildrenFromStringFootprint() {
Expand Down
3 changes: 3 additions & 0 deletions lib/components/base-components/PrimitiveComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ export abstract class PrimitiveComponent<
componentName = ""
lowercaseComponentName = ""

externallyAddedAliases: string[]

source_group_id: string | null = null
source_component_id: string | null = null
schematic_component_id: string | null = null
Expand All @@ -57,6 +59,7 @@ export abstract class PrimitiveComponent<
this.children = []
this.childrenPendingRemoval = []
this.props = props ?? {}
this.externallyAddedAliases = []
this._parsedProps = this.config.zodProps.parse(
props ?? {},
) as z.infer<ZodProps>
Expand Down
2 changes: 2 additions & 0 deletions lib/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ export { Trace } from "./primitive-components/Trace"
export { TraceHint } from "./primitive-components/TraceHint"
export { Group } from "./primitive-components/Group"
export { Chip } from "./normal-components/Chip"
export { Jumper } from "./normal-components/Jumper"
export { SilkscreenPath } from "./primitive-components/SilkscreenPath"
19 changes: 0 additions & 19 deletions lib/components/normal-components/Chip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,6 @@ export class Chip<PinLabels extends string = never> extends NormalComponent<
}
}

initPorts() {
super.initPorts()

const { _parsedProps: props } = this

if (props.pinLabels) {
for (const [pinNumber, label] of Object.entries(props.pinLabels)) {
const port = this.selectOne(`port[pinNumber='${pinNumber}']`)
if (!port) {
throw new Error(
`Could not find port for pin number ${pinNumber} in chip ${this.getString()}`,
)
}
port.props.aliases.push(port.props.name)
port.props.name = label
}
}
}

doInitialSourceRender(): void {
const { db } = this.project!
const { _parsedProps: props } = this
Expand Down
101 changes: 101 additions & 0 deletions lib/components/normal-components/Jumper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { NormalComponent } from "lib/components/base-components/NormalComponent"
import { jumperProps } from "@tscircuit/props"
import { Port } from "../primitive-components/Port"
import type { BaseSymbolName } from "lib/utils/constants"
import {
getAllDimensionsForSchematicBox,
type SchematicBoxDimensions,
} from "lib/utils/schematic/getAllDimensionsForSchematicBox"
import { underscorifyPortArrangement } from "lib/soup/underscorifyPortArrangement"
import { underscorifyPinStyles } from "lib/soup/underscorifyPinStyles"

export class Jumper<PinLabels extends string = never> extends NormalComponent<
typeof jumperProps,
PinLabels
> {
schematicDimensions: SchematicBoxDimensions | null = null

get config() {
return {
zodProps: jumperProps,
}
}

doInitialSourceRender(): void {
const { db } = this.project!
const { _parsedProps: props } = this

const source_component = db.source_component.insert({
ftype: "simple_chip", // TODO unknown or jumper
name: props.name,
manufacturer_part_number: props.manufacturerPartNumber,
supplier_part_numbers: props.supplierPartNumbers,
})

this.source_component_id = source_component.source_component_id!
}

doInitialSchematicComponentRender() {
const { db } = this.project!
const { _parsedProps: props } = this

const ports = this.children.filter((child) => child instanceof Port)

const pinSpacing = props.schPinSpacing ?? 0.2

const dimensions = getAllDimensionsForSchematicBox({
schWidth: props.schWidth,
schHeight: props.schHeight,
schPinSpacing: pinSpacing,
schPinStyle: props.schPinStyle,

pinCount: ports.length,

// @ts-ignore there's a subtley in the definition difference with
// leftSide/rightSide/topSide/bottomSide in how the direction is defined
// that doesn't really matter
schPortArrangement: {
// TODO use schematic direction or schPortArrangement
rightSize: ports.length,
},
})
this.schematicDimensions = dimensions

const schematic_component = db.schematic_component.insert({
center: { x: props.schX ?? 0, y: props.schY ?? 0 },
rotation: props.schRotation ?? 0,
size: dimensions.getSize(),

port_arrangement: underscorifyPortArrangement(
props.schPortArrangement as any,
),

pin_spacing: pinSpacing,

// @ts-ignore soup needs to support distance for pin_styles
pin_styles: underscorifyPinStyles(props.schPinStyle),

port_labels: props.pinLabels,

source_component_id: this.source_component_id!,
})

this.schematic_component_id = schematic_component.schematic_component_id
}

doInitialPcbComponentRender() {
const { db } = this.project!
const { _parsedProps: props } = this

const pcb_component = db.pcb_component.insert({
center: { x: props.pcbX ?? 0, y: props.pcbY ?? 0 },
width: 2, // Default width, adjust as needed
height: 3, // Default height, adjust as needed
layer: props.layer ?? "top",
rotation: props.pcbRotation ?? 0,
source_component_id: this.source_component_id!,
})

this.pcb_component_id = pcb_component.pcb_component_id
}
}
1 change: 1 addition & 0 deletions lib/components/primitive-components/Port.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export class Port extends PrimitiveComponent<typeof portProps> {
...(typeof props.pinNumber === "number"
? [`pin${props.pinNumber}`, props.pinNumber.toString()]
: []),
...this.externallyAddedAliases,
]),
) as string[]
}
Expand Down
35 changes: 35 additions & 0 deletions lib/components/primitive-components/SilkscreenPath.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { silkscreenPathProps } from "@tscircuit/props"
import { PrimitiveComponent } from "../base-components/PrimitiveComponent"

export class SilkscreenPath extends PrimitiveComponent<
typeof silkscreenPathProps
> {
pcb_silkscreen_path_id: string | null = null

get config() {
return {
zodProps: silkscreenPathProps,
}
}

doInitialPcbPrimitiveRender(): void {
const { db } = this.project!
const { _parsedProps: props } = this

const layer = props.layer ?? "top"
if (layer !== "top" && layer !== "bottom") {
throw new Error(
`Invalid layer "${layer}" for SilkscreenPath. Must be "top" or "bottom".`,
)
}

const pcb_silkscreen_path = db.pcb_silkscreen_path.insert({
pcb_component_id: this.parent?.pcb_component_id!,
layer,
route: props.route,
stroke_width: props.strokeWidth ?? 0.1,
})

this.pcb_silkscreen_path_id = pcb_silkscreen_path.pcb_silkscreen_path_id
}
}
1 change: 1 addition & 0 deletions lib/fiber/intrinsic-jsx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ declare global {
diode: Props.DiodeProps
led: Props.LedProps
board: Props.BoardProps
jumper: Props.JumperProps
bug: Props.ChipProps
// TODO use ChipProps once it gets merged in @tscircuit/props
chip: Props.ChipProps
Expand Down
59 changes: 9 additions & 50 deletions lib/utils/createComponentsFromSoup.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { AnySoupElement } from "@tscircuit/soup"
import type { PrimitiveComponent } from "../components/base-components/PrimitiveComponent"
import { SmtPad } from "lib/components/primitive-components/SmtPad"
import { SilkscreenPath } from "lib/components/primitive-components/SilkscreenPath"

export const createComponentsFromSoup = (
soup: AnySoupElement[],
Expand Down Expand Up @@ -30,57 +31,15 @@ export const createComponentsFromSoup = (
portHints: elm.port_hints,
}),
)
} else if (elm.type === "pcb_silkscreen_path") {
components.push(
new SilkscreenPath({
layer: elm.layer,
route: elm.route,
strokeWidth: elm.stroke_width,
}),
)
}
}
return components
// if (elm.type === "pcb_smtpad") {
// this.add("smtpad", (pb) => pb.setProps(elm))
// } else if (elm.type === "pcb_plated_hole") {
// this.add("platedhole", (pb) => pb.setProps(elm))
// } else if (elm.type === "pcb_hole") {
// this.add("hole", (pb) => pb.setProps(elm))
// } else if (elm.type === "pcb_silkscreen_circle") {
// this.add("silkscreencircle", (pb) =>
// pb.setProps({
// ...elm,
// pcbX: elm.center.x,
// pcbY: elm.center.y,
// })
// )
// } else if (elm.type === "pcb_silkscreen_line") {
// this.add("silkscreenline", (pb) =>
// pb.setProps({
// ...elm,
// strokeWidth: elm.stroke_width,
// })
// )
// } else if (elm.type === "pcb_silkscreen_path") {
// this.add("silkscreenpath", (pb) =>
// pb.setProps({
// ...elm,
// strokeWidth: elm.stroke_width,
// })
// )
// } else if (elm.type === "pcb_silkscreen_rect") {
// this.add("silkscreenrect", (pb) =>
// pb.setProps({
// ...elm,
// pcbX: elm.center.x,
// pcbY: elm.center.y,
// // TODO silkscreen rect isFilled, isOutline etc.
// })
// )
// } else if (elm.type === "pcb_fabrication_note_path") {
// this.add("fabricationnotepath", (pb) => pb.setProps(elm))
// } else if (elm.type === "pcb_fabrication_note_text") {
// this.add("fabricationnotetext", (pb) =>
// pb.setProps({
// ...elm,
// pcbX: elm.anchor_position.x,
// pcbY: elm.anchor_position.y,
// anchorAlignment: elm.anchor_alignment,
// fontSize: elm.font_size,
// })
// )
// }
}
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
},
"devDependencies": {
"@biomejs/biome": "^1.8.3",
"@tscircuit/layout": "^0.0.27",
"@tscircuit/log-soup": "^1.0.2",
"@types/bun": "latest",
"@types/react": "^18.3.3",
"@types/react-reconciler": "^0.28.8",
"circuit-to-svg": "^0.0.3",
"bun-match-svg": "0.0.2",
"circuit-to-svg": "^0.0.13",
"howfat": "^0.3.8",
"looks-same": "^9.0.1",
"tsup": "^8.2.4"
Expand All @@ -30,7 +32,7 @@
},
"dependencies": {
"@tscircuit/infgrid-ijump-astar": "0.0.5",
"@tscircuit/props": "^0.0.46",
"@tscircuit/props": "^0.0.49",
"@tscircuit/soup": "^0.0.58",
"@tscircuit/soup-util": "0.0.18",
"footprinter": "^0.0.44",
Expand Down
7 changes: 7 additions & 0 deletions tests/__snapshots__/example1.snap.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 9bf1da9

Please sign in to comment.