@tscircuit/parts-engine 0.0.19 → 0.0.21
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 +163 -23
- 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)
|
|
@@ -9097,6 +9212,10 @@ var handleCutout = (solidRegion, index) => {
|
|
|
9097
9212
|
}))
|
|
9098
9213
|
});
|
|
9099
9214
|
};
|
|
9215
|
+
var LEAD_SHAPE_LAYER = 100;
|
|
9216
|
+
var isPcbSolidRegionCutout = (shape) => {
|
|
9217
|
+
return shape.fillStyle === "cutout" && shape.layermask !== LEAD_SHAPE_LAYER;
|
|
9218
|
+
};
|
|
9100
9219
|
var getCadPositionZMmFromMetadata = (easyEdaJson) => {
|
|
9101
9220
|
const svgNode = easyEdaJson.packageDetail.dataStr.shape.find(
|
|
9102
9221
|
(shape) => shape.type === "SVGNODE" && shape.svgData.attrs?.uuid
|
|
@@ -9115,6 +9234,7 @@ var convertEasyEdaJsonToCircuitJson = (easyEdaJson, {
|
|
|
9115
9234
|
cadPositionXMm,
|
|
9116
9235
|
cadPositionYMm,
|
|
9117
9236
|
cadPositionZMm,
|
|
9237
|
+
cadModelBounds,
|
|
9118
9238
|
showDesignator = false
|
|
9119
9239
|
} = {}) => {
|
|
9120
9240
|
const resolvedCadPositionZMm = cadPositionZMm ?? getCadPositionZMmFromMetadata(easyEdaJson);
|
|
@@ -9194,15 +9314,12 @@ var convertEasyEdaJsonToCircuitJson = (easyEdaJson, {
|
|
|
9194
9314
|
const innerWidth = largestOuterDimensionName === "width" ? largestInnerDimension : smallestInnerDimension;
|
|
9195
9315
|
const innerHeight = largestOuterDimensionName === "height" ? largestInnerDimension : smallestInnerDimension;
|
|
9196
9316
|
additionalPlatedHoleProps = {
|
|
9197
|
-
shape: "
|
|
9198
|
-
hole_shape: "pill",
|
|
9199
|
-
pad_shape: "rect",
|
|
9317
|
+
shape: "pill",
|
|
9200
9318
|
hole_width: innerWidth,
|
|
9201
9319
|
hole_height: innerHeight,
|
|
9202
|
-
|
|
9203
|
-
|
|
9204
|
-
|
|
9205
|
-
hole_offset_y: 0
|
|
9320
|
+
outer_width: mil2mm(pad.width),
|
|
9321
|
+
outer_height: mil2mm(pad.height),
|
|
9322
|
+
ccw_rotation: pad.rotation || 0
|
|
9206
9323
|
};
|
|
9207
9324
|
} else if (pad.shape === "RECT") {
|
|
9208
9325
|
const padWidth = mil2mm(pad.width);
|
|
@@ -9256,7 +9373,7 @@ var convertEasyEdaJsonToCircuitJson = (easyEdaJson, {
|
|
|
9256
9373
|
} else if (pad.shape === "ELLIPSE") {
|
|
9257
9374
|
soupShape = "rect";
|
|
9258
9375
|
} else if (pad.shape === "OVAL") {
|
|
9259
|
-
soupShape = "
|
|
9376
|
+
soupShape = "pill";
|
|
9260
9377
|
} else if (pad.shape === "POLYGON") {
|
|
9261
9378
|
soupShape = "polygon";
|
|
9262
9379
|
}
|
|
@@ -9276,12 +9393,17 @@ var convertEasyEdaJsonToCircuitJson = (easyEdaJson, {
|
|
|
9276
9393
|
x: mil2mm(pad.center.x),
|
|
9277
9394
|
y: mil2mm(pad.center.y)
|
|
9278
9395
|
},
|
|
9279
|
-
...soupShape === "rect" ? rectSize : soupShape === "
|
|
9396
|
+
...soupShape === "rect" ? rectSize : soupShape === "pill" ? {
|
|
9397
|
+
...rectSize,
|
|
9398
|
+
radius: Math.min(rectSize.width, rectSize.height) / 2
|
|
9399
|
+
} : soupShape === "polygon" && pad.points ? {
|
|
9280
9400
|
points: pad.points.map((p) => ({
|
|
9281
9401
|
x: milx10(p.x),
|
|
9282
9402
|
y: milx10(p.y)
|
|
9283
9403
|
}))
|
|
9284
|
-
} : {
|
|
9404
|
+
} : {
|
|
9405
|
+
radius: Math.min(mil2mm(pad.width), mil2mm(pad.height)) / 2
|
|
9406
|
+
},
|
|
9285
9407
|
layer: "top",
|
|
9286
9408
|
port_hints: [`pin${pinNumber}`],
|
|
9287
9409
|
pcb_component_id: "pcb_component_1",
|
|
@@ -9300,7 +9422,7 @@ var convertEasyEdaJsonToCircuitJson = (easyEdaJson, {
|
|
|
9300
9422
|
circuitElements.push(handleVia(v, index));
|
|
9301
9423
|
});
|
|
9302
9424
|
easyEdaJson.packageDetail.dataStr.shape.filter(
|
|
9303
|
-
(shape) => shape.type === "SOLIDREGION" && shape
|
|
9425
|
+
(shape) => shape.type === "SOLIDREGION" && isPcbSolidRegionCutout(shape)
|
|
9304
9426
|
).forEach((sr, index) => {
|
|
9305
9427
|
circuitElements.push(handleCutout(sr, index));
|
|
9306
9428
|
});
|
|
@@ -9352,7 +9474,7 @@ var convertEasyEdaJsonToCircuitJson = (easyEdaJson, {
|
|
|
9352
9474
|
circuitElements.push(
|
|
9353
9475
|
pcb_silkscreen_text.parse({
|
|
9354
9476
|
type: "pcb_silkscreen_text",
|
|
9355
|
-
pcb_silkscreen_text_id:
|
|
9477
|
+
pcb_silkscreen_text_id: "pcb_silkscreen_text_designator_fallback",
|
|
9356
9478
|
pcb_component_id: "pcb_component_1",
|
|
9357
9479
|
text: "{NAME}",
|
|
9358
9480
|
anchor_position: {
|
|
@@ -9470,6 +9592,14 @@ var convertEasyEdaJsonToCircuitJson = (easyEdaJson, {
|
|
|
9470
9592
|
if (!cad.model_origin_position) {
|
|
9471
9593
|
cad.model_origin_position = { x: 0, y: 0, z: 0 };
|
|
9472
9594
|
}
|
|
9595
|
+
const resolvedCadModelBounds = cadModelBounds ?? easyEdaJson._objMetadata?.bounds;
|
|
9596
|
+
const recenteredCadOffset = resolvedCadModelBounds && getCadModelOffsetMmFromBounds(easyEdaJson, resolvedCadModelBounds, {
|
|
9597
|
+
footprintBoundsCenterMm: bounds.center
|
|
9598
|
+
});
|
|
9599
|
+
if (recenteredCadOffset) {
|
|
9600
|
+
cad.model_origin_position.x = recenteredCadOffset.x;
|
|
9601
|
+
cad.model_origin_position.y = recenteredCadOffset.y;
|
|
9602
|
+
}
|
|
9473
9603
|
const side = pcb_component2.layer ?? "top";
|
|
9474
9604
|
const t = DEFAULT_PCB_THICKNESS_MM / 2;
|
|
9475
9605
|
const attrs = svgNode?.svgData?.attrs ?? {};
|
|
@@ -10035,6 +10165,12 @@ var parsePath = (str) => {
|
|
|
10035
10165
|
};
|
|
10036
10166
|
};
|
|
10037
10167
|
var PathShapeSchema = external_exports.string().startsWith("PT~").transform(parsePath).pipe(PathShapeOutputSchema);
|
|
10168
|
+
var optionalEasyEdaTextField = (fieldSchema) => external_exports.preprocess((textField) => {
|
|
10169
|
+
if (textField == null || textField === "" || textField === "undefined") {
|
|
10170
|
+
return void 0;
|
|
10171
|
+
}
|
|
10172
|
+
return textField;
|
|
10173
|
+
}, fieldSchema);
|
|
10038
10174
|
var TextShapeOutputSchema = external_exports.object({
|
|
10039
10175
|
type: external_exports.literal("TEXT"),
|
|
10040
10176
|
alignment: external_exports.enum(["L", "C", "R"]),
|
|
@@ -10042,11 +10178,13 @@ var TextShapeOutputSchema = external_exports.object({
|
|
|
10042
10178
|
y: external_exports.number(),
|
|
10043
10179
|
rotation: external_exports.number(),
|
|
10044
10180
|
fontColor: external_exports.string(),
|
|
10045
|
-
backgroundColor: external_exports.string().optional(),
|
|
10181
|
+
backgroundColor: optionalEasyEdaTextField(external_exports.string().optional()),
|
|
10046
10182
|
fontSize: external_exports.string(),
|
|
10047
|
-
fontWeight: external_exports.string().optional().default("normal"),
|
|
10048
|
-
fontStyle:
|
|
10049
|
-
|
|
10183
|
+
fontWeight: optionalEasyEdaTextField(external_exports.string().optional().default("normal")),
|
|
10184
|
+
fontStyle: optionalEasyEdaTextField(
|
|
10185
|
+
external_exports.enum(["normal", "italic"]).optional().default("normal")
|
|
10186
|
+
),
|
|
10187
|
+
fontDecoration: optionalEasyEdaTextField(external_exports.string().optional().default("")),
|
|
10050
10188
|
content: external_exports.string(),
|
|
10051
10189
|
textType: external_exports.string(),
|
|
10052
10190
|
visibility: external_exports.enum(["0", "1"]),
|
|
@@ -10079,11 +10217,11 @@ var parseText = (str) => {
|
|
|
10079
10217
|
y: Number(y),
|
|
10080
10218
|
rotation: Number(rotation2),
|
|
10081
10219
|
fontColor,
|
|
10082
|
-
backgroundColor
|
|
10220
|
+
backgroundColor,
|
|
10083
10221
|
fontSize,
|
|
10084
|
-
fontWeight
|
|
10085
|
-
fontStyle
|
|
10086
|
-
fontDecoration
|
|
10222
|
+
fontWeight,
|
|
10223
|
+
fontStyle,
|
|
10224
|
+
fontDecoration,
|
|
10087
10225
|
content,
|
|
10088
10226
|
textType,
|
|
10089
10227
|
visibility,
|
|
@@ -10250,6 +10388,7 @@ var EasyEdaJsonSchema = external_exports.object({
|
|
|
10250
10388
|
lcsc: LcscSchema,
|
|
10251
10389
|
owner: OwnerSchema,
|
|
10252
10390
|
tags: external_exports.array(external_exports.string()),
|
|
10391
|
+
category: external_exports.string().optional(),
|
|
10253
10392
|
updateTime: external_exports.number(),
|
|
10254
10393
|
updated_at: external_exports.string(),
|
|
10255
10394
|
dataStr: DataStrSchema,
|
|
@@ -10551,6 +10690,7 @@ var JlcPcbPartsEngine = class {
|
|
|
10551
10690
|
} = {}) {
|
|
10552
10691
|
this.defaultPlatformFetch = defaultPlatformFetch;
|
|
10553
10692
|
this.easyEdaProxyConfig = easyEdaProxyConfig;
|
|
10693
|
+
this.fetchPartCircuitJson = this.fetchPartCircuitJson.bind(this);
|
|
10554
10694
|
}
|
|
10555
10695
|
getEasyEdaPlatformFetch(platformFetchOverride) {
|
|
10556
10696
|
const resolvedPlatformFetch = platformFetchOverride ?? this.defaultPlatformFetch ?? globalThis.fetch;
|