@tscircuit/parts-engine 0.0.20 → 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.js +167 -27
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -8869,11 +8869,11 @@ function generateArcFromSweep(startX, startY, endX, endY, radius, largeArcFlag,
|
|
|
8869
8869
|
const midY = (startY + endY) / 2;
|
|
8870
8870
|
const dx = endX - startX;
|
|
8871
8871
|
const dy = endY - startY;
|
|
8872
|
-
const
|
|
8873
|
-
if (
|
|
8872
|
+
const distance3 = Math.sqrt(dx * dx + dy * dy);
|
|
8873
|
+
if (distance3 === 0 || radius < distance3 / 2) {
|
|
8874
8874
|
return [start, end];
|
|
8875
8875
|
}
|
|
8876
|
-
const h = Math.sqrt(radius * radius -
|
|
8876
|
+
const h = Math.sqrt(radius * radius - distance3 * distance3 / 4);
|
|
8877
8877
|
const angle = Math.atan2(dy, dx);
|
|
8878
8878
|
const centerX = midX + h * Math.sin(angle) * (sweepFlag ? -1 : 1);
|
|
8879
8879
|
const centerY = midY - h * Math.cos(angle) * (sweepFlag ? -1 : 1);
|
|
@@ -8906,6 +8906,121 @@ function generateArcFromSweep(startX, startY, endX, endY, radius, largeArcFlag,
|
|
|
8906
8906
|
return path;
|
|
8907
8907
|
}
|
|
8908
8908
|
var mil10ToMm = (value) => value * 10 * 0.0254;
|
|
8909
|
+
var getBoundsCenter = (bounds) => ({
|
|
8910
|
+
x: (bounds.minX + bounds.maxX) / 2,
|
|
8911
|
+
y: (bounds.minY + bounds.maxY) / 2
|
|
8912
|
+
});
|
|
8913
|
+
var getBoundsFromPoints = (points) => {
|
|
8914
|
+
if (points.length === 0) {
|
|
8915
|
+
return null;
|
|
8916
|
+
}
|
|
8917
|
+
let minX = points[0].x;
|
|
8918
|
+
let minY = points[0].y;
|
|
8919
|
+
let maxX = points[0].x;
|
|
8920
|
+
let maxY = points[0].y;
|
|
8921
|
+
for (let i = 1; i < points.length; i++) {
|
|
8922
|
+
const point2 = points[i];
|
|
8923
|
+
if (point2.x < minX) minX = point2.x;
|
|
8924
|
+
if (point2.y < minY) minY = point2.y;
|
|
8925
|
+
if (point2.x > maxX) maxX = point2.x;
|
|
8926
|
+
if (point2.y > maxY) maxY = point2.y;
|
|
8927
|
+
}
|
|
8928
|
+
return { minX, minY, maxX, maxY };
|
|
8929
|
+
};
|
|
8930
|
+
var getCadSvgNode = (easyEdaJson) => {
|
|
8931
|
+
const svgNode = easyEdaJson.packageDetail.dataStr.shape.find(
|
|
8932
|
+
(shape) => shape.type === "SVGNODE" && shape.svgData.attrs?.uuid
|
|
8933
|
+
);
|
|
8934
|
+
return svgNode?.type === "SVGNODE" ? svgNode : null;
|
|
8935
|
+
};
|
|
8936
|
+
var isSvgChildNodeWithAttrs = (childNode) => typeof childNode === "object" && childNode !== null;
|
|
8937
|
+
var getXyBoundsFromModelBounds = (bounds) => ({
|
|
8938
|
+
minX: bounds.min.x,
|
|
8939
|
+
minY: bounds.min.y,
|
|
8940
|
+
maxX: bounds.max.x,
|
|
8941
|
+
maxY: bounds.max.y
|
|
8942
|
+
});
|
|
8943
|
+
var rotateScenePoint = (point2, rotationDeg) => {
|
|
8944
|
+
switch (rotationDeg) {
|
|
8945
|
+
case 0:
|
|
8946
|
+
return point2;
|
|
8947
|
+
case 90:
|
|
8948
|
+
return { x: point2.y, y: -point2.x };
|
|
8949
|
+
case 180:
|
|
8950
|
+
return { x: -point2.x, y: -point2.y };
|
|
8951
|
+
case 270:
|
|
8952
|
+
return { x: -point2.y, y: point2.x };
|
|
8953
|
+
}
|
|
8954
|
+
};
|
|
8955
|
+
var getEasyEdaModelOriginOnBoardMm = ({
|
|
8956
|
+
svgNode,
|
|
8957
|
+
footprintCenterMm
|
|
8958
|
+
}) => {
|
|
8959
|
+
const points = [];
|
|
8960
|
+
for (const childNode of svgNode.svgData.childNodes ?? []) {
|
|
8961
|
+
if (!isSvgChildNodeWithAttrs(childNode)) continue;
|
|
8962
|
+
const rawPoints = childNode.attrs?.points;
|
|
8963
|
+
if (!rawPoints) continue;
|
|
8964
|
+
const values = String(rawPoints).trim().split(/\s+/).map(Number);
|
|
8965
|
+
for (let i = 0; i + 1 < values.length; i += 2) {
|
|
8966
|
+
const x = values[i];
|
|
8967
|
+
const y = values[i + 1];
|
|
8968
|
+
if (Number.isFinite(x) && Number.isFinite(y)) {
|
|
8969
|
+
points.push({ x: mil10ToMm(x), y: mil10ToMm(y) });
|
|
8970
|
+
}
|
|
8971
|
+
}
|
|
8972
|
+
}
|
|
8973
|
+
let modelOriginMm = null;
|
|
8974
|
+
if (points.length > 0) {
|
|
8975
|
+
const bounds = getBoundsFromPoints(points);
|
|
8976
|
+
modelOriginMm = bounds ? getBoundsCenter(bounds) : null;
|
|
8977
|
+
} else {
|
|
8978
|
+
const [originX, originY] = String(svgNode.svgData.attrs?.c_origin ?? "0,0").split(",").map((value) => Number(value.trim()));
|
|
8979
|
+
if (Number.isFinite(originX) && Number.isFinite(originY)) {
|
|
8980
|
+
modelOriginMm = { x: mil10ToMm(originX), y: mil10ToMm(originY) };
|
|
8981
|
+
}
|
|
8982
|
+
}
|
|
8983
|
+
if (!modelOriginMm) return null;
|
|
8984
|
+
return {
|
|
8985
|
+
x: modelOriginMm.x - footprintCenterMm.x,
|
|
8986
|
+
y: footprintCenterMm.y - modelOriginMm.y
|
|
8987
|
+
};
|
|
8988
|
+
};
|
|
8989
|
+
var snapZero = (value) => Math.abs(value) < 1e-6 ? 0 : value;
|
|
8990
|
+
var normalizePoint = (point2) => ({
|
|
8991
|
+
x: snapZero(point2.x),
|
|
8992
|
+
y: snapZero(point2.y)
|
|
8993
|
+
});
|
|
8994
|
+
var getCadModelOffsetMmFromBounds = (easyEdaJson, bounds, {
|
|
8995
|
+
footprintBoundsCenterMm
|
|
8996
|
+
} = {}) => {
|
|
8997
|
+
const svgNode = getCadSvgNode(easyEdaJson);
|
|
8998
|
+
if (!svgNode || !bounds) return null;
|
|
8999
|
+
const [, , rotationZRaw] = String(
|
|
9000
|
+
svgNode.svgData.attrs?.c_rotation ?? "0,0,0"
|
|
9001
|
+
).split(",").map((value) => Number(value.trim()));
|
|
9002
|
+
const rotationDeg = (rotationZRaw % 360 + 360) % 360;
|
|
9003
|
+
if (![0, 90, 180, 270].includes(rotationDeg)) return null;
|
|
9004
|
+
const modelCenter = getBoundsCenter(getXyBoundsFromModelBounds(bounds));
|
|
9005
|
+
const footprintCenter = easyEdaJson.packageDetail.dataStr.head;
|
|
9006
|
+
const footprintCenterMm = footprintBoundsCenterMm ?? {
|
|
9007
|
+
x: mil10ToMm(footprintCenter.x),
|
|
9008
|
+
y: mil10ToMm(footprintCenter.y)
|
|
9009
|
+
};
|
|
9010
|
+
const targetOriginOnBoardMm = getEasyEdaModelOriginOnBoardMm({
|
|
9011
|
+
svgNode,
|
|
9012
|
+
footprintCenterMm
|
|
9013
|
+
});
|
|
9014
|
+
if (!targetOriginOnBoardMm) return null;
|
|
9015
|
+
const targetOriginInModelFrame = rotateScenePoint(
|
|
9016
|
+
targetOriginOnBoardMm,
|
|
9017
|
+
rotationDeg
|
|
9018
|
+
);
|
|
9019
|
+
return normalizePoint({
|
|
9020
|
+
x: modelCenter.x - targetOriginInModelFrame.x,
|
|
9021
|
+
y: modelCenter.y - targetOriginInModelFrame.y
|
|
9022
|
+
});
|
|
9023
|
+
};
|
|
8909
9024
|
var normalizePinLabels = (inputPinLabels) => {
|
|
8910
9025
|
const uniqueInputPinLabels = inputPinLabels.map((labels) => [
|
|
8911
9026
|
...new Set(labels)
|
|
@@ -9076,13 +9191,14 @@ var handleHoleCutout = (hole, index) => {
|
|
|
9076
9191
|
});
|
|
9077
9192
|
};
|
|
9078
9193
|
var handleVia = (via, index) => {
|
|
9194
|
+
const holeDiameter = via.holeRadius * 2;
|
|
9079
9195
|
return pcb_via.parse({
|
|
9080
9196
|
type: "pcb_via",
|
|
9081
9197
|
pcb_via_id: `pcb_via_${index + 1}`,
|
|
9082
9198
|
x: milx10(via.center.x),
|
|
9083
9199
|
y: milx10(via.center.y),
|
|
9084
9200
|
outer_diameter: milx10(via.outerDiameter),
|
|
9085
|
-
hole_diameter: milx10(
|
|
9201
|
+
hole_diameter: milx10(holeDiameter),
|
|
9086
9202
|
layers: ["top", "bottom"]
|
|
9087
9203
|
});
|
|
9088
9204
|
};
|
|
@@ -9097,6 +9213,10 @@ var handleCutout = (solidRegion, index) => {
|
|
|
9097
9213
|
}))
|
|
9098
9214
|
});
|
|
9099
9215
|
};
|
|
9216
|
+
var LEAD_SHAPE_LAYER = 100;
|
|
9217
|
+
var isPcbSolidRegionCutout = (shape) => {
|
|
9218
|
+
return shape.fillStyle === "cutout" && shape.layermask !== LEAD_SHAPE_LAYER;
|
|
9219
|
+
};
|
|
9100
9220
|
var getCadPositionZMmFromMetadata = (easyEdaJson) => {
|
|
9101
9221
|
const svgNode = easyEdaJson.packageDetail.dataStr.shape.find(
|
|
9102
9222
|
(shape) => shape.type === "SVGNODE" && shape.svgData.attrs?.uuid
|
|
@@ -9115,6 +9235,7 @@ var convertEasyEdaJsonToCircuitJson = (easyEdaJson, {
|
|
|
9115
9235
|
cadPositionXMm,
|
|
9116
9236
|
cadPositionYMm,
|
|
9117
9237
|
cadPositionZMm,
|
|
9238
|
+
cadModelBounds,
|
|
9118
9239
|
showDesignator = false
|
|
9119
9240
|
} = {}) => {
|
|
9120
9241
|
const resolvedCadPositionZMm = cadPositionZMm ?? getCadPositionZMmFromMetadata(easyEdaJson);
|
|
@@ -9194,15 +9315,12 @@ var convertEasyEdaJsonToCircuitJson = (easyEdaJson, {
|
|
|
9194
9315
|
const innerWidth = largestOuterDimensionName === "width" ? largestInnerDimension : smallestInnerDimension;
|
|
9195
9316
|
const innerHeight = largestOuterDimensionName === "height" ? largestInnerDimension : smallestInnerDimension;
|
|
9196
9317
|
additionalPlatedHoleProps = {
|
|
9197
|
-
shape: "
|
|
9198
|
-
hole_shape: "pill",
|
|
9199
|
-
pad_shape: "rect",
|
|
9318
|
+
shape: "pill",
|
|
9200
9319
|
hole_width: innerWidth,
|
|
9201
9320
|
hole_height: innerHeight,
|
|
9202
|
-
|
|
9203
|
-
|
|
9204
|
-
|
|
9205
|
-
hole_offset_y: 0
|
|
9321
|
+
outer_width: mil2mm(pad.width),
|
|
9322
|
+
outer_height: mil2mm(pad.height),
|
|
9323
|
+
ccw_rotation: pad.rotation || 0
|
|
9206
9324
|
};
|
|
9207
9325
|
} else if (pad.shape === "RECT") {
|
|
9208
9326
|
const padWidth = mil2mm(pad.width);
|
|
@@ -9256,7 +9374,7 @@ var convertEasyEdaJsonToCircuitJson = (easyEdaJson, {
|
|
|
9256
9374
|
} else if (pad.shape === "ELLIPSE") {
|
|
9257
9375
|
soupShape = "rect";
|
|
9258
9376
|
} else if (pad.shape === "OVAL") {
|
|
9259
|
-
soupShape = "
|
|
9377
|
+
soupShape = "pill";
|
|
9260
9378
|
} else if (pad.shape === "POLYGON") {
|
|
9261
9379
|
soupShape = "polygon";
|
|
9262
9380
|
}
|
|
@@ -9276,12 +9394,17 @@ var convertEasyEdaJsonToCircuitJson = (easyEdaJson, {
|
|
|
9276
9394
|
x: mil2mm(pad.center.x),
|
|
9277
9395
|
y: mil2mm(pad.center.y)
|
|
9278
9396
|
},
|
|
9279
|
-
...soupShape === "rect" ? rectSize : soupShape === "
|
|
9397
|
+
...soupShape === "rect" ? rectSize : soupShape === "pill" ? {
|
|
9398
|
+
...rectSize,
|
|
9399
|
+
radius: Math.min(rectSize.width, rectSize.height) / 2
|
|
9400
|
+
} : soupShape === "polygon" && pad.points ? {
|
|
9280
9401
|
points: pad.points.map((p) => ({
|
|
9281
9402
|
x: milx10(p.x),
|
|
9282
9403
|
y: milx10(p.y)
|
|
9283
9404
|
}))
|
|
9284
|
-
} : {
|
|
9405
|
+
} : {
|
|
9406
|
+
radius: Math.min(mil2mm(pad.width), mil2mm(pad.height)) / 2
|
|
9407
|
+
},
|
|
9285
9408
|
layer: "top",
|
|
9286
9409
|
port_hints: [`pin${pinNumber}`],
|
|
9287
9410
|
pcb_component_id: "pcb_component_1",
|
|
@@ -9300,7 +9423,7 @@ var convertEasyEdaJsonToCircuitJson = (easyEdaJson, {
|
|
|
9300
9423
|
circuitElements.push(handleVia(v, index));
|
|
9301
9424
|
});
|
|
9302
9425
|
easyEdaJson.packageDetail.dataStr.shape.filter(
|
|
9303
|
-
(shape) => shape.type === "SOLIDREGION" && shape
|
|
9426
|
+
(shape) => shape.type === "SOLIDREGION" && isPcbSolidRegionCutout(shape)
|
|
9304
9427
|
).forEach((sr, index) => {
|
|
9305
9428
|
circuitElements.push(handleCutout(sr, index));
|
|
9306
9429
|
});
|
|
@@ -9352,7 +9475,7 @@ var convertEasyEdaJsonToCircuitJson = (easyEdaJson, {
|
|
|
9352
9475
|
circuitElements.push(
|
|
9353
9476
|
pcb_silkscreen_text.parse({
|
|
9354
9477
|
type: "pcb_silkscreen_text",
|
|
9355
|
-
pcb_silkscreen_text_id:
|
|
9478
|
+
pcb_silkscreen_text_id: "pcb_silkscreen_text_designator_fallback",
|
|
9356
9479
|
pcb_component_id: "pcb_component_1",
|
|
9357
9480
|
text: "{NAME}",
|
|
9358
9481
|
anchor_position: {
|
|
@@ -9470,6 +9593,14 @@ var convertEasyEdaJsonToCircuitJson = (easyEdaJson, {
|
|
|
9470
9593
|
if (!cad.model_origin_position) {
|
|
9471
9594
|
cad.model_origin_position = { x: 0, y: 0, z: 0 };
|
|
9472
9595
|
}
|
|
9596
|
+
const resolvedCadModelBounds = cadModelBounds ?? easyEdaJson._objMetadata?.bounds;
|
|
9597
|
+
const recenteredCadOffset = resolvedCadModelBounds && getCadModelOffsetMmFromBounds(easyEdaJson, resolvedCadModelBounds, {
|
|
9598
|
+
footprintBoundsCenterMm: bounds.center
|
|
9599
|
+
});
|
|
9600
|
+
if (recenteredCadOffset) {
|
|
9601
|
+
cad.model_origin_position.x = recenteredCadOffset.x;
|
|
9602
|
+
cad.model_origin_position.y = recenteredCadOffset.y;
|
|
9603
|
+
}
|
|
9473
9604
|
const side = pcb_component2.layer ?? "top";
|
|
9474
9605
|
const t = DEFAULT_PCB_THICKNESS_MM / 2;
|
|
9475
9606
|
const attrs = svgNode?.svgData?.attrs ?? {};
|
|
@@ -9623,7 +9754,7 @@ var ViaSchema = BaseShapeSchema.extend({
|
|
|
9623
9754
|
type: external_exports.literal("VIA"),
|
|
9624
9755
|
center: PointSchema,
|
|
9625
9756
|
outerDiameter: external_exports.number(),
|
|
9626
|
-
|
|
9757
|
+
holeRadius: external_exports.number()
|
|
9627
9758
|
});
|
|
9628
9759
|
var RectSchema = BaseShapeSchema.extend({
|
|
9629
9760
|
type: external_exports.literal("RECT"),
|
|
@@ -9773,13 +9904,13 @@ var ShapeItemSchema = external_exports.object({
|
|
|
9773
9904
|
});
|
|
9774
9905
|
}
|
|
9775
9906
|
case "VIA": {
|
|
9776
|
-
const [x, y, outerDiameter, ,
|
|
9907
|
+
const [x, y, outerDiameter, , holeRadius, id] = shape.data.split("~");
|
|
9777
9908
|
const center = [Number(x), Number(y)];
|
|
9778
9909
|
return ViaSchema.parse({
|
|
9779
9910
|
type: "VIA",
|
|
9780
9911
|
center,
|
|
9781
9912
|
outerDiameter: Number(outerDiameter),
|
|
9782
|
-
|
|
9913
|
+
holeRadius: Number(holeRadius),
|
|
9783
9914
|
id
|
|
9784
9915
|
});
|
|
9785
9916
|
}
|
|
@@ -10035,6 +10166,12 @@ var parsePath = (str) => {
|
|
|
10035
10166
|
};
|
|
10036
10167
|
};
|
|
10037
10168
|
var PathShapeSchema = external_exports.string().startsWith("PT~").transform(parsePath).pipe(PathShapeOutputSchema);
|
|
10169
|
+
var optionalEasyEdaTextField = (fieldSchema) => external_exports.preprocess((textField) => {
|
|
10170
|
+
if (textField == null || textField === "" || textField === "undefined") {
|
|
10171
|
+
return void 0;
|
|
10172
|
+
}
|
|
10173
|
+
return textField;
|
|
10174
|
+
}, fieldSchema);
|
|
10038
10175
|
var TextShapeOutputSchema = external_exports.object({
|
|
10039
10176
|
type: external_exports.literal("TEXT"),
|
|
10040
10177
|
alignment: external_exports.enum(["L", "C", "R"]),
|
|
@@ -10042,11 +10179,13 @@ var TextShapeOutputSchema = external_exports.object({
|
|
|
10042
10179
|
y: external_exports.number(),
|
|
10043
10180
|
rotation: external_exports.number(),
|
|
10044
10181
|
fontColor: external_exports.string(),
|
|
10045
|
-
backgroundColor: external_exports.string().optional(),
|
|
10182
|
+
backgroundColor: optionalEasyEdaTextField(external_exports.string().optional()),
|
|
10046
10183
|
fontSize: external_exports.string(),
|
|
10047
|
-
fontWeight: external_exports.string().optional().default("normal"),
|
|
10048
|
-
fontStyle:
|
|
10049
|
-
|
|
10184
|
+
fontWeight: optionalEasyEdaTextField(external_exports.string().optional().default("normal")),
|
|
10185
|
+
fontStyle: optionalEasyEdaTextField(
|
|
10186
|
+
external_exports.enum(["normal", "italic"]).optional().default("normal")
|
|
10187
|
+
),
|
|
10188
|
+
fontDecoration: optionalEasyEdaTextField(external_exports.string().optional().default("")),
|
|
10050
10189
|
content: external_exports.string(),
|
|
10051
10190
|
textType: external_exports.string(),
|
|
10052
10191
|
visibility: external_exports.enum(["0", "1"]),
|
|
@@ -10079,11 +10218,11 @@ var parseText = (str) => {
|
|
|
10079
10218
|
y: Number(y),
|
|
10080
10219
|
rotation: Number(rotation2),
|
|
10081
10220
|
fontColor,
|
|
10082
|
-
backgroundColor
|
|
10221
|
+
backgroundColor,
|
|
10083
10222
|
fontSize,
|
|
10084
|
-
fontWeight
|
|
10085
|
-
fontStyle
|
|
10086
|
-
fontDecoration
|
|
10223
|
+
fontWeight,
|
|
10224
|
+
fontStyle,
|
|
10225
|
+
fontDecoration,
|
|
10087
10226
|
content,
|
|
10088
10227
|
textType,
|
|
10089
10228
|
visibility,
|
|
@@ -10250,6 +10389,7 @@ var EasyEdaJsonSchema = external_exports.object({
|
|
|
10250
10389
|
lcsc: LcscSchema,
|
|
10251
10390
|
owner: OwnerSchema,
|
|
10252
10391
|
tags: external_exports.array(external_exports.string()),
|
|
10392
|
+
category: external_exports.string().optional(),
|
|
10253
10393
|
updateTime: external_exports.number(),
|
|
10254
10394
|
updated_at: external_exports.string(),
|
|
10255
10395
|
dataStr: DataStrSchema,
|