diff --git a/lib/convert-easyeda-json-to-tscircuit-soup-json.ts b/lib/convert-easyeda-json-to-tscircuit-soup-json.ts index 879f9971..63a5fe86 100644 --- a/lib/convert-easyeda-json-to-tscircuit-soup-json.ts +++ b/lib/convert-easyeda-json-to-tscircuit-soup-json.ts @@ -2,7 +2,7 @@ import { findBoundsAndCenter, transformPCBElements, } from "@tscircuit/circuit-json-util" -import { mm, mil2mm } from "@tscircuit/mm" +import { mil2mm, mm } from "@tscircuit/mm" import type { AnyCircuitElement, PcbComponentInput, @@ -21,6 +21,7 @@ import { import * as Soup from "circuit-json" import { applyToPoint, compose, scale, translate } from "transformation-matrix" import type { z } from "zod" +import { DEFAULT_PCB_THICKNESS_MM } from "./constants" import { generateArcFromSweep, generateArcPathWithMid } from "./math/arc-utils" import type { BetterEasyEdaJson } from "./schemas/easy-eda-json-schema" import type { @@ -34,10 +35,9 @@ import type { ViaSchema, } from "./schemas/package-detail-shape-schema" import { mil10ToMm } from "./utils/easyeda-unit-to-mm" -import { getCadModelOffsetMmFromBounds } from "./websafe/get-easyeda-cad-placement-helpers" import { normalizePinLabels } from "./utils/normalize-pin-labels" import { normalizeSymbolName } from "./utils/normalize-symbol-name" -import { DEFAULT_PCB_THICKNESS_MM } from "./constants" +import { getCadModelOffsetMmFromBounds } from "./websafe/get-easyeda-cad-placement-helpers" const EASYEDA_STEP_MODEL_URL = "https://modules.easyeda.com/qAxj6KHrDKw4blvCG8QJPs7Y" @@ -321,7 +321,37 @@ export const convertEasyEdaJsonToCircuitJson = ( return labels }) - const normalizedPinLabels = normalizePinLabels(pinLabelSets) + // Duplicate pad numbers are multiple physical geometries for the SAME + // logical pin (e.g. C5656610's four polygon pads all numbered "3" are one + // GND terminal). Normalize one label set per *unique* pad number so the + // duplicates share a logical pin instead of being renumbered into + // synthetic pins (#411). + const padNumberKeys = pads.map((pad, index) => + pad.number !== undefined && pad.number !== null && `${pad.number}` !== "" + ? `num:${pad.number}` + : `idx:${index}`, + ) + const uniquePadKeys: string[] = [] + const uniqueLabelSets: string[][] = [] + const padKeyToUniqueIndex = new Map() + pads.forEach((pad, index) => { + const key = padNumberKeys[index]! + if (!padKeyToUniqueIndex.has(key)) { + padKeyToUniqueIndex.set(key, uniquePadKeys.length) + uniquePadKeys.push(key) + uniqueLabelSets.push(pinLabelSets[index]!) + } + }) + const normalizedUniquePinLabels = normalizePinLabels(uniqueLabelSets) + const normalizedPinLabels = pads.map( + (_, index) => + normalizedUniquePinLabels[ + padKeyToUniqueIndex.get(padNumberKeys[index]!)! + ]!, + ) + + // Only emit one source port per logical pin + const sourcePortEmittedForUniqueIndex = new Set() // Add source ports and pcb_smtpads pads.forEach((pad, index) => { @@ -330,15 +360,19 @@ export const convertEasyEdaJsonToCircuitJson = ( portHints.find((hint) => hint.match(/pin\d+/))!.replace("pin", ""), ) - // Add source port - circuitElements.push({ - type: "source_port", - source_port_id: `source_port_${index + 1}`, - source_component_id: "source_component_1", - name: `pin${pinNumber}`, - pin_number: pinNumber, - port_hints: portHints.filter((hint) => hint !== `pin${pinNumber}`), - }) + // Add source port (one per logical pin — duplicate pad geometries share it) + const uniqueIndex = padKeyToUniqueIndex.get(padNumberKeys[index]!)! + if (!sourcePortEmittedForUniqueIndex.has(uniqueIndex)) { + sourcePortEmittedForUniqueIndex.add(uniqueIndex) + circuitElements.push({ + type: "source_port", + source_port_id: `source_port_${index + 1}`, + source_component_id: "source_component_1", + name: `pin${pinNumber}`, + pin_number: pinNumber, + port_hints: portHints.filter((hint) => hint !== `pin${pinNumber}`), + }) + } if (pad.holeRadius !== undefined && mil2mm(pad.holeRadius) !== 0) { // Add pcb_plated_hole diff --git a/tests/assets/C5656610.raweasy.json b/tests/assets/C5656610.raweasy.json new file mode 100644 index 00000000..2c9b9323 --- /dev/null +++ b/tests/assets/C5656610.raweasy.json @@ -0,0 +1,239 @@ +{ + "uuid": "bb5ae0d2bf12487ea3dcd0a34e5b28ca", + "title": "ICS-43434_C5656610", + "description": "", + "docType": 2, + "type": 3, + "thumb": "//image.lceda.cn/components/bb5ae0d2bf12487ea3dcd0a34e5b28ca.png", + "lcsc": { + "id": 6577565, + "number": "C5656610" + }, + "szlcsc": { + "id": 6577565, + "number": "C5656610" + }, + "owner": { + "uuid": "0819f05c4eef4c71ace90d822a990e87", + "username": "lcsc", + "nickname": "LCSC", + "avatar": "//image.lceda.cn/avatars/2018/6/kFlrasi7W06gTdBLAqW3fkrqbDhbowynuSzkjqso.png" + }, + "tags": [ + "MEMS Microphones" + ], + "updateTime": 1736583604, + "updated_at": "2026-07-21 18:05:30", + "dataStr": { + "head": { + "docType": "2", + "editorVersion": "6.5.42", + "x": 400, + "y": 300, + "c_para": { + "pre": "U?", + "name": "ICS-43434_C5656610", + "package": "MIC-SMD_6P-L3.5-W2.7-P0.90-BL", + "Supplier": "LCSC", + "Supplier Part": "C5656610", + "Manufacturer": "TDK InvenSense(应美盛)", + "Manufacturer Part": "ICS-43434", + "JLCPCB Part Class": "Extended Part", + "Contributor": "lcsc" + }, + "uuid": "bb5ae0d2bf12487ea3dcd0a34e5b28ca", + "puuid": "9a1bd085c9154f9fa0392ad1d3d15d6d", + "importFlag": 0, + "c_spiceCmd": null, + "pre": "U?", + "name": "ICS-43434_C5656610", + "hasIdFlag": true, + "utime": 1713779469 + }, + "canvas": "CA~1000~1000~#FFFFFF~yes~#CCCCCC~5~1000~1000~line~5~pixel~5~400~300", + "shape": [ + "R~375~280~2~2~50~40~#880000~1~0~none~gge1~0~", + "E~380~285~1.5~1.5~#880000~1~0~#880000~gge2~0", + "P~show~0~1~365~290~180~gge41~0^^365~290^^M365,290h10~#880000^^1~378.7~294~0~WS~start~~~#0000FF^^1~374.5~289~0~1~end~~~#0000FF^^0~372~290^^0~M 375 293 L 378 290 L 375 287", + "P~show~0~2~365~300~180~gge42~0^^365~300^^M365,300h10~#880000^^1~378.7~304~0~LR~start~~~#0000FF^^1~374.5~299~0~2~end~~~#0000FF^^0~372~300^^0~M 375 303 L 378 300 L 375 297", + "P~show~0~3~365~310~180~gge43~0^^365~310^^M365,310h10~#000000^^1~378.7~314~0~GND~start~~~#000000^^1~374.5~309~0~3~end~~~#000000^^0~372~310^^0~M 375 313 L 378 310 L 375 307", + "P~show~0~4~435~310~0~gge44~0^^435~310^^M435,310h-10~#880000^^1~421.3~314~0~SCK~end~~~#0000FF^^1~425.5~309~0~4~start~~~#0000FF^^0~428~310^^0~M 425 307 L 422 310 L 425 313", + "P~show~0~5~435~300~0~gge45~0^^435~300^^M435,300h-10~#FF0000^^1~421.3~304~0~VDD~end~~~#FF0000^^1~425.5~299~0~5~start~~~#FF0000^^0~428~300^^0~M 425 297 L 422 300 L 425 303", + "P~show~0~6~435~290~0~gge46~0^^435~290^^M435,290h-10~#880000^^1~421.3~294~0~SD~end~~~#0000FF^^1~425.5~289~0~6~start~~~#0000FF^^0~428~290^^0~M 425 287 L 422 290 L 425 293" + ], + "BBox": { + "x": 364, + "y": 279.6, + "width": 72, + "height": 40.4 + }, + "colors": [] + }, + "jlcOnSale": 1, + "datastrid": "76ff9e77d903406b93851f57d45fbf01", + "verify": true, + "SMT": true, + "writable": false, + "isFavorite": false, + "packageDetail": { + "uuid": "9a1bd085c9154f9fa0392ad1d3d15d6d", + "title": "MIC-SMD_6P-L3.5-W2.7-P0.90-BL", + "docType": 4, + "updateTime": 1702621848, + "owner": { + "uuid": "0819f05c4eef4c71ace90d822a990e87", + "username": "lcsc", + "nickname": "LCSC", + "avatar": "//image.lceda.cn/avatars/2018/6/kFlrasi7W06gTdBLAqW3fkrqbDhbowynuSzkjqso.png" + }, + "datastrid": "01c826d0f72f411b94b00db5a8434ab0", + "writable": false, + "dataStr": { + "head": { + "docType": "4", + "editorVersion": "6.5.39", + "newgId": true, + "c_para": { + "package": "MIC-SMD_6P-L3.5-W2.7-P0.90-BL", + "pre": "U?", + "Contributor": "lcsc", + "link": "https://img.jlc.com/pdf/applyPasteComponent/2021-09-27/871184A/aa9d1109048a4e3fb0c66b359aba0933/ICS43434.pdf", + "3DModel": "MIC-SMD_6P-L3.5-W2.7-P0.90-BL" + }, + "x": 4003.954, + "y": 2992.0275, + "hasIdFlag": true, + "utime": 1702621848, + "uuid": "9a1bd085c9154f9fa0392ad1d3d15d6d", + "importFlag": 0, + "transformList": "", + "uuid_3d": "47034944b7bb40569079cac3ae762dda" + }, + "canvas": "CA~1000~1000~#000000~yes~#FFFFFF~10~1000~1000~line~0.003937~mm~0.5984~ARC~visible~0.5~4003.954~2992.0275~0~none", + "shape": [ + "CIRCLE~3997.362~2997.244~0.118~0.2362~101~gge347~0~~", + "CIRCLE~3997.598~2997.933~0.472~0.9449~12~gge127~0~~", + "SOLIDREGION~100~~M 3997.8661 2993.2087 L 3997.8661 2990.8465 L 3999.9132 2990.8465 L 3999.9132 2993.2087 Z~solid~gge93~~~~0", + "SOLIDREGION~100~~M 3997.8661 2989.6654 L 3997.8661 2987.3032 L 3999.9132 2987.3032 L 3999.9132 2989.6654 Z~solid~gge94~~~~0", + "SOLIDREGION~100~~M 4001.1023 2989.6654 L 4001.1023 2987.3032 L 4003.1494 2987.3032 L 4003.1494 2989.6654 Z~solid~gge95~~~~0", + "SOLIDREGION~100~~M 4001.1023 2996.752 L 4001.1023 2994.3898 L 4003.1494 2994.3898 L 4003.1494 2996.752 Z~solid~gge96~~~~0", + "SOLIDREGION~100~~M 3997.8661 2996.752 L 3997.8661 2994.3898 L 3999.9133 2994.3898 L 3999.9133 2996.752 Z~solid~gge97~~~~0", + "SOLIDREGION~100~~M 4003.8531 2991.6431 L 4004.8464 2991.6431 L 4004.8468 2991.6428 A 2.2165 2.2165 0 0 1 4006.6448 2989.8447 L 4006.6448 2988.8548 L 4006.6408 2988.8508 A 3.2008 3.2008 0 0 0 4003.8531 2991.6385 L 4003.8531 2991.6431 Z ~solid~gge263~~~~0", + "SOLIDREGION~100~~M 4006.6454 2995.2038 L 4006.6454 2994.2106 L 4006.6449 2994.2101 A 2.2165 2.2165 0 0 1 4004.8468 2992.4122 L 4003.8569 2992.4122 L 4003.8529 2992.4162 A 3.2008 3.2008 0 0 0 4006.6407 2995.2038 L 4006.6454 2995.2038 Z~solid~gge284~~~~0", + "SOLIDREGION~100~~M 4010.206 2992.412 L 4009.2127 2992.412 L 4009.2123 2992.4124 A 2.2165 2.2165 0 0 1 4007.4143 2994.2105 L 4007.4143 2995.2004 L 4007.4183 2995.2044 A 3.2008 3.2008 0 0 0 4010.206 2992.4167 L 4010.206 2992.412 Z~solid~gge308~~~~0", + "SOLIDREGION~100~~M 4007.414 2988.8512 L 4007.414 2989.8446 L 4007.4144 2989.845 A 2.2165 2.2165 0 0 1 4009.2125 2991.643 L 4010.2024 2991.643 L 4010.2064 2991.639 A 3.2008 3.2008 0 0 0 4007.4187 2988.8512 L 4007.414 2988.8512 Z~solid~gge332~~~~0", + "SOLIDREGION~99~~M 4011.1417 2997.2441 L 3997.3622 2997.2441 L 3997.3622 2986.811 L 4011.1417 2986.811 Z~solid~gge6~~~~0", + "PAD~RECT~3998.89~2995.571~2.3622~2.0472~1~~1~0~3997.8661 2996.752 3997.8661 2994.3898 3999.9133 2994.3898 3999.9133 2996.752~90~gge42~0~~Y~0~0~0.1969~3998.8897,2995.5709", + "PAD~RECT~4002.126~2995.571~2.3622~2.0472~1~~2~0~4001.1023 2996.752 4001.1023 2994.3898 4003.1494 2994.3898 4003.1494 2996.752~90~gge62~0~~Y~0~0~0.1969~4002.1258,2995.5709", + "PAD~RECT~4002.126~2988.484~2.3622~2.0472~1~~4~0~4001.1023 2989.6654 4001.1023 2987.3032 4003.1494 2987.3032 4003.1494 2989.6654~90~gge68~0~~Y~0~0~0.1969~4002.1258,2988.4843", + "PAD~RECT~3998.89~2988.484~2.3622~2.0472~1~~5~0~3997.8661 2989.6654 3997.8661 2987.3032 3999.9132 2987.3032 3999.9132 2989.6654~90~gge76~0~~Y~0~0~0.1969~3998.8896,2988.4843", + "PAD~RECT~3998.89~2992.028~2.3622~2.0472~1~~6~0~3997.8661 2993.2087 3997.8661 2990.8465 3999.9132 2990.8465 3999.9132 2993.2087~90~gge84~0~~Y~0~0~0.1969~3998.8896,2992.0276", + "PAD~POLYGON~4005.249~2990.039~2.7917~2.7922~1~~3~0~4003.853 2991.6431 4004.8463 2991.6431 4004.8467 2991.6427 4004.8743 2991.5102 4004.9099 2991.3795 4004.9534 2991.2513 4005.0047 2991.126 4005.0635 2991.0041 4005.1296 2990.886 4005.2029 2990.7721 4005.2829 2990.6629 4005.3695 2990.5588 4005.4622 2990.4602 4005.5608 2990.3675 4005.6649 2990.2809 4005.7741 2990.2009 4005.888 2990.1276 4006.0061 2990.0615 4006.128 2990.0027 4006.2533 2989.9514 4006.3815 2989.9079 4006.5122 2989.8723 4006.6447 2989.8447 4006.6447 2988.8548 4006.6407 2988.8508 4006.4791 2988.8748 4006.319 2988.907 4006.1607 2988.9473 4006.0047 2988.9957 4005.8514 2989.0519 4005.7011 2989.1159 4005.5543 2989.1875 4005.4113 2989.2665 4005.2726 2989.3527 4005.1384 2989.4458 4005.0091 2989.5457 4004.8851 2989.652 4004.7667 2989.7645 4004.6542 2989.8829 4004.5479 2990.0069 4004.448 2990.1362 4004.3549 2990.2704 4004.2687 2990.4091 4004.1897 2990.5521 4004.1181 2990.6989 4004.0541 2990.8492 4003.9979 2991.0025 4003.9495 2991.1585 4003.9092 2991.3168 4003.877 2991.4769 4003.853 2991.6385 4003.853 2991.6431~0~gge257~0~~Y~0~~0.19685~4005.2489,2990.0392", + "PAD~POLYGON~4005.041~2993.808~2.7917~2.7922~1~~3~0~4006.6454 2995.204 4006.6454 2994.2106 4006.6449 2994.2103 4006.5123 2994.1827 4006.3817 2994.1471 4006.2535 2994.1036 4006.1283 2994.0523 4006.0062 2993.9934 4005.8882 2993.9273 4005.7742 2993.854 4005.6652 2993.774 4005.5611 2993.6874 4005.4624 2993.5948 4005.3697 2993.4961 4005.2832 2993.392 4005.2032 2993.2829 4005.1299 2993.169 4005.0638 2993.0509 4005.0049 2992.9289 4004.9536 2992.8037 4004.91 2992.6755 4004.8745 2992.5448 4004.8468 2992.4123 4003.8569 2992.4123 4003.8529 2992.4163 4003.8769 2992.5779 4003.9091 2992.738 4003.9496 2992.8963 4003.9979 2993.0523 4004.0541 2993.2056 4004.1182 2993.3558 4004.1897 2993.5026 4004.2686 2993.6456 4004.3549 2993.7843 4004.448 2993.9186 4004.5478 2994.0478 4004.6541 2994.1719 4004.7668 2994.2903 4004.885 2994.4028 4005.0091 2994.5091 4005.1384 2994.609 4005.2726 2994.702 4005.4113 2994.7883 4005.5543 2994.8673 4005.7011 2994.9388 4005.8513 2995.0029 4006.0046 2995.0591 4006.1607 2995.1074 4006.3189 2995.1478 4006.479 2995.18 4006.6407 2995.204 4006.6454 2995.204~90~gge287~0~~Y~0~~0.19685~4005.0412,2993.8083", + "PAD~POLYGON~4008.81~2994.016~2.7917~2.7922~1~~3~0~4010.2061 2992.412 4009.2128 2992.412 4009.2124 2992.4125 4009.1848 2992.5449 4009.1492 2992.6757 4009.1057 2992.8039 4009.0544 2992.9291 4008.9956 2993.0511 4008.9295 2993.1692 4008.8562 2993.2831 4008.7762 2993.3922 4008.6896 2993.4963 4008.5969 2993.595 4008.4983 2993.6877 4008.3942 2993.7742 4008.285 2993.8542 4008.1711 2993.9275 4008.053 2993.9936 4007.9311 2994.0525 4007.8058 2994.1038 4007.6776 2994.1473 4007.5469 2994.1829 4007.4144 2994.2105 4007.4144 2995.2004 4007.4184 2995.2044 4007.58 2995.1804 4007.7401 2995.1482 4007.8984 2995.1078 4008.0544 2995.0595 4008.2077 2995.0033 4008.358 2994.9392 4008.5048 2994.8677 4008.6478 2994.7886 4008.7865 2994.7025 4008.9207 2994.6094 4009.05 2994.5095 4009.174 2994.4032 4009.2924 2994.2906 4009.4049 2994.1723 4009.5112 2994.0483 4009.6111 2993.919 4009.7042 2993.7848 4009.7904 2993.6461 4009.8694 2993.5031 4009.941 2993.3563 4010.005 2993.206 4010.0612 2993.0527 4010.1096 2992.8967 4010.1499 2992.7384 4010.1821 2992.5783 4010.2061 2992.4167 4010.2061 2992.412~180~gge311~0~~Y~0~~0.19685~4008.8103,2994.016", + "PAD~POLYGON~4009.018~2990.247~2.7917~2.7922~1~~3~0~4007.414 2988.8512 4007.414 2989.8445 4007.4144 2989.8449 4007.5469 2989.8725 4007.6777 2989.9081 4007.8058 2989.9516 4007.9311 2990.0029 4008.0531 2990.0616 4008.1712 2990.1277 4008.2851 2990.201 4008.3942 2990.2811 4008.4983 2990.3677 4008.597 2990.4604 4008.6896 2990.5589 4008.7762 2990.663 4008.8562 2990.7723 4008.9295 2990.8862 4008.9956 2991.0043 4009.0545 2991.1262 4009.1057 2991.2515 4009.1493 2991.3797 4009.1849 2991.5104 4009.2125 2991.6428 4010.2024 2991.6428 4010.2064 2991.6389 4010.1824 2991.4773 4010.1502 2991.3172 4010.1098 2991.1589 4010.0614 2991.0029 4010.0052 2990.8496 4009.9412 2990.6992 4009.8697 2990.5525 4009.7906 2990.4094 4009.7044 2990.2708 4009.6114 2990.1365 4009.5115 2990.0072 4009.4052 2989.8833 4009.2926 2989.7649 4009.1743 2989.6524 4009.0502 2989.5461 4008.9209 2989.4462 4008.7867 2989.353 4008.648 2989.2669 4008.505 2989.1879 4008.3582 2989.1163 4008.208 2989.0522 4008.0547 2988.996 4007.8987 2988.9476 4007.7404 2988.9074 4007.5803 2988.8752 4007.4187 2988.8512 4007.414 2988.8512~270~gge335~0~~Y~0~~0.19685~4009.018,2990.2469", + "TRACK~0.5984~3~~4011.3778 2997.5395 3997.2047 2997.5393~gge142~0", + "TRACK~0.5984~3~~3997.0079 2986.5158 3997.0079 2997.5395~gge141~0", + "TRACK~0.5984~3~~3997.0079 2986.5158 4011.3778 2986.5158 4011.3778 2997.5395~gge140~0", + "CIRCLE~3998.78~2999.114~0.472~0.9449~3~gge124~0~~", + "HOLE~4007.0485~2992.0275~0.7874~gge363~0", + "SVGNODE~{\"gId\":\"g1_outline\",\"nodeName\":\"g\",\"nodeType\":1,\"layerid\":\"19\",\"attrs\":{\"c_width\":\"10.43305\",\"c_height\":\"13.7795\",\"c_rotation\":\"0,0,90\",\"z\":\"0\",\"c_origin\":\"4004.2737,2992.0276\",\"uuid\":\"7098589742ce4a2fb4f80d2ad85dc714\",\"c_etype\":\"outline3D\",\"id\":\"g1_outline\",\"title\":\"MIC-SMD_6P-L3.5-W2.7-P0.90-BL\",\"layerid\":\"19\",\"transform\":\"scale(1) translate(0, 0)\"},\"childNodes\":[{\"gId\":\"g1_outline_line0\",\"nodeName\":\"polyline\",\"nodeType\":1,\"attrs\":{\"fill\":\"none\",\"id\":\"g1_outline_line0\",\"c_shapetype\":\"line\",\"points\":\"3997.3839 2997.2442 4000.5335 2997.2442 4001.3209 2997.2442 4002.3446 2997.2442 4003.5257 2997.2442 4011.1634 2997.2442 4011.1634 2996.0237 4011.1634 2994.0552 4011.1634 2992.9922 4011.1634 2992.2442 4011.1634 2991.693 4011.1634 2990.9843 4011.1634 2990.1182 4011.1634 2986.8111 4003.5257 2986.8111 4002.3446 2986.8111 4001.3209 2986.8111 4000.5335 2986.8111 3997.3839 2986.8111 3997.3839 2990.1182 3997.3839 2990.9843 3997.3839 2991.693 3997.3839 2992.2442 3997.3839 2992.9922 3997.3839 2994.0552 3997.3839 2996.0237 3997.3839 2997.2442 3997.3839 2997.2442\"}}]}" + ], + "layers": [ + "1~TopLayer~#FF0000~true~true~true~", + "2~BottomLayer~#0000FF~true~false~true~", + "3~TopSilkLayer~#FFCC00~true~false~true~", + "4~BottomSilkLayer~#66CC33~true~false~true~", + "5~TopPasteMaskLayer~#808080~true~false~true~", + "6~BottomPasteMaskLayer~#800000~true~false~true~", + "7~TopSolderMaskLayer~#800080~true~false~true~0.3", + "8~BottomSolderMaskLayer~#AA00FF~true~false~true~0.3", + "9~Ratlines~#6464FF~true~false~true~", + "10~BoardOutLine~#FF00FF~true~false~true~", + "11~Multi-Layer~#C0C0C0~true~false~true~", + "12~Document~#FFFFFF~true~false~true~", + "13~TopAssembly~#33CC99~true~false~true~", + "14~BottomAssembly~#5555FF~true~false~true~", + "15~Mechanical~#F022F0~true~false~true~", + "19~3DModel~#66CCFF~true~false~true~", + "21~Inner1~#999966~false~false~false~~", + "22~Inner2~#008000~false~false~false~~", + "23~Inner3~#00FF00~false~false~false~~", + "24~Inner4~#BC8E00~false~false~false~~", + "25~Inner5~#70DBFA~false~false~false~~", + "26~Inner6~#00CC66~false~false~false~~", + "27~Inner7~#9966FF~false~false~false~~", + "28~Inner8~#800080~false~false~false~~", + "29~Inner9~#008080~false~false~false~~", + "30~Inner10~#15935F~false~false~false~~", + "31~Inner11~#000080~false~false~false~~", + "32~Inner12~#00B400~false~false~false~~", + "33~Inner13~#2E4756~false~false~false~~", + "34~Inner14~#99842F~false~false~false~~", + "35~Inner15~#FFFFAA~false~false~false~~", + "36~Inner16~#99842F~false~false~false~~", + "37~Inner17~#2E4756~false~false~false~~", + "38~Inner18~#3535FF~false~false~false~~", + "39~Inner19~#8000BC~false~false~false~~", + "40~Inner20~#43AE5F~false~false~false~~", + "41~Inner21~#C3ECCE~false~false~false~~", + "42~Inner22~#728978~false~false~false~~", + "43~Inner23~#39503F~false~false~false~~", + "44~Inner24~#0C715D~false~false~false~~", + "45~Inner25~#5A8A80~false~false~false~~", + "46~Inner26~#2B937E~false~false~false~~", + "47~Inner27~#23999D~false~false~false~~", + "48~Inner28~#45B4E3~false~false~false~~", + "49~Inner29~#215DA1~false~false~false~~", + "50~Inner30~#4564D7~false~false~false~~", + "51~Inner31~#6969E9~false~false~false~~", + "52~Inner32~#9069E9~false~false~false~~", + "99~ComponentShapeLayer~#00CCCC~true~false~true~0.4", + "100~LeadShapeLayer~#CC9999~true~false~true~", + "101~ComponentMarkingLayer~#66FFCC~true~false~true~", + "Hole~Hole~#222222~false~false~true~", + "DRCError~DRCError~#FAD609~false~false~true~" + ], + "objects": [ + "All~true~false", + "Component~true~true", + "Prefix~true~true", + "Name~true~false", + "Track~true~true", + "Pad~true~true", + "Via~true~true", + "Hole~true~true", + "Copper_Area~true~true", + "Circle~true~true", + "Arc~true~true", + "Solid_Region~true~true", + "Text~true~true", + "Image~true~true", + "Rect~true~true", + "Dimension~true~true", + "Protractor~true~true" + ], + "BBox": { + "x": 3997, + "y": 2986.5, + "width": 14.4, + "height": 13.1 + }, + "netColors": [] + } + }, + "_objMetadata": { + "bounds": { + "min": { + "x": -1.325, + "y": -1.75, + "z": -0.02 + }, + "max": { + "x": 1.325, + "y": 1.75, + "z": 0.75 + } + } + } +} \ No newline at end of file diff --git a/tests/convert-to-soup-tests/duplicate-pad-numbers-411.test.ts b/tests/convert-to-soup-tests/duplicate-pad-numbers-411.test.ts new file mode 100644 index 00000000..28eb5ef3 --- /dev/null +++ b/tests/convert-to-soup-tests/duplicate-pad-numbers-411.test.ts @@ -0,0 +1,38 @@ +import { expect, it } from "bun:test" +import { convertEasyEdaJsonToCircuitJson } from "lib/convert-easyeda-json-to-tscircuit-soup-json" +import { EasyEdaJsonSchema } from "lib/schemas/easy-eda-json-schema" +import chipRawEasy from "../assets/C5656610.raweasy.json" + +// https://github.com/tscircuit/easyeda-converter/issues/411 +// +// C5656610 (ICS-43434) has nine pad geometries numbered 1,2,4,5,6,3,3,3,3 — +// the four polygon pads numbered "3" are four copper shapes for the same GND +// terminal. They must share logical pin 3, not be renumbered into synthetic +// pins 7/8/9. +it("keeps duplicate pad numbers on one logical pin", () => { + const easyEdaJson = EasyEdaJsonSchema.parse(chipRawEasy) + const circuitJson = convertEasyEdaJsonToCircuitJson(easyEdaJson) + + const sourcePorts = circuitJson.filter( + (element) => element.type === "source_port", + ) + // One source port per logical pin — no synthetic pins 7/8/9 + expect(sourcePorts.map((port) => port.pin_number).sort()).toEqual([ + 1, 2, 3, 4, 5, 6, + ]) + + // All four duplicate geometries carry the pin3 hint + const pin3Pads = circuitJson.filter( + (element) => + element.type === "pcb_smtpad" && element.port_hints?.includes("pin3"), + ) + expect(pin3Pads.length).toBe(4) + + // No synthetic pin hints remain anywhere + const allPadHints = circuitJson + .filter((element) => element.type === "pcb_smtpad") + .flatMap((element) => element.port_hints ?? []) + for (const syntheticPin of ["pin7", "pin8", "pin9"]) { + expect(allPadHints).not.toContain(syntheticPin) + } +}) diff --git a/tests/convert-to-ts/C2838502-to-ts.test.ts b/tests/convert-to-ts/C2838502-to-ts.test.ts index 8c39cb1d..2c7eabbf 100644 --- a/tests/convert-to-ts/C2838502-to-ts.test.ts +++ b/tests/convert-to-ts/C2838502-to-ts.test.ts @@ -77,15 +77,7 @@ it("should convert C2838502 into typescript file", async () => { pin50: ["GND18"], pin51: ["GND19"], pin52: ["GND20"], - pin53: ["GND21"], - pin54: ["pin49_alt1"], - pin55: ["pin49_alt1"], - pin56: ["pin49_alt1"], - pin57: ["pin49_alt1"], - pin58: ["pin49_alt1"], - pin59: ["pin49_alt1"], - pin60: ["pin49_alt1"], - pin61: ["pin49_alt1"] + pin53: ["GND21"] } as const export const ESP32_C3_MINI_1_N4 = (props: ChipProps) => { @@ -152,14 +144,14 @@ it("should convert C2838502 into typescript file", async () => { - - - - - - - - + + + + + + + + diff --git a/tests/convert-to-ts/C2913206-to-ts.test.ts b/tests/convert-to-ts/C2913206-to-ts.test.ts index 6a89cbd6..c9726128 100644 --- a/tests/convert-to-ts/C2913206-to-ts.test.ts +++ b/tests/convert-to-ts/C2913206-to-ts.test.ts @@ -83,19 +83,7 @@ it("should convert C2913206 into typescript file", async () => { pin58: ["GND17"], pin59: ["GND18"], pin60: ["GND19"], - pin61: ["GND20"], - pin62: ["GND21"], - pin63: ["GND22"], - pin64: ["GND23"], - pin65: ["GND24"], - pin66: ["GND25"], - pin67: ["GND26"], - pin68: ["GND27"], - pin69: ["GND28"], - pin70: ["GND29"], - pin71: ["GND30"], - pin72: ["GND31"], - pin73: ["GND32"] + pin61: ["GND20"] } as const export const ESP32_S3_MINI_1_N8 = (props: ChipProps) => { @@ -170,18 +158,18 @@ it("should convert C2913206 into typescript file", async () => { - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/tests/convert-to-ts/C51950748-to-ts.test.ts b/tests/convert-to-ts/C51950748-to-ts.test.ts index 9189841d..e0a2b355 100644 --- a/tests/convert-to-ts/C51950748-to-ts.test.ts +++ b/tests/convert-to-ts/C51950748-to-ts.test.ts @@ -55,18 +55,10 @@ it("should convert C51950748 into typescript file", async () => { pin26: ["IO25"], pin27: ["IO26"], pin28: ["GND2"], - pin29: ["EPAD1"], + pin29: ["EPAD"], pin30: ["GND3"], pin31: ["ANT2"], - pin32: ["GND4"], - pin33: ["pin29_alt1"], - pin34: ["pin29_alt1"], - pin35: ["pin29_alt1"], - pin36: ["pin29_alt1"], - pin37: ["pin29_alt1"], - pin38: ["pin29_alt1"], - pin39: ["pin29_alt1"], - pin40: ["pin29_alt1"] + pin32: ["GND4"] } as const export const ESP32_C5_WROOM_1U_N8R8 = (props: ChipProps) => { @@ -109,14 +101,14 @@ it("should convert C51950748 into typescript file", async () => { - - - - - - - - + + + + + + + + diff --git a/tests/convert-to-ts/__snapshots__/C5656610-to-ts-simple-3d.snap.png b/tests/convert-to-ts/__snapshots__/C5656610-to-ts-simple-3d.snap.png new file mode 100644 index 00000000..ace56e3c Binary files /dev/null and b/tests/convert-to-ts/__snapshots__/C5656610-to-ts-simple-3d.snap.png differ