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,102 @@
|
|
|
1
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
2
|
+
import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
3
|
+
|
|
4
|
+
const FLAG_TOKENS = new Set([
|
|
5
|
+
"board_only",
|
|
6
|
+
"exclude_from_pos_files",
|
|
7
|
+
"exclude_from_bom",
|
|
8
|
+
])
|
|
9
|
+
|
|
10
|
+
export class FootprintAttr extends SxClass {
|
|
11
|
+
static override token = "attr"
|
|
12
|
+
static override parentToken = "footprint"
|
|
13
|
+
token = "attr"
|
|
14
|
+
|
|
15
|
+
private _type?: string
|
|
16
|
+
private _boardOnly = false
|
|
17
|
+
private _excludeFromPosFiles = false
|
|
18
|
+
private _excludeFromBom = false
|
|
19
|
+
|
|
20
|
+
static override fromSexprPrimitives(
|
|
21
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
22
|
+
): FootprintAttr {
|
|
23
|
+
const attr = new FootprintAttr()
|
|
24
|
+
for (const primitive of primitiveSexprs) {
|
|
25
|
+
if (typeof primitive !== "string") {
|
|
26
|
+
throw new Error(
|
|
27
|
+
`attr encountered unsupported child: ${JSON.stringify(primitive)}`,
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
if (FLAG_TOKENS.has(primitive)) {
|
|
31
|
+
attr.applyFlag(primitive)
|
|
32
|
+
continue
|
|
33
|
+
}
|
|
34
|
+
if (attr._type === undefined) {
|
|
35
|
+
attr._type = primitive
|
|
36
|
+
continue
|
|
37
|
+
}
|
|
38
|
+
throw new Error(`attr encountered duplicate or unknown token "${primitive}"`)
|
|
39
|
+
}
|
|
40
|
+
return attr
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private applyFlag(flag: string) {
|
|
44
|
+
switch (flag) {
|
|
45
|
+
case "board_only":
|
|
46
|
+
this._boardOnly = true
|
|
47
|
+
break
|
|
48
|
+
case "exclude_from_pos_files":
|
|
49
|
+
this._excludeFromPosFiles = true
|
|
50
|
+
break
|
|
51
|
+
case "exclude_from_bom":
|
|
52
|
+
this._excludeFromBom = true
|
|
53
|
+
break
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get type(): string | undefined {
|
|
58
|
+
return this._type
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
set type(value: string | undefined) {
|
|
62
|
+
this._type = value
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
get boardOnly(): boolean {
|
|
66
|
+
return this._boardOnly
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
set boardOnly(value: boolean) {
|
|
70
|
+
this._boardOnly = value
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
get excludeFromPosFiles(): boolean {
|
|
74
|
+
return this._excludeFromPosFiles
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
set excludeFromPosFiles(value: boolean) {
|
|
78
|
+
this._excludeFromPosFiles = value
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
get excludeFromBom(): boolean {
|
|
82
|
+
return this._excludeFromBom
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
set excludeFromBom(value: boolean) {
|
|
86
|
+
this._excludeFromBom = value
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
override getChildren(): SxClass[] {
|
|
90
|
+
return []
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
override getString(): string {
|
|
94
|
+
const tokens = ["attr"]
|
|
95
|
+
if (this._type) tokens.push(this._type)
|
|
96
|
+
if (this._boardOnly) tokens.push("board_only")
|
|
97
|
+
if (this._excludeFromPosFiles) tokens.push("exclude_from_pos_files")
|
|
98
|
+
if (this._excludeFromBom) tokens.push("exclude_from_bom")
|
|
99
|
+
return `(${tokens.join(" ")})`
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
SxClass.register(FootprintAttr)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SxPrimitiveNumber } from "../base-classes/SxPrimitiveNumber"
|
|
2
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
3
|
+
|
|
4
|
+
export class FootprintAutoplaceCost180 extends SxPrimitiveNumber {
|
|
5
|
+
static override token = "autoplace_cost180"
|
|
6
|
+
static override parentToken = "footprint"
|
|
7
|
+
token = "autoplace_cost180"
|
|
8
|
+
}
|
|
9
|
+
SxClass.register(FootprintAutoplaceCost180)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SxPrimitiveNumber } from "../base-classes/SxPrimitiveNumber"
|
|
2
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
3
|
+
|
|
4
|
+
export class FootprintAutoplaceCost90 extends SxPrimitiveNumber {
|
|
5
|
+
static override token = "autoplace_cost90"
|
|
6
|
+
static override parentToken = "footprint"
|
|
7
|
+
token = "autoplace_cost90"
|
|
8
|
+
}
|
|
9
|
+
SxClass.register(FootprintAutoplaceCost90)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SxPrimitiveNumber } from "../base-classes/SxPrimitiveNumber"
|
|
2
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
3
|
+
|
|
4
|
+
export class FootprintClearance extends SxPrimitiveNumber {
|
|
5
|
+
static override token = "clearance"
|
|
6
|
+
static override parentToken = "footprint"
|
|
7
|
+
token = "clearance"
|
|
8
|
+
}
|
|
9
|
+
SxClass.register(FootprintClearance)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
2
|
+
import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
3
|
+
import { quoteSExprString } from "../utils/quoteSExprString"
|
|
4
|
+
import { toStringValue } from "../utils/toStringValue"
|
|
5
|
+
|
|
6
|
+
export class FootprintDescr extends SxClass {
|
|
7
|
+
static override token = "descr"
|
|
8
|
+
static override parentToken = "footprint"
|
|
9
|
+
token = "descr"
|
|
10
|
+
|
|
11
|
+
private _value: string
|
|
12
|
+
|
|
13
|
+
constructor(value: string) {
|
|
14
|
+
super()
|
|
15
|
+
this._value = value
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
static override fromSexprPrimitives(
|
|
19
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
20
|
+
): FootprintDescr {
|
|
21
|
+
const value = toStringValue(primitiveSexprs[0])
|
|
22
|
+
if (value === undefined) {
|
|
23
|
+
throw new Error("descr expects a string value")
|
|
24
|
+
}
|
|
25
|
+
return new FootprintDescr(value)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get value(): string {
|
|
29
|
+
return this._value
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
set value(value: string) {
|
|
33
|
+
this._value = value
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
override getChildren(): SxClass[] {
|
|
37
|
+
return []
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
override getString(): string {
|
|
41
|
+
return `(descr ${quoteSExprString(this._value)})`
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
SxClass.register(FootprintDescr)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
2
|
+
import { SxPrimitiveBoolean } from "../base-classes/SxPrimitiveBoolean"
|
|
3
|
+
import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
4
|
+
import { parseYesNo } from "../utils/parseYesNo"
|
|
5
|
+
|
|
6
|
+
export class FootprintLocked extends SxPrimitiveBoolean {
|
|
7
|
+
static override token = "locked"
|
|
8
|
+
static override parentToken = "footprint"
|
|
9
|
+
token = "locked"
|
|
10
|
+
|
|
11
|
+
constructor(value = true) {
|
|
12
|
+
super(value)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
static override fromSexprPrimitives(
|
|
16
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
17
|
+
): FootprintLocked {
|
|
18
|
+
if (primitiveSexprs.length === 0) {
|
|
19
|
+
return new FootprintLocked(true)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const parsed = parseYesNo(primitiveSexprs[0])
|
|
23
|
+
if (parsed === undefined) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
`locked expects yes/no, received ${JSON.stringify(primitiveSexprs[0])}`,
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return new FootprintLocked(parsed)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
SxClass.register(FootprintLocked)
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
2
|
+
import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
3
|
+
import { quoteSExprString } from "../utils/quoteSExprString"
|
|
4
|
+
import { toNumberValue } from "../utils/toNumberValue"
|
|
5
|
+
import { toStringValue } from "../utils/toStringValue"
|
|
6
|
+
|
|
7
|
+
export interface ModelVector {
|
|
8
|
+
x: number
|
|
9
|
+
y: number
|
|
10
|
+
z: number
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const DEFAULT_VECTOR: ModelVector = { x: 0, y: 0, z: 0 }
|
|
14
|
+
|
|
15
|
+
export class FootprintModel extends SxClass {
|
|
16
|
+
static override token = "model"
|
|
17
|
+
static override parentToken = "footprint"
|
|
18
|
+
override token = "model"
|
|
19
|
+
|
|
20
|
+
private _path: string
|
|
21
|
+
private _offset?: ModelVector
|
|
22
|
+
private _scale?: ModelVector
|
|
23
|
+
private _rotate?: ModelVector
|
|
24
|
+
|
|
25
|
+
constructor(path: string) {
|
|
26
|
+
super()
|
|
27
|
+
this._path = path
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static override fromSexprPrimitives(
|
|
31
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
32
|
+
): FootprintModel {
|
|
33
|
+
if (primitiveSexprs.length === 0) {
|
|
34
|
+
throw new Error("model requires a path argument")
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const [rawPath, ...rest] = primitiveSexprs
|
|
38
|
+
const path = toStringValue(rawPath)
|
|
39
|
+
if (path === undefined) {
|
|
40
|
+
throw new Error("model path must be a string value")
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const model = new FootprintModel(path)
|
|
44
|
+
|
|
45
|
+
for (const primitive of rest) {
|
|
46
|
+
if (!Array.isArray(primitive) || primitive.length === 0) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
`model encountered invalid child expression: ${JSON.stringify(primitive)}`,
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
const [token, ...args] = primitive
|
|
52
|
+
if (token === "offset") {
|
|
53
|
+
model._offset = parseVectorArgs(args, "offset")
|
|
54
|
+
continue
|
|
55
|
+
}
|
|
56
|
+
if (token === "scale") {
|
|
57
|
+
model._scale = parseVectorArgs(args, "scale")
|
|
58
|
+
continue
|
|
59
|
+
}
|
|
60
|
+
if (token === "rotate") {
|
|
61
|
+
model._rotate = parseVectorArgs(args, "rotate")
|
|
62
|
+
continue
|
|
63
|
+
}
|
|
64
|
+
throw new Error(`model encountered unsupported child token "${token}"`)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return model
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
get path(): string {
|
|
71
|
+
return this._path
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
set path(value: string) {
|
|
75
|
+
this._path = value
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
get offset(): ModelVector | undefined {
|
|
79
|
+
return this._offset ? { ...this._offset } : undefined
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
set offset(value: ModelVector | undefined) {
|
|
83
|
+
this._offset = value ? { ...value } : undefined
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
get scale(): ModelVector | undefined {
|
|
87
|
+
return this._scale ? { ...this._scale } : undefined
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
set scale(value: ModelVector | undefined) {
|
|
91
|
+
this._scale = value ? { ...value } : undefined
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
get rotate(): ModelVector | undefined {
|
|
95
|
+
return this._rotate ? { ...this._rotate } : undefined
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
set rotate(value: ModelVector | undefined) {
|
|
99
|
+
this._rotate = value ? { ...value } : undefined
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
override getChildren(): SxClass[] {
|
|
103
|
+
return []
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
override getString(): string {
|
|
107
|
+
const lines = [`(model ${quoteSExprString(this._path)}`]
|
|
108
|
+
if (this._offset) {
|
|
109
|
+
lines.push(renderVectorBlock("offset", this._offset))
|
|
110
|
+
}
|
|
111
|
+
if (this._scale) {
|
|
112
|
+
lines.push(renderVectorBlock("scale", this._scale))
|
|
113
|
+
}
|
|
114
|
+
if (this._rotate) {
|
|
115
|
+
lines.push(renderVectorBlock("rotate", this._rotate))
|
|
116
|
+
}
|
|
117
|
+
lines.push(")")
|
|
118
|
+
return lines.join("\n")
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
SxClass.register(FootprintModel)
|
|
122
|
+
|
|
123
|
+
function parseVectorArgs(
|
|
124
|
+
args: PrimitiveSExpr[],
|
|
125
|
+
token: string,
|
|
126
|
+
): ModelVector {
|
|
127
|
+
if (args.length !== 1) {
|
|
128
|
+
throw new Error(`model ${token} expects a single xyz child`)
|
|
129
|
+
}
|
|
130
|
+
const [first] = args
|
|
131
|
+
if (!Array.isArray(first) || first.length !== 4 || first[0] !== "xyz") {
|
|
132
|
+
throw new Error(
|
|
133
|
+
`model ${token} expects (xyz x y z), received ${JSON.stringify(first)}`,
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
const [, rawX, rawY, rawZ] = first
|
|
137
|
+
const x = toNumberValue(rawX) ?? DEFAULT_VECTOR.x
|
|
138
|
+
const y = toNumberValue(rawY) ?? DEFAULT_VECTOR.y
|
|
139
|
+
const z = toNumberValue(rawZ) ?? DEFAULT_VECTOR.z
|
|
140
|
+
return { x, y, z }
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function renderVectorBlock(label: string, vector: ModelVector): string {
|
|
144
|
+
return ` (${label}\n (xyz ${vector.x} ${vector.y} ${vector.z})\n )`
|
|
145
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { SxClass } from "../base-classes/SxClass"
|
|
2
|
+
import type { PrimitiveSExpr } from "../parseToPrimitiveSExpr"
|
|
3
|
+
import { quoteSExprString } from "../utils/quoteSExprString"
|
|
4
|
+
import { toStringValue } from "../utils/toStringValue"
|
|
5
|
+
|
|
6
|
+
export class FootprintNetTiePadGroups extends SxClass {
|
|
7
|
+
static override token = "net_tie_pad_groups"
|
|
8
|
+
static override parentToken = "footprint"
|
|
9
|
+
token = "net_tie_pad_groups"
|
|
10
|
+
|
|
11
|
+
private _groups: string[] = []
|
|
12
|
+
|
|
13
|
+
constructor(groups: string[]) {
|
|
14
|
+
super()
|
|
15
|
+
this.groups = groups
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
static override fromSexprPrimitives(
|
|
19
|
+
primitiveSexprs: PrimitiveSExpr[],
|
|
20
|
+
): FootprintNetTiePadGroups {
|
|
21
|
+
const groups = primitiveSexprs.map((primitive) => {
|
|
22
|
+
const value = toStringValue(primitive)
|
|
23
|
+
if (value === undefined) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
`net_tie_pad_groups expects string group entries, received ${JSON.stringify(primitive)}`,
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
return value
|
|
29
|
+
})
|
|
30
|
+
return new FootprintNetTiePadGroups(groups)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get groups(): string[] {
|
|
34
|
+
return [...this._groups]
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
set groups(values: string[]) {
|
|
38
|
+
this._groups = values.map((value) => String(value))
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
override getChildren(): SxClass[] {
|
|
42
|
+
return []
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
override getString(): string {
|
|
46
|
+
const rendered = this._groups.map((group) => quoteSExprString(group)).join(" ")
|
|
47
|
+
return `(net_tie_pad_groups ${rendered})`
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
SxClass.register(FootprintNetTiePadGroups)
|