Skip to content

Commit

Permalink
allow schematic boxes for components other than chip to be automatica…
Browse files Browse the repository at this point in the history
…lly computed
  • Loading branch information
seveibar committed Nov 5, 2024
1 parent 0244ab7 commit 6f9f839
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 98 deletions.
118 changes: 108 additions & 10 deletions lib/components/base-components/NormalComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
CadModelObj,
CadModelProp,
CadModelStl,
SchematicPortArrangement,
} from "@tscircuit/props"
import { point3, rotation } from "circuit-json"
import Debug from "debug"
Expand All @@ -25,6 +26,12 @@ import { ZodType, z } from "zod"
import { Footprint } from "../primitive-components/Footprint"
import { Port } from "../primitive-components/Port"
import { PrimitiveComponent } from "./PrimitiveComponent"
import {
getAllDimensionsForSchematicBox,
type SchematicBoxDimensions,
} from "lib/utils/schematic/getAllDimensionsForSchematicBox"
import { underscorifyPortArrangement } from "lib/soup/underscorifyPortArrangement"
import { underscorifyPinStyles } from "lib/soup/underscorifyPinStyles"

const debug = Debug("tscircuit:core")

Expand Down Expand Up @@ -253,14 +260,29 @@ export class NormalComponent<

/**
* Render the schematic component for this NormalComponent using the
* config.schematicSymbolName if it exists.
* config.schematicSymbolName if it exists, or create a generic box if
* no symbol is defined.
*
* You can override this method to do more complicated things.
*/
doInitialSchematicComponentRender() {
const { db } = this.root!
const { schematicSymbolName } = this.config
if (!schematicSymbolName) return
if (schematicSymbolName) {
return this._doInitialSchematicComponentRenderWithSymbol()
}

const dimensions = this._getSchematicBoxDimensions()
if (dimensions) {
return this._doInitialSchematicComponentRenderWithSchematicBoxDimensions()
}

// No schematic symbol or dimensions defined, this could be a board, group
// or other NormalComponent that doesn't have a schematic representation
}

_doInitialSchematicComponentRenderWithSymbol() {
const { db } = this.root!

// TODO switch between horizontal and vertical based on schRotation
const base_symbol_name = this.config.schematicSymbolName
const symbol_name_horz = `${base_symbol_name}_horz`
Expand All @@ -281,18 +303,49 @@ export class NormalComponent<

const symbol: SchSymbol | undefined = symbols[symbol_name]

if (!symbol) {
throw new Error(`Could not find schematic-symbol "${symbol_name}"`)
if (symbol) {
const schematic_component = db.schematic_component.insert({
center: { x: this.props.schX ?? 0, y: this.props.schY ?? 0 },
rotation: this.props.schRotation ?? 0,
size: symbol.size,
source_component_id: this.source_component_id!,

symbol_name,
})
this.schematic_component_id = schematic_component.schematic_component_id
}
}

_doInitialSchematicComponentRenderWithSchematicBoxDimensions() {
const { db } = this.root!
const { _parsedProps: props } = this
const dimensions = this._getSchematicBoxDimensions()!

const primaryPortLabels: Record<string, string> = {}
for (const [port, label] of Object.entries(props.pinLabels ?? {})) {
primaryPortLabels[port] = Array.isArray(label) ? label[0] : label
}

console.log("inserting schematic component")
const schematic_component = db.schematic_component.insert({
center: { x: this.props.schX ?? 0, y: this.props.schY ?? 0 },
rotation: this.props.schRotation ?? 0,
size: symbol.size,
source_component_id: this.source_component_id!,
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: props.schPinSpacing ?? 0.2,

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

symbol_name,
port_labels: primaryPortLabels,

source_component_id: this.source_component_id!,
})

this.schematic_component_id = schematic_component.schematic_component_id
}

Expand Down Expand Up @@ -545,6 +598,51 @@ export class NormalComponent<
}
}

_getPinCount(): number {
const { _parsedProps: props } = this
const pinCountFromSchArrangement =
(props.schPortArrangement?.leftSize ?? 0) +
(props.schPortArrangement?.rightSize ?? 0) +
(props.schPortArrangement?.topSize ?? 0) +
(props.schPortArrangement?.bottomSize ?? 0)
const pinCount =
pinCountFromSchArrangement || this.getPortsFromFootprint().length
return pinCount
}

