kicadts 0.0.1
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/.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc +111 -0
- package/.vscode/settings.json +16 -0
- package/AGENTS.md +30 -0
- package/README.md +206 -0
- package/biome.json +93 -0
- package/bun.lock +48 -0
- package/bunfig.toml +5 -0
- package/lib/index.ts +1 -0
- package/lib/sexpr/base-classes/SxClass.ts +164 -0
- package/lib/sexpr/base-classes/SxPrimitiveBoolean.ts +35 -0
- package/lib/sexpr/base-classes/SxPrimitiveNumber.ts +26 -0
- package/lib/sexpr/base-classes/SxPrimitiveString.ts +26 -0
- package/lib/sexpr/classes/At.ts +38 -0
- package/lib/sexpr/classes/Bus.ts +83 -0
- package/lib/sexpr/classes/BusEntry.ts +142 -0
- package/lib/sexpr/classes/Color.ts +29 -0
- package/lib/sexpr/classes/Dnp.ts +8 -0
- package/lib/sexpr/classes/EmbeddedFonts.ts +70 -0
- package/lib/sexpr/classes/ExcludeFromSim.ts +8 -0
- package/lib/sexpr/classes/FieldsAutoplaced.ts +8 -0
- package/lib/sexpr/classes/Footprint.ts +719 -0
- package/lib/sexpr/classes/FootprintAttr.ts +102 -0
- package/lib/sexpr/classes/FootprintAutoplaceCost180.ts +9 -0
- package/lib/sexpr/classes/FootprintAutoplaceCost90.ts +9 -0
- package/lib/sexpr/classes/FootprintClearance.ts +9 -0
- package/lib/sexpr/classes/FootprintDescr.ts +44 -0
- package/lib/sexpr/classes/FootprintLocked.ts +32 -0
- package/lib/sexpr/classes/FootprintModel.ts +145 -0
- package/lib/sexpr/classes/FootprintNetTiePadGroups.ts +50 -0
- package/lib/sexpr/classes/FootprintPad.ts +705 -0
- package/lib/sexpr/classes/FootprintPath.ts +44 -0
- package/lib/sexpr/classes/FootprintPlaced.ts +32 -0
- package/lib/sexpr/classes/FootprintPrivateLayers.ts +56 -0
- package/lib/sexpr/classes/FootprintSheetfile.ts +44 -0
- package/lib/sexpr/classes/FootprintSheetname.ts +44 -0
- package/lib/sexpr/classes/FootprintSolderMaskMargin.ts +9 -0
- package/lib/sexpr/classes/FootprintSolderPasteMargin.ts +9 -0
- package/lib/sexpr/classes/FootprintSolderPasteRatio.ts +9 -0
- package/lib/sexpr/classes/FootprintTags.ts +44 -0
- package/lib/sexpr/classes/FootprintTedit.ts +21 -0
- package/lib/sexpr/classes/FootprintThermalGap.ts +9 -0
- package/lib/sexpr/classes/FootprintThermalWidth.ts +9 -0
- package/lib/sexpr/classes/FootprintZoneConnect.ts +9 -0
- package/lib/sexpr/classes/FpArc.ts +289 -0
- package/lib/sexpr/classes/FpCircle.ts +293 -0
- package/lib/sexpr/classes/FpLine.ts +288 -0
- package/lib/sexpr/classes/FpPoly.ts +266 -0
- package/lib/sexpr/classes/FpPolyFill.ts +48 -0
- package/lib/sexpr/classes/FpPolyLocked.ts +40 -0
- package/lib/sexpr/classes/FpRect.ts +293 -0
- package/lib/sexpr/classes/FpText.ts +341 -0
- package/lib/sexpr/classes/FpTextBox.ts +412 -0
- package/lib/sexpr/classes/GrLine.ts +245 -0
- package/lib/sexpr/classes/GrLineAngle.ts +32 -0
- package/lib/sexpr/classes/GrLineEnd.ts +61 -0
- package/lib/sexpr/classes/GrLineLocked.ts +40 -0
- package/lib/sexpr/classes/GrLineStart.ts +61 -0
- package/lib/sexpr/classes/GrText.ts +202 -0
- package/lib/sexpr/classes/Image.ts +256 -0
- package/lib/sexpr/classes/InBom.ts +8 -0
- package/lib/sexpr/classes/Junction.ts +134 -0
- package/lib/sexpr/classes/KicadPcb.ts +313 -0
- package/lib/sexpr/classes/KicadSch.ts +303 -0
- package/lib/sexpr/classes/KicadSchGenerator.ts +32 -0
- package/lib/sexpr/classes/KicadSchGeneratorVersion.ts +30 -0
- package/lib/sexpr/classes/KicadSchVersion.ts +22 -0
- package/lib/sexpr/classes/Label.ts +136 -0
- package/lib/sexpr/classes/Layer.ts +51 -0
- package/lib/sexpr/classes/Layers.ts +47 -0
- package/lib/sexpr/classes/LibSymbols.ts +61 -0
- package/lib/sexpr/classes/NoConnect.ts +73 -0
- package/lib/sexpr/classes/OnBoard.ts +8 -0
- package/lib/sexpr/classes/PadChamfer.ts +50 -0
- package/lib/sexpr/classes/PadChamferRatio.ts +9 -0
- package/lib/sexpr/classes/PadClearance.ts +9 -0
- package/lib/sexpr/classes/PadDieLength.ts +9 -0
- package/lib/sexpr/classes/PadDrill.ts +145 -0
- package/lib/sexpr/classes/PadDrillOffset.ts +54 -0
- package/lib/sexpr/classes/PadLayers.ts +59 -0
- package/lib/sexpr/classes/PadNet.ts +56 -0
- package/lib/sexpr/classes/PadOptions.ts +182 -0
- package/lib/sexpr/classes/PadPinFunction.ts +9 -0
- package/lib/sexpr/classes/PadPinType.ts +9 -0
- package/lib/sexpr/classes/PadPrimitiveGrArc.ts +254 -0
- package/lib/sexpr/classes/PadPrimitiveGrCircle.ts +279 -0
- package/lib/sexpr/classes/PadPrimitiveGrLine.ts +126 -0
- package/lib/sexpr/classes/PadPrimitives.ts +289 -0
- package/lib/sexpr/classes/PadRectDelta.ts +57 -0
- package/lib/sexpr/classes/PadRoundrectRratio.ts +9 -0
- package/lib/sexpr/classes/PadSize.ts +54 -0
- package/lib/sexpr/classes/PadSolderMaskMargin.ts +9 -0
- package/lib/sexpr/classes/PadSolderPasteMargin.ts +9 -0
- package/lib/sexpr/classes/PadSolderPasteMarginRatio.ts +9 -0
- package/lib/sexpr/classes/PadTeardrops.ts +208 -0
- package/lib/sexpr/classes/PadThermalBridgeAngle.ts +9 -0
- package/lib/sexpr/classes/PadThermalGap.ts +9 -0
- package/lib/sexpr/classes/PadThermalWidth.ts +9 -0
- package/lib/sexpr/classes/PadZoneConnect.ts +9 -0
- package/lib/sexpr/classes/Paper.ts +119 -0
- package/lib/sexpr/classes/PcbGeneral.ts +75 -0
- package/lib/sexpr/classes/PcbGeneralLegacyTeardrops.ts +44 -0
- package/lib/sexpr/classes/PcbGeneralThickness.ts +9 -0
- package/lib/sexpr/classes/PcbGenerator.ts +16 -0
- package/lib/sexpr/classes/PcbGeneratorVersion.ts +16 -0
- package/lib/sexpr/classes/PcbLayerDefinition.ts +102 -0
- package/lib/sexpr/classes/PcbLayers.ts +34 -0
- package/lib/sexpr/classes/PcbNet.ts +56 -0
- package/lib/sexpr/classes/PcbVersion.ts +9 -0
- package/lib/sexpr/classes/Property.ts +246 -0
- package/lib/sexpr/classes/PropertyHide.ts +9 -0
- package/lib/sexpr/classes/PropertyUnlocked.ts +9 -0
- package/lib/sexpr/classes/Pts.ts +65 -0
- package/lib/sexpr/classes/RenderCache.ts +221 -0
- package/lib/sexpr/classes/SchematicText.ts +141 -0
- package/lib/sexpr/classes/Segment.ts +222 -0
- package/lib/sexpr/classes/SegmentEnd.ts +59 -0
- package/lib/sexpr/classes/SegmentLocked.ts +33 -0
- package/lib/sexpr/classes/SegmentNet.ts +62 -0
- package/lib/sexpr/classes/SegmentStart.ts +59 -0
- package/lib/sexpr/classes/Setup/PcbPlotParams.ts +729 -0
- package/lib/sexpr/classes/Setup/PcbPlotParamsBase.ts +9 -0
- package/lib/sexpr/classes/Setup/PcbPlotParamsNumericProperties.ts +105 -0
- package/lib/sexpr/classes/Setup/PcbPlotParamsStringPropertiesA.ts +104 -0
- package/lib/sexpr/classes/Setup/PcbPlotParamsStringPropertiesB.ts +105 -0
- package/lib/sexpr/classes/Setup/Setup.ts +573 -0
- package/lib/sexpr/classes/Setup/SetupPropertyTypes.ts +119 -0
- package/lib/sexpr/classes/Setup/Stackup.ts +140 -0
- package/lib/sexpr/classes/Setup/StackupLayer.ts +233 -0
- package/lib/sexpr/classes/Setup/StackupLayerProperties.ts +78 -0
- package/lib/sexpr/classes/Setup/StackupProperties.ts +41 -0
- package/lib/sexpr/classes/Setup/base.ts +167 -0
- package/lib/sexpr/classes/Setup/index.ts +14 -0
- package/lib/sexpr/classes/Setup/setupMultiValueProperties.ts +54 -0
- package/lib/sexpr/classes/Setup/setupNumericProperties.ts +151 -0
- package/lib/sexpr/classes/Setup/setupPropertyHandlers.ts +90 -0
- package/lib/sexpr/classes/Setup/setupStringProperties.ts +75 -0
- package/lib/sexpr/classes/Sheet.ts +205 -0
- package/lib/sexpr/classes/SheetFill.ts +44 -0
- package/lib/sexpr/classes/SheetInstances.ts +168 -0
- package/lib/sexpr/classes/SheetInstancesRoot.ts +165 -0
- package/lib/sexpr/classes/SheetPin.ts +122 -0
- package/lib/sexpr/classes/SheetProperty.ts +115 -0
- package/lib/sexpr/classes/SheetSize.ts +44 -0
- package/lib/sexpr/classes/Stroke.ts +58 -0
- package/lib/sexpr/classes/StrokeType.ts +34 -0
- package/lib/sexpr/classes/Symbol.ts +1541 -0
- package/lib/sexpr/classes/TextEffects.ts +444 -0
- package/lib/sexpr/classes/TitleBlock.ts +352 -0
- package/lib/sexpr/classes/Unit.ts +28 -0
- package/lib/sexpr/classes/Uuid.ts +8 -0
- package/lib/sexpr/classes/Via.ts +328 -0
- package/lib/sexpr/classes/ViaNet.ts +59 -0
- package/lib/sexpr/classes/Width.ts +8 -0
- package/lib/sexpr/classes/Wire.ts +91 -0
- package/lib/sexpr/classes/Xy.ts +35 -0
- package/lib/sexpr/classes/Zone.ts +41 -0
- package/lib/sexpr/index.ts +130 -0
- package/lib/sexpr/parseKicadSexpr.ts +5 -0
- package/lib/sexpr/parseToPrimitiveSExpr.ts +240 -0
- package/lib/sexpr/utils/indentLines.ts +3 -0
- package/lib/sexpr/utils/parseYesNo.ts +12 -0
- package/lib/sexpr/utils/quoteSExprString.ts +8 -0
- package/lib/sexpr/utils/strokeFromArgs.ts +19 -0
- package/lib/sexpr/utils/toNumberValue.ts +13 -0
- package/lib/sexpr/utils/toStringValue.ts +10 -0
- package/package.json +26 -0
- package/scripts/download-references.ts +66 -0
- package/tests/fixtures/expectEqualPrimitiveSExpr.ts +200 -0
- package/tests/sexpr/KicadPcbDemos.test.ts +48 -0
- package/tests/sexpr/KicadSchDemos.test.ts +49 -0
- package/tests/sexpr/classes/Footprint.test.ts +277 -0
- package/tests/sexpr/classes/FootprintPad.test.ts +71 -0
- package/tests/sexpr/classes/FpArc.test.ts +45 -0
- package/tests/sexpr/classes/FpCircle.test.ts +39 -0
- package/tests/sexpr/classes/FpPoly.test.ts +43 -0
- package/tests/sexpr/classes/FpRect.test.ts +40 -0
- package/tests/sexpr/classes/FpTextBox.test.ts +84 -0
- package/tests/sexpr/classes/Image.test.ts +50 -0
- package/tests/sexpr/classes/KicadSch.test.ts +97 -0
- package/tests/sexpr/classes/Paper.test.ts +30 -0
- package/tests/sexpr/classes/Property.test.ts +48 -0
- package/tests/sexpr/classes/Setup.test.ts +189 -0
- package/tests/sexpr/classes/Sheet.test.ts +107 -0
- package/tests/sexpr/classes/Stroke.test.ts +15 -0
- package/tests/sexpr/classes/Symbol.test.ts +96 -0
- package/tests/sexpr/classes/TextEffects.test.ts +56 -0
- package/tests/sexpr/classes/TitleBlock.test.ts +40 -0
- package/tsconfig.json +35 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
2
|
+
import { SxPrimitiveBoolean } from "../base-classes/SxPrimitiveBoolean"
|
|
3
|
+
import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
4
|
+
import { Pts } from "./Pts"
|
|
5
|
+
import { Width } from "./Width"
|
|
6
|
+
import { PadPrimitiveGrLine } from "./PadPrimitiveGrLine"
|
|
7
|
+
import { PadPrimitiveGrArc } from "./PadPrimitiveGrArc"
|
|
8
|
+
import { PadPrimitiveGrCircle } from "./PadPrimitiveGrCircle"
|
|
9
|
+
|
|
10
|
+
type PadPrimitiveGraphic =
|
|
11
|
+
| PadPrimitiveGrPoly
|
|
12
|
+
| PadPrimitiveGrLine
|
|
13
|
+
| PadPrimitiveGrArc
|
|
14
|
+
| PadPrimitiveGrCircle
|
|
15
|
+
|
|
16
|
+
export class PadPrimitives extends SxClass {
|
|
17
|
+
static override token = "primitives"
|
|
18
|
+
static override parentToken = "pad"
|
|
19
|
+
override token = "primitives"
|
|
20
|
+
|
|
21
|
+
private _graphics: PadPrimitiveGraphic[] = []
|
|
22
|
+
private _sxWidth?: Width
|
|
23
|
+
private _sxFill?: PadPrimitivesFill
|
|
24
|
+
|
|
25
|
+
static override fromSexprPrimitives(
|
|
26
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
27
|
+
): PadPrimitives {
|
|
28
|
+
const primitives = new PadPrimitives()
|
|
29
|
+
|
|
30
|
+
for (const primitive of primitiveSexprs) {
|
|
31
|
+
if (!Array.isArray(primitive) || primitive.length === 0) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
`pad primitives encountered invalid child expression: ${JSON.stringify(primitive)}`,
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const parsed = SxClass.parsePrimitiveSexpr(primitive, {
|
|
38
|
+
parentToken: this.token,
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
if (!(parsed instanceof SxClass)) {
|
|
42
|
+
throw new Error(
|
|
43
|
+
`pad primitives child did not resolve to an SxClass: ${JSON.stringify(primitive)}`,
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (parsed instanceof Width) {
|
|
48
|
+
if (primitives._sxWidth) {
|
|
49
|
+
throw new Error("pad primitives encountered duplicate width tokens")
|
|
50
|
+
}
|
|
51
|
+
primitives._sxWidth = parsed
|
|
52
|
+
continue
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (parsed instanceof PadPrimitivesFill) {
|
|
56
|
+
if (primitives._sxFill) {
|
|
57
|
+
throw new Error("pad primitives encountered duplicate fill tokens")
|
|
58
|
+
}
|
|
59
|
+
primitives._sxFill = parsed
|
|
60
|
+
continue
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (parsed instanceof PadPrimitiveGrPoly) {
|
|
64
|
+
primitives._graphics.push(parsed)
|
|
65
|
+
continue
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (parsed instanceof PadPrimitiveGrLine) {
|
|
69
|
+
primitives._graphics.push(parsed)
|
|
70
|
+
continue
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (parsed instanceof PadPrimitiveGrArc) {
|
|
74
|
+
primitives._graphics.push(parsed)
|
|
75
|
+
continue
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (parsed instanceof PadPrimitiveGrCircle) {
|
|
79
|
+
primitives._graphics.push(parsed)
|
|
80
|
+
continue
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
throw new Error(`pad primitives encountered unsupported token "${parsed.token}"`)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return primitives
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
get graphics(): PadPrimitiveGraphic[] {
|
|
90
|
+
return [...this._graphics]
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
set graphics(value: PadPrimitiveGraphic[]) {
|
|
94
|
+
this._graphics = [...value]
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
addGraphic(graphic: PadPrimitiveGraphic) {
|
|
98
|
+
this._graphics.push(graphic)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
get width(): number | undefined {
|
|
102
|
+
return this._sxWidth?.value
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
set width(value: number | undefined) {
|
|
106
|
+
this._sxWidth = value === undefined ? undefined : new Width(value)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
get fill(): boolean | undefined {
|
|
110
|
+
return this._sxFill?.value
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
set fill(value: boolean | undefined) {
|
|
114
|
+
this._sxFill =
|
|
115
|
+
value === undefined ? undefined : new PadPrimitivesFill({ value })
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
override getChildren(): SxClass[] {
|
|
119
|
+
const children: SxClass[] = []
|
|
120
|
+
children.push(...this._graphics)
|
|
121
|
+
if (this._sxWidth) children.push(this._sxWidth)
|
|
122
|
+
if (this._sxFill) children.push(this._sxFill)
|
|
123
|
+
return children
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
SxClass.register(PadPrimitives)
|
|
127
|
+
|
|
128
|
+
class PadPrimitivesFill extends SxPrimitiveBoolean {
|
|
129
|
+
static override token = "fill"
|
|
130
|
+
static override parentToken = "primitives"
|
|
131
|
+
override token = "fill"
|
|
132
|
+
|
|
133
|
+
constructor(options: { value?: boolean } = {}) {
|
|
134
|
+
super(options.value ?? false)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
static override fromSexprPrimitives(
|
|
138
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
139
|
+
): PadPrimitivesFill {
|
|
140
|
+
const [raw] = primitiveSexprs
|
|
141
|
+
const normalized = typeof raw === "string" ? raw.toLowerCase() : raw
|
|
142
|
+
if (normalized === undefined) {
|
|
143
|
+
return new PadPrimitivesFill({ value: false })
|
|
144
|
+
}
|
|
145
|
+
if (normalized === "yes") {
|
|
146
|
+
return new PadPrimitivesFill({ value: true })
|
|
147
|
+
}
|
|
148
|
+
if (normalized === "no") {
|
|
149
|
+
return new PadPrimitivesFill({ value: false })
|
|
150
|
+
}
|
|
151
|
+
if (typeof normalized === "boolean") {
|
|
152
|
+
return new PadPrimitivesFill({ value: normalized })
|
|
153
|
+
}
|
|
154
|
+
throw new Error(
|
|
155
|
+
`pad primitives fill expects yes/no or boolean, received ${JSON.stringify(raw)}`,
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
SxClass.register(PadPrimitivesFill)
|
|
160
|
+
|
|
161
|
+
export class PadPrimitiveGrPoly extends SxClass {
|
|
162
|
+
static override token = "gr_poly"
|
|
163
|
+
static override parentToken = "primitives"
|
|
164
|
+
override token = "gr_poly"
|
|
165
|
+
|
|
166
|
+
private _contours: Pts[] = []
|
|
167
|
+
private _sxWidth?: Width
|
|
168
|
+
private _sxFill?: PadPrimitiveFill
|
|
169
|
+
|
|
170
|
+
static override fromSexprPrimitives(
|
|
171
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
172
|
+
): PadPrimitiveGrPoly {
|
|
173
|
+
const polygon = new PadPrimitiveGrPoly()
|
|
174
|
+
|
|
175
|
+
for (const primitive of primitiveSexprs) {
|
|
176
|
+
if (!Array.isArray(primitive) || primitive.length === 0) {
|
|
177
|
+
throw new Error(
|
|
178
|
+
`gr_poly primitive encountered invalid child: ${JSON.stringify(primitive)}`,
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const parsed = SxClass.parsePrimitiveSexpr(primitive, {
|
|
183
|
+
parentToken: this.token,
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
if (!(parsed instanceof SxClass)) {
|
|
187
|
+
throw new Error(
|
|
188
|
+
`gr_poly primitive child did not resolve to an SxClass: ${JSON.stringify(primitive)}`,
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (parsed instanceof Pts) {
|
|
193
|
+
polygon._contours.push(parsed)
|
|
194
|
+
continue
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (parsed instanceof Width) {
|
|
198
|
+
if (polygon._sxWidth) {
|
|
199
|
+
throw new Error("gr_poly encountered duplicate width tokens")
|
|
200
|
+
}
|
|
201
|
+
polygon._sxWidth = parsed
|
|
202
|
+
continue
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (parsed instanceof PadPrimitiveFill) {
|
|
206
|
+
if (polygon._sxFill) {
|
|
207
|
+
throw new Error("gr_poly encountered duplicate fill tokens")
|
|
208
|
+
}
|
|
209
|
+
polygon._sxFill = parsed
|
|
210
|
+
continue
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
throw new Error(`gr_poly encountered unsupported token "${parsed.token}"`)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (polygon._contours.length === 0) {
|
|
217
|
+
throw new Error("gr_poly requires at least one pts child")
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return polygon
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
get contours(): Pts[] {
|
|
224
|
+
return [...this._contours]
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
set contours(value: Pts[]) {
|
|
228
|
+
this._contours = [...value]
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
get width(): number | undefined {
|
|
232
|
+
return this._sxWidth?.value
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
set width(value: number | undefined) {
|
|
236
|
+
this._sxWidth = value === undefined ? undefined : new Width(value)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
get filled(): boolean | undefined {
|
|
240
|
+
return this._sxFill?.value
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
set filled(value: boolean | undefined) {
|
|
244
|
+
this._sxFill =
|
|
245
|
+
value === undefined ? undefined : new PadPrimitiveFill({ value })
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
override getChildren(): SxClass[] {
|
|
249
|
+
const children: SxClass[] = []
|
|
250
|
+
children.push(...this._contours)
|
|
251
|
+
if (this._sxWidth) children.push(this._sxWidth)
|
|
252
|
+
if (this._sxFill) children.push(this._sxFill)
|
|
253
|
+
return children
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
SxClass.register(PadPrimitiveGrPoly)
|
|
257
|
+
|
|
258
|
+
class PadPrimitiveFill extends SxPrimitiveBoolean {
|
|
259
|
+
static override token = "fill"
|
|
260
|
+
static override parentToken = "gr_poly"
|
|
261
|
+
override token = "fill"
|
|
262
|
+
|
|
263
|
+
constructor(options: { value?: boolean } = {}) {
|
|
264
|
+
super(options.value ?? false)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
static override fromSexprPrimitives(
|
|
268
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
269
|
+
): PadPrimitiveFill {
|
|
270
|
+
const [raw] = primitiveSexprs
|
|
271
|
+
if (raw === undefined) {
|
|
272
|
+
return new PadPrimitiveFill({ value: false })
|
|
273
|
+
}
|
|
274
|
+
if (typeof raw === "boolean") {
|
|
275
|
+
return new PadPrimitiveFill({ value: raw })
|
|
276
|
+
}
|
|
277
|
+
if (typeof raw === "string") {
|
|
278
|
+
return new PadPrimitiveFill({ value: raw.toLowerCase() === "yes" })
|
|
279
|
+
}
|
|
280
|
+
throw new Error(
|
|
281
|
+
`gr_poly fill expects yes/no or boolean, received ${JSON.stringify(raw)}`,
|
|
282
|
+
)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
override getString(): string {
|
|
286
|
+
return `(fill ${this.value ? "yes" : "no"})`
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
SxClass.register(PadPrimitiveFill)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
2
|
+
import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
3
|
+
import { toNumberValue } from "../utils/toNumberValue"
|
|
4
|
+
|
|
5
|
+
export class PadRectDelta extends SxClass {
|
|
6
|
+
static override token = "rect_delta"
|
|
7
|
+
static override parentToken = "pad"
|
|
8
|
+
override token = "rect_delta"
|
|
9
|
+
|
|
10
|
+
private _x: number
|
|
11
|
+
private _y: number
|
|
12
|
+
|
|
13
|
+
constructor(x = 0, y = 0) {
|
|
14
|
+
super()
|
|
15
|
+
this._x = x
|
|
16
|
+
this._y = y
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static override fromSexprPrimitives(
|
|
20
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
21
|
+
): PadRectDelta {
|
|
22
|
+
const [rawX, rawY] = primitiveSexprs
|
|
23
|
+
const x = toNumberValue(rawX)
|
|
24
|
+
const y = toNumberValue(rawY)
|
|
25
|
+
|
|
26
|
+
if (x === undefined || y === undefined) {
|
|
27
|
+
throw new Error("pad rect_delta expects two numeric arguments")
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return new PadRectDelta(x, y)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get x(): number {
|
|
34
|
+
return this._x
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
set x(value: number) {
|
|
38
|
+
this._x = value
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get y(): number {
|
|
42
|
+
return this._y
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
set y(value: number) {
|
|
46
|
+
this._y = value
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
override getChildren(): SxClass[] {
|
|
50
|
+
return []
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
override getString(): string {
|
|
54
|
+
return `(rect_delta ${this._x} ${this._y})`
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
SxClass.register(PadRectDelta)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SxPrimitiveNumber } from "../base-classes/SxPrimitiveNumber"
|
|
2
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
3
|
+
|
|
4
|
+
export class PadRoundrectRratio extends SxPrimitiveNumber {
|
|
5
|
+
static override token = "roundrect_rratio"
|
|
6
|
+
static override parentToken = "pad"
|
|
7
|
+
token = "roundrect_rratio"
|
|
8
|
+
}
|
|
9
|
+
SxClass.register(PadRoundrectRratio)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
2
|
+
import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
3
|
+
import { toNumberValue } from "../utils/toNumberValue"
|
|
4
|
+
|
|
5
|
+
export class PadSize extends SxClass {
|
|
6
|
+
static override token = "size"
|
|
7
|
+
static override parentToken = "pad"
|
|
8
|
+
token = "size"
|
|
9
|
+
|
|
10
|
+
private _width: number
|
|
11
|
+
private _height: number
|
|
12
|
+
|
|
13
|
+
constructor(width: number, height: number) {
|
|
14
|
+
super()
|
|
15
|
+
this._width = width
|
|
16
|
+
this._height = height
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static override fromSexprPrimitives(
|
|
20
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
21
|
+
): PadSize {
|
|
22
|
+
const width = toNumberValue(primitiveSexprs[0])
|
|
23
|
+
const height = toNumberValue(primitiveSexprs[1])
|
|
24
|
+
if (width === undefined || height === undefined) {
|
|
25
|
+
throw new Error("size requires width and height numeric values")
|
|
26
|
+
}
|
|
27
|
+
return new PadSize(width, height)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
get width(): number {
|
|
31
|
+
return this._width
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
set width(value: number) {
|
|
35
|
+
this._width = value
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
get height(): number {
|
|
39
|
+
return this._height
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
set height(value: number) {
|
|
43
|
+
this._height = value
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
override getChildren(): SxClass[] {
|
|
47
|
+
return []
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
override getString(): string {
|
|
51
|
+
return `(size ${this._width} ${this._height})`
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
SxClass.register(PadSize)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SxPrimitiveNumber } from "../base-classes/SxPrimitiveNumber"
|
|
2
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
3
|
+
|
|
4
|
+
export class PadSolderMaskMargin extends SxPrimitiveNumber {
|
|
5
|
+
static override token = "solder_mask_margin"
|
|
6
|
+
static override parentToken = "pad"
|
|
7
|
+
token = "solder_mask_margin"
|
|
8
|
+
}
|
|
9
|
+
SxClass.register(PadSolderMaskMargin)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SxPrimitiveNumber } from "../base-classes/SxPrimitiveNumber"
|
|
2
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
3
|
+
|
|
4
|
+
export class PadSolderPasteMargin extends SxPrimitiveNumber {
|
|
5
|
+
static override token = "solder_paste_margin"
|
|
6
|
+
static override parentToken = "pad"
|
|
7
|
+
token = "solder_paste_margin"
|
|
8
|
+
}
|
|
9
|
+
SxClass.register(PadSolderPasteMargin)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SxPrimitiveNumber } from "../base-classes/SxPrimitiveNumber"
|
|
2
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
3
|
+
|
|
4
|
+
export class PadSolderPasteMarginRatio extends SxPrimitiveNumber {
|
|
5
|
+
static override token = "solder_paste_margin_ratio"
|
|
6
|
+
static override parentToken = "pad"
|
|
7
|
+
token = "solder_paste_margin_ratio"
|
|
8
|
+
}
|
|
9
|
+
SxClass.register(PadSolderPasteMarginRatio)
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
2
|
+
import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
3
|
+
import { toNumberValue } from "../utils/toNumberValue"
|
|
4
|
+
import { parseYesNo } from "../utils/parseYesNo"
|
|
5
|
+
|
|
6
|
+
type NumericTeardropProperty =
|
|
7
|
+
| "bestLengthRatio"
|
|
8
|
+
| "maxLength"
|
|
9
|
+
| "bestWidthRatio"
|
|
10
|
+
| "maxWidth"
|
|
11
|
+
| "filterRatio"
|
|
12
|
+
|
|
13
|
+
type BooleanTeardropProperty =
|
|
14
|
+
| "curvedEdges"
|
|
15
|
+
| "enabled"
|
|
16
|
+
| "allowTwoSegments"
|
|
17
|
+
| "preferZoneConnections"
|
|
18
|
+
|
|
19
|
+
const NUMERIC_TOKENS = new Map<string, NumericTeardropProperty>([
|
|
20
|
+
["best_length_ratio", "bestLengthRatio"],
|
|
21
|
+
["max_length", "maxLength"],
|
|
22
|
+
["best_width_ratio", "bestWidthRatio"],
|
|
23
|
+
["max_width", "maxWidth"],
|
|
24
|
+
["filter_ratio", "filterRatio"],
|
|
25
|
+
])
|
|
26
|
+
|
|
27
|
+
const BOOLEAN_TOKENS = new Map<string, BooleanTeardropProperty>([
|
|
28
|
+
["curved_edges", "curvedEdges"],
|
|
29
|
+
["enabled", "enabled"],
|
|
30
|
+
["allow_two_segments", "allowTwoSegments"],
|
|
31
|
+
["prefer_zone_connections", "preferZoneConnections"],
|
|
32
|
+
])
|
|
33
|
+
|
|
34
|
+
export class PadTeardrops extends SxClass {
|
|
35
|
+
static override token = "teardrops"
|
|
36
|
+
static override parentToken = "pad"
|
|
37
|
+
override token = "teardrops"
|
|
38
|
+
|
|
39
|
+
private _bestLengthRatio?: number
|
|
40
|
+
private _maxLength?: number
|
|
41
|
+
private _bestWidthRatio?: number
|
|
42
|
+
private _maxWidth?: number
|
|
43
|
+
private _filterRatio?: number
|
|
44
|
+
private _curvedEdges?: boolean
|
|
45
|
+
private _enabled?: boolean
|
|
46
|
+
private _allowTwoSegments?: boolean
|
|
47
|
+
private _preferZoneConnections?: boolean
|
|
48
|
+
|
|
49
|
+
static override fromSexprPrimitives(
|
|
50
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
51
|
+
): PadTeardrops {
|
|
52
|
+
const teardrops = new PadTeardrops()
|
|
53
|
+
|
|
54
|
+
for (const primitive of primitiveSexprs) {
|
|
55
|
+
if (!Array.isArray(primitive) || primitive.length === 0) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
`teardrops encountered invalid child expression: ${JSON.stringify(primitive)}`,
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
const [rawToken, rawValue] = primitive
|
|
61
|
+
if (typeof rawToken !== "string") {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`teardrops encountered non-string token: ${JSON.stringify(rawToken)}`,
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (NUMERIC_TOKENS.has(rawToken)) {
|
|
68
|
+
const property = NUMERIC_TOKENS.get(rawToken)!
|
|
69
|
+
const numeric = toNumberValue(rawValue)
|
|
70
|
+
if (numeric === undefined) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
`teardrops ${rawToken} expects a numeric value, received ${JSON.stringify(rawValue)}`,
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
teardrops[property] = numeric
|
|
76
|
+
continue
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (BOOLEAN_TOKENS.has(rawToken)) {
|
|
80
|
+
const property = BOOLEAN_TOKENS.get(rawToken)!
|
|
81
|
+
const booleanValue = parseYesNo(rawValue)
|
|
82
|
+
if (booleanValue === undefined) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
`teardrops ${rawToken} expects yes/no, received ${JSON.stringify(rawValue)}`,
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
teardrops[property] = booleanValue
|
|
88
|
+
continue
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
throw new Error(`teardrops encountered unsupported token "${rawToken}"`)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return teardrops
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
get bestLengthRatio(): number | undefined {
|
|
98
|
+
return this._bestLengthRatio
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
set bestLengthRatio(value: number | undefined) {
|
|
102
|
+
this._bestLengthRatio = value
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
get maxLength(): number | undefined {
|
|
106
|
+
return this._maxLength
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
set maxLength(value: number | undefined) {
|
|
110
|
+
this._maxLength = value
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
get bestWidthRatio(): number | undefined {
|
|
114
|
+
return this._bestWidthRatio
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
set bestWidthRatio(value: number | undefined) {
|
|
118
|
+
this._bestWidthRatio = value
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
get maxWidth(): number | undefined {
|
|
122
|
+
return this._maxWidth
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
set maxWidth(value: number | undefined) {
|
|
126
|
+
this._maxWidth = value
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
get filterRatio(): number | undefined {
|
|
130
|
+
return this._filterRatio
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
set filterRatio(value: number | undefined) {
|
|
134
|
+
this._filterRatio = value
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
get curvedEdges(): boolean | undefined {
|
|
138
|
+
return this._curvedEdges
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
set curvedEdges(value: boolean | undefined) {
|
|
142
|
+
this._curvedEdges = value
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
get enabled(): boolean | undefined {
|
|
146
|
+
return this._enabled
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
set enabled(value: boolean | undefined) {
|
|
150
|
+
this._enabled = value
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
get allowTwoSegments(): boolean | undefined {
|
|
154
|
+
return this._allowTwoSegments
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
set allowTwoSegments(value: boolean | undefined) {
|
|
158
|
+
this._allowTwoSegments = value
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
get preferZoneConnections(): boolean | undefined {
|
|
162
|
+
return this._preferZoneConnections
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
set preferZoneConnections(value: boolean | undefined) {
|
|
166
|
+
this._preferZoneConnections = value
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
override getChildren(): SxClass[] {
|
|
170
|
+
return []
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
override getString(): string {
|
|
174
|
+
const lines = ["(teardrops"]
|
|
175
|
+
if (this._bestLengthRatio !== undefined) {
|
|
176
|
+
lines.push(` (best_length_ratio ${this._bestLengthRatio})`)
|
|
177
|
+
}
|
|
178
|
+
if (this._maxLength !== undefined) {
|
|
179
|
+
lines.push(` (max_length ${this._maxLength})`)
|
|
180
|
+
}
|
|
181
|
+
if (this._bestWidthRatio !== undefined) {
|
|
182
|
+
lines.push(` (best_width_ratio ${this._bestWidthRatio})`)
|
|
183
|
+
}
|
|
184
|
+
if (this._maxWidth !== undefined) {
|
|
185
|
+
lines.push(` (max_width ${this._maxWidth})`)
|
|
186
|
+
}
|
|
187
|
+
if (this._curvedEdges !== undefined) {
|
|
188
|
+
lines.push(` (curved_edges ${this._curvedEdges ? "yes" : "no"})`)
|
|
189
|
+
}
|
|
190
|
+
if (this._filterRatio !== undefined) {
|
|
191
|
+
lines.push(` (filter_ratio ${this._filterRatio})`)
|
|
192
|
+
}
|
|
193
|
+
if (this._enabled !== undefined) {
|
|
194
|
+
lines.push(` (enabled ${this._enabled ? "yes" : "no"})`)
|
|
195
|
+
}
|
|
196
|
+
if (this._allowTwoSegments !== undefined) {
|
|
197
|
+
lines.push(` (allow_two_segments ${this._allowTwoSegments ? "yes" : "no"})`)
|
|
198
|
+
}
|
|
199
|
+
if (this._preferZoneConnections !== undefined) {
|
|
200
|
+
lines.push(
|
|
201
|
+
` (prefer_zone_connections ${this._preferZoneConnections ? "yes" : "no"})`,
|
|
202
|
+
)
|
|
203
|
+
}
|
|
204
|
+
lines.push(")")
|
|
205
|
+
return lines.join("\n")
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
SxClass.register(PadTeardrops)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
2
|
+
import { SxPrimitiveNumber } from "../base-classes/SxPrimitiveNumber"
|
|
3
|
+
|
|
4
|
+
export class PadThermalBridgeAngle extends SxPrimitiveNumber {
|
|
5
|
+
static override token = "thermal_bridge_angle"
|
|
6
|
+
static override parentToken = "pad"
|
|
7
|
+
override token = "thermal_bridge_angle"
|
|
8
|
+
}
|
|
9
|
+
SxClass.register(PadThermalBridgeAngle)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SxPrimitiveNumber } from "../base-classes/SxPrimitiveNumber"
|
|
2
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
3
|
+
|
|
4
|
+
export class PadThermalGap extends SxPrimitiveNumber {
|
|
5
|
+
static override token = "thermal_gap"
|
|
6
|
+
static override parentToken = "pad"
|
|
7
|
+
token = "thermal_gap"
|
|
8
|
+
}
|
|
9
|
+
SxClass.register(PadThermalGap)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SxPrimitiveNumber } from "../base-classes/SxPrimitiveNumber"
|
|
2
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
3
|
+
|
|
4
|
+
export class PadThermalWidth extends SxPrimitiveNumber {
|
|
5
|
+
static override token = "thermal_width"
|
|
6
|
+
static override parentToken = "pad"
|
|
7
|
+
token = "thermal_width"
|
|
8
|
+
}
|
|
9
|
+
SxClass.register(PadThermalWidth)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SxPrimitiveNumber } from "../base-classes/SxPrimitiveNumber"
|
|
2
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
3
|
+
|
|
4
|
+
export class PadZoneConnect extends SxPrimitiveNumber {
|
|
5
|
+
static override token = "zone_connect"
|
|
6
|
+
static override parentToken = "pad"
|
|
7
|
+
token = "zone_connect"
|
|
8
|
+
}
|
|
9
|
+
SxClass.register(PadZoneConnect)
|