circuit-json-to-step 0.0.30 → 0.0.32

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
@@ -828,7 +828,7 @@ function normalizeStepNumericExponents(stepText) {
828
828
  var package_default = {
829
829
  name: "circuit-json-to-step",
830
830
  main: "dist/index.js",
831
- version: "0.0.28",
831
+ version: "0.0.31",
832
832
  type: "module",
833
833
  scripts: {
834
834
  "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"' {} \\;`,
@@ -916,6 +916,26 @@ function rotatePoint(x, y, centerX, centerY, angle) {
916
916
  y: centerY + dx * sin + dy * cos
917
917
  };
918
918
  }
919
+ function createVertexAt(repo, x, y, z) {
920
+ return repo.add(
921
+ new VertexPoint2("", repo.add(new CartesianPoint3("", x, y, z)))
922
+ );
923
+ }
924
+ function createVertexCache(repo, z) {
925
+ const vertices = /* @__PURE__ */ new Map();
926
+ const normalize = (value) => {
927
+ const rounded = Number(value.toFixed(9));
928
+ return Object.is(rounded, -0) ? 0 : rounded;
929
+ };
930
+ return (x, y) => {
931
+ const key = `${normalize(x)},${normalize(y)},${normalize(z)}`;
932
+ const existing = vertices.get(key);
933
+ if (existing) return existing;
934
+ const vertex = createVertexAt(repo, x, y, z);
935
+ vertices.set(key, vertex);
936
+ return vertex;
937
+ };
938
+ }
919
939
  function createLineEdge(repo, v1, v2) {
920
940
  const p1 = v1.resolve(repo).pnt.resolve(repo);
921
941
  const p2 = v2.resolve(repo).pnt.resolve(repo);
@@ -934,228 +954,54 @@ function createLineEdge(repo, v1, v2) {
934
954
  const line = repo.add(new Line2("", v1.resolve(repo).pnt, vec));
935
955
  return repo.add(new EdgeCurve2("", v1, v2, line, true));
936
956
  }
937
- function createArcEdge(repo, centerX, centerY, z, radius, startAngle, endAngle, rotation, centerX0, centerY0) {
938
- const startX = centerX + radius * Math.cos(startAngle);
939
- const startY = centerY + radius * Math.sin(startAngle);
940
- const endX = centerX + radius * Math.cos(endAngle);
941
- const endY = centerY + radius * Math.sin(endAngle);
942
- const startRotated = rotatePoint(startX, startY, centerX0, centerY0, rotation);
943
- const endRotated = rotatePoint(endX, endY, centerX0, centerY0, rotation);
944
- const startVertex = repo.add(
945
- new VertexPoint2(
946
- "",
947
- repo.add(new CartesianPoint3("", startRotated.x, startRotated.y, z))
948
- )
949
- );
950
- const endVertex = repo.add(
951
- new VertexPoint2(
952
- "",
953
- repo.add(new CartesianPoint3("", endRotated.x, endRotated.y, z))
954
- )
955
- );
956
- const centerRotated = rotatePoint(
957
- centerX,
958
- centerY,
957
+ function createLineSegment(repo, start, end, getVertex) {
958
+ const startVertex = getVertex(start.x, start.y);
959
+ const endVertex = getVertex(end.x, end.y);
960
+ return {
961
+ kind: "line",
962
+ edge: createLineEdge(repo, startVertex, endVertex),
963
+ start: startVertex,
964
+ end: endVertex
965
+ };
966
+ }
967
+ function createArcSegment(repo, centerX, centerY, z, radius, startAngle, endAngle, rotation, centerX0, centerY0, getVertex) {
968
+ const start = rotatePoint(
969
+ centerX + radius * Math.cos(startAngle),
970
+ centerY + radius * Math.sin(startAngle),
959
971
  centerX0,
960
972
  centerY0,
961
973
  rotation
962
974
  );
963
- const centerPoint = repo.add(
964
- new CartesianPoint3("", centerRotated.x, centerRotated.y, z)
975
+ const end = rotatePoint(
976
+ centerX + radius * Math.cos(endAngle),
977
+ centerY + radius * Math.sin(endAngle),
978
+ centerX0,
979
+ centerY0,
980
+ rotation
965
981
  );
982
+ const center = rotatePoint(centerX, centerY, centerX0, centerY0, rotation);
983
+ const startVertex = getVertex(start.x, start.y);
984
+ const endVertex = getVertex(end.x, end.y);
985
+ const centerPoint = repo.add(new CartesianPoint3("", center.x, center.y, z));
966
986
  const normalDir = repo.add(new Direction3("", 0, 0, -1));
967
- const refAngle = rotation;
968
987
  const refDir = repo.add(
969
- new Direction3("", Math.cos(refAngle), Math.sin(refAngle), 0)
988
+ new Direction3("", Math.cos(rotation), Math.sin(rotation), 0)
970
989
  );
971
990
  const placement = repo.add(
972
991
  new Axis2Placement3D3("", centerPoint, normalDir, refDir)
973
992
  );
974
993
  const circle = repo.add(new Circle("", placement, radius));
975
- return repo.add(new EdgeCurve2("", startVertex, endVertex, circle, false));
976
- }
977
- function createPillHoleLoop(repo, hole, z, xDir) {
978
- const geom = getPillGeometry(hole);
979
- const {
994
+ return {
995
+ kind: "arc",
996
+ edge: repo.add(new EdgeCurve2("", startVertex, endVertex, circle, false)),
997
+ start: startVertex,
998
+ end: endVertex,
980
999
  centerX,
981
1000
  centerY,
982
- radius,
983
- straightHalfLength,
984
- rotation,
985
- isHorizontal
986
- } = geom;
987
- const edges = [];
988
- if (isHorizontal) {
989
- const capOffset = straightHalfLength;
990
- const rightArc = createArcEdge(
991
- repo,
992
- centerX + capOffset,
993
- centerY,
994
- z,
995
- radius,
996
- -Math.PI / 2,
997
- Math.PI / 2,
998
- rotation,
999
- centerX,
1000
- centerY
1001
- );
1002
- edges.push(rightArc);
1003
- const bottomStart = rotatePoint(
1004
- centerX + capOffset,
1005
- centerY - radius,
1006
- centerX,
1007
- centerY,
1008
- rotation
1009
- );
1010
- const bottomEnd = rotatePoint(
1011
- centerX - capOffset,
1012
- centerY - radius,
1013
- centerX,
1014
- centerY,
1015
- rotation
1016
- );
1017
- const bottomV1 = repo.add(
1018
- new VertexPoint2(
1019
- "",
1020
- repo.add(new CartesianPoint3("", bottomStart.x, bottomStart.y, z))
1021
- )
1022
- );
1023
- const bottomV2 = repo.add(
1024
- new VertexPoint2(
1025
- "",
1026
- repo.add(new CartesianPoint3("", bottomEnd.x, bottomEnd.y, z))
1027
- )
1028
- );
1029
- edges.push(createLineEdge(repo, bottomV1, bottomV2));
1030
- const leftArc = createArcEdge(
1031
- repo,
1032
- centerX - capOffset,
1033
- centerY,
1034
- z,
1035
- radius,
1036
- Math.PI / 2,
1037
- 3 * Math.PI / 2,
1038
- rotation,
1039
- centerX,
1040
- centerY
1041
- );
1042
- edges.push(leftArc);
1043
- const topStart = rotatePoint(
1044
- centerX - capOffset,
1045
- centerY + radius,
1046
- centerX,
1047
- centerY,
1048
- rotation
1049
- );
1050
- const topEnd = rotatePoint(
1051
- centerX + capOffset,
1052
- centerY + radius,
1053
- centerX,
1054
- centerY,
1055
- rotation
1056
- );
1057
- const topV1 = repo.add(
1058
- new VertexPoint2(
1059
- "",
1060
- repo.add(new CartesianPoint3("", topStart.x, topStart.y, z))
1061
- )
1062
- );
1063
- const topV2 = repo.add(
1064
- new VertexPoint2(
1065
- "",
1066
- repo.add(new CartesianPoint3("", topEnd.x, topEnd.y, z))
1067
- )
1068
- );
1069
- edges.push(createLineEdge(repo, topV1, topV2));
1070
- } else {
1071
- const capOffset = straightHalfLength;
1072
- const topArc = createArcEdge(
1073
- repo,
1074
- centerX,
1075
- centerY - capOffset,
1076
- z,
1077
- radius,
1078
- Math.PI,
1079
- 0,
1080
- rotation,
1081
- centerX,
1082
- centerY
1083
- );
1084
- edges.push(topArc);
1085
- const rightStart = rotatePoint(
1086
- centerX + radius,
1087
- centerY - capOffset,
1088
- centerX,
1089
- centerY,
1090
- rotation
1091
- );
1092
- const rightEnd = rotatePoint(
1093
- centerX + radius,
1094
- centerY + capOffset,
1095
- centerX,
1096
- centerY,
1097
- rotation
1098
- );
1099
- const rightV1 = repo.add(
1100
- new VertexPoint2(
1101
- "",
1102
- repo.add(new CartesianPoint3("", rightStart.x, rightStart.y, z))
1103
- )
1104
- );
1105
- const rightV2 = repo.add(
1106
- new VertexPoint2(
1107
- "",
1108
- repo.add(new CartesianPoint3("", rightEnd.x, rightEnd.y, z))
1109
- )
1110
- );
1111
- edges.push(createLineEdge(repo, rightV1, rightV2));
1112
- const bottomArc = createArcEdge(
1113
- repo,
1114
- centerX,
1115
- centerY + capOffset,
1116
- z,
1117
- radius,
1118
- 0,
1119
- Math.PI,
1120
- rotation,
1121
- centerX,
1122
- centerY
1123
- );
1124
- edges.push(bottomArc);
1125
- const leftStart = rotatePoint(
1126
- centerX - radius,
1127
- centerY + capOffset,
1128
- centerX,
1129
- centerY,
1130
- rotation
1131
- );
1132
- const leftEnd = rotatePoint(
1133
- centerX - radius,
1134
- centerY - capOffset,
1135
- centerX,
1136
- centerY,
1137
- rotation
1138
- );
1139
- const leftV1 = repo.add(
1140
- new VertexPoint2(
1141
- "",
1142
- repo.add(new CartesianPoint3("", leftStart.x, leftStart.y, z))
1143
- )
1144
- );
1145
- const leftV2 = repo.add(
1146
- new VertexPoint2(
1147
- "",
1148
- repo.add(new CartesianPoint3("", leftEnd.x, leftEnd.y, z))
1149
- )
1150
- );
1151
- edges.push(createLineEdge(repo, leftV1, leftV2));
1152
- }
1153
- const orientedEdges = edges.map(
1154
- (edge) => repo.add(new OrientedEdge2("", edge, true))
1155
- );
1156
- return repo.add(new EdgeLoop2("", orientedEdges));
1001
+ radius
1002
+ };
1157
1003
  }
1158
- function createPillCylindricalFaces(repo, hole, zMin, zMax, xDir, zDir) {
1004
+ function createPillBoundarySegments(repo, hole, z) {
1159
1005
  const geom = getPillGeometry(hole);
1160
1006
  const {
1161
1007
  centerX,
@@ -1165,341 +1011,243 @@ function createPillCylindricalFaces(repo, hole, zMin, zMax, xDir, zDir) {
1165
1011
  rotation,
1166
1012
  isHorizontal
1167
1013
  } = geom;
1168
- const faces = [];
1014
+ const capOffset = straightHalfLength;
1015
+ const getVertex = createVertexCache(repo, z);
1169
1016
  if (isHorizontal) {
1170
- const capOffset = straightHalfLength;
1171
- faces.push(
1172
- createCylindricalWall(
1017
+ return [
1018
+ createArcSegment(
1173
1019
  repo,
1174
1020
  centerX + capOffset,
1175
1021
  centerY,
1022
+ z,
1176
1023
  radius,
1177
1024
  -Math.PI / 2,
1178
1025
  Math.PI / 2,
1179
1026
  rotation,
1180
1027
  centerX,
1181
1028
  centerY,
1182
- zMin,
1183
- zMax,
1184
- zDir,
1185
- xDir
1186
- )
1187
- );
1188
- faces.push(
1189
- createPlanarWall(
1029
+ getVertex
1030
+ ),
1031
+ createLineSegment(
1190
1032
  repo,
1191
- centerX - capOffset,
1192
- centerY - radius,
1193
- centerX + capOffset,
1194
- centerY - radius,
1195
- rotation,
1196
- centerX,
1197
- centerY,
1198
- zMin,
1199
- zMax,
1200
- zDir
1201
- )
1202
- );
1203
- faces.push(
1204
- createCylindricalWall(
1033
+ rotatePoint(
1034
+ centerX + capOffset,
1035
+ centerY - radius,
1036
+ centerX,
1037
+ centerY,
1038
+ rotation
1039
+ ),
1040
+ rotatePoint(
1041
+ centerX - capOffset,
1042
+ centerY - radius,
1043
+ centerX,
1044
+ centerY,
1045
+ rotation
1046
+ ),
1047
+ getVertex
1048
+ ),
1049
+ createArcSegment(
1205
1050
  repo,
1206
1051
  centerX - capOffset,
1207
1052
  centerY,
1053
+ z,
1208
1054
  radius,
1209
1055
  Math.PI / 2,
1210
1056
  3 * Math.PI / 2,
1211
1057
  rotation,
1212
1058
  centerX,
1213
1059
  centerY,
1214
- zMin,
1215
- zMax,
1216
- zDir,
1217
- xDir
1218
- )
1219
- );
1220
- faces.push(
1221
- createPlanarWall(
1060
+ getVertex
1061
+ ),
1062
+ createLineSegment(
1222
1063
  repo,
1223
- centerX + capOffset,
1224
- centerY + radius,
1225
- centerX - capOffset,
1226
- centerY + radius,
1227
- rotation,
1228
- centerX,
1229
- centerY,
1230
- zMin,
1231
- zMax,
1232
- zDir
1064
+ rotatePoint(
1065
+ centerX - capOffset,
1066
+ centerY + radius,
1067
+ centerX,
1068
+ centerY,
1069
+ rotation
1070
+ ),
1071
+ rotatePoint(
1072
+ centerX + capOffset,
1073
+ centerY + radius,
1074
+ centerX,
1075
+ centerY,
1076
+ rotation
1077
+ ),
1078
+ getVertex
1233
1079
  )
1234
- );
1235
- } else {
1236
- const capOffset = straightHalfLength;
1237
- faces.push(
1238
- createCylindricalWall(
1239
- repo,
1240
- centerX,
1080
+ ];
1081
+ }
1082
+ return [
1083
+ createArcSegment(
1084
+ repo,
1085
+ centerX,
1086
+ centerY - capOffset,
1087
+ z,
1088
+ radius,
1089
+ Math.PI,
1090
+ 0,
1091
+ rotation,
1092
+ centerX,
1093
+ centerY,
1094
+ getVertex
1095
+ ),
1096
+ createLineSegment(
1097
+ repo,
1098
+ rotatePoint(
1099
+ centerX + radius,
1241
1100
  centerY - capOffset,
1242
- radius,
1243
- Math.PI,
1244
- 0,
1245
- rotation,
1246
1101
  centerX,
1247
1102
  centerY,
1248
- zMin,
1249
- zMax,
1250
- zDir,
1251
- xDir
1252
- )
1253
- );
1254
- faces.push(
1255
- createPlanarWall(
1256
- repo,
1257
- centerX + radius,
1258
- centerY - capOffset,
1103
+ rotation
1104
+ ),
1105
+ rotatePoint(
1259
1106
  centerX + radius,
1260
1107
  centerY + capOffset,
1261
- rotation,
1262
1108
  centerX,
1263
1109
  centerY,
1264
- zMin,
1265
- zMax,
1266
- zDir
1267
- )
1268
- );
1269
- faces.push(
1270
- createCylindricalWall(
1271
- repo,
1272
- centerX,
1110
+ rotation
1111
+ ),
1112
+ getVertex
1113
+ ),
1114
+ createArcSegment(
1115
+ repo,
1116
+ centerX,
1117
+ centerY + capOffset,
1118
+ z,
1119
+ radius,
1120
+ 0,
1121
+ Math.PI,
1122
+ rotation,
1123
+ centerX,
1124
+ centerY,
1125
+ getVertex
1126
+ ),
1127
+ createLineSegment(
1128
+ repo,
1129
+ rotatePoint(
1130
+ centerX - radius,
1273
1131
  centerY + capOffset,
1274
- radius,
1275
- 0,
1276
- Math.PI,
1277
- rotation,
1278
1132
  centerX,
1279
1133
  centerY,
1280
- zMin,
1281
- zMax,
1282
- zDir,
1283
- xDir
1284
- )
1285
- );
1286
- faces.push(
1287
- createPlanarWall(
1288
- repo,
1289
- centerX - radius,
1290
- centerY + capOffset,
1134
+ rotation
1135
+ ),
1136
+ rotatePoint(
1291
1137
  centerX - radius,
1292
1138
  centerY - capOffset,
1293
- rotation,
1294
1139
  centerX,
1295
1140
  centerY,
1296
- zMin,
1297
- zMax,
1298
- zDir
1299
- )
1300
- );
1301
- }
1302
- return faces;
1303
- }
1304
- function createCylindricalWall(repo, centerX, centerY, radius, startAngle, endAngle, rotation, centerX0, centerY0, zMin, zMax, zDir, xDir) {
1305
- const bottomStartX = centerX + radius * Math.cos(startAngle);
1306
- const bottomStartY = centerY + radius * Math.sin(startAngle);
1307
- const bottomEndX = centerX + radius * Math.cos(endAngle);
1308
- const bottomEndY = centerY + radius * Math.sin(endAngle);
1309
- const bottomStart = rotatePoint(
1310
- bottomStartX,
1311
- bottomStartY,
1312
- centerX0,
1313
- centerY0,
1314
- rotation
1315
- );
1316
- const bottomEnd = rotatePoint(
1317
- bottomEndX,
1318
- bottomEndY,
1319
- centerX0,
1320
- centerY0,
1321
- rotation
1322
- );
1323
- const bottomStartVertex = repo.add(
1324
- new VertexPoint2(
1325
- "",
1326
- repo.add(new CartesianPoint3("", bottomStart.x, bottomStart.y, zMin))
1327
- )
1328
- );
1329
- const bottomEndVertex = repo.add(
1330
- new VertexPoint2(
1331
- "",
1332
- repo.add(new CartesianPoint3("", bottomEnd.x, bottomEnd.y, zMin))
1333
- )
1334
- );
1335
- const topStart = repo.add(
1336
- new VertexPoint2(
1337
- "",
1338
- repo.add(new CartesianPoint3("", bottomStart.x, bottomStart.y, zMax))
1339
- )
1340
- );
1341
- const topEnd = repo.add(
1342
- new VertexPoint2(
1343
- "",
1344
- repo.add(new CartesianPoint3("", bottomEnd.x, bottomEnd.y, zMax))
1141
+ rotation
1142
+ ),
1143
+ getVertex
1345
1144
  )
1346
- );
1347
- const centerRotated = rotatePoint(
1348
- centerX,
1349
- centerY,
1350
- centerX0,
1351
- centerY0,
1352
- rotation
1353
- );
1354
- const bottomCenter = repo.add(
1355
- new CartesianPoint3("", centerRotated.x, centerRotated.y, zMin)
1356
- );
1357
- const bottomPlacement = repo.add(
1358
- new Axis2Placement3D3(
1359
- "",
1360
- bottomCenter,
1361
- repo.add(new Direction3("", 0, 0, -1)),
1362
- xDir
1363
- )
1364
- );
1365
- const bottomCircle = repo.add(new Circle("", bottomPlacement, radius));
1366
- const bottomArc = repo.add(
1367
- new EdgeCurve2("", bottomStartVertex, bottomEndVertex, bottomCircle, false)
1368
- );
1369
- const topCenter = repo.add(
1370
- new CartesianPoint3("", centerRotated.x, centerRotated.y, zMax)
1371
- );
1372
- const topPlacement = repo.add(new Axis2Placement3D3("", topCenter, zDir, xDir));
1373
- const topCircle = repo.add(new Circle("", topPlacement, radius));
1374
- const topArc = repo.add(new EdgeCurve2("", topEnd, topStart, topCircle, false));
1375
- const v1 = repo.add(
1376
- new VertexPoint2(
1377
- "",
1378
- repo.add(new CartesianPoint3("", bottomStart.x, bottomStart.y, zMin))
1379
- )
1380
- );
1381
- const v2 = repo.add(
1382
- new VertexPoint2(
1383
- "",
1384
- repo.add(new CartesianPoint3("", bottomStart.x, bottomStart.y, zMax))
1385
- )
1386
- );
1387
- const v3 = repo.add(
1388
- new VertexPoint2(
1389
- "",
1390
- repo.add(new CartesianPoint3("", bottomEnd.x, bottomEnd.y, zMin))
1391
- )
1392
- );
1393
- const v4 = repo.add(
1394
- new VertexPoint2(
1395
- "",
1396
- repo.add(new CartesianPoint3("", bottomEnd.x, bottomEnd.y, zMax))
1397
- )
1398
- );
1399
- const dir1 = repo.add(new Direction3("", 0, 0, 1));
1400
- const height = zMax - zMin;
1401
- const vec1 = repo.add(new Vector2("", dir1, height));
1402
- const line1 = repo.add(new Line2("", v1.resolve(repo).pnt, vec1));
1403
- const edge1 = repo.add(new EdgeCurve2("", v1, v2, line1, true));
1404
- const dir2 = repo.add(new Direction3("", 0, 0, 1));
1405
- const vec2 = repo.add(new Vector2("", dir2, height));
1406
- const line2 = repo.add(new Line2("", v3.resolve(repo).pnt, vec2));
1407
- const edge2 = repo.add(new EdgeCurve2("", v3, v4, line2, true));
1408
- const loop = repo.add(
1409
- new EdgeLoop2("", [
1410
- repo.add(new OrientedEdge2("", bottomArc, true)),
1411
- repo.add(new OrientedEdge2("", edge2, true)),
1412
- repo.add(new OrientedEdge2("", topArc, false)),
1413
- repo.add(new OrientedEdge2("", edge1, false))
1414
- ])
1415
- );
1416
- const cylinderPlacement = repo.add(
1417
- new Axis2Placement3D3("", bottomCenter, zDir, xDir)
1418
- );
1419
- const cylinderSurface = repo.add(
1420
- new CylindricalSurface("", cylinderPlacement, radius)
1421
- );
1422
- return repo.add(
1423
- new AdvancedFace2(
1424
- "",
1425
- [repo.add(new FaceOuterBound2("", loop, true))],
1426
- cylinderSurface,
1427
- false
1428
- )
1429
- );
1145
+ ];
1430
1146
  }
1431
- function createPlanarWall(repo, startX, startY, endX, endY, rotation, centerX0, centerY0, zMin, zMax, zDir) {
1432
- const start = rotatePoint(startX, startY, centerX0, centerY0, rotation);
1433
- const end = rotatePoint(endX, endY, centerX0, centerY0, rotation);
1434
- const v1 = repo.add(
1435
- new VertexPoint2(
1436
- "",
1437
- repo.add(new CartesianPoint3("", start.x, start.y, zMin))
1438
- )
1439
- );
1440
- const v2 = repo.add(
1441
- new VertexPoint2("", repo.add(new CartesianPoint3("", end.x, end.y, zMin)))
1442
- );
1443
- const v3 = repo.add(
1444
- new VertexPoint2("", repo.add(new CartesianPoint3("", end.x, end.y, zMax)))
1445
- );
1446
- const v4 = repo.add(
1447
- new VertexPoint2(
1448
- "",
1449
- repo.add(new CartesianPoint3("", start.x, start.y, zMax))
1450
- )
1451
- );
1452
- const dx = end.x - start.x;
1453
- const dy = end.y - start.y;
1454
- const edgeLength = Math.sqrt(dx * dx + dy * dy);
1455
- const bottomDir = repo.add(
1456
- new Direction3("", dx / edgeLength, dy / edgeLength, 0)
1457
- );
1458
- const bottomVec = repo.add(new Vector2("", bottomDir, edgeLength));
1459
- const bottomLine = repo.add(new Line2("", v1.resolve(repo).pnt, bottomVec));
1460
- const bottomEdge = repo.add(new EdgeCurve2("", v1, v2, bottomLine, true));
1461
- const topDir = repo.add(
1462
- new Direction3("", dx / edgeLength, dy / edgeLength, 0)
1463
- );
1464
- const topVec = repo.add(new Vector2("", topDir, edgeLength));
1465
- const topLine = repo.add(new Line2("", v4.resolve(repo).pnt, topVec));
1466
- const topEdge = repo.add(new EdgeCurve2("", v4, v3, topLine, true));
1467
- const vertDir = repo.add(new Direction3("", 0, 0, 1));
1468
- const height = zMax - zMin;
1469
- const vertVec1 = repo.add(new Vector2("", vertDir, height));
1470
- const vertLine1 = repo.add(new Line2("", v2.resolve(repo).pnt, vertVec1));
1471
- const vertEdge1 = repo.add(new EdgeCurve2("", v2, v3, vertLine1, true));
1472
- const vertVec2 = repo.add(new Vector2("", vertDir, height));
1473
- const vertLine2 = repo.add(new Line2("", v1.resolve(repo).pnt, vertVec2));
1474
- const vertEdge2 = repo.add(new EdgeCurve2("", v1, v4, vertLine2, true));
1475
- const loop = repo.add(
1476
- new EdgeLoop2("", [
1477
- repo.add(new OrientedEdge2("", bottomEdge, true)),
1478
- repo.add(new OrientedEdge2("", vertEdge1, true)),
1479
- repo.add(new OrientedEdge2("", topEdge, false)),
1480
- repo.add(new OrientedEdge2("", vertEdge2, false))
1481
- ])
1482
- );
1483
- const normalDir = repo.add(
1484
- new Direction3("", dy / edgeLength, -dx / edgeLength, 0)
1485
- );
1486
- const refDir = repo.add(
1487
- new Direction3("", dx / edgeLength, dy / edgeLength, 0)
1488
- );
1489
- const planeOrigin = repo.add(new CartesianPoint3("", start.x, start.y, zMin));
1490
- const placement = repo.add(
1491
- new Axis2Placement3D3("", planeOrigin, normalDir, refDir)
1492
- );
1493
- const plane = repo.add(new Plane2("", placement));
1147
+ function createLoopFromSegments(repo, segments, orientation) {
1494
1148
  return repo.add(
1495
- new AdvancedFace2(
1149
+ new EdgeLoop2(
1496
1150
  "",
1497
- [repo.add(new FaceOuterBound2("", loop, true))],
1498
- plane,
1499
- true
1151
+ segments.map(
1152
+ (segment) => repo.add(new OrientedEdge2("", segment.edge, orientation))
1153
+ )
1500
1154
  )
1501
1155
  );
1502
1156
  }
1157
+ function createPillHoleGeometry(repo, hole, zMin, zMax, zDir) {
1158
+ const geom = getPillGeometry(hole);
1159
+ const bottomSegments = createPillBoundarySegments(repo, hole, zMin);
1160
+ const topSegments = createPillBoundarySegments(repo, hole, zMax);
1161
+ const bottomLoop = createLoopFromSegments(repo, bottomSegments, true);
1162
+ const topLoop = createLoopFromSegments(repo, topSegments, true);
1163
+ const wallFaces = [];
1164
+ const verticalEdges = /* @__PURE__ */ new Map();
1165
+ const getVerticalEdge = (bottomVertex, topVertex) => {
1166
+ const key = `${bottomVertex.id}:${topVertex.id}`;
1167
+ const existing = verticalEdges.get(key);
1168
+ if (existing) return existing;
1169
+ const edge = createLineEdge(repo, bottomVertex, topVertex);
1170
+ verticalEdges.set(key, edge);
1171
+ return edge;
1172
+ };
1173
+ for (let i = 0; i < bottomSegments.length; i++) {
1174
+ const bottomSegment = bottomSegments[i];
1175
+ const topSegment = topSegments[i];
1176
+ const startVertical = getVerticalEdge(bottomSegment.start, topSegment.start);
1177
+ const endVertical = getVerticalEdge(bottomSegment.end, topSegment.end);
1178
+ const loop = repo.add(
1179
+ new EdgeLoop2("", [
1180
+ repo.add(new OrientedEdge2("", bottomSegment.edge, true)),
1181
+ repo.add(new OrientedEdge2("", endVertical, true)),
1182
+ repo.add(new OrientedEdge2("", topSegment.edge, false)),
1183
+ repo.add(new OrientedEdge2("", startVertical, false))
1184
+ ])
1185
+ );
1186
+ if (bottomSegment.kind === "arc") {
1187
+ const center = rotatePoint(
1188
+ bottomSegment.centerX,
1189
+ bottomSegment.centerY,
1190
+ geom.centerX,
1191
+ geom.centerY,
1192
+ geom.rotation
1193
+ );
1194
+ const bottomCenter = repo.add(
1195
+ new CartesianPoint3("", center.x, center.y, zMin)
1196
+ );
1197
+ const refDir2 = repo.add(
1198
+ new Direction3("", Math.cos(geom.rotation), Math.sin(geom.rotation), 0)
1199
+ );
1200
+ const cylinderPlacement = repo.add(
1201
+ new Axis2Placement3D3("", bottomCenter, zDir, refDir2)
1202
+ );
1203
+ const cylinderSurface = repo.add(
1204
+ new CylindricalSurface("", cylinderPlacement, bottomSegment.radius)
1205
+ );
1206
+ wallFaces.push(
1207
+ repo.add(
1208
+ new AdvancedFace2(
1209
+ "",
1210
+ [repo.add(new FaceOuterBound2("", loop, true))],
1211
+ cylinderSurface,
1212
+ false
1213
+ )
1214
+ )
1215
+ );
1216
+ continue;
1217
+ }
1218
+ const startPoint = bottomSegment.start.resolve(repo).pnt.resolve(repo);
1219
+ const endPoint = bottomSegment.end.resolve(repo).pnt.resolve(repo);
1220
+ const dx = endPoint.x - startPoint.x;
1221
+ const dy = endPoint.y - startPoint.y;
1222
+ const edgeLength = Math.sqrt(dx * dx + dy * dy);
1223
+ const normalDir = repo.add(
1224
+ new Direction3("", dy / edgeLength, -dx / edgeLength, 0)
1225
+ );
1226
+ const refDir = repo.add(
1227
+ new Direction3("", dx / edgeLength, dy / edgeLength, 0)
1228
+ );
1229
+ const placement = repo.add(
1230
+ new Axis2Placement3D3(
1231
+ "",
1232
+ bottomSegment.start.resolve(repo).pnt,
1233
+ normalDir,
1234
+ refDir
1235
+ )
1236
+ );
1237
+ const plane = repo.add(new Plane2("", placement));
1238
+ wallFaces.push(
1239
+ repo.add(
1240
+ new AdvancedFace2(
1241
+ "",
1242
+ [repo.add(new FaceOuterBound2("", loop, true))],
1243
+ plane,
1244
+ true
1245
+ )
1246
+ )
1247
+ );
1248
+ }
1249
+ return { bottomLoop, topLoop, wallFaces };
1250
+ }
1503
1251
 
1504
1252
  // lib/index.ts
1505
1253
  async function circuitJsonToStep(circuitJson, options = {}) {
@@ -1711,53 +1459,6 @@ async function circuitJsonToStep(circuitJson, options = {}) {
1711
1459
  bottomEdges.map((edge) => repo.add(new OrientedEdge3("", edge, true)))
1712
1460
  )
1713
1461
  );
1714
- const bottomHoleLoops = [];
1715
- for (const hole of holes) {
1716
- const holeShape = hole.hole_shape ?? hole.shape;
1717
- if (holeShape === "circle") {
1718
- const holeX = typeof hole.x === "number" ? hole.x : hole.x ?? 0;
1719
- const holeY = typeof hole.y === "number" ? hole.y : hole.y ?? 0;
1720
- const radius = (hole.hole_diameter ?? 0) / 2;
1721
- const holeCenter = repo.add(
1722
- new CartesianPoint4("", holeX, holeY, -halfBoardThickness)
1723
- );
1724
- const holeVertex = repo.add(
1725
- new VertexPoint3(
1726
- "",
1727
- repo.add(
1728
- new CartesianPoint4("", holeX + radius, holeY, -halfBoardThickness)
1729
- )
1730
- )
1731
- );
1732
- const holePlacement = repo.add(
1733
- new Axis2Placement3D4(
1734
- "",
1735
- holeCenter,
1736
- repo.add(new Direction4("", 0, 0, -1)),
1737
- xDir
1738
- )
1739
- );
1740
- const holeCircle = repo.add(new Circle2("", holePlacement, radius));
1741
- const holeEdge = repo.add(
1742
- new EdgeCurve3("", holeVertex, holeVertex, holeCircle, true)
1743
- );
1744
- const holeLoop = repo.add(
1745
- new EdgeLoop3("", [repo.add(new OrientedEdge3("", holeEdge, false))])
1746
- );
1747
- bottomHoleLoops.push(repo.add(new FaceBound("", holeLoop, true)));
1748
- } else if (holeShape === "rotated_pill" || holeShape === "pill") {
1749
- const pillLoop = createPillHoleLoop(repo, hole, -halfBoardThickness, xDir);
1750
- bottomHoleLoops.push(repo.add(new FaceBound("", pillLoop, true)));
1751
- }
1752
- }
1753
- const bottomFace = repo.add(
1754
- new AdvancedFace3(
1755
- "",
1756
- [repo.add(new FaceOuterBound3("", bottomLoop, true)), ...bottomHoleLoops],
1757
- bottomPlane,
1758
- true
1759
- )
1760
- );
1761
1462
  const topOrigin = repo.add(new CartesianPoint4("", 0, 0, halfBoardThickness));
1762
1463
  const topFrame = repo.add(new Axis2Placement3D4("", topOrigin, zDir, xDir));
1763
1464
  const topPlane = repo.add(new Plane3("", topFrame));
@@ -1767,40 +1468,124 @@ async function circuitJsonToStep(circuitJson, options = {}) {
1767
1468
  topEdges.map((edge) => repo.add(new OrientedEdge3("", edge, false)))
1768
1469
  )
1769
1470
  );
1770
- const topHoleLoops = [];
1471
+ function getHoleCoordinate(coordinate) {
1472
+ if (typeof coordinate === "number") return coordinate;
1473
+ return coordinate?.value ?? 0;
1474
+ }
1475
+ function createCircularHoleGeometry(hole) {
1476
+ const holeX = getHoleCoordinate(hole.x);
1477
+ const holeY = getHoleCoordinate(hole.y);
1478
+ const radius = (hole.hole_diameter ?? 0) / 2;
1479
+ const bottomHoleCenter = repo.add(
1480
+ new CartesianPoint4("", holeX, holeY, -halfBoardThickness)
1481
+ );
1482
+ const bottomHoleVertex = repo.add(
1483
+ new VertexPoint3(
1484
+ "",
1485
+ repo.add(
1486
+ new CartesianPoint4("", holeX + radius, holeY, -halfBoardThickness)
1487
+ )
1488
+ )
1489
+ );
1490
+ const bottomHolePlacement = repo.add(
1491
+ new Axis2Placement3D4(
1492
+ "",
1493
+ bottomHoleCenter,
1494
+ repo.add(new Direction4("", 0, 0, -1)),
1495
+ xDir
1496
+ )
1497
+ );
1498
+ const bottomHoleCircle = repo.add(
1499
+ new Circle2("", bottomHolePlacement, radius)
1500
+ );
1501
+ const bottomHoleEdge = repo.add(
1502
+ new EdgeCurve3(
1503
+ "",
1504
+ bottomHoleVertex,
1505
+ bottomHoleVertex,
1506
+ bottomHoleCircle,
1507
+ true
1508
+ )
1509
+ );
1510
+ const topHoleCenter = repo.add(
1511
+ new CartesianPoint4("", holeX, holeY, halfBoardThickness)
1512
+ );
1513
+ const topHoleVertex = repo.add(
1514
+ new VertexPoint3(
1515
+ "",
1516
+ repo.add(
1517
+ new CartesianPoint4("", holeX + radius, holeY, halfBoardThickness)
1518
+ )
1519
+ )
1520
+ );
1521
+ const topHolePlacement = repo.add(
1522
+ new Axis2Placement3D4("", topHoleCenter, zDir, xDir)
1523
+ );
1524
+ const topHoleCircle = repo.add(new Circle2("", topHolePlacement, radius));
1525
+ const topHoleEdge = repo.add(
1526
+ new EdgeCurve3("", topHoleVertex, topHoleVertex, topHoleCircle, true)
1527
+ );
1528
+ const bottomLoop2 = repo.add(
1529
+ new EdgeLoop3("", [repo.add(new OrientedEdge3("", bottomHoleEdge, false))])
1530
+ );
1531
+ const topLoop2 = repo.add(
1532
+ new EdgeLoop3("", [repo.add(new OrientedEdge3("", topHoleEdge, true))])
1533
+ );
1534
+ const wallLoop = repo.add(
1535
+ new EdgeLoop3("", [
1536
+ repo.add(new OrientedEdge3("", bottomHoleEdge, true)),
1537
+ repo.add(new OrientedEdge3("", topHoleEdge, false))
1538
+ ])
1539
+ );
1540
+ const holeCylinderPlacement = repo.add(
1541
+ new Axis2Placement3D4("", bottomHoleCenter, zDir, xDir)
1542
+ );
1543
+ const holeCylinderSurface = repo.add(
1544
+ new CylindricalSurface2("", holeCylinderPlacement, radius)
1545
+ );
1546
+ const wallFace = repo.add(
1547
+ new AdvancedFace3(
1548
+ "",
1549
+ [repo.add(new FaceOuterBound3("", wallLoop, true))],
1550
+ holeCylinderSurface,
1551
+ false
1552
+ )
1553
+ );
1554
+ return { bottomLoop: bottomLoop2, topLoop: topLoop2, wallFaces: [wallFace] };
1555
+ }
1556
+ const sharedHoleGeometries = [];
1771
1557
  for (const hole of holes) {
1772
1558
  const holeShape = hole.hole_shape ?? hole.shape;
1773
1559
  if (holeShape === "circle") {
1774
- const holeX = typeof hole.x === "number" ? hole.x : hole.x ?? 0;
1775
- const holeY = typeof hole.y === "number" ? hole.y : hole.y ?? 0;
1776
- const radius = (hole.hole_diameter ?? 0) / 2;
1777
- const holeCenter = repo.add(
1778
- new CartesianPoint4("", holeX, holeY, halfBoardThickness)
1779
- );
1780
- const holeVertex = repo.add(
1781
- new VertexPoint3(
1782
- "",
1783
- repo.add(
1784
- new CartesianPoint4("", holeX + radius, holeY, halfBoardThickness)
1785
- )
1560
+ sharedHoleGeometries.push(createCircularHoleGeometry(hole));
1561
+ } else if (holeShape === "rotated_pill" || holeShape === "pill") {
1562
+ sharedHoleGeometries.push(
1563
+ createPillHoleGeometry(
1564
+ repo,
1565
+ hole,
1566
+ -halfBoardThickness,
1567
+ halfBoardThickness,
1568
+ zDir
1786
1569
  )
1787
1570
  );
1788
- const holePlacement = repo.add(
1789
- new Axis2Placement3D4("", holeCenter, zDir, xDir)
1790
- );
1791
- const holeCircle = repo.add(new Circle2("", holePlacement, radius));
1792
- const holeEdge = repo.add(
1793
- new EdgeCurve3("", holeVertex, holeVertex, holeCircle, true)
1794
- );
1795
- const holeLoop = repo.add(
1796
- new EdgeLoop3("", [repo.add(new OrientedEdge3("", holeEdge, true))])
1797
- );
1798
- topHoleLoops.push(repo.add(new FaceBound("", holeLoop, true)));
1799
- } else if (holeShape === "rotated_pill" || holeShape === "pill") {
1800
- const pillLoop = createPillHoleLoop(repo, hole, halfBoardThickness, xDir);
1801
- topHoleLoops.push(repo.add(new FaceBound("", pillLoop, true)));
1802
1571
  }
1803
1572
  }
1573
+ const bottomHoleLoops = [];
1574
+ const topHoleLoops = [];
1575
+ for (const holeGeometry of sharedHoleGeometries) {
1576
+ bottomHoleLoops.push(
1577
+ repo.add(new FaceBound("", holeGeometry.bottomLoop, true))
1578
+ );
1579
+ topHoleLoops.push(repo.add(new FaceBound("", holeGeometry.topLoop, true)));
1580
+ }
1581
+ const bottomFace = repo.add(
1582
+ new AdvancedFace3(
1583
+ "",
1584
+ [repo.add(new FaceOuterBound3("", bottomLoop, true)), ...bottomHoleLoops],
1585
+ bottomPlane,
1586
+ true
1587
+ )
1588
+ );
1804
1589
  const topFace = repo.add(
1805
1590
  new AdvancedFace3(
1806
1591
  "",
@@ -1809,6 +1594,10 @@ async function circuitJsonToStep(circuitJson, options = {}) {
1809
1594
  true
1810
1595
  )
1811
1596
  );
1597
+ const holeCylindricalFaces = [];
1598
+ for (const holeGeometry of sharedHoleGeometries) {
1599
+ holeCylindricalFaces.push(...holeGeometry.wallFaces);
1600
+ }
1812
1601
  const sideFaces = [];
1813
1602
  for (let i = 0; i < bottomEdges.length; i++) {
1814
1603
  const nextI = (i + 1) % bottomEdges.length;
@@ -1845,95 +1634,6 @@ async function circuitJsonToStep(circuitJson, options = {}) {
1845
1634
  );
1846
1635
  sideFaces.push(sideFace);
1847
1636
  }
1848
- const holeCylindricalFaces = [];
1849
- for (const hole of holes) {
1850
- const holeShape = hole.hole_shape ?? hole.shape;
1851
- if (holeShape === "circle") {
1852
- const holeX = typeof hole.x === "number" ? hole.x : hole.x ?? 0;
1853
- const holeY = typeof hole.y === "number" ? hole.y : hole.y ?? 0;
1854
- const radius = (hole.hole_diameter ?? 0) / 2;
1855
- const bottomHoleCenter = repo.add(
1856
- new CartesianPoint4("", holeX, holeY, -halfBoardThickness)
1857
- );
1858
- const bottomHoleVertex = repo.add(
1859
- new VertexPoint3(
1860
- "",
1861
- repo.add(
1862
- new CartesianPoint4("", holeX + radius, holeY, -halfBoardThickness)
1863
- )
1864
- )
1865
- );
1866
- const bottomHolePlacement = repo.add(
1867
- new Axis2Placement3D4(
1868
- "",
1869
- bottomHoleCenter,
1870
- repo.add(new Direction4("", 0, 0, -1)),
1871
- xDir
1872
- )
1873
- );
1874
- const bottomHoleCircle = repo.add(
1875
- new Circle2("", bottomHolePlacement, radius)
1876
- );
1877
- const bottomHoleEdge = repo.add(
1878
- new EdgeCurve3(
1879
- "",
1880
- bottomHoleVertex,
1881
- bottomHoleVertex,
1882
- bottomHoleCircle,
1883
- true
1884
- )
1885
- );
1886
- const topHoleCenter = repo.add(
1887
- new CartesianPoint4("", holeX, holeY, halfBoardThickness)
1888
- );
1889
- const topHoleVertex = repo.add(
1890
- new VertexPoint3(
1891
- "",
1892
- repo.add(
1893
- new CartesianPoint4("", holeX + radius, holeY, halfBoardThickness)
1894
- )
1895
- )
1896
- );
1897
- const topHolePlacement = repo.add(
1898
- new Axis2Placement3D4("", topHoleCenter, zDir, xDir)
1899
- );
1900
- const topHoleCircle = repo.add(new Circle2("", topHolePlacement, radius));
1901
- const topHoleEdge = repo.add(
1902
- new EdgeCurve3("", topHoleVertex, topHoleVertex, topHoleCircle, true)
1903
- );
1904
- const holeCylinderLoop = repo.add(
1905
- new EdgeLoop3("", [
1906
- repo.add(new OrientedEdge3("", bottomHoleEdge, true)),
1907
- repo.add(new OrientedEdge3("", topHoleEdge, false))
1908
- ])
1909
- );
1910
- const holeCylinderPlacement = repo.add(
1911
- new Axis2Placement3D4("", bottomHoleCenter, zDir, xDir)
1912
- );
1913
- const holeCylinderSurface = repo.add(
1914
- new CylindricalSurface2("", holeCylinderPlacement, radius)
1915
- );
1916
- const holeCylinderFace = repo.add(
1917
- new AdvancedFace3(
1918
- "",
1919
- [repo.add(new FaceOuterBound3("", holeCylinderLoop, true))],
1920
- holeCylinderSurface,
1921
- false
1922
- )
1923
- );
1924
- holeCylindricalFaces.push(holeCylinderFace);
1925
- } else if (holeShape === "rotated_pill" || holeShape === "pill") {
1926
- const pillFaces = createPillCylindricalFaces(
1927
- repo,
1928
- hole,
1929
- -halfBoardThickness,
1930
- halfBoardThickness,
1931
- xDir,
1932
- zDir
1933
- );
1934
- holeCylindricalFaces.push(...pillFaces);
1935
- }
1936
- }
1937
1637
  const allFaces = [bottomFace, topFace, ...sideFaces, ...holeCylindricalFaces];
1938
1638
  const styleCache = createStyleCache();
1939
1639
  const boardStyledItems = createStyledItems(repo, {