/**
* Override the schematic port arrangement if you want to customize where pins
* appear on a schematic box, e.g. for a pin header
*/
_getSchematicPortArrangement(): SchematicPortArrangement | null {
return this._parsedProps.schPortArrangement
}

_getSchematicBoxDimensions(): SchematicBoxDimensions | null {
// Only valid if we don't have a schematic symbol
if (this.getSchematicSymbol()) return null
if (!this.config.shouldRenderAsSchematicBox) return null

const { _parsedProps: props } = this

const pinCount = this._getPinCount()

const pinSpacing = props.schPinSpacing ?? 0.2

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

pinCount,

schPortArrangement: this._getSchematicPortArrangement(),
})

return dimensions
}

doInitialCadModelRender(): void {
const { db } = this.root!
const { boardThickness = 0 } = this.root?._getBoard() ?? {}
Expand Down
18 changes: 18 additions & 0 deletions lib/components/base-components/PrimitiveComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ import { z } from "zod"
import type { Circuit } from "../../Circuit"
import type { ISubcircuit } from "../primitive-components/Group/ISubcircuit"
import { Renderable } from "./Renderable"
import type { SchematicBoxDimensions } from "lib/utils/schematic/getAllDimensionsForSchematicBox"

export interface BaseComponentConfig {
componentName: string
schematicSymbolName?: BaseSymbolName | null
zodProps: ZodType
sourceFtype?: AnySourceComponent["ftype"] | null
shouldRenderAsSchematicBox?: boolean
}

/**
Expand Down Expand Up @@ -509,6 +511,22 @@ export abstract class PrimitiveComponent<
return descendants
}

/**
* Return the number of pins in this component, this is important for
* NormalComponents
*/
_getPinCount(): number {
return 0
}

/**
* If this component represents a SchematicBox (like a Chip), return the
* dimensions of the box, which allows computing the position of ports etc.
*/
_getSchematicBoxDimensions(): SchematicBoxDimensions | null {
return null
}

// TODO we shouldn't need to override this, errors can be rendered and handled
// by the Renderable class, however, the Renderable class currently doesn't
// have access to the database or cleanup
Expand Down
73 changes: 26 additions & 47 deletions lib/components/normal-components/Chip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ export class Chip<PinLabels extends string = never> extends NormalComponent<
typeof chipProps,
PinLabels
> {
schematicDimensions: SchematicBoxDimensions | null = null
schematicBoxDimensions: SchematicBoxDimensions | null = null

get config() {
return {
componentName: "Chip",
zodProps: chipProps,
shouldRenderAsSchematicBox: true,
}
}

Expand All @@ -34,60 +35,38 @@ export class Chip<PinLabels extends string = never> extends NormalComponent<
this.source_component_id = source_component.source_component_id!
}

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

const pinCountFromSchArrangement =
(props.schPortArrangement?.leftSize ?? 0) +
(props.schPortArrangement?.rightSize ?? 0) +
(props.schPortArrangement?.topSize ?? 0) +
(props.schPortArrangement?.bottomSize ?? 0)
const pinCount = pinCountFromSchArrangement || this.getPortsFromFootprint().length

const pinSpacing = props.schPinSpacing ?? 0.2

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

pinCount,
// doInitialSchematicComponentRender() {
// const { db } = this.root!
// const { _parsedProps: props } = this
// const dimensions = this._getSchematicBoxDimensions()!
// this.schematicBoxDimensions = dimensions

// @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: props.schPortArrangement,
})
this.schematicDimensions = dimensions

const primaryPortLabels: Record<string, string> = {}
for (const [port, label] of Object.entries(props.pinLabels ?? {})) {
primaryPortLabels[port] = Array.isArray(label) ? label[0] : label
}
// const primaryPortLabels: Record<string, string> = {}
// for (const [port, label] of Object.entries(props.pinLabels ?? {})) {
// primaryPortLabels[port] = Array.isArray(label) ? label[0] : label
// }

