pcb-scene3d-viewer 1.1.48 → 1.1.49
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/package.json +2 -1
- package/src/PcbScene3dCopperDetailGroupBuilder.mjs +16 -0
- package/src/PcbScene3dCopperFactory.mjs +64 -93
- package/src/PcbScene3dCopperFillAreaClipper.mjs +726 -0
- package/src/PcbScene3dCopperFillMeshBuilder.mjs +530 -8
- package/src/PcbScene3dCopperFillPolygonBoolean.mjs +235 -0
- package/src/PcbScene3dCopperPrismBuilder.mjs +92 -0
- package/src/PcbScene3dMaskCoveredCopperSideGroupBuilder.mjs +2 -1
- package/src/PcbScene3dMaskCoveredCopperSurfaceFilter.mjs +64 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pcb-scene3d-viewer",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.49",
|
|
4
4
|
"description": "Reusable Three.js PCB 3D scene viewer for normalized ECAD and CircuitJSON scene descriptions",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pcb",
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"circuitjson-toolkit": "^1.0.10",
|
|
56
56
|
"earcut": "^3.0.2",
|
|
57
57
|
"fflate": "^0.8.2",
|
|
58
|
+
"polygon-clipping": "^0.15.7",
|
|
58
59
|
"three": "^0.183.2"
|
|
59
60
|
},
|
|
60
61
|
"devDependencies": {
|
|
@@ -96,6 +96,10 @@ export class PcbScene3dCopperDetailGroupBuilder {
|
|
|
96
96
|
),
|
|
97
97
|
drillCutouts,
|
|
98
98
|
drillDetail: sceneDescription?.detail,
|
|
99
|
+
unionCoveredLayerPrimitives:
|
|
100
|
+
PcbScene3dCopperDetailGroupBuilder.#usesGerberLayerUnion(
|
|
101
|
+
sceneDescription
|
|
102
|
+
),
|
|
99
103
|
occlusionCutouts:
|
|
100
104
|
PcbScene3dCopperDetailGroupBuilder.#resolveCoveredCopperOcclusions(
|
|
101
105
|
sceneDescription?.detail
|
|
@@ -136,6 +140,18 @@ export class PcbScene3dCopperDetailGroupBuilder {
|
|
|
136
140
|
)
|
|
137
141
|
}
|
|
138
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Checks whether the source format represents copper as Gerber polarity union.
|
|
145
|
+
* @param {object | undefined} sceneDescription Scene description.
|
|
146
|
+
* @returns {boolean}
|
|
147
|
+
*/
|
|
148
|
+
static #usesGerberLayerUnion(sceneDescription) {
|
|
149
|
+
return (
|
|
150
|
+
String(sceneDescription?.sourceFormat || '').toLowerCase() ===
|
|
151
|
+
'gerber'
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
|
|
139
155
|
/**
|
|
140
156
|
* Builds exposed copper detail.
|
|
141
157
|
* @param {any} THREE Three.js namespace.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PcbScene3dArcUtils } from './PcbScene3dArcUtils.mjs'
|
|
2
|
+
import { PcbScene3dCopperPrismBuilder } from './PcbScene3dCopperPrismBuilder.mjs'
|
|
2
3
|
import { PcbScene3dPadFactory } from './PcbScene3dPadFactory.mjs'
|
|
3
4
|
import { PcbScene3dCopperTextFactory } from './PcbScene3dCopperTextFactory.mjs'
|
|
4
5
|
import { PcbScene3dMaskCoveredCopperMaterial } from './PcbScene3dMaskCoveredCopperMaterial.mjs'
|
|
@@ -7,6 +8,7 @@ import { PcbScene3dCopperLayerFilter } from './PcbScene3dCopperLayerFilter.mjs'
|
|
|
7
8
|
import { PcbScene3dCopperFillMeshBuilder } from './PcbScene3dCopperFillMeshBuilder.mjs'
|
|
8
9
|
import { PcbScene3dMaskCoveredCopperSideGroupBuilder } from './PcbScene3dMaskCoveredCopperSideGroupBuilder.mjs'
|
|
9
10
|
import { PcbScene3dCopperDrillCutoutBuilder } from './PcbScene3dCopperDrillCutoutBuilder.mjs'
|
|
11
|
+
import { PcbScene3dCopperFillAreaClipper } from './PcbScene3dCopperFillAreaClipper.mjs'
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
14
|
* Builds copper-detail meshes for the interactive 3D PCB scene.
|
|
@@ -15,7 +17,6 @@ export class PcbScene3dCopperFactory {
|
|
|
15
17
|
static #ARC_SEGMENT_DEGREES = 3
|
|
16
18
|
static #FULL_CIRCLE_EPSILON = 0.001
|
|
17
19
|
static #ROUND_CAP_SEGMENTS = 16
|
|
18
|
-
static #COPPER_THICKNESS_MIL = 2.2
|
|
19
20
|
static #COPPER_COLOR = 0xd9a61d
|
|
20
21
|
|
|
21
22
|
/**
|
|
@@ -23,7 +24,7 @@ export class PcbScene3dCopperFactory {
|
|
|
23
24
|
* @returns {number}
|
|
24
25
|
*/
|
|
25
26
|
static visualHalfThicknessMil() {
|
|
26
|
-
return
|
|
27
|
+
return PcbScene3dCopperPrismBuilder.halfThicknessMil()
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
/**
|
|
@@ -101,7 +102,7 @@ export class PcbScene3dCopperFactory {
|
|
|
101
102
|
* @param {number} topZ
|
|
102
103
|
* @param {number} bottomZ
|
|
103
104
|
* @param {(x: number, y: number) => { x: number, y: number }} normalizeBoardPoint
|
|
104
|
-
* @param {{ solderMaskColor?: number, occlusionCutouts?: object, drillCutouts?: any[], drillDetail?: object }} [options]
|
|
105
|
+
* @param {{ solderMaskColor?: number, occlusionCutouts?: object, drillCutouts?: any[], drillDetail?: object, unionCoveredLayerPrimitives?: boolean }} [options]
|
|
105
106
|
* @returns {any}
|
|
106
107
|
*/
|
|
107
108
|
static buildMaskCoveredGroup(
|
|
@@ -149,7 +150,8 @@ export class PcbScene3dCopperFactory {
|
|
|
149
150
|
normalizeBoardPoint,
|
|
150
151
|
false,
|
|
151
152
|
material,
|
|
152
|
-
topCutouts
|
|
153
|
+
topCutouts,
|
|
154
|
+
options
|
|
153
155
|
)
|
|
154
156
|
const bottomGroup = PcbScene3dCopperFactory.#buildMaskCoveredSideGroup(
|
|
155
157
|
THREE,
|
|
@@ -168,7 +170,8 @@ export class PcbScene3dCopperFactory {
|
|
|
168
170
|
normalizeBoardPoint,
|
|
169
171
|
true,
|
|
170
172
|
material,
|
|
171
|
-
bottomCutouts
|
|
173
|
+
bottomCutouts,
|
|
174
|
+
options
|
|
172
175
|
)
|
|
173
176
|
|
|
174
177
|
if (topGroup.children.length) group.add(topGroup)
|
|
@@ -221,7 +224,7 @@ export class PcbScene3dCopperFactory {
|
|
|
221
224
|
THREE,
|
|
222
225
|
detail?.fills || [],
|
|
223
226
|
z,
|
|
224
|
-
|
|
227
|
+
PcbScene3dCopperPrismBuilder.thicknessMil(),
|
|
225
228
|
normalizeBoardPoint,
|
|
226
229
|
mirrorY,
|
|
227
230
|
PcbScene3dCopperFactory.#buildMaterial(THREE),
|
|
@@ -268,6 +271,7 @@ export class PcbScene3dCopperFactory {
|
|
|
268
271
|
* @param {boolean} mirrorY
|
|
269
272
|
* @param {any} material Shared covered-trace material.
|
|
270
273
|
* @param {{ x: number, y: number }[][]} occlusionCutouts Silkscreen ink polygons covering this copper.
|
|
274
|
+
* @param {{ unionCoveredLayerPrimitives?: boolean }} [options] Build options.
|
|
271
275
|
* @returns {any}
|
|
272
276
|
*/
|
|
273
277
|
static #buildMaskCoveredSideGroup(
|
|
@@ -277,9 +281,10 @@ export class PcbScene3dCopperFactory {
|
|
|
277
281
|
normalizeBoardPoint,
|
|
278
282
|
mirrorY,
|
|
279
283
|
material,
|
|
280
|
-
occlusionCutouts
|
|
284
|
+
occlusionCutouts,
|
|
285
|
+
options = {}
|
|
281
286
|
) {
|
|
282
|
-
|
|
287
|
+
let trackMesh = PcbScene3dCopperFactory.#buildTrackMesh(
|
|
283
288
|
THREE,
|
|
284
289
|
detail?.tracks || [],
|
|
285
290
|
z,
|
|
@@ -288,7 +293,7 @@ export class PcbScene3dCopperFactory {
|
|
|
288
293
|
material,
|
|
289
294
|
occlusionCutouts
|
|
290
295
|
)
|
|
291
|
-
|
|
296
|
+
let arcMesh = PcbScene3dCopperFactory.#buildArcMesh(
|
|
292
297
|
THREE,
|
|
293
298
|
detail?.arcs || [],
|
|
294
299
|
z,
|
|
@@ -297,15 +302,42 @@ export class PcbScene3dCopperFactory {
|
|
|
297
302
|
material,
|
|
298
303
|
occlusionCutouts
|
|
299
304
|
)
|
|
305
|
+
if (
|
|
306
|
+
PcbScene3dCopperFactory.#shouldUnionCoveredLayerPrimitives(options)
|
|
307
|
+
) {
|
|
308
|
+
trackMesh = PcbScene3dCopperFillAreaClipper.filter(
|
|
309
|
+
THREE,
|
|
310
|
+
trackMesh,
|
|
311
|
+
detail?.fills || [],
|
|
312
|
+
normalizeBoardPoint,
|
|
313
|
+
mirrorY,
|
|
314
|
+
{ subdividePartialTriangles: false }
|
|
315
|
+
)
|
|
316
|
+
arcMesh = PcbScene3dCopperFillAreaClipper.filter(
|
|
317
|
+
THREE,
|
|
318
|
+
arcMesh,
|
|
319
|
+
detail?.fills || [],
|
|
320
|
+
normalizeBoardPoint,
|
|
321
|
+
mirrorY,
|
|
322
|
+
{ subdividePartialTriangles: false }
|
|
323
|
+
)
|
|
324
|
+
}
|
|
300
325
|
const fillMesh = PcbScene3dCopperFillMeshBuilder.build(
|
|
301
326
|
THREE,
|
|
302
327
|
detail?.fills || [],
|
|
303
328
|
z,
|
|
304
|
-
|
|
329
|
+
PcbScene3dCopperPrismBuilder.thicknessMil(),
|
|
305
330
|
normalizeBoardPoint,
|
|
306
331
|
mirrorY,
|
|
307
332
|
material,
|
|
308
|
-
occlusionCutouts
|
|
333
|
+
occlusionCutouts,
|
|
334
|
+
{
|
|
335
|
+
surfaceOnly: true,
|
|
336
|
+
clipContainedFillOverlaps:
|
|
337
|
+
PcbScene3dCopperFactory.#shouldUnionCoveredLayerPrimitives(
|
|
338
|
+
options
|
|
339
|
+
)
|
|
340
|
+
}
|
|
309
341
|
)
|
|
310
342
|
return PcbScene3dMaskCoveredCopperSideGroupBuilder.build(THREE, {
|
|
311
343
|
trackMesh,
|
|
@@ -325,6 +357,15 @@ export class PcbScene3dCopperFactory {
|
|
|
325
357
|
return String(options?.coordinateSystem || '') === 'kicad-3d-y-up'
|
|
326
358
|
}
|
|
327
359
|
|
|
360
|
+
/**
|
|
361
|
+
* Checks whether covered primitives should render as one layer union.
|
|
362
|
+
* @param {{ unionCoveredLayerPrimitives?: boolean } | undefined} options Build options.
|
|
363
|
+
* @returns {boolean}
|
|
364
|
+
*/
|
|
365
|
+
static #shouldUnionCoveredLayerPrimitives(options) {
|
|
366
|
+
return options?.unionCoveredLayerPrimitives === true
|
|
367
|
+
}
|
|
368
|
+
|
|
328
369
|
/**
|
|
329
370
|
* Builds one widened copper-track mesh for one face.
|
|
330
371
|
* @param {any} THREE
|
|
@@ -524,13 +565,13 @@ export class PcbScene3dCopperFactory {
|
|
|
524
565
|
{ x: start.x - normalX, y: start.y - normalY },
|
|
525
566
|
z
|
|
526
567
|
)
|
|
527
|
-
|
|
568
|
+
PcbScene3dCopperPrismBuilder.appendBoundarySideTriangles(
|
|
528
569
|
positions,
|
|
529
570
|
{ x: start.x + normalX, y: start.y + normalY },
|
|
530
571
|
{ x: end.x + normalX, y: end.y + normalY },
|
|
531
572
|
z
|
|
532
573
|
)
|
|
533
|
-
|
|
574
|
+
PcbScene3dCopperPrismBuilder.appendBoundarySideTriangles(
|
|
534
575
|
positions,
|
|
535
576
|
{ x: end.x - normalX, y: end.y - normalY },
|
|
536
577
|
{ x: start.x - normalX, y: start.y - normalY },
|
|
@@ -608,14 +649,14 @@ export class PcbScene3dCopperFactory {
|
|
|
608
649
|
}
|
|
609
650
|
|
|
610
651
|
if (innerRadius <= 0.001) {
|
|
611
|
-
|
|
652
|
+
PcbScene3dCopperPrismBuilder.appendTriangle(
|
|
612
653
|
positions,
|
|
613
654
|
{ x: center.x, y: center.y },
|
|
614
655
|
outerStart,
|
|
615
656
|
outerEnd,
|
|
616
657
|
z
|
|
617
658
|
)
|
|
618
|
-
|
|
659
|
+
PcbScene3dCopperPrismBuilder.appendBoundarySideTriangles(
|
|
619
660
|
positions,
|
|
620
661
|
outerStart,
|
|
621
662
|
outerEnd,
|
|
@@ -641,13 +682,13 @@ export class PcbScene3dCopperFactory {
|
|
|
641
682
|
innerStart,
|
|
642
683
|
z
|
|
643
684
|
)
|
|
644
|
-
|
|
685
|
+
PcbScene3dCopperPrismBuilder.appendBoundarySideTriangles(
|
|
645
686
|
positions,
|
|
646
687
|
outerStart,
|
|
647
688
|
outerEnd,
|
|
648
689
|
z
|
|
649
690
|
)
|
|
650
|
-
|
|
691
|
+
PcbScene3dCopperPrismBuilder.appendBoundarySideTriangles(
|
|
651
692
|
positions,
|
|
652
693
|
innerEnd,
|
|
653
694
|
innerStart,
|
|
@@ -710,8 +751,8 @@ export class PcbScene3dCopperFactory {
|
|
|
710
751
|
* @returns {void}
|
|
711
752
|
*/
|
|
712
753
|
static #appendQuadTriangles(positions, a, b, c, d, z) {
|
|
713
|
-
|
|
714
|
-
|
|
754
|
+
PcbScene3dCopperPrismBuilder.appendTriangle(positions, a, b, c, z)
|
|
755
|
+
PcbScene3dCopperPrismBuilder.appendTriangle(positions, a, c, d, z)
|
|
715
756
|
}
|
|
716
757
|
|
|
717
758
|
/**
|
|
@@ -738,7 +779,7 @@ export class PcbScene3dCopperFactory {
|
|
|
738
779
|
(Math.PI * 2 * (index + 1)) /
|
|
739
780
|
PcbScene3dCopperFactory.#ROUND_CAP_SEGMENTS
|
|
740
781
|
|
|
741
|
-
|
|
782
|
+
PcbScene3dCopperPrismBuilder.appendTriangle(
|
|
742
783
|
positions,
|
|
743
784
|
center,
|
|
744
785
|
{
|
|
@@ -751,7 +792,7 @@ export class PcbScene3dCopperFactory {
|
|
|
751
792
|
},
|
|
752
793
|
z
|
|
753
794
|
)
|
|
754
|
-
|
|
795
|
+
PcbScene3dCopperPrismBuilder.appendBoundarySideTriangles(
|
|
755
796
|
positions,
|
|
756
797
|
{
|
|
757
798
|
x: center.x + Math.cos(startAngle) * safeRadius,
|
|
@@ -835,7 +876,7 @@ export class PcbScene3dCopperFactory {
|
|
|
835
876
|
endAngle
|
|
836
877
|
)
|
|
837
878
|
|
|
838
|
-
|
|
879
|
+
PcbScene3dCopperPrismBuilder.appendTriangle(
|
|
839
880
|
positions,
|
|
840
881
|
center,
|
|
841
882
|
start,
|
|
@@ -843,7 +884,7 @@ export class PcbScene3dCopperFactory {
|
|
|
843
884
|
z
|
|
844
885
|
)
|
|
845
886
|
if (includeSideWall) {
|
|
846
|
-
|
|
887
|
+
PcbScene3dCopperPrismBuilder.appendBoundarySideTriangles(
|
|
847
888
|
positions,
|
|
848
889
|
start,
|
|
849
890
|
end,
|
|
@@ -917,74 +958,4 @@ export class PcbScene3dCopperFactory {
|
|
|
917
958
|
y: mirrorY ? -point.y : point.y
|
|
918
959
|
}
|
|
919
960
|
}
|
|
920
|
-
|
|
921
|
-
/**
|
|
922
|
-
* Appends one shallow triangular prism into the position buffer.
|
|
923
|
-
* @param {number[]} positions Position buffer.
|
|
924
|
-
* @param {{ x: number, y: number }} a First point.
|
|
925
|
-
* @param {{ x: number, y: number }} b Second point.
|
|
926
|
-
* @param {{ x: number, y: number }} c Third point.
|
|
927
|
-
* @param {number} z Center Z position.
|
|
928
|
-
* @returns {void}
|
|
929
|
-
*/
|
|
930
|
-
static #appendTriangle(positions, a, b, c, z) {
|
|
931
|
-
const halfThickness = PcbScene3dCopperFactory.#COPPER_THICKNESS_MIL / 2
|
|
932
|
-
const topZ = z + halfThickness
|
|
933
|
-
const bottomZ = z - halfThickness
|
|
934
|
-
positions.push(
|
|
935
|
-
a.x,
|
|
936
|
-
a.y,
|
|
937
|
-
topZ,
|
|
938
|
-
b.x,
|
|
939
|
-
b.y,
|
|
940
|
-
topZ,
|
|
941
|
-
c.x,
|
|
942
|
-
c.y,
|
|
943
|
-
topZ,
|
|
944
|
-
c.x,
|
|
945
|
-
c.y,
|
|
946
|
-
bottomZ,
|
|
947
|
-
b.x,
|
|
948
|
-
b.y,
|
|
949
|
-
bottomZ,
|
|
950
|
-
a.x,
|
|
951
|
-
a.y,
|
|
952
|
-
bottomZ
|
|
953
|
-
)
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
/**
|
|
957
|
-
* Appends a side wall for one actual copper boundary edge.
|
|
958
|
-
* @param {number[]} positions Position buffer.
|
|
959
|
-
* @param {{ x: number, y: number }} start Wall start point.
|
|
960
|
-
* @param {{ x: number, y: number }} end Wall end point.
|
|
961
|
-
* @param {number} z Center Z position.
|
|
962
|
-
* @returns {void}
|
|
963
|
-
*/
|
|
964
|
-
static #appendBoundarySideTriangles(positions, start, end, z) {
|
|
965
|
-
const halfThickness = PcbScene3dCopperFactory.#COPPER_THICKNESS_MIL / 2
|
|
966
|
-
const topZ = z + halfThickness
|
|
967
|
-
const bottomZ = z - halfThickness
|
|
968
|
-
|
|
969
|
-
positions.push(
|
|
970
|
-
start.x,
|
|
971
|
-
start.y,
|
|
972
|
-
topZ,
|
|
973
|
-
end.x,
|
|
974
|
-
end.y,
|
|
975
|
-
topZ,
|
|
976
|
-
end.x,
|
|
977
|
-
end.y,
|
|
978
|
-
bottomZ,
|
|
979
|
-
start.x,
|
|
980
|
-
start.y,
|
|
981
|
-
topZ,
|
|
982
|
-
end.x,
|
|
983
|
-
end.y,
|
|
984
|
-
bottomZ,
|
|
985
|
-
start.x,
|
|
986
|
-
start.y,
|
|
987
|
-
bottomZ
|
|
988
|
-
)
|
|
989
|
-
}
|
|
990
961
|
}
|