altium-to-circuit-json 0.0.13 → 0.0.15
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 +178 -9
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -695,6 +695,11 @@ var CARDINAL_DIRECTIONS = [
|
|
|
695
695
|
];
|
|
696
696
|
var SYMBOL_CATALOG = symbols;
|
|
697
697
|
var SYMBOL_NAMES = Object.keys(SYMBOL_CATALOG);
|
|
698
|
+
var INLINE_NET_LABEL_COLOR = "rgb(132, 0, 0)";
|
|
699
|
+
var DEFAULT_INLINE_NET_LABEL_FONT_SIZE = 0.18;
|
|
700
|
+
var MIN_INLINE_NET_LABEL_FONT_SIZE = 0.1;
|
|
701
|
+
var INLINE_NET_LABEL_CHARACTER_WIDTH = 0.12;
|
|
702
|
+
var INLINE_NET_LABEL_HORIZONTAL_PADDING = 0.12;
|
|
698
703
|
function convertSemanticSchematic(document, options) {
|
|
699
704
|
const handledRecords = /* @__PURE__ */ new Set();
|
|
700
705
|
const elements = [];
|
|
@@ -742,6 +747,12 @@ function convertComponents(params) {
|
|
|
742
747
|
(record) => record.recordKind === "2" && (!isPinHidden(record) || options.includeHidden === true)
|
|
743
748
|
);
|
|
744
749
|
if (pins.length === 0) continue;
|
|
750
|
+
const visibleSymbolLabels = new Set(
|
|
751
|
+
visibleOwnedRecords.filter((record) => record.recordKind === "4").flatMap((record) => {
|
|
752
|
+
const text = record.getDecoded("TEXT")?.trim().toUpperCase();
|
|
753
|
+
return text ? [text] : [];
|
|
754
|
+
})
|
|
755
|
+
);
|
|
745
756
|
const designator = findOwnedText(ownedRecords, "34", "Designator") ?? componentRecord.getDecoded("DESIGNATOR") ?? `U${componentIndex}`;
|
|
746
757
|
const value = findOwnedText(ownedRecords, "41", "Comment") ?? componentRecord.getDecoded("COMMENT") ?? componentRecord.getDecoded("DESIGNITEMID") ?? componentRecord.getDecoded("LIBREFERENCE") ?? "";
|
|
747
758
|
const libraryReference = componentRecord.getDecoded("LIBREFERENCE") ?? componentRecord.getDecoded("DESIGNITEMID") ?? designator;
|
|
@@ -774,7 +785,8 @@ function convertComponents(params) {
|
|
|
774
785
|
pin,
|
|
775
786
|
pinIndex,
|
|
776
787
|
schematicComponentId,
|
|
777
|
-
sourceComponentId
|
|
788
|
+
sourceComponentId,
|
|
789
|
+
visibleSymbolLabels
|
|
778
790
|
})
|
|
779
791
|
);
|
|
780
792
|
const bodyBounds = getComponentBodyBounds(
|
|
@@ -863,7 +875,8 @@ function convertComponentPin(params) {
|
|
|
863
875
|
pin,
|
|
864
876
|
pinIndex,
|
|
865
877
|
schematicComponentId,
|
|
866
|
-
sourceComponentId
|
|
878
|
+
sourceComponentId,
|
|
879
|
+
visibleSymbolLabels
|
|
867
880
|
} = params;
|
|
868
881
|
const recordIndex = document.records.indexOf(pin);
|
|
869
882
|
const pinConglomerate = pin.getNumber("PINCONGLOMERATE");
|
|
@@ -894,10 +907,13 @@ function convertComponentPin(params) {
|
|
|
894
907
|
...pinNumber === void 0 ? {} : { pin_number: pinNumber }
|
|
895
908
|
};
|
|
896
909
|
const electricalType = pin.getNumber("ELECTRICAL");
|
|
910
|
+
const normalizedName = name.trim().toUpperCase();
|
|
911
|
+
const functionalName = normalizedName.replace(/\d+$/u, "");
|
|
912
|
+
const showName = pinConglomerate === void 0 || (pinConglomerate & 8) !== 0 || visibleSymbolLabels.has(normalizedName) || visibleSymbolLabels.has(functionalName);
|
|
897
913
|
const schematicPort = {
|
|
898
914
|
type: "schematic_port",
|
|
899
915
|
center: scalePoint(terminalPoint, options.scale),
|
|
900
|
-
display_pin_label: name,
|
|
916
|
+
...showName && name ? { display_pin_label: name } : {},
|
|
901
917
|
distance_from_component_edge: pinLength * options.scale,
|
|
902
918
|
facing_direction: direction,
|
|
903
919
|
is_connected: false,
|
|
@@ -1030,7 +1046,7 @@ function buildSemanticNetGraph(document, convertedPorts) {
|
|
|
1030
1046
|
if (!["4", "17", "18", "25", "29"].includes(record.recordKind ?? "")) {
|
|
1031
1047
|
return [];
|
|
1032
1048
|
}
|
|
1033
|
-
const point = getLocation(record);
|
|
1049
|
+
const point = record.recordKind === "18" ? getPortConnectionGeometry(record, segments)?.anchor : getLocation(record);
|
|
1034
1050
|
return point ? [{ point, record }] : [];
|
|
1035
1051
|
});
|
|
1036
1052
|
const positionedPins = convertedPorts.map(({ point, record }) => ({
|
|
@@ -1201,6 +1217,8 @@ function convertConnectivity(params) {
|
|
|
1201
1217
|
} = params;
|
|
1202
1218
|
const sourceNetIdByName = /* @__PURE__ */ new Map();
|
|
1203
1219
|
const sourceNetIdByRecord = /* @__PURE__ */ new Map();
|
|
1220
|
+
const sourcePortCountByRecord = /* @__PURE__ */ new Map();
|
|
1221
|
+
const sourceTraceIdByRecord = /* @__PURE__ */ new Map();
|
|
1204
1222
|
const schematicTraceIdByRecord = /* @__PURE__ */ new Map();
|
|
1205
1223
|
const portsByPoint = groupByPoint(convertedPorts);
|
|
1206
1224
|
for (const [netIndex, net] of graph.nets.entries()) {
|
|
@@ -1226,6 +1244,10 @@ function convertConnectivity(params) {
|
|
|
1226
1244
|
if (firstSourceNetId) sourceNetIdByRecord.set(record, firstSourceNetId);
|
|
1227
1245
|
}
|
|
1228
1246
|
const sourceTraceId = `source_trace_altium_${netIndex}`;
|
|
1247
|
+
for (const record of net.records) {
|
|
1248
|
+
sourcePortCountByRecord.set(record, connectedPorts.length);
|
|
1249
|
+
sourceTraceIdByRecord.set(record, sourceTraceId);
|
|
1250
|
+
}
|
|
1229
1251
|
const sourceTrace = {
|
|
1230
1252
|
type: "source_trace",
|
|
1231
1253
|
connected_source_net_ids: sourceNetIds,
|
|
@@ -1324,19 +1346,22 @@ function convertConnectivity(params) {
|
|
|
1324
1346
|
return {
|
|
1325
1347
|
schematicTraceIdByRecord,
|
|
1326
1348
|
sourceNetIdByName,
|
|
1327
|
-
sourceNetIdByRecord
|
|
1349
|
+
sourceNetIdByRecord,
|
|
1350
|
+
sourcePortCountByRecord,
|
|
1351
|
+
sourceTraceIdByRecord
|
|
1328
1352
|
};
|
|
1329
1353
|
}
|
|
1330
1354
|
function getEquivalentPortPrunedSegmentKeys(params) {
|
|
1331
1355
|
const { convertedPorts, net, wires } = params;
|
|
1332
1356
|
const hiddenPortPoints = convertedPorts.filter((port) => !port.isSchematicVisible).map((port) => port.point);
|
|
1333
1357
|
if (hiddenPortPoints.length === 0) return /* @__PURE__ */ new Set();
|
|
1358
|
+
const wireSegments = getWireSegments(wires);
|
|
1334
1359
|
const protectedPointKeys = new Set(
|
|
1335
1360
|
convertedPorts.filter((port) => port.isSchematicVisible).map((port) => pointKey(port.point))
|
|
1336
1361
|
);
|
|
1337
1362
|
for (const record of net.records) {
|
|
1338
1363
|
if (!["4", "17", "18", "25"].includes(record.recordKind ?? "")) continue;
|
|
1339
|
-
const location = getLocation(record);
|
|
1364
|
+
const location = record.recordKind === "18" ? getPortConnectionGeometry(record, wireSegments)?.anchor : getLocation(record);
|
|
1340
1365
|
if (location) protectedPointKeys.add(pointKey(location));
|
|
1341
1366
|
}
|
|
1342
1367
|
const segments = /* @__PURE__ */ new Map();
|
|
@@ -1421,6 +1446,9 @@ function convertNetLabels(params) {
|
|
|
1421
1446
|
options,
|
|
1422
1447
|
semanticNetGraph: graph
|
|
1423
1448
|
} = params;
|
|
1449
|
+
const allWireSegments = getWireSegments(
|
|
1450
|
+
document.records.filter((record) => record.recordKind === "27")
|
|
1451
|
+
);
|
|
1424
1452
|
for (const [recordIndex, record] of document.records.entries()) {
|
|
1425
1453
|
const recordKind = record.recordKind;
|
|
1426
1454
|
if (!recordKind || !["4", "17", "18", "25"].includes(recordKind)) {
|
|
@@ -1431,10 +1459,30 @@ function convertNetLabels(params) {
|
|
|
1431
1459
|
continue;
|
|
1432
1460
|
}
|
|
1433
1461
|
const name = record.recordKind === "18" ? record.getDecoded("NAME") : record.getDecoded("TEXT");
|
|
1434
|
-
const
|
|
1462
|
+
const portConnection = recordKind === "18" ? getPortConnectionGeometry(record, allWireSegments) : void 0;
|
|
1463
|
+
const location = portConnection?.anchor ?? getLocation(record);
|
|
1435
1464
|
if (!name || !location) continue;
|
|
1436
|
-
const
|
|
1465
|
+
const connectedWires = graph.getConnectedWiresForRecord(record);
|
|
1466
|
+
const wire = connectedWires[0];
|
|
1437
1467
|
if (recordKind === "4" && !wire) continue;
|
|
1468
|
+
const sourceTraceId = connectivity.sourceTraceIdByRecord.get(record);
|
|
1469
|
+
const shouldRenderInline = Boolean(sourceTraceId) && (recordKind === "25" || recordKind === "18" && (record.getNumber("IOTYPE") ?? 0) === 0 && connectivity.sourcePortCountByRecord.get(record) === 2 && !isPowerNet(name));
|
|
1470
|
+
if (shouldRenderInline && sourceTraceId) {
|
|
1471
|
+
handledRecords.add(record);
|
|
1472
|
+
elements.push(
|
|
1473
|
+
createInlineNetLabelText({
|
|
1474
|
+
connectedWires,
|
|
1475
|
+
document,
|
|
1476
|
+
location,
|
|
1477
|
+
name,
|
|
1478
|
+
options,
|
|
1479
|
+
record,
|
|
1480
|
+
recordIndex,
|
|
1481
|
+
sourceTraceId
|
|
1482
|
+
})
|
|
1483
|
+
);
|
|
1484
|
+
continue;
|
|
1485
|
+
}
|
|
1438
1486
|
handledRecords.add(record);
|
|
1439
1487
|
const sourceNetId = connectivity.sourceNetIdByRecord.get(record) ?? getOrCreateSourceNet({
|
|
1440
1488
|
elements,
|
|
@@ -1447,7 +1495,9 @@ function convertNetLabels(params) {
|
|
|
1447
1495
|
const schematicNetLabel = {
|
|
1448
1496
|
type: "schematic_net_label",
|
|
1449
1497
|
anchor_position: scalePoint(location, options.scale),
|
|
1450
|
-
anchor_side:
|
|
1498
|
+
anchor_side: directionToOppositeSide(
|
|
1499
|
+
portConnection?.bodyDirection ?? direction
|
|
1500
|
+
),
|
|
1451
1501
|
center: scalePoint(location, options.scale),
|
|
1452
1502
|
schematic_net_label_id: `schematic_net_label_altium_${recordIndex}`,
|
|
1453
1503
|
schematic_sheet_id: options.schematicSheetId,
|
|
@@ -1459,6 +1509,125 @@ function convertNetLabels(params) {
|
|
|
1459
1509
|
elements.push(schematicNetLabel);
|
|
1460
1510
|
}
|
|
1461
1511
|
}
|
|
1512
|
+
function createInlineNetLabelText(params) {
|
|
1513
|
+
const {
|
|
1514
|
+
connectedWires,
|
|
1515
|
+
document,
|
|
1516
|
+
location,
|
|
1517
|
+
name,
|
|
1518
|
+
options,
|
|
1519
|
+
record,
|
|
1520
|
+
recordIndex,
|
|
1521
|
+
sourceTraceId
|
|
1522
|
+
} = params;
|
|
1523
|
+
const direction = getInlineNetLabelDirection(record, location, connectedWires);
|
|
1524
|
+
const scaledLocation = scalePoint(location, options.scale);
|
|
1525
|
+
const fontSize = getInlineNetLabelFontSize(record, document, options.scale);
|
|
1526
|
+
const fontScale = fontSize / DEFAULT_INLINE_NET_LABEL_FONT_SIZE;
|
|
1527
|
+
const textWidth = (name.length * INLINE_NET_LABEL_CHARACTER_WIDTH + INLINE_NET_LABEL_HORIZONTAL_PADDING) * fontScale;
|
|
1528
|
+
const isVertical = direction === "up" || direction === "down";
|
|
1529
|
+
const directionSign = direction === "left" || direction === "down" ? -1 : 1;
|
|
1530
|
+
const isTerminalPort = record.recordKind === "18";
|
|
1531
|
+
const anchor = isTerminalPort ? directionSign > 0 ? "left" : "right" : "center";
|
|
1532
|
+
const position = isTerminalPort ? isVertical ? {
|
|
1533
|
+
x: scaledLocation.x - fontSize / 2,
|
|
1534
|
+
y: scaledLocation.y
|
|
1535
|
+
} : {
|
|
1536
|
+
x: scaledLocation.x,
|
|
1537
|
+
y: scaledLocation.y + fontSize / 2
|
|
1538
|
+
} : isVertical ? {
|
|
1539
|
+
x: scaledLocation.x - fontSize / 2,
|
|
1540
|
+
y: scaledLocation.y + directionSign * textWidth / 2
|
|
1541
|
+
} : {
|
|
1542
|
+
x: scaledLocation.x + directionSign * textWidth / 2,
|
|
1543
|
+
y: scaledLocation.y + fontSize / 2
|
|
1544
|
+
};
|
|
1545
|
+
return {
|
|
1546
|
+
type: "schematic_text",
|
|
1547
|
+
anchor,
|
|
1548
|
+
color: INLINE_NET_LABEL_COLOR,
|
|
1549
|
+
font_size: fontSize,
|
|
1550
|
+
position,
|
|
1551
|
+
rotation: isVertical ? -90 : 0,
|
|
1552
|
+
schematic_sheet_id: options.schematicSheetId,
|
|
1553
|
+
schematic_text_id: `schematic_inline_net_label_altium_${recordIndex}`,
|
|
1554
|
+
source_trace_id: sourceTraceId,
|
|
1555
|
+
text: name
|
|
1556
|
+
};
|
|
1557
|
+
}
|
|
1558
|
+
function getInlineNetLabelFontSize(record, document, scale) {
|
|
1559
|
+
const fontId = Math.max(
|
|
1560
|
+
Math.round(Number(record.getCaseInsensitive("FONTID") ?? 1)),
|
|
1561
|
+
1
|
|
1562
|
+
);
|
|
1563
|
+
const sheetRecord = document.records.find(
|
|
1564
|
+
(candidate) => candidate.recordKind === "31"
|
|
1565
|
+
);
|
|
1566
|
+
const sourceFontSize = Number(
|
|
1567
|
+
sheetRecord?.getCaseInsensitive(`SIZE${fontId}`) ?? DEFAULT_INLINE_NET_LABEL_FONT_SIZE / scale
|
|
1568
|
+
);
|
|
1569
|
+
return Math.min(
|
|
1570
|
+
DEFAULT_INLINE_NET_LABEL_FONT_SIZE,
|
|
1571
|
+
Math.max(MIN_INLINE_NET_LABEL_FONT_SIZE, sourceFontSize * scale)
|
|
1572
|
+
);
|
|
1573
|
+
}
|
|
1574
|
+
function getInlineNetLabelDirection(record, location, connectedWires) {
|
|
1575
|
+
if (record.recordKind !== "18") return getRecordDirection(record);
|
|
1576
|
+
for (const wire of connectedWires) {
|
|
1577
|
+
const points = getSchematicRecordPoints(wire);
|
|
1578
|
+
for (let pointIndex = 1; pointIndex < points.length; pointIndex++) {
|
|
1579
|
+
const start = points[pointIndex - 1];
|
|
1580
|
+
const end = points[pointIndex];
|
|
1581
|
+
if (!start || !end || !isPointOnSegment(location, start, end)) continue;
|
|
1582
|
+
const other = pointsEqual(location, start) ? end : pointsEqual(location, end) ? start : void 0;
|
|
1583
|
+
if (!other) continue;
|
|
1584
|
+
const dx = location.x - other.x;
|
|
1585
|
+
const dy = location.y - other.y;
|
|
1586
|
+
if (Math.abs(dx) >= Math.abs(dy)) return dx < 0 ? "left" : "right";
|
|
1587
|
+
return dy < 0 ? "down" : "up";
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
return getRecordDirection(record);
|
|
1591
|
+
}
|
|
1592
|
+
function getWireSegments(wires) {
|
|
1593
|
+
return wires.flatMap((wire) => {
|
|
1594
|
+
const points = getSchematicRecordPoints(wire);
|
|
1595
|
+
const segments = [];
|
|
1596
|
+
for (let pointIndex = 1; pointIndex < points.length; pointIndex++) {
|
|
1597
|
+
const start = points[pointIndex - 1];
|
|
1598
|
+
const end = points[pointIndex];
|
|
1599
|
+
if (start && end) segments.push({ end, start });
|
|
1600
|
+
}
|
|
1601
|
+
return segments;
|
|
1602
|
+
});
|
|
1603
|
+
}
|
|
1604
|
+
function getPortConnectionGeometry(record, wireSegments) {
|
|
1605
|
+
const origin = getLocation(record);
|
|
1606
|
+
if (!origin) return void 0;
|
|
1607
|
+
const originToExtremity = getRecordDirection(record);
|
|
1608
|
+
const directionVector = VECTOR_BY_DIRECTION[originToExtremity];
|
|
1609
|
+
const width = Math.max(record.getNumber("WIDTH") ?? 16, 0);
|
|
1610
|
+
const extremity = {
|
|
1611
|
+
x: origin.x + directionVector.x * width,
|
|
1612
|
+
y: origin.y + directionVector.y * width
|
|
1613
|
+
};
|
|
1614
|
+
const touchesWire = (point) => wireSegments.some(
|
|
1615
|
+
(segment) => isPointOnSegment(point, segment.start, segment.end)
|
|
1616
|
+
);
|
|
1617
|
+
const originConnected = touchesWire(origin);
|
|
1618
|
+
const extremityConnected = touchesWire(extremity);
|
|
1619
|
+
const connectedEnd = record.getNumber("CONNECTEDEND");
|
|
1620
|
+
const connectsAtExtremity = connectedEnd === 2 || connectedEnd !== 1 && connectedEnd !== 3 && !originConnected && extremityConnected;
|
|
1621
|
+
return connectsAtExtremity ? {
|
|
1622
|
+
anchor: extremity,
|
|
1623
|
+
bodyDirection: getOppositeDirection(originToExtremity)
|
|
1624
|
+
} : { anchor: origin, bodyDirection: originToExtremity };
|
|
1625
|
+
}
|
|
1626
|
+
function getOppositeDirection(direction) {
|
|
1627
|
+
if (direction === "up") return "down";
|
|
1628
|
+
if (direction === "down") return "up";
|
|
1629
|
+
return direction === "left" ? "right" : "left";
|
|
1630
|
+
}
|
|
1462
1631
|
function getOrCreateSourceNet(params) {
|
|
1463
1632
|
const { elements, name, sourceNetIdByName } = params;
|
|
1464
1633
|
const normalizedName = name.trim().toUpperCase();
|