circuit-json-to-lbrn 0.0.21 → 0.0.22
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 +1 -0
- package/dist/index.js +489 -182
- package/lib/ConvertContext.ts +6 -2
- package/lib/element-handlers/addPcbTrace/index.ts +145 -61
- package/lib/element-handlers/addPcbVia/index.ts +34 -12
- package/lib/element-handlers/addPlatedHole/addCirclePlatedHole.ts +34 -12
- package/lib/element-handlers/addPlatedHole/addCircularHoleWithRectPad.ts +24 -9
- package/lib/element-handlers/addPlatedHole/addHoleWithPolygonPad.ts +24 -9
- package/lib/element-handlers/addPlatedHole/addOvalPlatedHole.ts +24 -9
- package/lib/element-handlers/addPlatedHole/addPillHoleWithRectPad.ts +24 -9
- package/lib/element-handlers/addPlatedHole/addPillPlatedHole.ts +24 -9
- package/lib/element-handlers/addPlatedHole/addRotatedPillHoleWithRectPad.ts +24 -9
- package/lib/element-handlers/addSmtPad/addCircleSmtPad.ts +21 -2
- package/lib/element-handlers/addSmtPad/addPillSmtPad.ts +21 -2
- package/lib/element-handlers/addSmtPad/addPolygonSmtPad.ts +20 -2
- package/lib/element-handlers/addSmtPad/addRectSmtPad.ts +20 -3
- package/lib/element-handlers/addSmtPad/addRotatedPillSmtPad.ts +21 -2
- package/lib/element-handlers/addSmtPad/addRotatedRectSmtPad.ts +21 -2
- package/lib/index.ts +92 -41
- package/package.json +1 -1
- package/tests/assets/keyboard-default60.json +92565 -0
- package/tests/examples/__snapshots__/board-outline-soldermask-preset.snap.svg +1 -1
- package/tests/examples/__snapshots__/board-outline.snap.svg +1 -1
- package/tests/examples/__snapshots__/lga-interconnect.snap.svg +1 -1
- package/tests/examples/__snapshots__/single-trace.snap.svg +1 -1
- package/tests/examples/addPcbCutout/__snapshots__/pcb-cutout-circle.snap.svg +1 -1
- package/tests/examples/addPcbCutout/__snapshots__/pcb-cutout-path.snap.svg +1 -1
- package/tests/examples/addPcbCutout/__snapshots__/pcb-cutout-polygon.snap.svg +1 -1
- package/tests/examples/addPcbCutout/__snapshots__/pcb-cutout-rect.snap.svg +1 -1
- package/tests/examples/addPcbHole/__snapshots__/pcb-hole-circle.snap.svg +1 -1
- package/tests/examples/addPcbHole/__snapshots__/pcb-hole-oval.snap.svg +1 -1
- package/tests/examples/addPcbHole/__snapshots__/pcb-hole-pill.snap.svg +1 -1
- package/tests/examples/addPcbHole/__snapshots__/pcb-hole-rect.snap.svg +1 -1
- package/tests/examples/addPcbHole/__snapshots__/pcb-hole-rotated-pill.snap.svg +2 -2
- package/tests/examples/addPcbHole/__snapshots__/pcb-hole-with-soldermask.snap.svg +1 -1
- package/tests/examples/addPcbVia/__snapshots__/pcb-via-basic.snap.svg +1 -1
- package/tests/examples/addPcbVia/__snapshots__/pcb-via-with-net.snap.svg +1 -1
- package/tests/examples/addPcbVia/__snapshots__/pcb-via-with-soldermask.snap.svg +1 -1
- package/tests/examples/addPlatedHole/__snapshots__/pcb-plated-hole-circle.snap.svg +1 -1
- package/tests/examples/addPlatedHole/__snapshots__/pcb-plated-hole-circular-hole-with-rect-pad.snap.svg +1 -1
- package/tests/examples/addPlatedHole/__snapshots__/pcb-plated-hole-oval.snap.svg +1 -1
- package/tests/examples/addPlatedHole/__snapshots__/pcb-plated-hole-pill-with-rect-pad.snap.svg +1 -1
- package/tests/examples/addPlatedHole/__snapshots__/pcb-plated-hole-pill.snap.svg +1 -1
- package/tests/examples/addPlatedHole/__snapshots__/pcb-plated-hole-polygon.snap.svg +1 -1
- package/tests/examples/addPlatedHole/__snapshots__/pcb-plated-hole-rotated-pill-with-rect-pad.snap.svg +1 -1
- package/tests/examples/addSmtPad/__snapshots__/circleSmtPad.snap.svg +1 -1
- package/tests/examples/addSmtPad/__snapshots__/pillSmtPad.snap.svg +1 -1
- package/tests/examples/addSmtPad/__snapshots__/polygonSmtPad.snap.svg +1 -1
- package/tests/examples/addSmtPad/__snapshots__/rotatedPillSmtPad.snap.svg +1 -1
- package/tests/examples/addSmtPad/__snapshots__/rotatedRectSmtPad.snap.svg +1 -1
- package/tests/examples/keyboard-defaul60/__snapshots__/keyboard-both-layer-includeSoldermask.snap.svg +8 -0
- package/tests/examples/keyboard-defaul60/__snapshots__/keyboard-both-layers.snap.svg +8 -0
- package/tests/examples/keyboard-defaul60/__snapshots__/keyboard-bottom-layer.snap.svg +8 -0
- package/tests/examples/keyboard-defaul60/__snapshots__/keyboard-top-layer.snap.svg +8 -0
- package/tests/examples/keyboard-defaul60/keyboard-both-layer-includeSoldermask.test.ts +27 -0
- package/tests/examples/keyboard-defaul60/keyboard-both-layers.test.ts +26 -0
- package/tests/examples/keyboard-defaul60/keyboard-bottom-layer.test.ts +26 -0
- package/tests/examples/keyboard-defaul60/keyboard-top-layer.test.ts +26 -0
- package/tests/examples/lga-interconnect.test.ts +3 -2
- package/tests/examples/soldermask/__snapshots__/copper-and-soldermask.snap.svg +1 -1
- package/tests/examples/soldermask/__snapshots__/copper-only.snap.svg +1 -1
- package/tests/examples/soldermask/__snapshots__/soldermask-only.snap.svg +1 -1
- package/tests/examples/soldermask/copper-and-soldermask.test.ts +18 -10
- package/tests/examples/soldermask/soldermask-only.test.ts +3 -3
- package/tests/examples/soldermask-margin/__snapshots__/negative-soldermask-margin.snap.svg +1 -1
- package/tests/examples/soldermask-margin/__snapshots__/positive-soldermask-margin.snap.svg +1 -1
- package/tsconfig.json +2 -1
package/lib/ConvertContext.ts
CHANGED
|
@@ -9,19 +9,23 @@ export interface ConvertContext {
|
|
|
9
9
|
db: CircuitJsonUtilObjects
|
|
10
10
|
project: LightBurnProject
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
topCopperCutSetting: CutSetting
|
|
13
|
+
bottomCopperCutSetting: CutSetting
|
|
13
14
|
throughBoardCutSetting: CutSetting
|
|
14
15
|
soldermaskCutSetting: CutSetting
|
|
15
16
|
|
|
16
17
|
connMap: ConnectivityMap
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
// Separate net geometries for top and bottom layers
|
|
20
|
+
topNetGeoms: Map<ConnectivityMapKey, Array<Polygon | Box>>
|
|
21
|
+
bottomNetGeoms: Map<ConnectivityMapKey, Array<Polygon | Box>>
|
|
19
22
|
|
|
20
23
|
origin: { x: number; y: number }
|
|
21
24
|
|
|
22
25
|
// Include flags
|
|
23
26
|
includeCopper: boolean
|
|
24
27
|
includeSoldermask: boolean
|
|
28
|
+
includeLayers: Array<"top" | "bottom">
|
|
25
29
|
|
|
26
30
|
// Soldermask margin (can be negative)
|
|
27
31
|
soldermaskMargin: number
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
import type { PcbTrace } from "circuit-json"
|
|
1
|
+
import type { PcbTrace, PcbTraceRoutePoint } from "circuit-json"
|
|
2
2
|
import type { ConvertContext } from "../../ConvertContext"
|
|
3
3
|
import Flatten, { BooleanOperations } from "@flatten-js/core"
|
|
4
4
|
import { circleToPolygon } from "./circle-to-polygon"
|
|
5
5
|
|
|
6
6
|
export const addPcbTrace = (trace: PcbTrace, ctx: ConvertContext) => {
|
|
7
|
-
const {
|
|
7
|
+
const {
|
|
8
|
+
topNetGeoms,
|
|
9
|
+
bottomNetGeoms,
|
|
10
|
+
connMap,
|
|
11
|
+
origin,
|
|
12
|
+
includeCopper,
|
|
13
|
+
includeLayers,
|
|
14
|
+
} = ctx
|
|
8
15
|
|
|
9
16
|
// Only include traces when including copper
|
|
10
17
|
// Traces are NOT included in soldermask-only mode to prevent accidental bridging
|
|
@@ -14,83 +21,160 @@ export const addPcbTrace = (trace: PcbTrace, ctx: ConvertContext) => {
|
|
|
14
21
|
|
|
15
22
|
const netId = connMap.getNetConnectedToId(
|
|
16
23
|
trace.source_trace_id ?? trace.pcb_trace_id,
|
|
17
|
-
)
|
|
24
|
+
)
|
|
18
25
|
|
|
19
26
|
if (!netId) {
|
|
20
|
-
|
|
27
|
+
// Skip traces that are not connected to any net
|
|
28
|
+
// This can happen for traces without a source_trace_id
|
|
21
29
|
return
|
|
22
30
|
}
|
|
23
31
|
|
|
24
32
|
if (!trace.route || trace.route.length < 2) {
|
|
25
|
-
console.warn(`Trace ${trace.pcb_trace_id} has insufficient route points`)
|
|
26
33
|
return
|
|
27
34
|
}
|
|
28
35
|
|
|
29
36
|
const { route } = trace
|
|
37
|
+
const wirePoint = route.find((point) => {
|
|
38
|
+
if (!("route_type" in point)) return true
|
|
39
|
+
return point.route_type === "wire"
|
|
40
|
+
})
|
|
41
|
+
const traceWidth = (wirePoint as any)?.width ?? 0.15
|
|
42
|
+
|
|
43
|
+
// Group consecutive wire segments by layer
|
|
44
|
+
// When we hit a via, we start a new segment on the new layer
|
|
45
|
+
const layerSegments = new Map<
|
|
46
|
+
"top" | "bottom",
|
|
47
|
+
Array<Array<{ x: number; y: number }>>
|
|
48
|
+
>()
|
|
49
|
+
|
|
50
|
+
let currentSegment: Array<{ x: number; y: number }> = []
|
|
51
|
+
let currentLayer: "top" | "bottom" | null = null
|
|
52
|
+
|
|
53
|
+
for (const point of route) {
|
|
54
|
+
if ("route_type" in point && point.route_type === "via") {
|
|
55
|
+
// Via marks end of current segment - save it
|
|
56
|
+
if (currentLayer && currentSegment.length > 0) {
|
|
57
|
+
if (!layerSegments.has(currentLayer)) {
|
|
58
|
+
layerSegments.set(currentLayer, [])
|
|
59
|
+
}
|
|
60
|
+
layerSegments.get(currentLayer)!.push(currentSegment)
|
|
61
|
+
}
|
|
62
|
+
// Reset for next segment
|
|
63
|
+
currentSegment = []
|
|
64
|
+
currentLayer = null
|
|
65
|
+
continue
|
|
66
|
+
}
|
|
30
67
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
68
|
+
// Treat points without route_type as wire points (default behavior)
|
|
69
|
+
const isWirePoint = !("route_type" in point) || point.route_type === "wire"
|
|
70
|
+
if (isWirePoint && "layer" in point && point.layer) {
|
|
71
|
+
const pointLayer = point.layer as "top" | "bottom" | string
|
|
72
|
+
if (pointLayer !== "top" && pointLayer !== "bottom") {
|
|
73
|
+
continue // Skip inner layers
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// If layer changed (shouldn't happen without via, but handle it)
|
|
77
|
+
if (currentLayer !== null && currentLayer !== pointLayer) {
|
|
78
|
+
// Save current segment
|
|
79
|
+
if (currentSegment.length > 0) {
|
|
80
|
+
if (!layerSegments.has(currentLayer)) {
|
|
81
|
+
layerSegments.set(currentLayer, [])
|
|
82
|
+
}
|
|
83
|
+
layerSegments.get(currentLayer)!.push(currentSegment)
|
|
84
|
+
}
|
|
85
|
+
// Start new segment
|
|
86
|
+
currentSegment = []
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
currentLayer = pointLayer
|
|
90
|
+
currentSegment.push({ x: point.x, y: point.y })
|
|
91
|
+
}
|
|
43
92
|
}
|
|
44
93
|
|
|
45
|
-
//
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const segmentLength = Math.hypot(p1.x - p2.x, p1.y - p2.y)
|
|
53
|
-
if (segmentLength === 0) continue
|
|
54
|
-
|
|
55
|
-
const centerX = (p1.x + p2.x) / 2 + origin.x
|
|
56
|
-
const centerY = (p1.y + p2.y) / 2 + origin.y
|
|
57
|
-
const rotationDeg = (Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180) / Math.PI
|
|
58
|
-
|
|
59
|
-
const w2 = segmentLength / 2
|
|
60
|
-
const h2 = traceWidth / 2
|
|
61
|
-
|
|
62
|
-
const angleRad = (rotationDeg * Math.PI) / 180
|
|
63
|
-
const cosAngle = Math.cos(angleRad)
|
|
64
|
-
const sinAngle = Math.sin(angleRad)
|
|
65
|
-
|
|
66
|
-
const corners = [
|
|
67
|
-
{ x: -w2, y: -h2 },
|
|
68
|
-
{ x: w2, y: -h2 },
|
|
69
|
-
{ x: w2, y: h2 },
|
|
70
|
-
{ x: -w2, y: h2 },
|
|
71
|
-
]
|
|
94
|
+
// Save final segment
|
|
95
|
+
if (currentLayer && currentSegment.length > 0) {
|
|
96
|
+
if (!layerSegments.has(currentLayer)) {
|
|
97
|
+
layerSegments.set(currentLayer, [])
|
|
98
|
+
}
|
|
99
|
+
layerSegments.get(currentLayer)!.push(currentSegment)
|
|
100
|
+
}
|
|
72
101
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
102
|
+
// Process each layer
|
|
103
|
+
for (const [layer, segments] of layerSegments.entries()) {
|
|
104
|
+
if (!includeLayers.includes(layer)) {
|
|
105
|
+
continue
|
|
106
|
+
}
|
|
77
107
|
|
|
78
|
-
polygons
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
108
|
+
// Combine all segments for this layer into one set of polygons
|
|
109
|
+
const polygons: Flatten.Polygon[] = []
|
|
110
|
+
|
|
111
|
+
for (const points of segments) {
|
|
112
|
+
if (points.length < 2) continue
|
|
113
|
+
|
|
114
|
+
// Add circles for each vertex in this segment
|
|
115
|
+
for (const routePoint of points) {
|
|
116
|
+
const circle = new Flatten.Circle(
|
|
117
|
+
new Flatten.Point(routePoint.x + origin.x, routePoint.y + origin.y),
|
|
118
|
+
traceWidth / 2,
|
|
119
|
+
)
|
|
120
|
+
polygons.push(circleToPolygon(circle))
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Add rectangles for each line segment
|
|
124
|
+
for (let i = 0; i < points.length - 1; i++) {
|
|
125
|
+
const p1 = points[i]
|
|
126
|
+
const p2 = points[i + 1]
|
|
127
|
+
|
|
128
|
+
if (!p1 || !p2) continue
|
|
129
|
+
|
|
130
|
+
const segmentLength = Math.hypot(p1.x - p2.x, p1.y - p2.y)
|
|
131
|
+
if (segmentLength === 0) continue
|
|
132
|
+
|
|
133
|
+
const centerX = (p1.x + p2.x) / 2 + origin.x
|
|
134
|
+
const centerY = (p1.y + p2.y) / 2 + origin.y
|
|
135
|
+
const rotationDeg =
|
|
136
|
+
(Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180) / Math.PI
|
|
137
|
+
|
|
138
|
+
const w2 = segmentLength / 2
|
|
139
|
+
const h2 = traceWidth / 2
|
|
140
|
+
|
|
141
|
+
const angleRad = (rotationDeg * Math.PI) / 180
|
|
142
|
+
const cosAngle = Math.cos(angleRad)
|
|
143
|
+
const sinAngle = Math.sin(angleRad)
|
|
144
|
+
|
|
145
|
+
const corners = [
|
|
146
|
+
{ x: -w2, y: -h2 },
|
|
147
|
+
{ x: w2, y: -h2 },
|
|
148
|
+
{ x: w2, y: h2 },
|
|
149
|
+
{ x: -w2, y: h2 },
|
|
150
|
+
]
|
|
151
|
+
|
|
152
|
+
const rotatedCorners = corners.map((p) => ({
|
|
153
|
+
x: centerX + p.x * cosAngle - p.y * sinAngle,
|
|
154
|
+
y: centerY + p.x * sinAngle + p.y * cosAngle,
|
|
155
|
+
}))
|
|
156
|
+
|
|
157
|
+
polygons.push(
|
|
158
|
+
new Flatten.Polygon(
|
|
159
|
+
rotatedCorners.map((p) => Flatten.point(p.x, p.y)),
|
|
160
|
+
),
|
|
161
|
+
)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
82
164
|
|
|
83
|
-
|
|
84
|
-
|
|
165
|
+
// Union all polygons together to create the final trace polygon for this layer
|
|
166
|
+
if (polygons.length === 0) continue
|
|
85
167
|
|
|
86
|
-
|
|
168
|
+
let tracePolygon = polygons[0]!
|
|
87
169
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
170
|
+
for (let i = 1; i < polygons.length; i++) {
|
|
171
|
+
const poly = polygons[i]
|
|
172
|
+
if (poly) {
|
|
173
|
+
tracePolygon = BooleanOperations.unify(tracePolygon, poly)
|
|
174
|
+
}
|
|
92
175
|
}
|
|
93
|
-
}
|
|
94
176
|
|
|
95
|
-
|
|
177
|
+
const netGeoms = layer === "top" ? topNetGeoms : bottomNetGeoms
|
|
178
|
+
netGeoms.get(netId)?.push(tracePolygon)
|
|
179
|
+
}
|
|
96
180
|
}
|
|
@@ -9,19 +9,24 @@ export const addPcbVia = (via: PcbVia, ctx: ConvertContext): void => {
|
|
|
9
9
|
const {
|
|
10
10
|
db,
|
|
11
11
|
project,
|
|
12
|
-
|
|
12
|
+
topCopperCutSetting,
|
|
13
|
+
bottomCopperCutSetting,
|
|
13
14
|
soldermaskCutSetting,
|
|
14
15
|
throughBoardCutSetting,
|
|
16
|
+
topNetGeoms,
|
|
17
|
+
bottomNetGeoms,
|
|
15
18
|
origin,
|
|
16
19
|
includeCopper,
|
|
17
20
|
includeSoldermask,
|
|
18
21
|
connMap,
|
|
19
22
|
soldermaskMargin,
|
|
23
|
+
includeLayers,
|
|
20
24
|
} = ctx
|
|
21
25
|
const centerX = via.x + origin.x
|
|
22
26
|
const centerY = via.y + origin.y
|
|
23
27
|
|
|
24
28
|
// Add outer circle (copper annulus) if drawing copper - add to netGeoms for merging
|
|
29
|
+
// Vias go through all layers, so add to both top and bottom
|
|
25
30
|
if (via.outer_diameter > 0 && includeCopper) {
|
|
26
31
|
// Find the pcb_port associated with this via (vias don't have pcb_port_id property)
|
|
27
32
|
// We need to find a port at the same location as the via
|
|
@@ -38,23 +43,40 @@ export const addPcbVia = (via: PcbVia, ctx: ConvertContext): void => {
|
|
|
38
43
|
const polygon = circleToPolygon(circle)
|
|
39
44
|
|
|
40
45
|
if (netId) {
|
|
41
|
-
// Add to
|
|
42
|
-
|
|
46
|
+
// Add to both top and bottom netGeoms since vias go through the board
|
|
47
|
+
if (includeLayers.includes("top")) {
|
|
48
|
+
topNetGeoms.get(netId)?.push(polygon.clone())
|
|
49
|
+
}
|
|
50
|
+
if (includeLayers.includes("bottom")) {
|
|
51
|
+
bottomNetGeoms.get(netId)?.push(polygon.clone())
|
|
52
|
+
}
|
|
43
53
|
} else {
|
|
44
|
-
// No net connection - draw directly
|
|
54
|
+
// No net connection - draw directly for each included layer
|
|
45
55
|
const outer = createCirclePath({
|
|
46
56
|
centerX,
|
|
47
57
|
centerY,
|
|
48
58
|
radius: outerRadius,
|
|
49
59
|
})
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
60
|
+
if (includeLayers.includes("top")) {
|
|
61
|
+
project.children.push(
|
|
62
|
+
new ShapePath({
|
|
63
|
+
cutIndex: topCopperCutSetting.index,
|
|
64
|
+
verts: outer.verts,
|
|
65
|
+
prims: outer.prims,
|
|
66
|
+
isClosed: true,
|
|
67
|
+
}),
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
if (includeLayers.includes("bottom")) {
|
|
71
|
+
project.children.push(
|
|
72
|
+
new ShapePath({
|
|
73
|
+
cutIndex: bottomCopperCutSetting.index,
|
|
74
|
+
verts: outer.verts,
|
|
75
|
+
prims: outer.prims,
|
|
76
|
+
isClosed: true,
|
|
77
|
+
}),
|
|
78
|
+
)
|
|
79
|
+
}
|
|
58
80
|
}
|
|
59
81
|
}
|
|
60
82
|
|
|
@@ -11,19 +11,24 @@ export const addCirclePlatedHole = (
|
|
|
11
11
|
): void => {
|
|
12
12
|
const {
|
|
13
13
|
project,
|
|
14
|
-
|
|
14
|
+
topCopperCutSetting,
|
|
15
|
+
bottomCopperCutSetting,
|
|
15
16
|
soldermaskCutSetting,
|
|
16
17
|
throughBoardCutSetting,
|
|
18
|
+
topNetGeoms,
|
|
19
|
+
bottomNetGeoms,
|
|
17
20
|
origin,
|
|
18
21
|
includeCopper,
|
|
19
22
|
includeSoldermask,
|
|
20
23
|
connMap,
|
|
21
24
|
soldermaskMargin,
|
|
25
|
+
includeLayers,
|
|
22
26
|
} = ctx
|
|
23
27
|
const centerX = platedHole.x + origin.x
|
|
24
28
|
const centerY = platedHole.y + origin.y
|
|
25
29
|
|
|
26
30
|
// Add outer circle (copper annulus) if drawing copper - add to netGeoms for merging
|
|
31
|
+
// Plated holes go through all layers, so add to both top and bottom
|
|
27
32
|
if (platedHole.outer_diameter > 0 && includeCopper) {
|
|
28
33
|
const netId = connMap.getNetConnectedToId(platedHole.pcb_plated_hole_id)
|
|
29
34
|
const outerRadius = platedHole.outer_diameter / 2
|
|
@@ -31,23 +36,40 @@ export const addCirclePlatedHole = (
|
|
|
31
36
|
const polygon = circleToPolygon(circle)
|
|
32
37
|
|
|
33
38
|
if (netId) {
|
|
34
|
-
// Add to
|
|
35
|
-
|
|
39
|
+
// Add to both top and bottom netGeoms since plated holes go through the board
|
|
40
|
+
if (includeLayers.includes("top")) {
|
|
41
|
+
topNetGeoms.get(netId)?.push(polygon.clone())
|
|
42
|
+
}
|
|
43
|
+
if (includeLayers.includes("bottom")) {
|
|
44
|
+
bottomNetGeoms.get(netId)?.push(polygon.clone())
|
|
45
|
+
}
|
|
36
46
|
} else {
|
|
37
|
-
// No net connection - draw directly
|
|
47
|
+
// No net connection - draw directly for each included layer
|
|
38
48
|
const outer = createCirclePath({
|
|
39
49
|
centerX,
|
|
40
50
|
centerY,
|
|
41
51
|
radius: outerRadius,
|
|
42
52
|
})
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
if (includeLayers.includes("top")) {
|
|
54
|
+
project.children.push(
|
|
55
|
+
new ShapePath({
|
|
56
|
+
cutIndex: topCopperCutSetting.index,
|
|
57
|
+
verts: outer.verts,
|
|
58
|
+
prims: outer.prims,
|
|
59
|
+
isClosed: true,
|
|
60
|
+
}),
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
if (includeLayers.includes("bottom")) {
|
|
64
|
+
project.children.push(
|
|
65
|
+
new ShapePath({
|
|
66
|
+
cutIndex: bottomCopperCutSetting.index,
|
|
67
|
+
verts: outer.verts,
|
|
68
|
+
prims: outer.prims,
|
|
69
|
+
isClosed: true,
|
|
70
|
+
}),
|
|
71
|
+
)
|
|
72
|
+
}
|
|
51
73
|
}
|
|
52
74
|
}
|
|
53
75
|
|
|
@@ -10,13 +10,15 @@ export const addCircularHoleWithRectPad = (
|
|
|
10
10
|
): void => {
|
|
11
11
|
const {
|
|
12
12
|
project,
|
|
13
|
-
|
|
13
|
+
topCopperCutSetting,
|
|
14
|
+
bottomCopperCutSetting,
|
|
14
15
|
soldermaskCutSetting,
|
|
15
16
|
throughBoardCutSetting,
|
|
16
17
|
origin,
|
|
17
18
|
includeCopper,
|
|
18
19
|
includeSoldermask,
|
|
19
20
|
soldermaskMargin,
|
|
21
|
+
includeLayers,
|
|
20
22
|
} = ctx
|
|
21
23
|
const centerX = platedHole.x + origin.x
|
|
22
24
|
const centerY = platedHole.y + origin.y
|
|
@@ -35,15 +37,28 @@ export const addCircularHoleWithRectPad = (
|
|
|
35
37
|
})
|
|
36
38
|
|
|
37
39
|
// Add the rectangular pad if drawing copper
|
|
40
|
+
// Plated holes go through all layers, so add to both top and bottom
|
|
38
41
|
if (includeCopper) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
if (includeLayers.includes("top")) {
|
|
43
|
+
project.children.push(
|
|
44
|
+
new ShapePath({
|
|
45
|
+
cutIndex: topCopperCutSetting.index,
|
|
46
|
+
verts: padPath.verts,
|
|
47
|
+
prims: padPath.prims,
|
|
48
|
+
isClosed: true,
|
|
49
|
+
}),
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
if (includeLayers.includes("bottom")) {
|
|
53
|
+
project.children.push(
|
|
54
|
+
new ShapePath({
|
|
55
|
+
cutIndex: bottomCopperCutSetting.index,
|
|
56
|
+
verts: padPath.verts,
|
|
57
|
+
prims: padPath.prims,
|
|
58
|
+
isClosed: true,
|
|
59
|
+
}),
|
|
60
|
+
)
|
|
61
|
+
}
|
|
47
62
|
}
|
|
48
63
|
|
|
49
64
|
// Add soldermask opening if drawing soldermask
|
|
@@ -10,13 +10,15 @@ export const addHoleWithPolygonPad = (
|
|
|
10
10
|
): void => {
|
|
11
11
|
const {
|
|
12
12
|
project,
|
|
13
|
-
|
|
13
|
+
topCopperCutSetting,
|
|
14
|
+
bottomCopperCutSetting,
|
|
14
15
|
soldermaskCutSetting,
|
|
15
16
|
throughBoardCutSetting,
|
|
16
17
|
origin,
|
|
17
18
|
includeCopper,
|
|
18
19
|
includeSoldermask,
|
|
19
20
|
soldermaskMargin,
|
|
21
|
+
includeLayers,
|
|
20
22
|
} = ctx
|
|
21
23
|
|
|
22
24
|
// Create the polygon pad
|
|
@@ -28,15 +30,28 @@ export const addHoleWithPolygonPad = (
|
|
|
28
30
|
})
|
|
29
31
|
|
|
30
32
|
// Add the polygon pad if drawing copper
|
|
33
|
+
// Plated holes go through all layers, so add to both top and bottom
|
|
31
34
|
if (includeCopper) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
if (includeLayers.includes("top")) {
|
|
36
|
+
project.children.push(
|
|
37
|
+
new ShapePath({
|
|
38
|
+
cutIndex: topCopperCutSetting.index,
|
|
39
|
+
verts: pad.verts,
|
|
40
|
+
prims: pad.prims,
|
|
41
|
+
isClosed: true,
|
|
42
|
+
}),
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
if (includeLayers.includes("bottom")) {
|
|
46
|
+
project.children.push(
|
|
47
|
+
new ShapePath({
|
|
48
|
+
cutIndex: bottomCopperCutSetting.index,
|
|
49
|
+
verts: pad.verts,
|
|
50
|
+
prims: pad.prims,
|
|
51
|
+
isClosed: true,
|
|
52
|
+
}),
|
|
53
|
+
)
|
|
54
|
+
}
|
|
40
55
|
}
|
|
41
56
|
|
|
42
57
|
// Add soldermask opening if drawing soldermask
|
|
@@ -9,13 +9,15 @@ export const addOvalPlatedHole = (
|
|
|
9
9
|
): void => {
|
|
10
10
|
const {
|
|
11
11
|
project,
|
|
12
|
-
|
|
12
|
+
topCopperCutSetting,
|
|
13
|
+
bottomCopperCutSetting,
|
|
13
14
|
soldermaskCutSetting,
|
|
14
15
|
throughBoardCutSetting,
|
|
15
16
|
origin,
|
|
16
17
|
includeCopper,
|
|
17
18
|
includeSoldermask,
|
|
18
19
|
soldermaskMargin,
|
|
20
|
+
includeLayers,
|
|
19
21
|
} = ctx
|
|
20
22
|
|
|
21
23
|
if (platedHole.outer_width <= 0 || platedHole.outer_height <= 0) {
|
|
@@ -27,6 +29,7 @@ export const addOvalPlatedHole = (
|
|
|
27
29
|
const rotation = (platedHole.ccw_rotation ?? 0) * (Math.PI / 180)
|
|
28
30
|
|
|
29
31
|
// Add outer oval (copper) if drawing copper
|
|
32
|
+
// Plated holes go through all layers, so add to both top and bottom
|
|
30
33
|
if (
|
|
31
34
|
platedHole.outer_width > 0 &&
|
|
32
35
|
platedHole.outer_height > 0 &&
|
|
@@ -39,14 +42,26 @@ export const addOvalPlatedHole = (
|
|
|
39
42
|
height: platedHole.outer_height,
|
|
40
43
|
rotation,
|
|
41
44
|
})
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
if (includeLayers.includes("top")) {
|
|
46
|
+
project.children.push(
|
|
47
|
+
new ShapePath({
|
|
48
|
+
cutIndex: topCopperCutSetting.index,
|
|
49
|
+
verts: outer.verts,
|
|
50
|
+
prims: outer.prims,
|
|
51
|
+
isClosed: true,
|
|
52
|
+
}),
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
if (includeLayers.includes("bottom")) {
|
|
56
|
+
project.children.push(
|
|
57
|
+
new ShapePath({
|
|
58
|
+
cutIndex: bottomCopperCutSetting.index,
|
|
59
|
+
verts: outer.verts,
|
|
60
|
+
prims: outer.prims,
|
|
61
|
+
isClosed: true,
|
|
62
|
+
}),
|
|
63
|
+
)
|
|
64
|
+
}
|
|
50
65
|
}
|
|
51
66
|
|
|
52
67
|
// Add soldermask opening if drawing soldermask
|
|
@@ -10,13 +10,15 @@ export const addPillHoleWithRectPad = (
|
|
|
10
10
|
): void => {
|
|
11
11
|
const {
|
|
12
12
|
project,
|
|
13
|
-
|
|
13
|
+
topCopperCutSetting,
|
|
14
|
+
bottomCopperCutSetting,
|
|
14
15
|
soldermaskCutSetting,
|
|
15
16
|
throughBoardCutSetting,
|
|
16
17
|
origin,
|
|
17
18
|
includeCopper,
|
|
18
19
|
includeSoldermask,
|
|
19
20
|
soldermaskMargin,
|
|
21
|
+
includeLayers,
|
|
20
22
|
} = ctx
|
|
21
23
|
const centerX = platedHole.x + origin.x
|
|
22
24
|
const centerY = platedHole.y + origin.y
|
|
@@ -35,15 +37,28 @@ export const addPillHoleWithRectPad = (
|
|
|
35
37
|
})
|
|
36
38
|
|
|
37
39
|
// Add the rectangular pad if drawing copper
|
|
40
|
+
// Plated holes go through all layers, so add to both top and bottom
|
|
38
41
|
if (includeCopper) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
if (includeLayers.includes("top")) {
|
|
43
|
+
project.children.push(
|
|
44
|
+
new ShapePath({
|
|
45
|
+
cutIndex: topCopperCutSetting.index,
|
|
46
|
+
verts: padPath.verts,
|
|
47
|
+
prims: padPath.prims,
|
|
48
|
+
isClosed: true,
|
|
49
|
+
}),
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
if (includeLayers.includes("bottom")) {
|
|
53
|
+
project.children.push(
|
|
54
|
+
new ShapePath({
|
|
55
|
+
cutIndex: bottomCopperCutSetting.index,
|
|
56
|
+
verts: padPath.verts,
|
|
57
|
+
prims: padPath.prims,
|
|
58
|
+
isClosed: true,
|
|
59
|
+
}),
|
|
60
|
+
)
|
|
61
|
+
}
|
|
47
62
|
}
|
|
48
63
|
|
|
49
64
|
// Add soldermask opening if drawing soldermask
|