const schematic_component = db.schematic_component.insert({
center: { x: props.schX ?? 0, y: props.schY ?? 0 },
rotation: props.schRotation ?? 0,
size: dimensions.getSize(),
// 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,
),
// port_arrangement: underscorifyPortArrangement(
// props.schPortArrangement as any,
// ),

pin_spacing: pinSpacing,
// pin_spacing: props.schPinSpacing ?? 0.2,

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

port_labels: primaryPortLabels,
// port_labels: primaryPortLabels,

source_component_id: this.source_component_id!,
})
// source_component_id: this.source_component_id!,
// })

this.schematic_component_id = schematic_component.schematic_component_id
}
// this.schematic_component_id = schematic_component.schematic_component_id
// }

doInitialPcbComponentRender() {
const { db } = this.root!
Expand Down
29 changes: 9 additions & 20 deletions lib/components/normal-components/PinHeader.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { pinHeaderProps } from "@tscircuit/props"
import { pinHeaderProps, type SchematicPortArrangement } from "@tscircuit/props"
import { NormalComponent } from "../base-components/NormalComponent"
import { Port } from "../primitive-components/Port"
import type { BaseSymbolName } from "lib/utils/constants"
Expand All @@ -8,7 +8,7 @@ export class PinHeader extends NormalComponent<typeof pinHeaderProps> {
return {
componentName: "PinHeader",
zodProps: pinHeaderProps,
schematicSymbolName: "pinrow_horz" as BaseSymbolName,
shouldRenderAsSchematicBox: true,
}
}

Expand Down Expand Up @@ -41,6 +41,13 @@ export class PinHeader extends NormalComponent<typeof pinHeaderProps> {
}
}

_getSchematicPortArrangement(): SchematicPortArrangement | null {
return {
leftSize: 0,
rightSize: this._parsedProps.pinCount ?? 1,
}
}

doInitialSourceRender() {
const { db } = this.root!
const { _parsedProps: props } = this
Expand All @@ -56,22 +63,4 @@ export class PinHeader extends NormalComponent<typeof pinHeaderProps> {

this.source_component_id = source_component.source_component_id
}

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

const schematic_component = db.schematic_component.insert({
center: { x: props.schX ?? 0, y: props.schY ?? 0 },
rotation: props.schRotation ?? 0,
size: { width: 2, height: props.pinCount ?? 1 },
source_component_id: this.source_component_id!,
port_arrangement: {
left_size: 0,
right_size: props.pinCount ?? 1,
},
})

this.schematic_component_id = schematic_component.schematic_component_id
}
}
34 changes: 18 additions & 16 deletions lib/components/primitive-components/Port.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,26 +79,28 @@ export class Port extends PrimitiveComponent<typeof portProps> {
}

_getGlobalSchematicPositionBeforeLayout(): { x: number; y: number } {
if (!this.schematicSymbolPortDef) {
return applyToPoint(this.parent!.computeSchematicGlobalTransform(), {
x: 0,
y: 0,
})
}

const symbol = this.parent?.getSchematicSymbol()
if (!symbol) {
console.warn(`Could not find parent symbol for ${this}`)
return { x: 0, y: 0 }
if (symbol && this.schematicSymbolPortDef) {
const transform = compose(
this.parent!.computeSchematicGlobalTransform(),
translate(-symbol.center.x, -symbol.center.y),
)

return applyToPoint(transform, this.schematicSymbolPortDef!)
}

const offsetY = -0.045
const transform = compose(
this.parent!.computeSchematicGlobalTransform(),
translate(-symbol.center.x, -symbol.center.y + offsetY),
)
const parentBoxDim = this?.parent?._getSchematicBoxDimensions()
if (parentBoxDim && this.props.pinNumber !== undefined) {
const localPortPosition = parentBoxDim.getPortPositionByPinNumber(
this.props.pinNumber!,
)
return applyToPoint(
this.parent!.computeSchematicGlobalTransform(),
localPortPosition,
)
}

return applyToPoint(transform, this.schematicSymbolPortDef)
return { x: 0, y: 0 }
}

_getGlobalSchematicPositionAfterLayout(): { x: number; y: number } {
Expand Down
Loading

0 comments on commit 6f9f839

Please sign in to comment.