altium-toolkit 0.1.1 → 0.1.16
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/README.md +24 -6
- package/docs/api.md +42 -4
- package/docs/model-format.md +95 -5
- package/docs/schemas/altium_toolkit/normalized_model_a1.schema.json +553 -0
- package/docs/testing.md +7 -2
- package/package.json +6 -2
- package/spec/library-scope.md +7 -1
- package/src/core/altium/AltiumParser.mjs +22 -325
- package/src/core/altium/NormalizedModelSchema.mjs +28 -0
- package/src/core/altium/PcbArcPrimitiveParser.mjs +87 -0
- package/src/core/altium/PcbBinaryPrimitiveParser.mjs +43 -370
- package/src/core/altium/PcbBoardRegionSemanticsParser.mjs +477 -0
- package/src/core/altium/PcbComponentAnnotationNormalizer.mjs +290 -0
- package/src/core/altium/PcbComponentBodyPlacementNormalizer.mjs +52 -0
- package/src/core/altium/PcbComponentPrimitiveIndexer.mjs +109 -0
- package/src/core/altium/PcbEmbeddedFontExtractor.mjs +484 -0
- package/src/core/altium/PcbFillPrimitiveParser.mjs +84 -0
- package/src/core/altium/PcbFontMetricsParser.mjs +308 -0
- package/src/core/altium/PcbGeometryFlipper.mjs +244 -0
- package/src/core/altium/PcbLayerIdCodec.mjs +136 -0
- package/src/core/altium/PcbLibModelParser.mjs +202 -0
- package/src/core/altium/PcbLibStreamExtractor.mjs +968 -0
- package/src/core/altium/PcbModelParser.mjs +618 -66
- package/src/core/altium/PcbOutlineRecovery.mjs +4 -112
- package/src/core/altium/PcbPadPrimitiveParser.mjs +347 -0
- package/src/core/altium/PcbPadShapeCodec.mjs +158 -0
- package/src/core/altium/PcbPadStackParser.mjs +903 -0
- package/src/core/altium/PcbPrimitiveOwnershipIndexParser.mjs +60 -0
- package/src/core/altium/PcbPrimitiveParameterParser.mjs +212 -0
- package/src/core/altium/PcbPrimitiveRecordSlicer.mjs +243 -0
- package/src/core/altium/PcbRawRecordRegistry.mjs +831 -0
- package/src/core/altium/PcbRegionPrimitiveParser.mjs +317 -0
- package/src/core/altium/PcbRuleParser.mjs +587 -0
- package/src/core/altium/PcbStreamExtractor.mjs +127 -4
- package/src/core/altium/PcbTextPrimitiveParser.mjs +537 -0
- package/src/core/altium/PcbTrackPrimitiveParser.mjs +87 -0
- package/src/core/altium/PcbViaPrimitiveParser.mjs +88 -0
- package/src/core/altium/PcbViaStackParser.mjs +548 -0
- package/src/core/altium/PcbWideStringTableParser.mjs +108 -0
- package/src/core/altium/PrjPcbModelParser.mjs +797 -0
- package/src/core/altium/SchematicComponentTextResolver.mjs +355 -0
- package/src/parser.mjs +13 -0
- package/src/renderers.mjs +5 -0
- package/src/styles/altium-renderers.css +11 -6
- package/src/ui/PcbCopperPrimitiveSplitter.mjs +113 -0
- package/src/ui/PcbEdgeFacingGlyphNormalizer.mjs +6 -5
- package/src/ui/PcbEmbeddedFontFaceRenderer.mjs +126 -0
- package/src/ui/PcbFootprintPrimitiveSelector.mjs +27 -6
- package/src/ui/PcbRegionPrimitiveRenderer.mjs +243 -0
- package/src/ui/PcbSideResolvedRenderModel.mjs +336 -0
- package/src/ui/PcbSvgRenderer.mjs +101 -109
- package/src/ui/PcbTextPrimitiveRenderer.mjs +252 -0
- package/src/ui/SchematicSheetChromeRenderer.mjs +2 -93
- package/src/ui/SchematicSheetZoneRenderer.mjs +104 -0
|
@@ -2,423 +2,96 @@
|
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
4
|
|
|
5
|
+
import { PcbArcPrimitiveParser } from './PcbArcPrimitiveParser.mjs'
|
|
6
|
+
import { PcbFillPrimitiveParser } from './PcbFillPrimitiveParser.mjs'
|
|
7
|
+
import { PcbPadPrimitiveParser } from './PcbPadPrimitiveParser.mjs'
|
|
8
|
+
import { PcbRegionPrimitiveParser } from './PcbRegionPrimitiveParser.mjs'
|
|
9
|
+
import { PcbTextPrimitiveParser } from './PcbTextPrimitiveParser.mjs'
|
|
10
|
+
import { PcbTrackPrimitiveParser } from './PcbTrackPrimitiveParser.mjs'
|
|
11
|
+
import { PcbViaPrimitiveParser } from './PcbViaPrimitiveParser.mjs'
|
|
12
|
+
|
|
5
13
|
/**
|
|
6
|
-
* Decodes
|
|
7
|
-
*
|
|
14
|
+
* Decodes binary PCB primitive streams recovered from OLE-backed PcbDoc files,
|
|
15
|
+
* including legacy fixed-layout records and object-id/length-prefixed records.
|
|
8
16
|
*/
|
|
9
17
|
export class PcbBinaryPrimitiveParser {
|
|
10
|
-
static #ARC_OBJECT_ID = 1
|
|
11
|
-
|
|
12
|
-
static #ARC_RECORD_MIN_BYTE_LENGTH = 45
|
|
13
|
-
|
|
14
|
-
static #TRACK_OBJECT_ID = 4
|
|
15
|
-
|
|
16
|
-
static #PAD_OBJECT_ID = 2
|
|
17
|
-
|
|
18
|
-
static #PAD_SUBRECORD_COUNT = 6
|
|
19
|
-
|
|
20
|
-
static #PAD_MAIN_SUBRECORD_INDEX = 4
|
|
21
|
-
|
|
22
|
-
static #PAD_EXTENSION_SUBRECORD_INDEX = 5
|
|
23
|
-
|
|
24
|
-
static #PAD_MAIN_RECORD_MIN_BYTE_LENGTH = 61
|
|
25
|
-
|
|
26
|
-
static #PAD_EXTENSION_MIN_BYTE_LENGTH = 596
|
|
27
|
-
|
|
28
18
|
/**
|
|
29
|
-
* Decodes one
|
|
19
|
+
* Decodes one track stream in either supported binary record format.
|
|
30
20
|
* @param {Uint8Array | ArrayBuffer} headerBytes
|
|
31
21
|
* @param {Uint8Array | ArrayBuffer} dataBytes
|
|
32
|
-
* @returns {{ x1: number, y1: number, x2: number, y2: number, width: number, layerCode: number, layerId: number }[]}
|
|
22
|
+
* @returns {{ x1: number, y1: number, x2: number, y2: number, width: number, componentIndex: number | null, netIndex: number | null, polygonIndex: number | null, layerCode: number, layerId: number }[]}
|
|
33
23
|
*/
|
|
34
24
|
static parseTrackStream(headerBytes, dataBytes) {
|
|
35
|
-
|
|
36
|
-
const normalizedData = PcbBinaryPrimitiveParser.#toUint8Array(dataBytes)
|
|
37
|
-
|
|
38
|
-
if (!count) {
|
|
39
|
-
return []
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
let offset = 0
|
|
43
|
-
const tracks = []
|
|
44
|
-
|
|
45
|
-
for (let index = 0; index < count; index += 1) {
|
|
46
|
-
if (offset + 5 > normalizedData.byteLength) {
|
|
47
|
-
return []
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const objectId = normalizedData[offset]
|
|
51
|
-
offset += 1
|
|
52
|
-
|
|
53
|
-
if (objectId !== PcbBinaryPrimitiveParser.#TRACK_OBJECT_ID) {
|
|
54
|
-
return []
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const payloadLength = new DataView(
|
|
58
|
-
normalizedData.buffer,
|
|
59
|
-
normalizedData.byteOffset + offset,
|
|
60
|
-
4
|
|
61
|
-
).getUint32(0, true)
|
|
62
|
-
offset += 4
|
|
63
|
-
|
|
64
|
-
if (offset + payloadLength > normalizedData.byteLength) {
|
|
65
|
-
return []
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const payload = new DataView(
|
|
69
|
-
normalizedData.buffer,
|
|
70
|
-
normalizedData.byteOffset + offset,
|
|
71
|
-
payloadLength
|
|
72
|
-
)
|
|
73
|
-
const layerId = payload.getUint8(0)
|
|
74
|
-
|
|
75
|
-
tracks.push({
|
|
76
|
-
x1: PcbBinaryPrimitiveParser.#readMil(payload, 13),
|
|
77
|
-
y1: PcbBinaryPrimitiveParser.#readMil(payload, 17),
|
|
78
|
-
x2: PcbBinaryPrimitiveParser.#readMil(payload, 21),
|
|
79
|
-
y2: PcbBinaryPrimitiveParser.#readMil(payload, 25),
|
|
80
|
-
width: PcbBinaryPrimitiveParser.#readMil(payload, 29),
|
|
81
|
-
layerCode: layerId,
|
|
82
|
-
layerId
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
offset += payloadLength
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return tracks
|
|
25
|
+
return PcbTrackPrimitiveParser.parseTrackStream(headerBytes, dataBytes)
|
|
89
26
|
}
|
|
90
27
|
|
|
91
28
|
/**
|
|
92
|
-
* Decodes one
|
|
29
|
+
* Decodes one via stream in either supported binary record format.
|
|
93
30
|
* @param {Uint8Array | ArrayBuffer} headerBytes
|
|
94
31
|
* @param {Uint8Array | ArrayBuffer} dataBytes
|
|
95
|
-
* @returns {{ x: number, y: number, diameter: number, holeDiameter: number }[]}
|
|
32
|
+
* @returns {{ x: number, y: number, diameter: number, holeDiameter: number, componentIndex: number | null, netIndex: number | null, polygonIndex: number | null, layerCode: number | null, layerId: number | null, layerStartId: number | null, layerEndId: number | null }[]}
|
|
96
33
|
*/
|
|
97
34
|
static parseViaStream(headerBytes, dataBytes) {
|
|
98
|
-
return
|
|
99
|
-
headerBytes,
|
|
100
|
-
dataBytes,
|
|
101
|
-
326
|
|
102
|
-
).map((view) => ({
|
|
103
|
-
x: PcbBinaryPrimitiveParser.#readMil(view, 18),
|
|
104
|
-
y: PcbBinaryPrimitiveParser.#readMil(view, 22),
|
|
105
|
-
diameter: PcbBinaryPrimitiveParser.#readMil(view, 26),
|
|
106
|
-
holeDiameter: PcbBinaryPrimitiveParser.#readMil(view, 30)
|
|
107
|
-
}))
|
|
35
|
+
return PcbViaPrimitiveParser.parseViaStream(headerBytes, dataBytes)
|
|
108
36
|
}
|
|
109
37
|
|
|
110
38
|
/**
|
|
111
|
-
* Decodes one
|
|
39
|
+
* Decodes one fill stream in either supported binary record format.
|
|
112
40
|
* @param {Uint8Array | ArrayBuffer} headerBytes
|
|
113
41
|
* @param {Uint8Array | ArrayBuffer} dataBytes
|
|
114
|
-
* @returns {{ x1: number, y1: number, x2: number, y2: number, layerCode: number, layerId: number }[]}
|
|
42
|
+
* @returns {{ x1: number, y1: number, x2: number, y2: number, componentIndex: number | null, netIndex: number | null, polygonIndex: number | null, layerCode: number, layerId: number }[]}
|
|
115
43
|
*/
|
|
116
44
|
static parseFillStream(headerBytes, dataBytes) {
|
|
117
|
-
return
|
|
118
|
-
headerBytes,
|
|
119
|
-
dataBytes,
|
|
120
|
-
55
|
|
121
|
-
).map((view) => ({
|
|
122
|
-
x1: PcbBinaryPrimitiveParser.#readMil(view, 18),
|
|
123
|
-
y1: PcbBinaryPrimitiveParser.#readMil(view, 22),
|
|
124
|
-
x2: PcbBinaryPrimitiveParser.#readMil(view, 26),
|
|
125
|
-
y2: PcbBinaryPrimitiveParser.#readMil(view, 30),
|
|
126
|
-
layerCode: view.getUint16(46, true),
|
|
127
|
-
layerId: view.getUint8(5)
|
|
128
|
-
}))
|
|
45
|
+
return PcbFillPrimitiveParser.parseFillStream(headerBytes, dataBytes)
|
|
129
46
|
}
|
|
130
47
|
|
|
131
48
|
/**
|
|
132
|
-
* Decodes one
|
|
49
|
+
* Decodes one arc stream in either supported binary record format.
|
|
133
50
|
* @param {Uint8Array | ArrayBuffer} headerBytes
|
|
134
51
|
* @param {Uint8Array | ArrayBuffer} dataBytes
|
|
135
|
-
* @returns {{ x: number, y: number, radius: number, startAngle: number, endAngle: number, width: number, layerCode: number, layerId: number }[]}
|
|
52
|
+
* @returns {{ x: number, y: number, radius: number, startAngle: number, endAngle: number, width: number, componentIndex: number | null, netIndex: number | null, polygonIndex: number | null, layerCode: number, layerId: number }[]}
|
|
136
53
|
*/
|
|
137
54
|
static parseArcStream(headerBytes, dataBytes) {
|
|
138
|
-
|
|
139
|
-
const normalizedData = PcbBinaryPrimitiveParser.#toUint8Array(dataBytes)
|
|
140
|
-
|
|
141
|
-
if (!count) {
|
|
142
|
-
return []
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
let offset = 0
|
|
146
|
-
const arcs = []
|
|
147
|
-
|
|
148
|
-
for (let index = 0; index < count; index += 1) {
|
|
149
|
-
if (offset + 5 > normalizedData.byteLength) {
|
|
150
|
-
return []
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const objectId = normalizedData[offset]
|
|
154
|
-
offset += 1
|
|
155
|
-
|
|
156
|
-
if (objectId !== PcbBinaryPrimitiveParser.#ARC_OBJECT_ID) {
|
|
157
|
-
return []
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const payloadLength = new DataView(
|
|
161
|
-
normalizedData.buffer,
|
|
162
|
-
normalizedData.byteOffset + offset,
|
|
163
|
-
4
|
|
164
|
-
).getUint32(0, true)
|
|
165
|
-
offset += 4
|
|
166
|
-
|
|
167
|
-
if (
|
|
168
|
-
payloadLength <
|
|
169
|
-
PcbBinaryPrimitiveParser.#ARC_RECORD_MIN_BYTE_LENGTH ||
|
|
170
|
-
offset + payloadLength > normalizedData.byteLength
|
|
171
|
-
) {
|
|
172
|
-
return []
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const payload = new DataView(
|
|
176
|
-
normalizedData.buffer,
|
|
177
|
-
normalizedData.byteOffset + offset,
|
|
178
|
-
payloadLength
|
|
179
|
-
)
|
|
180
|
-
const layerId = payload.getUint8(0)
|
|
181
|
-
|
|
182
|
-
arcs.push({
|
|
183
|
-
x: PcbBinaryPrimitiveParser.#readMil(payload, 13),
|
|
184
|
-
y: PcbBinaryPrimitiveParser.#readMil(payload, 17),
|
|
185
|
-
radius: PcbBinaryPrimitiveParser.#readMil(payload, 21),
|
|
186
|
-
startAngle: payload.getFloat64(25, true),
|
|
187
|
-
endAngle: payload.getFloat64(33, true),
|
|
188
|
-
width: PcbBinaryPrimitiveParser.#readMil(payload, 41),
|
|
189
|
-
layerCode: layerId,
|
|
190
|
-
layerId
|
|
191
|
-
})
|
|
192
|
-
|
|
193
|
-
offset += payloadLength
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
return arcs
|
|
55
|
+
return PcbArcPrimitiveParser.parseArcStream(headerBytes, dataBytes)
|
|
197
56
|
}
|
|
198
57
|
|
|
199
58
|
/**
|
|
200
59
|
* Decodes one variable-length pad stream.
|
|
201
60
|
* @param {Uint8Array | ArrayBuffer} headerBytes
|
|
202
61
|
* @param {Uint8Array | ArrayBuffer} dataBytes
|
|
203
|
-
* @returns {{ x: number, y: number, sizeTopX: number, sizeTopY: number, sizeMidX: number, sizeMidY: number, sizeBottomX: number, sizeBottomY: number, holeDiameter: number, shapeTop: number, shapeMid: number, shapeBottom: number, rotation: number, isPlated: boolean, holeShape: number | null, holeSlotLength: number | null, holeRotation: number | null, hasRoundedRect: boolean, roundedRectShapeTop: number | null, cornerRadiusTop: number | null, offsetTopX: number, offsetTopY: number }[]}
|
|
62
|
+
* @returns {{ x: number, y: number, sizeTopX: number, sizeTopY: number, sizeMidX: number, sizeMidY: number, sizeBottomX: number, sizeBottomY: number, holeDiameter: number, shapeTop: number, shapeMid: number, shapeBottom: number, shapeTopName: string | null, shapeMidName: string | null, shapeBottomName: string | null, rotation: number, isPlated: boolean, holeShape: number | null, holeSlotLength: number | null, holeRotation: number | null, hasRoundedRect: boolean, roundedRectShapeTop: number | null, cornerRadiusTop: number | null, offsetTopX: number, offsetTopY: number, componentIndex: number | null, netIndex: number | null, polygonIndex: number | null, layerCode: number | null, layerId: number | null, legacyLayerId: number | null, layerV7SaveId: number | null, [key: string]: unknown }[]}
|
|
204
63
|
*/
|
|
205
64
|
static parsePadStream(headerBytes, dataBytes) {
|
|
206
|
-
|
|
207
|
-
const normalizedData = PcbBinaryPrimitiveParser.#toUint8Array(dataBytes)
|
|
208
|
-
|
|
209
|
-
if (!count) {
|
|
210
|
-
return []
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
let offset = 0
|
|
214
|
-
const pads = []
|
|
215
|
-
|
|
216
|
-
for (let index = 0; index < count; index += 1) {
|
|
217
|
-
if (offset + 1 > normalizedData.byteLength) {
|
|
218
|
-
return []
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
const objectId = normalizedData[offset]
|
|
222
|
-
offset += 1
|
|
223
|
-
|
|
224
|
-
if (objectId !== PcbBinaryPrimitiveParser.#PAD_OBJECT_ID) {
|
|
225
|
-
return []
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const subrecords = []
|
|
229
|
-
|
|
230
|
-
for (
|
|
231
|
-
let subrecordIndex = 0;
|
|
232
|
-
subrecordIndex < PcbBinaryPrimitiveParser.#PAD_SUBRECORD_COUNT;
|
|
233
|
-
subrecordIndex += 1
|
|
234
|
-
) {
|
|
235
|
-
if (offset + 4 > normalizedData.byteLength) {
|
|
236
|
-
return []
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const subrecordLength = new DataView(
|
|
240
|
-
normalizedData.buffer,
|
|
241
|
-
normalizedData.byteOffset + offset,
|
|
242
|
-
4
|
|
243
|
-
).getUint32(0, true)
|
|
244
|
-
offset += 4
|
|
245
|
-
|
|
246
|
-
if (offset + subrecordLength > normalizedData.byteLength) {
|
|
247
|
-
return []
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
subrecords.push(
|
|
251
|
-
new DataView(
|
|
252
|
-
normalizedData.buffer,
|
|
253
|
-
normalizedData.byteOffset + offset,
|
|
254
|
-
subrecordLength
|
|
255
|
-
)
|
|
256
|
-
)
|
|
257
|
-
offset += subrecordLength
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const pad = PcbBinaryPrimitiveParser.#parsePadSubrecords(subrecords)
|
|
261
|
-
|
|
262
|
-
if (!pad) {
|
|
263
|
-
return []
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
pads.push(pad)
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
return pads
|
|
65
|
+
return PcbPadPrimitiveParser.parsePadStream(headerBytes, dataBytes)
|
|
270
66
|
}
|
|
271
67
|
|
|
272
68
|
/**
|
|
273
|
-
*
|
|
69
|
+
* Decodes one variable-length PCB text stream.
|
|
274
70
|
* @param {Uint8Array | ArrayBuffer} headerBytes
|
|
275
71
|
* @param {Uint8Array | ArrayBuffer} dataBytes
|
|
276
|
-
* @param {number}
|
|
277
|
-
* @returns {
|
|
72
|
+
* @param {{ wideStrings?: Map<number | string, string> | Record<string, string> | { byIndex?: Record<string, string> } }} [options]
|
|
73
|
+
* @returns {{ text: string, x: number, y: number, height: number, layerId: number, ownerIndex: number | null, kind: number, visibilityFlags: number, rotation: number, role?: string, isDesignator?: boolean, isComment?: boolean, isPlaceholder?: boolean, componentIndex?: number }[]}
|
|
278
74
|
*/
|
|
279
|
-
static
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
if (normalizedData.byteLength < count * recordByteLength) {
|
|
288
|
-
return []
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
const views = []
|
|
292
|
-
|
|
293
|
-
for (let index = 0; index < count; index += 1) {
|
|
294
|
-
views.push(
|
|
295
|
-
new DataView(
|
|
296
|
-
normalizedData.buffer,
|
|
297
|
-
normalizedData.byteOffset + index * recordByteLength,
|
|
298
|
-
recordByteLength
|
|
299
|
-
)
|
|
300
|
-
)
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
return views
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* Decodes one pad payload from its subrecords.
|
|
308
|
-
* @param {DataView[]} subrecords
|
|
309
|
-
* @returns {{ x: number, y: number, sizeTopX: number, sizeTopY: number, sizeMidX: number, sizeMidY: number, sizeBottomX: number, sizeBottomY: number, holeDiameter: number, shapeTop: number, shapeMid: number, shapeBottom: number, rotation: number, isPlated: boolean, holeShape: number | null, holeSlotLength: number | null, holeRotation: number | null, hasRoundedRect: boolean, roundedRectShapeTop: number | null, cornerRadiusTop: number | null, offsetTopX: number, offsetTopY: number } | null}
|
|
310
|
-
*/
|
|
311
|
-
static #parsePadSubrecords(subrecords) {
|
|
312
|
-
const mainRecord =
|
|
313
|
-
subrecords[PcbBinaryPrimitiveParser.#PAD_MAIN_SUBRECORD_INDEX]
|
|
314
|
-
const extensionRecord =
|
|
315
|
-
subrecords[PcbBinaryPrimitiveParser.#PAD_EXTENSION_SUBRECORD_INDEX]
|
|
316
|
-
|
|
317
|
-
if (
|
|
318
|
-
!mainRecord ||
|
|
319
|
-
mainRecord.byteLength <
|
|
320
|
-
PcbBinaryPrimitiveParser.#PAD_MAIN_RECORD_MIN_BYTE_LENGTH
|
|
321
|
-
) {
|
|
322
|
-
return null
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
return {
|
|
326
|
-
x: PcbBinaryPrimitiveParser.#readMil(mainRecord, 13),
|
|
327
|
-
y: PcbBinaryPrimitiveParser.#readMil(mainRecord, 17),
|
|
328
|
-
sizeTopX: PcbBinaryPrimitiveParser.#readMil(mainRecord, 21),
|
|
329
|
-
sizeTopY: PcbBinaryPrimitiveParser.#readMil(mainRecord, 25),
|
|
330
|
-
sizeMidX: PcbBinaryPrimitiveParser.#readMil(mainRecord, 29),
|
|
331
|
-
sizeMidY: PcbBinaryPrimitiveParser.#readMil(mainRecord, 33),
|
|
332
|
-
sizeBottomX: PcbBinaryPrimitiveParser.#readMil(mainRecord, 37),
|
|
333
|
-
sizeBottomY: PcbBinaryPrimitiveParser.#readMil(mainRecord, 41),
|
|
334
|
-
holeDiameter: PcbBinaryPrimitiveParser.#readMil(mainRecord, 45),
|
|
335
|
-
shapeTop: mainRecord.getUint8(49),
|
|
336
|
-
shapeMid: mainRecord.getUint8(50),
|
|
337
|
-
shapeBottom: mainRecord.getUint8(51),
|
|
338
|
-
rotation: mainRecord.getFloat64(52, true),
|
|
339
|
-
isPlated: mainRecord.getUint8(60) !== 0,
|
|
340
|
-
...PcbBinaryPrimitiveParser.#parsePadExtensionBlock(extensionRecord)
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
* Decodes one optional pad extension block.
|
|
346
|
-
* @param {DataView | undefined} extensionRecord
|
|
347
|
-
* @returns {{ holeShape: number | null, holeSlotLength: number | null, holeRotation: number | null, hasRoundedRect: boolean, roundedRectShapeTop: number | null, cornerRadiusTop: number | null, offsetTopX: number, offsetTopY: number }}
|
|
348
|
-
*/
|
|
349
|
-
static #parsePadExtensionBlock(extensionRecord) {
|
|
350
|
-
if (
|
|
351
|
-
!extensionRecord ||
|
|
352
|
-
extensionRecord.byteLength <
|
|
353
|
-
PcbBinaryPrimitiveParser.#PAD_EXTENSION_MIN_BYTE_LENGTH
|
|
354
|
-
) {
|
|
355
|
-
return {
|
|
356
|
-
holeShape: null,
|
|
357
|
-
holeSlotLength: null,
|
|
358
|
-
holeRotation: null,
|
|
359
|
-
hasRoundedRect: false,
|
|
360
|
-
roundedRectShapeTop: null,
|
|
361
|
-
cornerRadiusTop: null,
|
|
362
|
-
offsetTopX: 0,
|
|
363
|
-
offsetTopY: 0
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
return {
|
|
368
|
-
holeShape: extensionRecord.getUint8(262),
|
|
369
|
-
holeSlotLength: PcbBinaryPrimitiveParser.#readMil(
|
|
370
|
-
extensionRecord,
|
|
371
|
-
263
|
|
372
|
-
),
|
|
373
|
-
holeRotation: extensionRecord.getFloat64(267, true),
|
|
374
|
-
hasRoundedRect: extensionRecord.getUint8(531) !== 0,
|
|
375
|
-
roundedRectShapeTop: extensionRecord.getUint8(532),
|
|
376
|
-
cornerRadiusTop: extensionRecord.getUint8(564),
|
|
377
|
-
offsetTopX: PcbBinaryPrimitiveParser.#readMil(extensionRecord, 275),
|
|
378
|
-
offsetTopY: PcbBinaryPrimitiveParser.#readMil(extensionRecord, 403)
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* Normalizes one byte-like input into a Uint8Array view.
|
|
384
|
-
* @param {Uint8Array | ArrayBuffer} bytes
|
|
385
|
-
* @returns {Uint8Array}
|
|
386
|
-
*/
|
|
387
|
-
static #toUint8Array(bytes) {
|
|
388
|
-
if (bytes instanceof Uint8Array) {
|
|
389
|
-
return bytes
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
return new Uint8Array(bytes)
|
|
75
|
+
static parseTextStream(headerBytes, dataBytes, options = {}) {
|
|
76
|
+
return PcbTextPrimitiveParser.parseTextStream(
|
|
77
|
+
headerBytes,
|
|
78
|
+
dataBytes,
|
|
79
|
+
options
|
|
80
|
+
)
|
|
393
81
|
}
|
|
394
82
|
|
|
395
83
|
/**
|
|
396
|
-
*
|
|
84
|
+
* Decodes one variable-length PCB region stream.
|
|
397
85
|
* @param {Uint8Array | ArrayBuffer} headerBytes
|
|
398
|
-
* @
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
const normalizedHeader =
|
|
402
|
-
PcbBinaryPrimitiveParser.#toUint8Array(headerBytes)
|
|
403
|
-
|
|
404
|
-
if (normalizedHeader.byteLength < 4) {
|
|
405
|
-
return 0
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
return new DataView(
|
|
409
|
-
normalizedHeader.buffer,
|
|
410
|
-
normalizedHeader.byteOffset,
|
|
411
|
-
normalizedHeader.byteLength
|
|
412
|
-
).getUint32(0, true)
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
/**
|
|
416
|
-
* Reads one signed fixed-point mil coordinate.
|
|
417
|
-
* @param {DataView} view
|
|
418
|
-
* @param {number} offset
|
|
419
|
-
* @returns {number}
|
|
86
|
+
* @param {Uint8Array | ArrayBuffer} dataBytes
|
|
87
|
+
* @param {{ shapeBased?: boolean }} [options]
|
|
88
|
+
* @returns {{ layerId: number, layerCode: number, netIndex: number | null, polygonIndex: number | null, componentIndex: number | null, kind: number, isKeepout: boolean, isBoardCutout: boolean, isShapeBased: boolean, points: object[], holes: object[][], properties: Record<string, string> }[]}
|
|
420
89
|
*/
|
|
421
|
-
static
|
|
422
|
-
return
|
|
90
|
+
static parseRegionStream(headerBytes, dataBytes, options = {}) {
|
|
91
|
+
return PcbRegionPrimitiveParser.parseRegionStream(
|
|
92
|
+
headerBytes,
|
|
93
|
+
dataBytes,
|
|
94
|
+
options
|
|
95
|
+
)
|
|
423
96
|
}
|
|
424
97
|
}
|