circuit-json-to-step 0.0.21 → 0.0.23

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.js CHANGED
@@ -26,7 +26,7 @@ import {
26
26
  AdvancedFace as AdvancedFace3,
27
27
  Circle as Circle2,
28
28
  ClosedShell as ClosedShell2,
29
- ManifoldSolidBrep as ManifoldSolidBrep3,
29
+ ManifoldSolidBrep as ManifoldSolidBrep4,
30
30
  ColourRgb,
31
31
  FillAreaStyleColour,
32
32
  FillAreaStyle,
@@ -41,192 +41,204 @@ import {
41
41
  } from "stepts";
42
42
 
43
43
  // lib/mesh-generation.ts
44
+ import "stepts";
45
+
46
+ // lib/scene-box-to-step.ts
47
+ import { ClosedShell, ManifoldSolidBrep } from "stepts";
48
+
49
+ // lib/scene-geometry.ts
50
+ function rotatePoint3(point, rotation) {
51
+ if (!rotation) return point;
52
+ let { x, y, z } = point;
53
+ if (rotation.x) {
54
+ const cos = Math.cos(rotation.x);
55
+ const sin = Math.sin(rotation.x);
56
+ const nextY = y * cos - z * sin;
57
+ const nextZ = y * sin + z * cos;
58
+ y = nextY;
59
+ z = nextZ;
60
+ }
61
+ if (rotation.y) {
62
+ const cos = Math.cos(rotation.y);
63
+ const sin = Math.sin(rotation.y);
64
+ const nextX = x * cos + z * sin;
65
+ const nextZ = -x * sin + z * cos;
66
+ x = nextX;
67
+ z = nextZ;
68
+ }
69
+ if (rotation.z) {
70
+ const cos = Math.cos(rotation.z);
71
+ const sin = Math.sin(rotation.z);
72
+ const nextX = x * cos - y * sin;
73
+ const nextY = x * sin + y * cos;
74
+ x = nextX;
75
+ y = nextY;
76
+ }
77
+ return { x, y, z };
78
+ }
79
+
80
+ // lib/step-brep-utils.ts
44
81
  import {
45
82
  AdvancedFace,
46
83
  Axis2Placement3D,
47
84
  CartesianPoint,
48
- ClosedShell,
49
85
  Direction,
50
86
  EdgeCurve,
51
87
  EdgeLoop,
52
88
  FaceOuterBound,
53
89
  Line,
54
- ManifoldSolidBrep,
55
90
  OrientedEdge,
56
91
  Plane,
57
92
  Vector,
58
93
  VertexPoint
59
94
  } from "stepts";
60
- function createBoxTriangles(box) {
61
- const { center, size } = box;
62
- const halfX = size.x / 2;
63
- const halfY = size.y / 2;
64
- const halfZ = size.z / 2;
65
- const corners = [
66
- { x: -halfX, y: -halfY, z: -halfZ },
67
- { x: halfX, y: -halfY, z: -halfZ },
68
- { x: halfX, y: halfY, z: -halfZ },
69
- { x: -halfX, y: halfY, z: -halfZ },
70
- { x: -halfX, y: -halfY, z: halfZ },
71
- { x: halfX, y: -halfY, z: halfZ },
72
- { x: halfX, y: halfY, z: halfZ },
73
- { x: -halfX, y: halfY, z: halfZ }
74
- ].map((p) => ({ x: p.x + center.x, y: p.y + center.y, z: p.z + center.z }));
75
- const triangles = [
76
- // Bottom face (z = -halfZ)
77
- {
78
- vertices: [corners[0], corners[1], corners[2]],
79
- normal: { x: 0, y: 0, z: -1 }
80
- },
81
- {
82
- vertices: [corners[0], corners[2], corners[3]],
83
- normal: { x: 0, y: 0, z: -1 }
84
- },
85
- // Top face (z = halfZ)
86
- {
87
- vertices: [corners[4], corners[6], corners[5]],
88
- normal: { x: 0, y: 0, z: 1 }
89
- },
90
- {
91
- vertices: [corners[4], corners[7], corners[6]],
92
- normal: { x: 0, y: 0, z: 1 }
93
- },
94
- // Front face (y = -halfY)
95
- {
96
- vertices: [corners[0], corners[5], corners[1]],
97
- normal: { x: 0, y: -1, z: 0 }
98
- },
99
- {
100
- vertices: [corners[0], corners[4], corners[5]],
101
- normal: { x: 0, y: -1, z: 0 }
102
- },
103
- // Back face (y = halfY)
104
- {
105
- vertices: [corners[2], corners[6], corners[7]],
106
- normal: { x: 0, y: 1, z: 0 }
107
- },
108
- {
109
- vertices: [corners[2], corners[7], corners[3]],
110
- normal: { x: 0, y: 1, z: 0 }
111
- },
112
- // Left face (x = -halfX)
113
- {
114
- vertices: [corners[0], corners[3], corners[7]],
115
- normal: { x: -1, y: 0, z: 0 }
116
- },
117
- {
118
- vertices: [corners[0], corners[7], corners[4]],
119
- normal: { x: -1, y: 0, z: 0 }
120
- },
121
- // Right face (x = halfX)
122
- {
123
- vertices: [corners[1], corners[6], corners[2]],
124
- normal: { x: 1, y: 0, z: 0 }
95
+ function createVertex(repo, point) {
96
+ return repo.add(
97
+ new VertexPoint(
98
+ "",
99
+ repo.add(new CartesianPoint("", point.x, point.y, point.z))
100
+ )
101
+ );
102
+ }
103
+ function createEdge(repo, vStart, vEnd) {
104
+ const pStart = vStart.resolve(repo).pnt.resolve(repo);
105
+ const pEnd = vEnd.resolve(repo).pnt.resolve(repo);
106
+ const dx = pEnd.x - pStart.x;
107
+ const dy = pEnd.y - pStart.y;
108
+ const dz = pEnd.z - pStart.z;
109
+ const length = Math.sqrt(dx * dx + dy * dy + dz * dz);
110
+ if (length < 1e-10) {
111
+ const dir2 = repo.add(new Direction("", 1, 0, 0));
112
+ const vec2 = repo.add(new Vector("", dir2, 1e-10));
113
+ const line2 = repo.add(new Line("", vStart.resolve(repo).pnt, vec2));
114
+ return repo.add(new EdgeCurve("", vStart, vEnd, line2, true));
115
+ }
116
+ const dir = repo.add(new Direction("", dx / length, dy / length, dz / length));
117
+ const vec = repo.add(new Vector("", dir, length));
118
+ const line = repo.add(new Line("", vStart.resolve(repo).pnt, vec));
119
+ return repo.add(new EdgeCurve("", vStart, vEnd, line, true));
120
+ }
121
+ function createFaceFromVertices(repo, vertices) {
122
+ const edges = vertices.map(
123
+ (vertex, index) => createEdge(repo, vertex, vertices[(index + 1) % vertices.length])
124
+ );
125
+ const edgeLoop = repo.add(
126
+ new EdgeLoop(
127
+ "",
128
+ edges.map((edge) => repo.add(new OrientedEdge("", edge, true)))
129
+ )
130
+ );
131
+ const p1 = vertices[0].resolve(repo).pnt.resolve(repo);
132
+ const p2 = vertices[1].resolve(repo).pnt.resolve(repo);
133
+ const p3 = vertices[2].resolve(repo).pnt.resolve(repo);
134
+ const ux = p2.x - p1.x;
135
+ const uy = p2.y - p1.y;
136
+ const uz = p2.z - p1.z;
137
+ const vx = p3.x - p1.x;
138
+ const vy = p3.y - p1.y;
139
+ const vz = p3.z - p1.z;
140
+ const nx = uy * vz - uz * vy;
141
+ const ny = uz * vx - ux * vz;
142
+ const nz = ux * vy - uy * vx;
143
+ const normalLength = Math.sqrt(nx * nx + ny * ny + nz * nz);
144
+ const normal = normalLength < 1e-10 ? repo.add(new Direction("", 0, 0, 1)) : repo.add(
145
+ new Direction(
146
+ "",
147
+ nx / normalLength,
148
+ ny / normalLength,
149
+ nz / normalLength
150
+ )
151
+ );
152
+ const refLength = Math.sqrt(ux * ux + uy * uy + uz * uz);
153
+ const refDir = refLength < 1e-10 ? repo.add(new Direction("", 1, 0, 0)) : repo.add(
154
+ new Direction("", ux / refLength, uy / refLength, uz / refLength)
155
+ );
156
+ const placement = repo.add(
157
+ new Axis2Placement3D("", vertices[0].resolve(repo).pnt, normal, refDir)
158
+ );
159
+ const plane = repo.add(new Plane("", placement));
160
+ return repo.add(
161
+ new AdvancedFace(
162
+ "",
163
+ [repo.add(new FaceOuterBound("", edgeLoop, true))],
164
+ plane,
165
+ true
166
+ )
167
+ );
168
+ }
169
+
170
+ // lib/scene-box-to-step.ts
171
+ function createSceneBoxSolid(repo, box) {
172
+ if (box.mesh?.triangles?.length) {
173
+ return createSceneMeshSolid(repo, box);
174
+ }
175
+ const localBounds = box.mesh?.boundingBox ? {
176
+ min: box.mesh.boundingBox.min,
177
+ max: box.mesh.boundingBox.max
178
+ } : {
179
+ min: {
180
+ x: -box.size.x / 2,
181
+ y: -box.size.y / 2,
182
+ z: -box.size.z / 2
125
183
  },
126
- {
127
- vertices: [corners[1], corners[5], corners[6]],
128
- normal: { x: 1, y: 0, z: 0 }
184
+ max: {
185
+ x: box.size.x / 2,
186
+ y: box.size.y / 2,
187
+ z: box.size.z / 2
129
188
  }
130
- ];
131
- return triangles;
132
- }
133
- function createStepFacesFromTriangles(repo, triangles) {
134
- const faces = [];
135
- for (const triangle of triangles) {
136
- const v1 = repo.add(
137
- new VertexPoint(
138
- "",
139
- repo.add(
140
- new CartesianPoint(
141
- "",
142
- triangle.vertices[0].x,
143
- triangle.vertices[0].y,
144
- triangle.vertices[0].z
145
- )
146
- )
147
- )
148
- );
149
- const v2 = repo.add(
150
- new VertexPoint(
151
- "",
152
- repo.add(
153
- new CartesianPoint(
154
- "",
155
- triangle.vertices[1].x,
156
- triangle.vertices[1].y,
157
- triangle.vertices[1].z
158
- )
159
- )
160
- )
161
- );
162
- const v3 = repo.add(
163
- new VertexPoint(
164
- "",
165
- repo.add(
166
- new CartesianPoint(
167
- "",
168
- triangle.vertices[2].x,
169
- triangle.vertices[2].y,
170
- triangle.vertices[2].z
171
- )
172
- )
173
- )
174
- );
175
- const p1 = v1.resolve(repo).pnt.resolve(repo);
176
- const p2 = v2.resolve(repo).pnt.resolve(repo);
177
- const createEdge = (vStart, vEnd) => {
178
- const pStart = vStart.resolve(repo).pnt.resolve(repo);
179
- const pEnd = vEnd.resolve(repo).pnt.resolve(repo);
180
- const dir = repo.add(
181
- new Direction(
182
- "",
183
- pEnd.x - pStart.x,
184
- pEnd.y - pStart.y,
185
- pEnd.z - pStart.z
186
- )
187
- );
188
- const vec = repo.add(new Vector("", dir, 1));
189
- const line = repo.add(new Line("", vStart.resolve(repo).pnt, vec));
190
- return repo.add(new EdgeCurve("", vStart, vEnd, line, true));
189
+ };
190
+ const corners = [
191
+ { x: localBounds.min.x, y: localBounds.min.y, z: localBounds.min.z },
192
+ { x: localBounds.max.x, y: localBounds.min.y, z: localBounds.min.z },
193
+ { x: localBounds.max.x, y: localBounds.max.y, z: localBounds.min.z },
194
+ { x: localBounds.min.x, y: localBounds.max.y, z: localBounds.min.z },
195
+ { x: localBounds.min.x, y: localBounds.min.y, z: localBounds.max.z },
196
+ { x: localBounds.max.x, y: localBounds.min.y, z: localBounds.max.z },
197
+ { x: localBounds.max.x, y: localBounds.max.y, z: localBounds.max.z },
198
+ { x: localBounds.min.x, y: localBounds.max.y, z: localBounds.max.z }
199
+ ].map((corner) => {
200
+ const rotated = rotatePoint3(corner, box.rotation);
201
+ return {
202
+ x: rotated.x + box.center.x,
203
+ y: rotated.y + box.center.y,
204
+ z: rotated.z + box.center.z
191
205
  };
192
- const edge1 = createEdge(v1, v2);
193
- const edge2 = createEdge(v2, v3);
194
- const edge3 = createEdge(v3, v1);
195
- const edgeLoop = repo.add(
196
- new EdgeLoop("", [
197
- repo.add(new OrientedEdge("", edge1, true)),
198
- repo.add(new OrientedEdge("", edge2, true)),
199
- repo.add(new OrientedEdge("", edge3, true))
200
- ])
201
- );
202
- const normalDir = repo.add(
203
- new Direction(
204
- "",
205
- triangle.normal.x,
206
- triangle.normal.y,
207
- triangle.normal.z
208
- )
209
- );
210
- const refX = p2.x - p1.x;
211
- const refY = p2.y - p1.y;
212
- const refZ = p2.z - p1.z;
213
- const refDir = repo.add(new Direction("", refX, refY, refZ));
214
- const placement = repo.add(
215
- new Axis2Placement3D("", v1.resolve(repo).pnt, normalDir, refDir)
216
- );
217
- const plane = repo.add(new Plane("", placement));
218
- const face = repo.add(
219
- new AdvancedFace(
220
- "",
221
- [repo.add(new FaceOuterBound("", edgeLoop, true))],
222
- plane,
223
- true
224
- )
225
- );
226
- faces.push(face);
227
- }
228
- return faces;
206
+ });
207
+ const stepCorners = corners.map((corner) => ({
208
+ x: corner.x,
209
+ y: corner.z,
210
+ z: corner.y
211
+ }));
212
+ const vertices = stepCorners.map((corner) => createVertex(repo, corner));
213
+ const faces = [
214
+ [vertices[0], vertices[1], vertices[2], vertices[3]],
215
+ [vertices[4], vertices[7], vertices[6], vertices[5]],
216
+ [vertices[0], vertices[4], vertices[5], vertices[1]],
217
+ [vertices[1], vertices[5], vertices[6], vertices[2]],
218
+ [vertices[2], vertices[6], vertices[7], vertices[3]],
219
+ [vertices[3], vertices[7], vertices[4], vertices[0]]
220
+ ].map((faceVertices) => createFaceFromVertices(repo, faceVertices));
221
+ const shell = repo.add(new ClosedShell("", faces));
222
+ return repo.add(new ManifoldSolidBrep("Component", shell));
223
+ }
224
+ function createSceneMeshSolid(repo, box) {
225
+ const faces = box.mesh.triangles.map((triangle) => {
226
+ const vertices = triangle.vertices.map((vertex) => {
227
+ const rotated = rotatePoint3(vertex, box.rotation);
228
+ const translated = {
229
+ x: rotated.x + box.center.x,
230
+ y: rotated.z + box.center.z,
231
+ z: rotated.y + box.center.y
232
+ };
233
+ return createVertex(repo, translated);
234
+ });
235
+ return createFaceFromVertices(repo, vertices);
236
+ });
237
+ const shell = repo.add(new ClosedShell("", faces));
238
+ return repo.add(new ManifoldSolidBrep("Component", shell));
229
239
  }
240
+
241
+ // lib/mesh-generation.ts
230
242
  async function generateComponentMeshes(options) {
231
243
  const {
232
244
  repo,
@@ -239,25 +251,25 @@ async function generateComponentMeshes(options) {
239
251
  } = options;
240
252
  const solids = [];
241
253
  try {
242
- const filteredCircuitJson = circuitJson.filter((e) => {
243
- if (e.type === "pcb_board") return false;
244
- if (e.type === "cad_component" && e.cad_component_id && excludeCadComponentIds?.has(e.cad_component_id)) {
254
+ const filteredCircuitJson = circuitJson.filter((element) => {
255
+ if (element.type === "pcb_board") return false;
256
+ if (element.type === "cad_component" && element.cad_component_id && excludeCadComponentIds?.has(element.cad_component_id)) {
245
257
  return false;
246
258
  }
247
- if (e.type === "pcb_component" && e.pcb_component_id && excludePcbComponentIds?.has(e.pcb_component_id)) {
259
+ if (element.type === "pcb_component" && element.pcb_component_id && excludePcbComponentIds?.has(element.pcb_component_id)) {
248
260
  return false;
249
261
  }
250
- if (e.type === "cad_component" && e.model_step_url) {
262
+ if (element.type === "cad_component" && element.model_step_url) {
251
263
  return false;
252
264
  }
253
- if (e.type === "cad_component" && e.pcb_component_id && pcbComponentIdsWithStepUrl?.has(e.pcb_component_id)) {
265
+ if (element.type === "cad_component" && element.pcb_component_id && pcbComponentIdsWithStepUrl?.has(element.pcb_component_id)) {
254
266
  return false;
255
267
  }
256
268
  return true;
257
- }).map((e) => {
258
- if (!includeExternalMeshes && e.type === "cad_component") {
269
+ }).map((element) => {
270
+ if (!includeExternalMeshes && element.type === "cad_component") {
259
271
  return {
260
- ...e,
272
+ ...element,
261
273
  model_3mf_url: void 0,
262
274
  model_obj_url: void 0,
263
275
  model_stl_url: void 0,
@@ -265,7 +277,7 @@ async function generateComponentMeshes(options) {
265
277
  model_gltf_url: void 0
266
278
  };
267
279
  }
268
- return e;
280
+ return element;
269
281
  });
270
282
  const gltfModule = "circuit-json-to-gltf";
271
283
  const { convertCircuitJsonTo3D } = await import(
@@ -276,43 +288,8 @@ async function generateComponentMeshes(options) {
276
288
  boardThickness,
277
289
  renderBoardTextures: false
278
290
  });
279
- const allTriangles = [];
280
291
  for (const box of scene3d.boxes) {
281
- if (box.mesh && "triangles" in box.mesh) {
282
- allTriangles.push(...box.mesh.triangles);
283
- } else {
284
- const boxTriangles = createBoxTriangles(box);
285
- allTriangles.push(...boxTriangles);
286
- }
287
- }
288
- if (allTriangles.length > 0) {
289
- const transformedTriangles = allTriangles.map((tri) => ({
290
- vertices: tri.vertices.map((v) => ({
291
- x: v.x,
292
- y: v.z,
293
- // GLTF Z becomes STEP Y
294
- z: v.y
295
- // GLTF Y becomes STEP Z
296
- })),
297
- normal: {
298
- x: tri.normal.x,
299
- y: tri.normal.z,
300
- // GLTF Z becomes STEP Y
301
- z: tri.normal.y
302
- // GLTF Y becomes STEP Z
303
- }
304
- }));
305
- const componentFaces = createStepFacesFromTriangles(
306
- repo,
307
- transformedTriangles
308
- );
309
- const componentShell = repo.add(
310
- new ClosedShell("", componentFaces)
311
- );
312
- const componentSolid = repo.add(
313
- new ManifoldSolidBrep("Components", componentShell)
314
- );
315
- solids.push(componentSolid);
292
+ solids.push(createSceneBoxSolid(repo, box));
316
293
  }
317
294
  } catch (error) {
318
295
  console.warn("Failed to generate component mesh:", error);
@@ -324,7 +301,7 @@ async function generateComponentMeshes(options) {
324
301
  import {
325
302
  CartesianPoint as CartesianPoint2,
326
303
  Direction as Direction2,
327
- ManifoldSolidBrep as ManifoldSolidBrep2,
304
+ ManifoldSolidBrep as ManifoldSolidBrep3,
328
305
  Ref,
329
306
  Unknown,
330
307
  parseRepository
@@ -498,7 +475,7 @@ function mergeSingleStepModel(targetRepo, stepText, transform, placement) {
498
475
  }
499
476
  const solids = [];
500
477
  for (const [oldId, entity] of entries) {
501
- if (entity instanceof ManifoldSolidBrep2) {
478
+ if (entity instanceof ManifoldSolidBrep3) {
502
479
  const mappedId = idMapping.get(oldId);
503
480
  if (mappedId !== void 0) {
504
481
  solids.push(new Ref(eid(mappedId)));
@@ -548,16 +525,16 @@ function adjustTransformForPlacement(entries, transform, placement) {
548
525
  transform.translation.x = targetX - center.x;
549
526
  transform.translation.y = targetY - center.y;
550
527
  if (isThroughHoleComponent) {
551
- transform.translation.z = boardThickness;
528
+ transform.translation.z = boardThickness / 2;
552
529
  }
553
530
  if (!isThroughHoleComponent && boardThickness > 0) {
554
531
  const halfThickness = boardThickness / 2;
555
- const offsetZ = targetZ - halfThickness;
532
+ const offsetZ = targetZ;
556
533
  if (normalizedLayer === "bottom") {
557
534
  transform.translation.z = -maxZ + offsetZ;
558
535
  transform.rotation.x = normalizeDegrees(transform.rotation.x + 180);
559
536
  } else {
560
- transform.translation.z = boardThickness - minZ + offsetZ;
537
+ transform.translation.z = halfThickness - minZ + offsetZ;
561
538
  }
562
539
  } else if (!isThroughHoleComponent) {
563
540
  transform.translation.z = targetZ - center.z;
@@ -722,7 +699,7 @@ function normalizeStepNumericExponents(stepText) {
722
699
  var package_default = {
723
700
  name: "circuit-json-to-step",
724
701
  main: "dist/index.js",
725
- version: "0.0.20",
702
+ version: "0.0.22",
726
703
  type: "module",
727
704
  scripts: {
728
705
  "pull-reference": `git clone https://github.com/tscircuit/circuit-json.git && find circuit-json/tests -name '*.test.ts' -exec bash -c 'mv "$0" "\${0%.test.ts}.ts"' {} \\; && git clone https://github.com/tscircuit/stepts.git && find stepts/tests -name '*.test.ts' -exec bash -c 'mv "$0" "\${0%.test.ts}.ts"' {} \\;`,
@@ -752,10 +729,10 @@ var package_default = {
752
729
  },
753
730
  dependencies: {
754
731
  "circuit-json-to-connectivity-map": "^0.0.22",
755
- "circuit-json-to-gltf": "^0.0.91",
732
+ "circuit-json-to-gltf": "^0.0.93",
756
733
  "circuit-to-svg": "^0.0.327",
757
734
  "schematic-symbols": "^0.0.202",
758
- stepts: "^0.0.3"
735
+ stepts: "^0.0.4"
759
736
  }
760
737
  };
761
738
 
@@ -1049,7 +1026,7 @@ function createPillHoleLoop(repo, hole, z, xDir) {
1049
1026
  );
1050
1027
  return repo.add(new EdgeLoop2("", orientedEdges));
1051
1028
  }
1052
- function createPillCylindricalFaces(repo, hole, boardThickness, xDir, zDir) {
1029
+ function createPillCylindricalFaces(repo, hole, zMin, zMax, xDir, zDir) {
1053
1030
  const geom = getPillGeometry(hole);
1054
1031
  const {
1055
1032
  centerX,
@@ -1073,7 +1050,8 @@ function createPillCylindricalFaces(repo, hole, boardThickness, xDir, zDir) {
1073
1050
  rotation,
1074
1051
  centerX,
1075
1052
  centerY,
1076
- boardThickness,
1053
+ zMin,
1054
+ zMax,
1077
1055
  zDir,
1078
1056
  xDir
1079
1057
  )
@@ -1088,7 +1066,8 @@ function createPillCylindricalFaces(repo, hole, boardThickness, xDir, zDir) {
1088
1066
  rotation,
1089
1067
  centerX,
1090
1068
  centerY,
1091
- boardThickness,
1069
+ zMin,
1070
+ zMax,
1092
1071
  zDir
1093
1072
  )
1094
1073
  );
@@ -1103,7 +1082,8 @@ function createPillCylindricalFaces(repo, hole, boardThickness, xDir, zDir) {
1103
1082
  rotation,
1104
1083
  centerX,
1105
1084
  centerY,
1106
- boardThickness,
1085
+ zMin,
1086
+ zMax,
1107
1087
  zDir,
1108
1088
  xDir
1109
1089
  )
@@ -1118,7 +1098,8 @@ function createPillCylindricalFaces(repo, hole, boardThickness, xDir, zDir) {
1118
1098
  rotation,
1119
1099
  centerX,
1120
1100
  centerY,
1121
- boardThickness,
1101
+ zMin,
1102
+ zMax,
1122
1103
  zDir
1123
1104
  )
1124
1105
  );
@@ -1135,7 +1116,8 @@ function createPillCylindricalFaces(repo, hole, boardThickness, xDir, zDir) {
1135
1116
  rotation,
1136
1117
  centerX,
1137
1118
  centerY,
1138
- boardThickness,
1119
+ zMin,
1120
+ zMax,
1139
1121
  zDir,
1140
1122
  xDir
1141
1123
  )
@@ -1150,7 +1132,8 @@ function createPillCylindricalFaces(repo, hole, boardThickness, xDir, zDir) {
1150
1132
  rotation,
1151
1133
  centerX,
1152
1134
  centerY,
1153
- boardThickness,
1135
+ zMin,
1136
+ zMax,
1154
1137
  zDir
1155
1138
  )
1156
1139
  );
@@ -1165,7 +1148,8 @@ function createPillCylindricalFaces(repo, hole, boardThickness, xDir, zDir) {
1165
1148
  rotation,
1166
1149
  centerX,
1167
1150
  centerY,
1168
- boardThickness,
1151
+ zMin,
1152
+ zMax,
1169
1153
  zDir,
1170
1154
  xDir
1171
1155
  )
@@ -1180,14 +1164,15 @@ function createPillCylindricalFaces(repo, hole, boardThickness, xDir, zDir) {
1180
1164
  rotation,
1181
1165
  centerX,
1182
1166
  centerY,
1183
- boardThickness,
1167
+ zMin,
1168
+ zMax,
1184
1169
  zDir
1185
1170
  )
1186
1171
  );
1187
1172
  }
1188
1173
  return faces;
1189
1174
  }
1190
- function createCylindricalWall(repo, centerX, centerY, radius, startAngle, endAngle, rotation, centerX0, centerY0, boardThickness, zDir, xDir) {
1175
+ function createCylindricalWall(repo, centerX, centerY, radius, startAngle, endAngle, rotation, centerX0, centerY0, zMin, zMax, zDir, xDir) {
1191
1176
  const bottomStartX = centerX + radius * Math.cos(startAngle);
1192
1177
  const bottomStartY = centerY + radius * Math.sin(startAngle);
1193
1178
  const bottomEndX = centerX + radius * Math.cos(endAngle);
@@ -1209,29 +1194,25 @@ function createCylindricalWall(repo, centerX, centerY, radius, startAngle, endAn
1209
1194
  const bottomStartVertex = repo.add(
1210
1195
  new VertexPoint2(
1211
1196
  "",
1212
- repo.add(new CartesianPoint3("", bottomStart.x, bottomStart.y, 0))
1197
+ repo.add(new CartesianPoint3("", bottomStart.x, bottomStart.y, zMin))
1213
1198
  )
1214
1199
  );
1215
1200
  const bottomEndVertex = repo.add(
1216
1201
  new VertexPoint2(
1217
1202
  "",
1218
- repo.add(new CartesianPoint3("", bottomEnd.x, bottomEnd.y, 0))
1203
+ repo.add(new CartesianPoint3("", bottomEnd.x, bottomEnd.y, zMin))
1219
1204
  )
1220
1205
  );
1221
1206
  const topStart = repo.add(
1222
1207
  new VertexPoint2(
1223
1208
  "",
1224
- repo.add(
1225
- new CartesianPoint3("", bottomStart.x, bottomStart.y, boardThickness)
1226
- )
1209
+ repo.add(new CartesianPoint3("", bottomStart.x, bottomStart.y, zMax))
1227
1210
  )
1228
1211
  );
1229
1212
  const topEnd = repo.add(
1230
1213
  new VertexPoint2(
1231
1214
  "",
1232
- repo.add(
1233
- new CartesianPoint3("", bottomEnd.x, bottomEnd.y, boardThickness)
1234
- )
1215
+ repo.add(new CartesianPoint3("", bottomEnd.x, bottomEnd.y, zMax))
1235
1216
  )
1236
1217
  );
1237
1218
  const centerRotated = rotatePoint(
@@ -1242,7 +1223,7 @@ function createCylindricalWall(repo, centerX, centerY, radius, startAngle, endAn
1242
1223
  rotation
1243
1224
  );
1244
1225
  const bottomCenter = repo.add(
1245
- new CartesianPoint3("", centerRotated.x, centerRotated.y, 0)
1226
+ new CartesianPoint3("", centerRotated.x, centerRotated.y, zMin)
1246
1227
  );
1247
1228
  const bottomPlacement = repo.add(
1248
1229
  new Axis2Placement3D2(
@@ -1257,7 +1238,7 @@ function createCylindricalWall(repo, centerX, centerY, radius, startAngle, endAn
1257
1238
  new EdgeCurve2("", bottomStartVertex, bottomEndVertex, bottomCircle, false)
1258
1239
  );
1259
1240
  const topCenter = repo.add(
1260
- new CartesianPoint3("", centerRotated.x, centerRotated.y, boardThickness)
1241
+ new CartesianPoint3("", centerRotated.x, centerRotated.y, zMax)
1261
1242
  );
1262
1243
  const topPlacement = repo.add(new Axis2Placement3D2("", topCenter, zDir, xDir));
1263
1244
  const topCircle = repo.add(new Circle("", topPlacement, radius));
@@ -1265,37 +1246,34 @@ function createCylindricalWall(repo, centerX, centerY, radius, startAngle, endAn
1265
1246
  const v1 = repo.add(
1266
1247
  new VertexPoint2(
1267
1248
  "",
1268
- repo.add(new CartesianPoint3("", bottomStart.x, bottomStart.y, 0))
1249
+ repo.add(new CartesianPoint3("", bottomStart.x, bottomStart.y, zMin))
1269
1250
  )
1270
1251
  );
1271
1252
  const v2 = repo.add(
1272
1253
  new VertexPoint2(
1273
1254
  "",
1274
- repo.add(
1275
- new CartesianPoint3("", bottomStart.x, bottomStart.y, boardThickness)
1276
- )
1255
+ repo.add(new CartesianPoint3("", bottomStart.x, bottomStart.y, zMax))
1277
1256
  )
1278
1257
  );
1279
1258
  const v3 = repo.add(
1280
1259
  new VertexPoint2(
1281
1260
  "",
1282
- repo.add(new CartesianPoint3("", bottomEnd.x, bottomEnd.y, 0))
1261
+ repo.add(new CartesianPoint3("", bottomEnd.x, bottomEnd.y, zMin))
1283
1262
  )
1284
1263
  );
1285
1264
  const v4 = repo.add(
1286
1265
  new VertexPoint2(
1287
1266
  "",
1288
- repo.add(
1289
- new CartesianPoint3("", bottomEnd.x, bottomEnd.y, boardThickness)
1290
- )
1267
+ repo.add(new CartesianPoint3("", bottomEnd.x, bottomEnd.y, zMax))
1291
1268
  )
1292
1269
  );
1293
1270
  const dir1 = repo.add(new Direction3("", 0, 0, 1));
1294
- const vec1 = repo.add(new Vector2("", dir1, boardThickness));
1271
+ const height = zMax - zMin;
1272
+ const vec1 = repo.add(new Vector2("", dir1, height));
1295
1273
  const line1 = repo.add(new Line2("", v1.resolve(repo).pnt, vec1));
1296
1274
  const edge1 = repo.add(new EdgeCurve2("", v1, v2, line1, true));
1297
1275
  const dir2 = repo.add(new Direction3("", 0, 0, 1));
1298
- const vec2 = repo.add(new Vector2("", dir2, boardThickness));
1276
+ const vec2 = repo.add(new Vector2("", dir2, height));
1299
1277
  const line2 = repo.add(new Line2("", v3.resolve(repo).pnt, vec2));
1300
1278
  const edge2 = repo.add(new EdgeCurve2("", v3, v4, line2, true));
1301
1279
  const loop = repo.add(
@@ -1321,25 +1299,25 @@ function createCylindricalWall(repo, centerX, centerY, radius, startAngle, endAn
1321
1299
  )
1322
1300
  );
1323
1301
  }
1324
- function createPlanarWall(repo, startX, startY, endX, endY, rotation, centerX0, centerY0, boardThickness, zDir) {
1302
+ function createPlanarWall(repo, startX, startY, endX, endY, rotation, centerX0, centerY0, zMin, zMax, zDir) {
1325
1303
  const start = rotatePoint(startX, startY, centerX0, centerY0, rotation);
1326
1304
  const end = rotatePoint(endX, endY, centerX0, centerY0, rotation);
1327
1305
  const v1 = repo.add(
1328
- new VertexPoint2("", repo.add(new CartesianPoint3("", start.x, start.y, 0)))
1306
+ new VertexPoint2(
1307
+ "",
1308
+ repo.add(new CartesianPoint3("", start.x, start.y, zMin))
1309
+ )
1329
1310
  );
1330
1311
  const v2 = repo.add(
1331
- new VertexPoint2("", repo.add(new CartesianPoint3("", end.x, end.y, 0)))
1312
+ new VertexPoint2("", repo.add(new CartesianPoint3("", end.x, end.y, zMin)))
1332
1313
  );
1333
1314
  const v3 = repo.add(
1334
- new VertexPoint2(
1335
- "",
1336
- repo.add(new CartesianPoint3("", end.x, end.y, boardThickness))
1337
- )
1315
+ new VertexPoint2("", repo.add(new CartesianPoint3("", end.x, end.y, zMax)))
1338
1316
  );
1339
1317
  const v4 = repo.add(
1340
1318
  new VertexPoint2(
1341
1319
  "",
1342
- repo.add(new CartesianPoint3("", start.x, start.y, boardThickness))
1320
+ repo.add(new CartesianPoint3("", start.x, start.y, zMax))
1343
1321
  )
1344
1322
  );
1345
1323
  const dx = end.x - start.x;
@@ -1358,10 +1336,11 @@ function createPlanarWall(repo, startX, startY, endX, endY, rotation, centerX0,
1358
1336
  const topLine = repo.add(new Line2("", v4.resolve(repo).pnt, topVec));
1359
1337
  const topEdge = repo.add(new EdgeCurve2("", v4, v3, topLine, true));
1360
1338
  const vertDir = repo.add(new Direction3("", 0, 0, 1));
1361
- const vertVec1 = repo.add(new Vector2("", vertDir, boardThickness));
1339
+ const height = zMax - zMin;
1340
+ const vertVec1 = repo.add(new Vector2("", vertDir, height));
1362
1341
  const vertLine1 = repo.add(new Line2("", v2.resolve(repo).pnt, vertVec1));
1363
1342
  const vertEdge1 = repo.add(new EdgeCurve2("", v2, v3, vertLine1, true));
1364
- const vertVec2 = repo.add(new Vector2("", vertDir, boardThickness));
1343
+ const vertVec2 = repo.add(new Vector2("", vertDir, height));
1365
1344
  const vertLine2 = repo.add(new Line2("", v1.resolve(repo).pnt, vertVec2));
1366
1345
  const vertEdge2 = repo.add(new EdgeCurve2("", v1, v4, vertLine2, true));
1367
1346
  const loop = repo.add(
@@ -1378,7 +1357,7 @@ function createPlanarWall(repo, startX, startY, endX, endY, rotation, centerX0,
1378
1357
  const refDir = repo.add(
1379
1358
  new Direction3("", dx / edgeLength, dy / edgeLength, 0)
1380
1359
  );
1381
- const planeOrigin = repo.add(new CartesianPoint3("", start.x, start.y, 0));
1360
+ const planeOrigin = repo.add(new CartesianPoint3("", start.x, start.y, zMin));
1382
1361
  const placement = repo.add(
1383
1362
  new Axis2Placement3D2("", planeOrigin, normalDir, refDir)
1384
1363
  );
@@ -1406,6 +1385,7 @@ async function circuitJsonToStep(circuitJson, options = {}) {
1406
1385
  const productName = options.productName ?? "PCB";
1407
1386
  const boardCenterX = pcbBoard?.center?.x ?? 0;
1408
1387
  const boardCenterY = pcbBoard?.center?.y ?? 0;
1388
+ const halfBoardThickness = boardThickness / 2;
1409
1389
  if (!boardWidth || !boardHeight) {
1410
1390
  throw new Error(
1411
1391
  "Board dimensions not found. Either provide boardWidth and boardHeight in options, or include a pcb_board in the circuit JSON with width and height properties."
@@ -1495,7 +1475,9 @@ async function circuitJsonToStep(circuitJson, options = {}) {
1495
1475
  (point) => repo.add(
1496
1476
  new VertexPoint3(
1497
1477
  "",
1498
- repo.add(new CartesianPoint4("", point.x, point.y, 0))
1478
+ repo.add(
1479
+ new CartesianPoint4("", point.x, point.y, -halfBoardThickness)
1480
+ )
1499
1481
  )
1500
1482
  )
1501
1483
  );
@@ -1503,7 +1485,9 @@ async function circuitJsonToStep(circuitJson, options = {}) {
1503
1485
  (point) => repo.add(
1504
1486
  new VertexPoint3(
1505
1487
  "",
1506
- repo.add(new CartesianPoint4("", point.x, point.y, boardThickness))
1488
+ repo.add(
1489
+ new CartesianPoint4("", point.x, point.y, halfBoardThickness)
1490
+ )
1507
1491
  )
1508
1492
  )
1509
1493
  );
@@ -1511,14 +1495,30 @@ async function circuitJsonToStep(circuitJson, options = {}) {
1511
1495
  const halfWidth = boardWidth / 2;
1512
1496
  const halfHeight = boardHeight / 2;
1513
1497
  const corners = [
1514
- [boardCenterX - halfWidth, boardCenterY - halfHeight, 0],
1515
- [boardCenterX + halfWidth, boardCenterY - halfHeight, 0],
1516
- [boardCenterX + halfWidth, boardCenterY + halfHeight, 0],
1517
- [boardCenterX - halfWidth, boardCenterY + halfHeight, 0],
1518
- [boardCenterX - halfWidth, boardCenterY - halfHeight, boardThickness],
1519
- [boardCenterX + halfWidth, boardCenterY - halfHeight, boardThickness],
1520
- [boardCenterX + halfWidth, boardCenterY + halfHeight, boardThickness],
1521
- [boardCenterX - halfWidth, boardCenterY + halfHeight, boardThickness]
1498
+ [
1499
+ boardCenterX - halfWidth,
1500
+ boardCenterY - halfHeight,
1501
+ -halfBoardThickness
1502
+ ],
1503
+ [
1504
+ boardCenterX + halfWidth,
1505
+ boardCenterY - halfHeight,
1506
+ -halfBoardThickness
1507
+ ],
1508
+ [
1509
+ boardCenterX + halfWidth,
1510
+ boardCenterY + halfHeight,
1511
+ -halfBoardThickness
1512
+ ],
1513
+ [
1514
+ boardCenterX - halfWidth,
1515
+ boardCenterY + halfHeight,
1516
+ -halfBoardThickness
1517
+ ],
1518
+ [boardCenterX - halfWidth, boardCenterY - halfHeight, halfBoardThickness],
1519
+ [boardCenterX + halfWidth, boardCenterY - halfHeight, halfBoardThickness],
1520
+ [boardCenterX + halfWidth, boardCenterY + halfHeight, halfBoardThickness],
1521
+ [boardCenterX - halfWidth, boardCenterY + halfHeight, halfBoardThickness]
1522
1522
  ];
1523
1523
  const vertices = corners.map(
1524
1524
  ([x, y, z]) => repo.add(
@@ -1528,7 +1528,7 @@ async function circuitJsonToStep(circuitJson, options = {}) {
1528
1528
  bottomVertices = [vertices[0], vertices[1], vertices[2], vertices[3]];
1529
1529
  topVertices = [vertices[4], vertices[5], vertices[6], vertices[7]];
1530
1530
  }
1531
- function createEdge(v1, v2) {
1531
+ function createEdge2(v1, v2) {
1532
1532
  const p1 = v1.resolve(repo).pnt.resolve(repo);
1533
1533
  const p2 = v2.resolve(repo).pnt.resolve(repo);
1534
1534
  const dx = p2.x - p1.x;
@@ -1554,17 +1554,17 @@ async function circuitJsonToStep(circuitJson, options = {}) {
1554
1554
  for (let i = 0; i < bottomVertices.length; i++) {
1555
1555
  const v1 = bottomVertices[i];
1556
1556
  const v2 = bottomVertices[(i + 1) % bottomVertices.length];
1557
- bottomEdges.push(createEdge(v1, v2));
1557
+ bottomEdges.push(createEdge2(v1, v2));
1558
1558
  }
1559
1559
  for (let i = 0; i < topVertices.length; i++) {
1560
1560
  const v1 = topVertices[i];
1561
1561
  const v2 = topVertices[(i + 1) % topVertices.length];
1562
- topEdges.push(createEdge(v1, v2));
1562
+ topEdges.push(createEdge2(v1, v2));
1563
1563
  }
1564
1564
  for (let i = 0; i < bottomVertices.length; i++) {
1565
- verticalEdges.push(createEdge(bottomVertices[i], topVertices[i]));
1565
+ verticalEdges.push(createEdge2(bottomVertices[i], topVertices[i]));
1566
1566
  }
1567
- const origin = repo.add(new CartesianPoint4("", 0, 0, 0));
1567
+ const origin = repo.add(new CartesianPoint4("", 0, 0, -halfBoardThickness));
1568
1568
  const xDir = repo.add(new Direction4("", 1, 0, 0));
1569
1569
  const zDir = repo.add(new Direction4("", 0, 0, 1));
1570
1570
  const bottomFrame = repo.add(
@@ -1589,11 +1589,15 @@ async function circuitJsonToStep(circuitJson, options = {}) {
1589
1589
  const holeX = typeof hole.x === "number" ? hole.x : hole.x.value;
1590
1590
  const holeY = typeof hole.y === "number" ? hole.y : hole.y.value;
1591
1591
  const radius = hole.hole_diameter / 2;
1592
- const holeCenter = repo.add(new CartesianPoint4("", holeX, holeY, 0));
1592
+ const holeCenter = repo.add(
1593
+ new CartesianPoint4("", holeX, holeY, -halfBoardThickness)
1594
+ );
1593
1595
  const holeVertex = repo.add(
1594
1596
  new VertexPoint3(
1595
1597
  "",
1596
- repo.add(new CartesianPoint4("", holeX + radius, holeY, 0))
1598
+ repo.add(
1599
+ new CartesianPoint4("", holeX + radius, holeY, -halfBoardThickness)
1600
+ )
1597
1601
  )
1598
1602
  );
1599
1603
  const holePlacement = repo.add(
@@ -1613,7 +1617,7 @@ async function circuitJsonToStep(circuitJson, options = {}) {
1613
1617
  );
1614
1618
  bottomHoleLoops.push(repo.add(new FaceBound("", holeLoop, true)));
1615
1619
  } else if (holeShape === "rotated_pill" || holeShape === "pill") {
1616
- const pillLoop = createPillHoleLoop(repo, hole, 0, xDir);
1620
+ const pillLoop = createPillHoleLoop(repo, hole, -halfBoardThickness, xDir);
1617
1621
  bottomHoleLoops.push(repo.add(new FaceBound("", pillLoop, true)));
1618
1622
  }
1619
1623
  }
@@ -1628,7 +1632,7 @@ async function circuitJsonToStep(circuitJson, options = {}) {
1628
1632
  true
1629
1633
  )
1630
1634
  );
1631
- const topOrigin = repo.add(new CartesianPoint4("", 0, 0, boardThickness));
1635
+ const topOrigin = repo.add(new CartesianPoint4("", 0, 0, halfBoardThickness));
1632
1636
  const topFrame = repo.add(new Axis2Placement3D3("", topOrigin, zDir, xDir));
1633
1637
  const topPlane = repo.add(new Plane3("", topFrame));
1634
1638
  const topLoop = repo.add(
@@ -1645,13 +1649,13 @@ async function circuitJsonToStep(circuitJson, options = {}) {
1645
1649
  const holeY = typeof hole.y === "number" ? hole.y : hole.y.value;
1646
1650
  const radius = hole.hole_diameter / 2;
1647
1651
  const holeCenter = repo.add(
1648
- new CartesianPoint4("", holeX, holeY, boardThickness)
1652
+ new CartesianPoint4("", holeX, holeY, halfBoardThickness)
1649
1653
  );
1650
1654
  const holeVertex = repo.add(
1651
1655
  new VertexPoint3(
1652
1656
  "",
1653
1657
  repo.add(
1654
- new CartesianPoint4("", holeX + radius, holeY, boardThickness)
1658
+ new CartesianPoint4("", holeX + radius, holeY, halfBoardThickness)
1655
1659
  )
1656
1660
  )
1657
1661
  );
@@ -1667,7 +1671,7 @@ async function circuitJsonToStep(circuitJson, options = {}) {
1667
1671
  );
1668
1672
  topHoleLoops.push(repo.add(new FaceBound("", holeLoop, true)));
1669
1673
  } else if (holeShape === "rotated_pill" || holeShape === "pill") {
1670
- const pillLoop = createPillHoleLoop(repo, hole, boardThickness, xDir);
1674
+ const pillLoop = createPillHoleLoop(repo, hole, halfBoardThickness, xDir);
1671
1675
  topHoleLoops.push(repo.add(new FaceBound("", pillLoop, true)));
1672
1676
  }
1673
1677
  }
@@ -1689,7 +1693,7 @@ async function circuitJsonToStep(circuitJson, options = {}) {
1689
1693
  const edgeDir = {
1690
1694
  x: bottomV2.x - bottomV1.x,
1691
1695
  y: bottomV2.y - bottomV1.y,
1692
- z: 0
1696
+ z: -halfBoardThickness
1693
1697
  };
1694
1698
  const normalDir = repo.add(new Direction4("", edgeDir.y, -edgeDir.x, 0));
1695
1699
  const refDir = repo.add(new Direction4("", edgeDir.x, edgeDir.y, 0));
@@ -1722,11 +1726,15 @@ async function circuitJsonToStep(circuitJson, options = {}) {
1722
1726
  const holeX = typeof hole.x === "number" ? hole.x : hole.x.value;
1723
1727
  const holeY = typeof hole.y === "number" ? hole.y : hole.y.value;
1724
1728
  const radius = hole.hole_diameter / 2;
1725
- const bottomHoleCenter = repo.add(new CartesianPoint4("", holeX, holeY, 0));
1729
+ const bottomHoleCenter = repo.add(
1730
+ new CartesianPoint4("", holeX, holeY, -halfBoardThickness)
1731
+ );
1726
1732
  const bottomHoleVertex = repo.add(
1727
1733
  new VertexPoint3(
1728
1734
  "",
1729
- repo.add(new CartesianPoint4("", holeX + radius, holeY, 0))
1735
+ repo.add(
1736
+ new CartesianPoint4("", holeX + radius, holeY, -halfBoardThickness)
1737
+ )
1730
1738
  )
1731
1739
  );
1732
1740
  const bottomHolePlacement = repo.add(
@@ -1750,13 +1758,13 @@ async function circuitJsonToStep(circuitJson, options = {}) {
1750
1758
  )
1751
1759
  );
1752
1760
  const topHoleCenter = repo.add(
1753
- new CartesianPoint4("", holeX, holeY, boardThickness)
1761
+ new CartesianPoint4("", holeX, holeY, halfBoardThickness)
1754
1762
  );
1755
1763
  const topHoleVertex = repo.add(
1756
1764
  new VertexPoint3(
1757
1765
  "",
1758
1766
  repo.add(
1759
- new CartesianPoint4("", holeX + radius, holeY, boardThickness)
1767
+ new CartesianPoint4("", holeX + radius, holeY, halfBoardThickness)
1760
1768
  )
1761
1769
  )
1762
1770
  );
@@ -1792,7 +1800,8 @@ async function circuitJsonToStep(circuitJson, options = {}) {
1792
1800
  const pillFaces = createPillCylindricalFaces(
1793
1801
  repo,
1794
1802
  hole,
1795
- boardThickness,
1803
+ -halfBoardThickness,
1804
+ halfBoardThickness,
1796
1805
  xDir,
1797
1806
  zDir
1798
1807
  );
@@ -1801,7 +1810,7 @@ async function circuitJsonToStep(circuitJson, options = {}) {
1801
1810
  }
1802
1811
  const allFaces = [bottomFace, topFace, ...sideFaces, ...holeCylindricalFaces];
1803
1812
  const shell = repo.add(new ClosedShell2("", allFaces));
1804
- const solid = repo.add(new ManifoldSolidBrep3(productName, shell));
1813
+ const solid = repo.add(new ManifoldSolidBrep4(productName, shell));
1805
1814
  const allSolids = [solid];
1806
1815
  let handledComponentIds = /* @__PURE__ */ new Set();
1807
1816
  let handledPcbComponentIds = /* @__PURE__ */ new Set();