@tscircuit/core 0.0.29 → 0.0.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +208 -56
- package/dist/index.js +368 -97
- package/lib/Project.ts +19 -15
- package/lib/components/base-components/NormalComponent.ts +61 -13
- package/lib/components/base-components/PrimitiveComponent.ts +63 -19
- package/lib/components/base-components/Renderable.ts +5 -3
- package/lib/components/index.ts +1 -0
- package/lib/components/normal-components/Board.ts +3 -3
- package/lib/components/normal-components/Capacitor.ts +1 -1
- package/lib/components/normal-components/Chip.ts +3 -3
- package/lib/components/normal-components/Jumper.ts +3 -3
- package/lib/components/normal-components/Resistor.ts +1 -1
- package/lib/components/primitive-components/Constraint.ts +49 -0
- package/lib/components/primitive-components/Footprint.ts +158 -1
- package/lib/components/primitive-components/Net.ts +4 -4
- package/lib/components/primitive-components/PlatedHole.ts +2 -2
- package/lib/components/primitive-components/Port.ts +12 -17
- package/lib/components/primitive-components/SilkscreenPath.ts +2 -2
- package/lib/components/primitive-components/SmtPad.ts +55 -5
- package/lib/components/primitive-components/Trace.ts +7 -7
- package/lib/components/primitive-components/TraceHint.ts +2 -2
- package/lib/fiber/intrinsic-jsx.ts +2 -0
- package/lib/utils/getClosest.ts +9 -3
- package/package.json +5 -2
|
@@ -1,4 +1,161 @@
|
|
|
1
1
|
import type { footprintProps } from "@tscircuit/props"
|
|
2
2
|
import { PrimitiveComponent } from "../base-components/PrimitiveComponent"
|
|
3
|
+
import type { Constraint } from "./Constraint"
|
|
4
|
+
import * as kiwi from "@lume/kiwi"
|
|
5
|
+
import Debug from "debug"
|
|
3
6
|
|
|
4
|
-
|
|
7
|
+
const debug = Debug("tscircuit:core:footprint")
|
|
8
|
+
|
|
9
|
+
export class Footprint extends PrimitiveComponent<typeof footprintProps> {
|
|
10
|
+
/**
|
|
11
|
+
* A footprint is a constrainedlayout, the db elements are adjusted according
|
|
12
|
+
* to any constraints that are defined.
|
|
13
|
+
*/
|
|
14
|
+
doInitialPcbFootprintLayout() {
|
|
15
|
+
const constraints = this.children.filter(
|
|
16
|
+
(child) => child.componentName === "Constraint",
|
|
17
|
+
) as Constraint[]
|
|
18
|
+
|
|
19
|
+
if (constraints.length === 0) return
|
|
20
|
+
|
|
21
|
+
const involvedComponents = constraints
|
|
22
|
+
.flatMap(
|
|
23
|
+
(constraint) =>
|
|
24
|
+
constraint._getAllReferencedComponents().componentsWithSelectors,
|
|
25
|
+
)
|
|
26
|
+
.map(({ component, selector }) => ({
|
|
27
|
+
component,
|
|
28
|
+
selector,
|
|
29
|
+
bounds: component._getCircuitJsonBounds(),
|
|
30
|
+
}))
|
|
31
|
+
|
|
32
|
+
function getComponentDetails(selector: string) {
|
|
33
|
+
return involvedComponents.find(({ selector: s }) => s === selector)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const solver = new kiwi.Solver()
|
|
37
|
+
|
|
38
|
+
const kVars: { [varName: string]: kiwi.Variable } = {}
|
|
39
|
+
function getKVar(name: string) {
|
|
40
|
+
if (!(name in kVars)) {
|
|
41
|
+
kVars[name] = new kiwi.Variable(name)
|
|
42
|
+
}
|
|
43
|
+
return kVars[name]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 1. Create kiwi variables to represent each component's center
|
|
47
|
+
for (const { selector, bounds } of involvedComponents) {
|
|
48
|
+
const kvx = getKVar(`${selector}_x`)
|
|
49
|
+
const kvy = getKVar(`${selector}_y`)
|
|
50
|
+
solver.addEditVariable(kvx, kiwi.Strength.weak)
|
|
51
|
+
solver.addEditVariable(kvy, kiwi.Strength.weak)
|
|
52
|
+
solver.suggestValue(kvx, bounds.center.x)
|
|
53
|
+
solver.suggestValue(kvy, bounds.center.y)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 2. Add kiwi constraints using the parsed constraint properties
|
|
57
|
+
for (const constraint of constraints) {
|
|
58
|
+
const props = constraint._parsedProps
|
|
59
|
+
|
|
60
|
+
if ("xdist" in props) {
|
|
61
|
+
const { xdist, left, right, edgeToEdge, centerToCenter } = props
|
|
62
|
+
const leftVar = getKVar(`${left}_x`)
|
|
63
|
+
const rightVar = getKVar(`${right}_x`)
|
|
64
|
+
const leftBounds = getComponentDetails(left)?.bounds!
|
|
65
|
+
const rightBounds = getComponentDetails(right)?.bounds!
|
|
66
|
+
|
|
67
|
+
if (centerToCenter) {
|
|
68
|
+
// right - left = xdist
|
|
69
|
+
const expr = new kiwi.Expression(rightVar, [-1, leftVar])
|
|
70
|
+
solver.addConstraint(
|
|
71
|
+
new kiwi.Constraint(
|
|
72
|
+
expr,
|
|
73
|
+
kiwi.Operator.Eq,
|
|
74
|
+
props.xdist,
|
|
75
|
+
kiwi.Strength.required,
|
|
76
|
+
),
|
|
77
|
+
)
|
|
78
|
+
} else if (edgeToEdge) {
|
|
79
|
+
// rightEdge - leftEdge = xdist
|
|
80
|
+
// right + rightBounds.width/2 - left - leftBounds.width/2 = xdist
|
|
81
|
+
const expr = new kiwi.Expression(
|
|
82
|
+
rightVar,
|
|
83
|
+
rightBounds.width / 2,
|
|
84
|
+
[-1, leftVar],
|
|
85
|
+
-leftBounds.width / 2,
|
|
86
|
+
)
|
|
87
|
+
solver.addConstraint(
|
|
88
|
+
new kiwi.Constraint(
|
|
89
|
+
expr,
|
|
90
|
+
kiwi.Operator.Eq,
|
|
91
|
+
props.xdist,
|
|
92
|
+
kiwi.Strength.required,
|
|
93
|
+
),
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// 3. Solve the system of equations
|
|
99
|
+
solver.updateVariables()
|
|
100
|
+
if (debug.enabled) {
|
|
101
|
+
console.log("Solution to layout constraints:")
|
|
102
|
+
console.table(
|
|
103
|
+
Object.entries(kVars).map(([key, kvar]) => ({
|
|
104
|
+
var: key,
|
|
105
|
+
val: kvar.value(),
|
|
106
|
+
})),
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// 3.1 Compute the global offset. There are different ways to do this:
|
|
111
|
+
// - If any component has a fixed position, then that can be used as the
|
|
112
|
+
// origin to determine the offset of all other components
|
|
113
|
+
// - If no component has a fixed position, then we recenter everything
|
|
114
|
+
// using the new bounds of all the involved components
|
|
115
|
+
|
|
116
|
+
// TODO determine if there's a fixed component
|
|
117
|
+
|
|
118
|
+
// Determine the new bounds all the involved components and compute the
|
|
119
|
+
// bounds of this footprint
|
|
120
|
+
const bounds = {
|
|
121
|
+
left: Infinity,
|
|
122
|
+
right: -Infinity,
|
|
123
|
+
top: -Infinity,
|
|
124
|
+
bottom: Infinity,
|
|
125
|
+
}
|
|
126
|
+
for (const {
|
|
127
|
+
selector,
|
|
128
|
+
bounds: { width, height },
|
|
129
|
+
} of involvedComponents) {
|
|
130
|
+
const kvx = getKVar(`${selector}_x`)
|
|
131
|
+
const kvy = getKVar(`${selector}_y`)
|
|
132
|
+
|
|
133
|
+
const newLeft = kvx.value() - width / 2
|
|
134
|
+
const newRight = kvx.value() + width / 2
|
|
135
|
+
const newTop = kvy.value() + height / 2
|
|
136
|
+
const newBottom = kvy.value() - height / 2
|
|
137
|
+
|
|
138
|
+
bounds.left = Math.min(bounds.left, newLeft)
|
|
139
|
+
bounds.right = Math.max(bounds.right, newRight)
|
|
140
|
+
bounds.top = Math.max(bounds.top, newTop)
|
|
141
|
+
bounds.bottom = Math.min(bounds.bottom, newBottom)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Compute the global offset, we can use this to recenter each component
|
|
145
|
+
const globalOffset = {
|
|
146
|
+
x: -(bounds.right + bounds.left) / 2,
|
|
147
|
+
y: -(bounds.top + bounds.bottom) / 2,
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// 4. Update the component positions
|
|
151
|
+
for (const { component, selector } of involvedComponents) {
|
|
152
|
+
const kvx = getKVar(`${selector}_x`)
|
|
153
|
+
const kvy = getKVar(`${selector}_y`)
|
|
154
|
+
component._setPositionFromLayout({
|
|
155
|
+
x: kvx.value() + globalOffset.x,
|
|
156
|
+
y: kvy.value() + globalOffset.y,
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -18,7 +18,7 @@ export class Net extends PrimitiveComponent<typeof netProps> {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
doInitialSourceComponentRender(): void {
|
|
21
|
-
const { db } = this.
|
|
21
|
+
const { db } = this.root!
|
|
22
22
|
const { _parsedProps: props } = this
|
|
23
23
|
|
|
24
24
|
const net = db.source_net.insert({
|
|
@@ -77,7 +77,7 @@ export class Net extends PrimitiveComponent<typeof netProps> {
|
|
|
77
77
|
* such that the nets are fully connected
|
|
78
78
|
*/
|
|
79
79
|
doInitialPcbRouteNetIslands(): void {
|
|
80
|
-
const { db } = this.
|
|
80
|
+
const { db } = this.root!
|
|
81
81
|
const { _parsedProps: props } = this
|
|
82
82
|
|
|
83
83
|
const traces = this._getAllDirectlyConnectedTraces().filter(
|
|
@@ -109,10 +109,10 @@ export class Net extends PrimitiveComponent<typeof netProps> {
|
|
|
109
109
|
for (const [A, B] of islandPairs) {
|
|
110
110
|
// Find two closest ports on the island
|
|
111
111
|
const Apositions: Array<{ x: number; y: number }> = A.ports.map((port) =>
|
|
112
|
-
port.
|
|
112
|
+
port._getGlobalPcbPositionBeforeLayout(),
|
|
113
113
|
)
|
|
114
114
|
const Bpositions: Array<{ x: number; y: number }> = B.ports.map((port) =>
|
|
115
|
-
port.
|
|
115
|
+
port._getGlobalPcbPositionBeforeLayout(),
|
|
116
116
|
)
|
|
117
117
|
|
|
118
118
|
let closestDist = Infinity
|
|
@@ -46,10 +46,10 @@ export class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
doInitialPcbPrimitiveRender(): void {
|
|
49
|
-
const { db } = this.
|
|
49
|
+
const { db } = this.root!
|
|
50
50
|
const { _parsedProps: props } = this
|
|
51
51
|
if (!props.portHints) return
|
|
52
|
-
const position = this.
|
|
52
|
+
const position = this._getGlobalPcbPositionBeforeLayout()
|
|
53
53
|
if (props.shape === "circle") {
|
|
54
54
|
const plated_hole_input: PCBPlatedHoleInput = {
|
|
55
55
|
pcb_component_id: this.parent?.pcb_component_id!,
|
|
@@ -32,7 +32,7 @@ export class Port extends PrimitiveComponent<typeof portProps> {
|
|
|
32
32
|
this.matchedComponents = []
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
_getGlobalPcbPositionBeforeLayout(): { x: number; y: number } {
|
|
36
36
|
const matchedPcbElm = this.matchedComponents.find((c) => c.isPcbPrimitive)
|
|
37
37
|
|
|
38
38
|
if (!matchedPcbElm) {
|
|
@@ -41,10 +41,10 @@ export class Port extends PrimitiveComponent<typeof portProps> {
|
|
|
41
41
|
)
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
return matchedPcbElm?.
|
|
44
|
+
return matchedPcbElm?._getGlobalPcbPositionBeforeLayout() ?? { x: 0, y: 0 }
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
_getGlobalSchematicPositionBeforeLayout(): { x: number; y: number } {
|
|
48
48
|
if (!this.schematicSymbolPortDef) {
|
|
49
49
|
return applyToPoint(this.parent!.computeSchematicGlobalTransform(), {
|
|
50
50
|
x: 0,
|
|
@@ -116,7 +116,7 @@ export class Port extends PrimitiveComponent<typeof portProps> {
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
doInitialSourceRender(): void {
|
|
119
|
-
const { db } = this.
|
|
119
|
+
const { db } = this.root!
|
|
120
120
|
const { _parsedProps: props } = this
|
|
121
121
|
|
|
122
122
|
const port_hints = this.getNameAndAliases()
|
|
@@ -132,7 +132,7 @@ export class Port extends PrimitiveComponent<typeof portProps> {
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
doInitialSourceParentAttachment(): void {
|
|
135
|
-
const { db } = this.
|
|
135
|
+
const { db } = this.root!
|
|
136
136
|
if (!this.parent?.source_component_id) {
|
|
137
137
|
throw new Error(
|
|
138
138
|
`${this.getString()} has no parent source component (parent: ${this.parent?.getString()})`,
|
|
@@ -146,13 +146,8 @@ export class Port extends PrimitiveComponent<typeof portProps> {
|
|
|
146
146
|
this.source_component_id = this.parent?.source_component_id
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
/**
|
|
150
|
-
* For PcbPorts, we use the parent attachment phase to determine where to place
|
|
151
|
-
* the pcb_port (prior to this phase, the smtpad/platedhole isn't guaranteed
|
|
152
|
-
* to exist)
|
|
153
|
-
*/
|
|
154
149
|
doInitialPcbPortRender(): void {
|
|
155
|
-
const { db } = this.
|
|
150
|
+
const { db } = this.root!
|
|
156
151
|
const { matchedComponents } = this
|
|
157
152
|
|
|
158
153
|
if (!this.parent?.pcb_component_id) {
|
|
@@ -173,31 +168,31 @@ export class Port extends PrimitiveComponent<typeof portProps> {
|
|
|
173
168
|
|
|
174
169
|
const pcbMatch: any = pcbMatches[0]
|
|
175
170
|
|
|
176
|
-
if ("
|
|
171
|
+
if ("_getCircuitJsonBounds" in pcbMatch) {
|
|
177
172
|
const pcb_port = db.pcb_port.insert({
|
|
178
173
|
pcb_component_id: this.parent?.pcb_component_id!,
|
|
179
174
|
layers: ["top"],
|
|
180
175
|
|
|
181
|
-
...pcbMatch.
|
|
176
|
+
...pcbMatch._getCircuitJsonBounds().center,
|
|
182
177
|
|
|
183
178
|
source_port_id: this.source_port_id!,
|
|
184
179
|
})
|
|
185
180
|
this.pcb_port_id = pcb_port.pcb_port_id
|
|
186
181
|
} else {
|
|
187
182
|
throw new Error(
|
|
188
|
-
`${pcbMatch.getString()} does not have a
|
|
183
|
+
`${pcbMatch.getString()} does not have a _getGlobalPcbPositionBeforeLayout method (needed for pcb_port placement)`,
|
|
189
184
|
)
|
|
190
185
|
}
|
|
191
186
|
}
|
|
192
187
|
|
|
193
188
|
doInitialSchematicPortRender(): void {
|
|
194
|
-
const { db } = this.
|
|
189
|
+
const { db } = this.root!
|
|
195
190
|
const { _parsedProps: props } = this
|
|
196
191
|
|
|
197
192
|
if (!this.parent) return
|
|
198
193
|
|
|
199
|
-
const center = this.
|
|
200
|
-
const parentCenter = this.parent?.
|
|
194
|
+
const center = this._getGlobalSchematicPositionBeforeLayout()
|
|
195
|
+
const parentCenter = this.parent?._getGlobalSchematicPositionBeforeLayout()
|
|
201
196
|
|
|
202
197
|
this.facingDirection = getRelativeDirection(parentCenter, center)
|
|
203
198
|
|
|
@@ -14,7 +14,7 @@ export class SilkscreenPath extends PrimitiveComponent<
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
doInitialPcbPrimitiveRender(): void {
|
|
17
|
-
const { db } = this.
|
|
17
|
+
const { db } = this.root!
|
|
18
18
|
const { _parsedProps: props } = this
|
|
19
19
|
|
|
20
20
|
const layer = props.layer ?? "top"
|
|
@@ -24,7 +24,7 @@ export class SilkscreenPath extends PrimitiveComponent<
|
|
|
24
24
|
)
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
const transform = this.
|
|
27
|
+
const transform = this._computePcbGlobalTransformBeforeLayout()
|
|
28
28
|
|
|
29
29
|
const pcb_silkscreen_path = db.pcb_silkscreen_path.insert({
|
|
30
30
|
pcb_component_id: this.parent?.pcb_component_id!,
|
|
@@ -32,8 +32,8 @@ export class SmtPad extends PrimitiveComponent<typeof smtPadProps> {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
doInitialPortMatching(): void {
|
|
35
|
-
const parentPorts =
|
|
36
|
-
|
|
35
|
+
const parentPorts = this.getPrimitiveContainer()?.selectAll(
|
|
36
|
+
"port",
|
|
37
37
|
) as Port[]
|
|
38
38
|
|
|
39
39
|
if (!this.props.portHints) {
|
|
@@ -50,11 +50,13 @@ export class SmtPad extends PrimitiveComponent<typeof smtPadProps> {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
doInitialPcbPrimitiveRender(): void {
|
|
53
|
-
const { db } = this.
|
|
53
|
+
const { db } = this.root!
|
|
54
54
|
const { _parsedProps: props } = this
|
|
55
55
|
if (!props.portHints) return
|
|
56
|
-
const position = this.
|
|
57
|
-
const decomposedMat = decomposeTSR(
|
|
56
|
+
const position = this._getGlobalPcbPositionBeforeLayout()
|
|
57
|
+
const decomposedMat = decomposeTSR(
|
|
58
|
+
this._computePcbGlobalTransformBeforeLayout(),
|
|
59
|
+
)
|
|
58
60
|
const isRotated90 =
|
|
59
61
|
Math.abs(decomposedMat.rotation.angle * (180 / Math.PI) - 90) < 0.01
|
|
60
62
|
let pcb_smtpad: PCBSMTPad | null = null
|
|
@@ -94,4 +96,52 @@ export class SmtPad extends PrimitiveComponent<typeof smtPadProps> {
|
|
|
94
96
|
this.pcb_smtpad_id = pcb_smtpad.pcb_smtpad_id
|
|
95
97
|
}
|
|
96
98
|
}
|
|
99
|
+
|
|
100
|
+
_getCircuitJsonBounds(): {
|
|
101
|
+
center: { x: number; y: number }
|
|
102
|
+
bounds: { left: number; top: number; right: number; bottom: number }
|
|
103
|
+
width: number
|
|
104
|
+
height: number
|
|
105
|
+
} {
|
|
106
|
+
const { db } = this.root!
|
|
107
|
+
const smtpad = db.pcb_smtpad.get(this.pcb_smtpad_id!)!
|
|
108
|
+
|
|
109
|
+
if (smtpad.shape === "rect") {
|
|
110
|
+
return {
|
|
111
|
+
center: { x: smtpad.x, y: smtpad.y },
|
|
112
|
+
bounds: {
|
|
113
|
+
left: smtpad.x - smtpad.width / 2,
|
|
114
|
+
top: smtpad.y - smtpad.height / 2,
|
|
115
|
+
right: smtpad.x + smtpad.width / 2,
|
|
116
|
+
bottom: smtpad.y + smtpad.height / 2,
|
|
117
|
+
},
|
|
118
|
+
width: smtpad.width,
|
|
119
|
+
height: smtpad.height,
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (smtpad.shape === "circle") {
|
|
123
|
+
return {
|
|
124
|
+
center: { x: smtpad.x, y: smtpad.y },
|
|
125
|
+
bounds: {
|
|
126
|
+
left: smtpad.x - smtpad.radius,
|
|
127
|
+
top: smtpad.y - smtpad.radius,
|
|
128
|
+
right: smtpad.x + smtpad.radius,
|
|
129
|
+
bottom: smtpad.y + smtpad.radius,
|
|
130
|
+
},
|
|
131
|
+
width: smtpad.radius * 2,
|
|
132
|
+
height: smtpad.radius * 2,
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
throw new Error(
|
|
136
|
+
`circuitJson bounds calculation not implemented for shape "${(smtpad as any).shape}"`,
|
|
137
|
+
)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
_setPositionFromLayout(newCenter: { x: number; y: number }) {
|
|
141
|
+
const { db } = this.root!
|
|
142
|
+
db.pcb_smtpad.update(this.pcb_smtpad_id!, {
|
|
143
|
+
x: newCenter.x,
|
|
144
|
+
y: newCenter.y,
|
|
145
|
+
})
|
|
146
|
+
}
|
|
97
147
|
}
|
|
@@ -38,7 +38,7 @@ type PcbRouteObjective =
|
|
|
38
38
|
| { layers: string[]; x: number; y: number; via?: boolean }
|
|
39
39
|
|
|
40
40
|
const portToObjective = (port: Port): PcbRouteObjective => {
|
|
41
|
-
const portPosition = port.
|
|
41
|
+
const portPosition = port._getGlobalPcbPositionBeforeLayout()
|
|
42
42
|
return {
|
|
43
43
|
...portPosition,
|
|
44
44
|
layers: port.getAvailablePcbLayers(),
|
|
@@ -104,7 +104,7 @@ export class Trace extends PrimitiveComponent<typeof traceProps> {
|
|
|
104
104
|
ports?: undefined
|
|
105
105
|
portsWithSelectors?: undefined
|
|
106
106
|
} {
|
|
107
|
-
const { db } = this.
|
|
107
|
+
const { db } = this.root!
|
|
108
108
|
const { _parsedProps: props, parent } = this
|
|
109
109
|
|
|
110
110
|
if (!parent) throw new Error("Trace has no parent")
|
|
@@ -215,7 +215,7 @@ export class Trace extends PrimitiveComponent<typeof traceProps> {
|
|
|
215
215
|
}
|
|
216
216
|
|
|
217
217
|
doInitialSourceTraceRender(): void {
|
|
218
|
-
const { db } = this.
|
|
218
|
+
const { db } = this.root!
|
|
219
219
|
const { _parsedProps: props, parent } = this
|
|
220
220
|
|
|
221
221
|
if (!parent) {
|
|
@@ -238,7 +238,7 @@ export class Trace extends PrimitiveComponent<typeof traceProps> {
|
|
|
238
238
|
}
|
|
239
239
|
|
|
240
240
|
doInitialPcbTraceRender(): void {
|
|
241
|
-
const { db } = this.
|
|
241
|
+
const { db } = this.root!
|
|
242
242
|
const { _parsedProps: props, parent } = this
|
|
243
243
|
|
|
244
244
|
if (!parent) throw new Error("Trace has no parent")
|
|
@@ -365,7 +365,7 @@ export class Trace extends PrimitiveComponent<typeof traceProps> {
|
|
|
365
365
|
|
|
366
366
|
// Cache the PCB obstacles, they'll be needed for each segment between
|
|
367
367
|
// ports/hints
|
|
368
|
-
const obstacles = getObstaclesFromSoup(this.
|
|
368
|
+
const obstacles = getObstaclesFromSoup(this.root!.db.toArray())
|
|
369
369
|
markObstaclesAsConnected(
|
|
370
370
|
obstacles,
|
|
371
371
|
orderedRouteObjectives,
|
|
@@ -445,7 +445,7 @@ export class Trace extends PrimitiveComponent<typeof traceProps> {
|
|
|
445
445
|
}
|
|
446
446
|
|
|
447
447
|
doInitialSchematicTraceRender(): void {
|
|
448
|
-
const { db } = this.
|
|
448
|
+
const { db } = this.root!
|
|
449
449
|
const { _parsedProps: props, parent } = this
|
|
450
450
|
|
|
451
451
|
if (!parent) throw new Error("Trace has no parent")
|
|
@@ -476,7 +476,7 @@ export class Trace extends PrimitiveComponent<typeof traceProps> {
|
|
|
476
476
|
for (const { port } of ports) {
|
|
477
477
|
connection.pointsToConnect.push(
|
|
478
478
|
projectPointInDirection(
|
|
479
|
-
port.
|
|
479
|
+
port._getGlobalSchematicPositionBeforeLayout(),
|
|
480
480
|
port.facingDirection!,
|
|
481
481
|
0.1501,
|
|
482
482
|
),
|
|
@@ -8,7 +8,7 @@ export class TraceHint extends PrimitiveComponent<typeof traceHintProps> {
|
|
|
8
8
|
matchedPort: Port | null = null
|
|
9
9
|
|
|
10
10
|
doInitialPortMatching(): void {
|
|
11
|
-
const { db } = this.
|
|
11
|
+
const { db } = this.root!
|
|
12
12
|
const { _parsedProps: props, parent } = this
|
|
13
13
|
|
|
14
14
|
if (!parent) return
|
|
@@ -46,7 +46,7 @@ export class TraceHint extends PrimitiveComponent<typeof traceHintProps> {
|
|
|
46
46
|
|
|
47
47
|
if (!offsets) return []
|
|
48
48
|
|
|
49
|
-
const globalTransform = this.
|
|
49
|
+
const globalTransform = this._computePcbGlobalTransformBeforeLayout()
|
|
50
50
|
|
|
51
51
|
return offsets.map(
|
|
52
52
|
(offset): RouteHintPoint => ({
|
|
@@ -39,6 +39,8 @@ declare global {
|
|
|
39
39
|
pcbtrace: Props.PcbTraceProps
|
|
40
40
|
fabricationnotetext: Props.FabricationNoteTextProps
|
|
41
41
|
fabricationnotepath: Props.FabricationNotePathProps
|
|
42
|
+
constraint: Props.ConstraintProps
|
|
43
|
+
constrainedlayout: Props.ConstrainedLayoutProps
|
|
42
44
|
jscad: any
|
|
43
45
|
}
|
|
44
46
|
}
|
package/lib/utils/getClosest.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
export type PointLike =
|
|
2
|
-
| {
|
|
2
|
+
| { _getGlobalPcbPositionBeforeLayout: () => { x: number; y: number } }
|
|
3
3
|
| { x: number; y: number }
|
|
4
4
|
|
|
5
5
|
const getDistance = (a: PointLike, b: PointLike) => {
|
|
6
|
-
const aPos =
|
|
7
|
-
|
|
6
|
+
const aPos =
|
|
7
|
+
"_getGlobalPcbPositionBeforeLayout" in a
|
|
8
|
+
? a._getGlobalPcbPositionBeforeLayout()
|
|
9
|
+
: a
|
|
10
|
+
const bPos =
|
|
11
|
+
"_getGlobalPcbPositionBeforeLayout" in b
|
|
12
|
+
? b._getGlobalPcbPositionBeforeLayout()
|
|
13
|
+
: b
|
|
8
14
|
return Math.sqrt((aPos.x - bPos.x) ** 2 + (aPos.y - bPos.y) ** 2)
|
|
9
15
|
}
|
|
10
16
|
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@tscircuit/core",
|
|
3
3
|
"module": "index.ts",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "0.0.
|
|
5
|
+
"version": "0.0.31",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"files": [
|
|
@@ -19,10 +19,12 @@
|
|
|
19
19
|
"@tscircuit/layout": "^0.0.28",
|
|
20
20
|
"@tscircuit/log-soup": "^1.0.2",
|
|
21
21
|
"@types/bun": "latest",
|
|
22
|
+
"@types/debug": "^4.1.12",
|
|
22
23
|
"@types/react": "^18.3.3",
|
|
23
24
|
"@types/react-reconciler": "^0.28.8",
|
|
24
25
|
"bun-match-svg": "0.0.2",
|
|
25
26
|
"circuit-to-svg": "^0.0.18",
|
|
27
|
+
"debug": "^4.3.6",
|
|
26
28
|
"howfat": "^0.3.8",
|
|
27
29
|
"looks-same": "^9.0.1",
|
|
28
30
|
"tsup": "^8.2.4"
|
|
@@ -31,8 +33,9 @@
|
|
|
31
33
|
"typescript": "^5.0.0"
|
|
32
34
|
},
|
|
33
35
|
"dependencies": {
|
|
36
|
+
"@lume/kiwi": "^0.4.3",
|
|
34
37
|
"@tscircuit/infgrid-ijump-astar": "^0.0.6",
|
|
35
|
-
"@tscircuit/props": "^0.0.
|
|
38
|
+
"@tscircuit/props": "^0.0.58",
|
|
36
39
|
"@tscircuit/soup": "^0.0.58",
|
|
37
40
|
"@tscircuit/soup-util": "0.0.18",
|
|
38
41
|
"footprinter": "^0.0.44",
|