@tscircuit/cli 0.1.2126 → 0.1.2127
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/cli/main.js +607 -218
- package/dist/lib/index.js +1 -1
- package/package.json +2 -2
package/dist/cli/main.js
CHANGED
|
@@ -154317,7 +154317,7 @@ var package_default = {
|
|
|
154317
154317
|
"@tscircuit/check-shorts": "https://jscdn.tscircuit.com/@tscircuit/check-shorts/0.0.24.tgz",
|
|
154318
154318
|
"@tscircuit/circuit-json-placement-analysis": "^0.0.15",
|
|
154319
154319
|
"@tscircuit/circuit-json-routing-analysis": "^0.0.8",
|
|
154320
|
-
"@tscircuit/circuit-json-schematic-placement-analysis": "
|
|
154320
|
+
"@tscircuit/circuit-json-schematic-placement-analysis": "https://jscdn.tscircuit.com/@tscircuit/circuit-json-schematic-placement-analysis/0.0.11.tgz",
|
|
154321
154321
|
"@tscircuit/circuit-json-util": "^0.0.113",
|
|
154322
154322
|
"@tscircuit/eval": "0.0.1402",
|
|
154323
154323
|
"@tscircuit/fake-snippets": "^0.0.182",
|
|
@@ -331022,8 +331022,129 @@ function segmentCrossesBox(a, b, box) {
|
|
|
331022
331022
|
return Math.max(a.x, b.x) > bounds.left && Math.min(a.x, b.x) < bounds.right && Math.max(a.y, b.y) > bounds.bottom && Math.min(a.y, b.y) < bounds.top;
|
|
331023
331023
|
}
|
|
331024
331024
|
|
|
331025
|
-
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/
|
|
331025
|
+
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/LowSideTransistorPlacementSolver/LowSideTransistorPlacementSolver.ts
|
|
331026
331026
|
import { BaseSolver as BaseSolver6 } from "@tscircuit/solver-utils";
|
|
331027
|
+
class LowSideTransistorPlacementSolver extends BaseSolver6 {
|
|
331028
|
+
index;
|
|
331029
|
+
positiveNets = new Set;
|
|
331030
|
+
transistorIds;
|
|
331031
|
+
issues;
|
|
331032
|
+
currentIndex = 0;
|
|
331033
|
+
constructor({
|
|
331034
|
+
ctx,
|
|
331035
|
+
issues
|
|
331036
|
+
}) {
|
|
331037
|
+
super();
|
|
331038
|
+
this.issues = issues;
|
|
331039
|
+
this.index = new PlacementNetworkIndex(ctx);
|
|
331040
|
+
for (const element of ctx.circuitJson) {
|
|
331041
|
+
if (element.type === "source_net" && element.is_positive_voltage_source)
|
|
331042
|
+
this.positiveNets.add(this.index.connected(element.source_net_id));
|
|
331043
|
+
}
|
|
331044
|
+
this.transistorIds = [...this.index.components.values()].filter((component) => component.ftype === "simple_transistor" && component.transistor_type === "npn").map((component) => component.source_component_id);
|
|
331045
|
+
this.solved = this.transistorIds.length === 0;
|
|
331046
|
+
}
|
|
331047
|
+
_step() {
|
|
331048
|
+
const id = this.transistorIds[this.currentIndex++];
|
|
331049
|
+
this.solved = this.currentIndex >= this.transistorIds.length;
|
|
331050
|
+
if (!id)
|
|
331051
|
+
return;
|
|
331052
|
+
const index = this.index;
|
|
331053
|
+
const transistor = index.placement(id);
|
|
331054
|
+
if (!transistor || index.portsByComponent.get(id)?.length !== 3)
|
|
331055
|
+
return;
|
|
331056
|
+
const base = index.namedPort(id, "base");
|
|
331057
|
+
const collector = index.namedPort(id, "collector");
|
|
331058
|
+
const emitter = index.namedPort(id, "emitter");
|
|
331059
|
+
if (!base || !collector || !emitter)
|
|
331060
|
+
return;
|
|
331061
|
+
const baseNet = index.connected(base.source_port_id);
|
|
331062
|
+
const collectorNet = index.connected(collector.source_port_id);
|
|
331063
|
+
const emitterNet = index.connected(emitter.source_port_id);
|
|
331064
|
+
if (new Set([baseNet, collectorNet, emitterNet]).size !== 3 || !index.groundNets.has(emitterNet) || index.powerNets.has(emitterNet) || index.isRail(baseNet) || index.isRail(collectorNet))
|
|
331065
|
+
return;
|
|
331066
|
+
const basePeers = (index.portsByNet.get(baseNet) ?? []).filter((port) => port.source_component_id !== id);
|
|
331067
|
+
if (basePeers.length !== 1)
|
|
331068
|
+
return;
|
|
331069
|
+
const resistorId = basePeers[0].source_component_id;
|
|
331070
|
+
const resistor = index.components.get(resistorId);
|
|
331071
|
+
const baseResistor = index.placement(resistorId);
|
|
331072
|
+
const resistorNets = index.twoTerminalNets(resistorId);
|
|
331073
|
+
const inputNet = resistorNets?.find((net) => net !== baseNet);
|
|
331074
|
+
if (resistor?.ftype !== "simple_resistor" || resistor.resistance <= 0 || !baseResistor || !index.sameLocalScope(transistor, baseResistor) || !inputNet || index.isRail(inputNet) || inputNet === collectorNet)
|
|
331075
|
+
return;
|
|
331076
|
+
const collectorPeers = (index.portsByNet.get(collectorNet) ?? []).filter((port) => port.source_component_id !== id);
|
|
331077
|
+
const loadPeers = collectorPeers.filter((port) => {
|
|
331078
|
+
const type = index.components.get(port.source_component_id)?.ftype;
|
|
331079
|
+
return type === "simple_chip";
|
|
331080
|
+
});
|
|
331081
|
+
if (loadPeers.length !== 1)
|
|
331082
|
+
return;
|
|
331083
|
+
const loadId = loadPeers[0].source_component_id;
|
|
331084
|
+
const load2 = index.placement(loadId);
|
|
331085
|
+
const loadNets = index.twoTerminalNets(loadId);
|
|
331086
|
+
const supplyNet = loadNets?.find((net) => net !== collectorNet);
|
|
331087
|
+
if (!load2 || !index.sameLocalScope(transistor, load2) || !supplyNet || !this.positiveNets.has(supplyNet) || index.groundNets.has(supplyNet))
|
|
331088
|
+
return;
|
|
331089
|
+
const clampPeers = collectorPeers.filter((port) => port.source_component_id !== loadId);
|
|
331090
|
+
if (clampPeers.length !== 1)
|
|
331091
|
+
return;
|
|
331092
|
+
const clampId = clampPeers[0].source_component_id;
|
|
331093
|
+
const clamp = index.placement(clampId);
|
|
331094
|
+
const anode = index.namedPort(clampId, "anode");
|
|
331095
|
+
const cathode = index.namedPort(clampId, "cathode");
|
|
331096
|
+
if (index.components.get(clampId)?.ftype !== "simple_diode" || !index.twoTerminalNets(clampId) || !anode || !cathode || index.connected(anode.source_port_id) !== collectorNet || index.connected(cathode.source_port_id) !== supplyNet || !clamp || !index.sameLocalScope(transistor, clamp))
|
|
331097
|
+
return;
|
|
331098
|
+
const collectorPin = index.port(collector);
|
|
331099
|
+
const emitterPin = index.port(emitter);
|
|
331100
|
+
const basePin = index.port(base);
|
|
331101
|
+
if (!collectorPin || !emitterPin || !basePin)
|
|
331102
|
+
return;
|
|
331103
|
+
const collectorFacingDirection = collectorPin.facing_direction;
|
|
331104
|
+
const emitterFacingDirection = emitterPin.facing_direction;
|
|
331105
|
+
if (!collectorFacingDirection || !emitterFacingDirection)
|
|
331106
|
+
return;
|
|
331107
|
+
const placementProblems = [];
|
|
331108
|
+
if (transistor.schY >= load2.schY)
|
|
331109
|
+
placementProblems.push("transistor_not_below_load");
|
|
331110
|
+
if (collectorFacingDirection !== "up")
|
|
331111
|
+
placementProblems.push("collector_not_up");
|
|
331112
|
+
if (emitterFacingDirection !== "down")
|
|
331113
|
+
placementProblems.push("emitter_not_down");
|
|
331114
|
+
if (placementProblems.length === 0)
|
|
331115
|
+
return;
|
|
331116
|
+
const name = transistor.sourceComponentName ?? id;
|
|
331117
|
+
const loadName = load2.sourceComponentName ?? loadId;
|
|
331118
|
+
this.issues.push({
|
|
331119
|
+
lineItemType: "LowSideTransistorNotAlignedWithLoad",
|
|
331120
|
+
transistorSchematicBox: transistor,
|
|
331121
|
+
loadSchematicBox: load2,
|
|
331122
|
+
baseResistorSchematicBox: baseResistor,
|
|
331123
|
+
clampDiodeSchematicBox: clamp,
|
|
331124
|
+
collectorSourcePortId: collector.source_port_id,
|
|
331125
|
+
emitterSourcePortId: emitter.source_port_id,
|
|
331126
|
+
collectorFacingDirection,
|
|
331127
|
+
emitterFacingDirection,
|
|
331128
|
+
placementProblems,
|
|
331129
|
+
message: `Arrange ${name} below ${loadName}, with its collector facing up toward the load and emitter facing down toward ground; place ${baseResistor.sourceComponentName ?? resistorId} beside the base. Preserve all pin connections and reroute affected traces.`
|
|
331130
|
+
});
|
|
331131
|
+
}
|
|
331132
|
+
static issueToString(issue) {
|
|
331133
|
+
const attrs = [];
|
|
331134
|
+
addAttr(attrs, "transistorName", issue.transistorSchematicBox.sourceComponentName);
|
|
331135
|
+
addAttr(attrs, "loadName", issue.loadSchematicBox.sourceComponentName);
|
|
331136
|
+
addAttr(attrs, "baseResistorName", issue.baseResistorSchematicBox.sourceComponentName);
|
|
331137
|
+
addAttr(attrs, "clampDiodeName", issue.clampDiodeSchematicBox.sourceComponentName);
|
|
331138
|
+
addAttr(attrs, "placementProblems", issue.placementProblems.join(","));
|
|
331139
|
+
addAttr(attrs, "collectorFacingDirection", issue.collectorFacingDirection);
|
|
331140
|
+
addAttr(attrs, "emitterFacingDirection", issue.emitterFacingDirection);
|
|
331141
|
+
addAttr(attrs, "message", issue.message);
|
|
331142
|
+
return `<LowSideTransistorNotAlignedWithLoad ${attrs.join(" ")} />`;
|
|
331143
|
+
}
|
|
331144
|
+
}
|
|
331145
|
+
|
|
331146
|
+
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/CapacitorOrientationSolver/CapacitorOrientationSolver.ts
|
|
331147
|
+
import { BaseSolver as BaseSolver7 } from "@tscircuit/solver-utils";
|
|
331027
331148
|
|
|
331028
331149
|
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/utils/graphics.ts
|
|
331029
331150
|
import { mergeGraphics as mergeGraphics2 } from "graphics-debug";
|
|
@@ -331058,7 +331179,8 @@ function visualizeCircuitJson(circuitJson) {
|
|
|
331058
331179
|
}
|
|
331059
331180
|
|
|
331060
331181
|
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/CapacitorOrientationSolver/CapacitorOrientationSolver.ts
|
|
331061
|
-
class CapacitorOrientationSolver extends
|
|
331182
|
+
class CapacitorOrientationSolver extends BaseSolver7 {
|
|
331183
|
+
static EPSILON = 0.01;
|
|
331062
331184
|
static ORIENTATION_MESSAGE = 'Use schOrientation="vertical" on this capacitor to fix the symbol orientation';
|
|
331063
331185
|
ctx;
|
|
331064
331186
|
out;
|
|
@@ -331163,12 +331285,32 @@ class CapacitorOrientationSolver extends BaseSolver6 {
|
|
|
331163
331285
|
return;
|
|
331164
331286
|
if (this.feedbackCapacitorIds.has(placement.sourceComponentId))
|
|
331165
331287
|
return;
|
|
331288
|
+
if (this.isInlineWithHorizontalTraces(placement.schematicComponentId))
|
|
331289
|
+
return;
|
|
331166
331290
|
return {
|
|
331167
331291
|
lineItemType: "CapacitorSymbolHorizontal",
|
|
331168
331292
|
schematicBox: this.createIssuePlacement(placement),
|
|
331169
331293
|
message: CapacitorOrientationSolver.ORIENTATION_MESSAGE
|
|
331170
331294
|
};
|
|
331171
331295
|
}
|
|
331296
|
+
isInlineWithHorizontalTraces(schematicComponentId) {
|
|
331297
|
+
const ports = this.ctx.circuitJson.filter((element) => element.type === "schematic_port" && element.schematic_component_id === schematicComponentId);
|
|
331298
|
+
if (ports.length !== 2)
|
|
331299
|
+
return false;
|
|
331300
|
+
const traces = ports.map((port) => this.getOutwardHorizontalTrace(port));
|
|
331301
|
+
return traces.every((trace) => trace !== undefined) && traces.some((trace) => trace !== undefined && trace.edges.every((edge) => Math.abs(edge.from.y - edge.to.y) <= CapacitorOrientationSolver.EPSILON));
|
|
331302
|
+
}
|
|
331303
|
+
getOutwardHorizontalTrace(port) {
|
|
331304
|
+
if (port.facing_direction !== "left" && port.facing_direction !== "right")
|
|
331305
|
+
return;
|
|
331306
|
+
return this.ctx.circuitJson.find((element) => element.type === "schematic_trace" && element.schematic_sheet_id === port.schematic_sheet_id && element.edges.some((edge) => {
|
|
331307
|
+
const other = this.pointsEqual(edge.from, port.center) ? edge.to : this.pointsEqual(edge.to, port.center) ? edge.from : undefined;
|
|
331308
|
+
return other !== undefined && Math.abs(other.y - port.center.y) <= CapacitorOrientationSolver.EPSILON && (port.facing_direction === "left" ? other.x < port.center.x - CapacitorOrientationSolver.EPSILON : other.x > port.center.x + CapacitorOrientationSolver.EPSILON);
|
|
331309
|
+
}));
|
|
331310
|
+
}
|
|
331311
|
+
pointsEqual(first, second) {
|
|
331312
|
+
return Math.abs(first.x - second.x) <= CapacitorOrientationSolver.EPSILON && Math.abs(first.y - second.y) <= CapacitorOrientationSolver.EPSILON;
|
|
331313
|
+
}
|
|
331172
331314
|
static issueToString(issue) {
|
|
331173
331315
|
const attrs = [];
|
|
331174
331316
|
addAttr(attrs, "componentName", issue.schematicBox.sourceComponentName);
|
|
@@ -331182,8 +331324,8 @@ class CapacitorOrientationSolver extends BaseSolver6 {
|
|
|
331182
331324
|
}
|
|
331183
331325
|
|
|
331184
331326
|
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/DecouplingCapacitorGroupingSolver/DecouplingCapacitorGroupingSolver.ts
|
|
331185
|
-
import { BaseSolver as
|
|
331186
|
-
class DecouplingCapacitorGroupingSolver extends
|
|
331327
|
+
import { BaseSolver as BaseSolver8 } from "@tscircuit/solver-utils";
|
|
331328
|
+
class DecouplingCapacitorGroupingSolver extends BaseSolver8 {
|
|
331187
331329
|
params;
|
|
331188
331330
|
static MIN_BODY_GAP = 4;
|
|
331189
331331
|
banks = [];
|
|
@@ -331279,13 +331421,45 @@ class DecouplingCapacitorGroupingSolver extends BaseSolver7 {
|
|
|
331279
331421
|
}
|
|
331280
331422
|
}
|
|
331281
331423
|
|
|
331424
|
+
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/utils/net-label-bounds.ts
|
|
331425
|
+
function getNetLabelBounds(label) {
|
|
331426
|
+
const anchorSide = label.anchor_side;
|
|
331427
|
+
const isVertical = anchorSide === "top" || anchorSide === "bottom";
|
|
331428
|
+
if (isVertical) {
|
|
331429
|
+
const anchorY = label.anchor_position?.y ?? label.center.y;
|
|
331430
|
+
const textHalfExtent = (label.text?.length ?? 8) * 0.13 / 2 + 0.1;
|
|
331431
|
+
const left = label.center.x - 0.1;
|
|
331432
|
+
const right = label.center.x + 0.1;
|
|
331433
|
+
if (anchorSide === "top") {
|
|
331434
|
+
return {
|
|
331435
|
+
left,
|
|
331436
|
+
right,
|
|
331437
|
+
top: anchorY,
|
|
331438
|
+
bottom: anchorY - textHalfExtent * 2
|
|
331439
|
+
};
|
|
331440
|
+
}
|
|
331441
|
+
return { left, right, top: anchorY + textHalfExtent * 2, bottom: anchorY };
|
|
331442
|
+
}
|
|
331443
|
+
const anchorX = label.anchor_position?.x ?? label.center.x;
|
|
331444
|
+
const halfWidth = Math.abs(label.center.x - anchorX);
|
|
331445
|
+
const farHalfWidth = halfWidth + 0.1;
|
|
331446
|
+
const top = label.center.y + 0.1;
|
|
331447
|
+
const bottom = label.center.y - 0.1;
|
|
331448
|
+
if (label.center.x >= anchorX) {
|
|
331449
|
+
return {
|
|
331450
|
+
left: anchorX,
|
|
331451
|
+
right: label.center.x + farHalfWidth,
|
|
331452
|
+
top,
|
|
331453
|
+
bottom
|
|
331454
|
+
};
|
|
331455
|
+
}
|
|
331456
|
+
return { left: label.center.x - farHalfWidth, right: anchorX, top, bottom };
|
|
331457
|
+
}
|
|
331458
|
+
|
|
331282
331459
|
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/ComponentNetLabelCollisionSolver/ComponentNetLabelCollisionSolver.ts
|
|
331283
|
-
import { BaseSolver as
|
|
331284
|
-
class ComponentNetLabelCollisionSolver extends
|
|
331460
|
+
import { BaseSolver as BaseSolver9 } from "@tscircuit/solver-utils";
|
|
331461
|
+
class ComponentNetLabelCollisionSolver extends BaseSolver9 {
|
|
331285
331462
|
params;
|
|
331286
|
-
LABEL_HALF_HEIGHT = 0.1;
|
|
331287
|
-
LABEL_BOUNDS_SLACK = 0.1;
|
|
331288
|
-
SCH_CHAR_WIDTH = 0.13;
|
|
331289
331463
|
placements;
|
|
331290
331464
|
netLabelsByComponentId;
|
|
331291
331465
|
rawCollisions = [];
|
|
@@ -331338,8 +331512,8 @@ class ComponentNetLabelCollisionSolver extends BaseSolver8 {
|
|
|
331338
331512
|
const hits = [];
|
|
331339
331513
|
for (const leftLabel of leftLabels) {
|
|
331340
331514
|
for (const rightLabel of rightLabels) {
|
|
331341
|
-
const leftBounds =
|
|
331342
|
-
const rightBounds =
|
|
331515
|
+
const leftBounds = getNetLabelBounds(leftLabel);
|
|
331516
|
+
const rightBounds = getNetLabelBounds(rightLabel);
|
|
331343
331517
|
if (rectOverlap(leftBounds, rightBounds)) {
|
|
331344
331518
|
hits.push({
|
|
331345
331519
|
type: "label-label",
|
|
@@ -331372,7 +331546,7 @@ class ComponentNetLabelCollisionSolver extends BaseSolver8 {
|
|
|
331372
331546
|
const boxIsLeft = boxComp.schX <= labelComp.schX;
|
|
331373
331547
|
const hits = [];
|
|
331374
331548
|
for (const label of labels) {
|
|
331375
|
-
const labelBounds =
|
|
331549
|
+
const labelBounds = getNetLabelBounds(label);
|
|
331376
331550
|
if (!rectOverlap(boxBounds, labelBounds))
|
|
331377
331551
|
continue;
|
|
331378
331552
|
let xSeparation;
|
|
@@ -331593,39 +331767,6 @@ class ComponentNetLabelCollisionSolver extends BaseSolver8 {
|
|
|
331593
331767
|
}
|
|
331594
331768
|
return result;
|
|
331595
331769
|
}
|
|
331596
|
-
getNetLabelBounds(label) {
|
|
331597
|
-
const anchorSide = label.anchor_side;
|
|
331598
|
-
const isVertical = anchorSide === "top" || anchorSide === "bottom";
|
|
331599
|
-
if (isVertical) {
|
|
331600
|
-
const anchorY = label.anchor_position?.y ?? label.center.y;
|
|
331601
|
-
const textHalfExtent = (label.text?.length ?? 8) * this.SCH_CHAR_WIDTH / 2 + this.LABEL_BOUNDS_SLACK;
|
|
331602
|
-
const left = label.center.x - this.LABEL_HALF_HEIGHT;
|
|
331603
|
-
const right = label.center.x + this.LABEL_HALF_HEIGHT;
|
|
331604
|
-
if (anchorSide === "top") {
|
|
331605
|
-
return {
|
|
331606
|
-
left,
|
|
331607
|
-
right,
|
|
331608
|
-
top: anchorY,
|
|
331609
|
-
bottom: anchorY - textHalfExtent * 2
|
|
331610
|
-
};
|
|
331611
|
-
}
|
|
331612
|
-
return { left, right, top: anchorY + textHalfExtent * 2, bottom: anchorY };
|
|
331613
|
-
}
|
|
331614
|
-
const anchorX = label.anchor_position?.x ?? label.center.x;
|
|
331615
|
-
const halfWidth = Math.abs(label.center.x - anchorX);
|
|
331616
|
-
const farHalfWidth = halfWidth + this.LABEL_BOUNDS_SLACK;
|
|
331617
|
-
const top = label.center.y + this.LABEL_HALF_HEIGHT;
|
|
331618
|
-
const bottom = label.center.y - this.LABEL_HALF_HEIGHT;
|
|
331619
|
-
if (label.center.x >= anchorX) {
|
|
331620
|
-
return {
|
|
331621
|
-
left: anchorX,
|
|
331622
|
-
right: label.center.x + farHalfWidth,
|
|
331623
|
-
top,
|
|
331624
|
-
bottom
|
|
331625
|
-
};
|
|
331626
|
-
}
|
|
331627
|
-
return { left: label.center.x - farHalfWidth, right: anchorX, top, bottom };
|
|
331628
|
-
}
|
|
331629
331770
|
static netLabelCollisionToString(issue) {
|
|
331630
331771
|
const pairAttrs = issue.pairs.map((pair, i) => `pair${i + 1}="${pair.comp1Name}/${pair.comp2Name}"`).join(" ");
|
|
331631
331772
|
const moves = issue.moves.map((move) => ` <Move componentName="${move.componentName}" newSchX="${move.newSchX}" newSchY="${move.newSchY}" />`);
|
|
@@ -331641,8 +331782,8 @@ class ComponentNetLabelCollisionSolver extends BaseSolver8 {
|
|
|
331641
331782
|
}
|
|
331642
331783
|
|
|
331643
331784
|
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/ComponentPinAlignmentSolver/ComponentPinAlignmentSolver.ts
|
|
331644
|
-
import { BaseSolver as
|
|
331645
|
-
class ComponentPinAlignmentSolver extends
|
|
331785
|
+
import { BaseSolver as BaseSolver10 } from "@tscircuit/solver-utils";
|
|
331786
|
+
class ComponentPinAlignmentSolver extends BaseSolver10 {
|
|
331646
331787
|
static ALIGNMENT_EPSILON = 0.01;
|
|
331647
331788
|
ctx;
|
|
331648
331789
|
out;
|
|
@@ -331776,8 +331917,8 @@ class ComponentPinAlignmentSolver extends BaseSolver9 {
|
|
|
331776
331917
|
}
|
|
331777
331918
|
|
|
331778
331919
|
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/CrystalLoadCapacitorPlacementSolver/CrystalLoadCapacitorPlacementSolver.ts
|
|
331779
|
-
import { BaseSolver as
|
|
331780
|
-
class CrystalLoadCapacitorPlacementSolver extends
|
|
331920
|
+
import { BaseSolver as BaseSolver11 } from "@tscircuit/solver-utils";
|
|
331921
|
+
class CrystalLoadCapacitorPlacementSolver extends BaseSolver11 {
|
|
331781
331922
|
static ALIGNMENT_TOLERANCE = 0.1;
|
|
331782
331923
|
issues;
|
|
331783
331924
|
networks;
|
|
@@ -331937,13 +332078,15 @@ var distance50 = (first, second) => Math.hypot(first.schX - second.schX, first.s
|
|
|
331937
332078
|
var round2 = (value) => Math.round(value * 100) / 100;
|
|
331938
332079
|
|
|
331939
332080
|
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/DiodeResistorAlignmentSolver/DiodeResistorAlignmentSolver.ts
|
|
331940
|
-
import { BaseSolver as
|
|
331941
|
-
|
|
332081
|
+
import { BaseSolver as BaseSolver12 } from "@tscircuit/solver-utils";
|
|
332082
|
+
import { getSourcePortConnectivityMapFromCircuitJson as getSourcePortConnectivityMapFromCircuitJson2 } from "circuit-json-to-connectivity-map";
|
|
332083
|
+
class DiodeResistorAlignmentSolver extends BaseSolver12 {
|
|
331942
332084
|
static DIODE_FTYPES = new Set(["simple_led", "simple_diode"]);
|
|
331943
332085
|
ctx;
|
|
331944
332086
|
out;
|
|
331945
332087
|
schematicTraces;
|
|
331946
332088
|
currentIndex = 0;
|
|
332089
|
+
sourceConnectivity;
|
|
331947
332090
|
sourceComponentFtypeById;
|
|
331948
332091
|
sourceComponentIdBySourcePortId;
|
|
331949
332092
|
schematicPorts;
|
|
@@ -331956,6 +332099,7 @@ class DiodeResistorAlignmentSolver extends BaseSolver11 {
|
|
|
331956
332099
|
this.ctx = ctx;
|
|
331957
332100
|
this.out = issues;
|
|
331958
332101
|
const { circuitJson } = ctx;
|
|
332102
|
+
this.sourceConnectivity = getSourcePortConnectivityMapFromCircuitJson2(circuitJson);
|
|
331959
332103
|
this.sourceComponentFtypeById = this.buildSourceComponentFtypeById(circuitJson);
|
|
331960
332104
|
this.sourceComponentIdBySourcePortId = this.buildSourceComponentIdBySourcePortId(circuitJson);
|
|
331961
332105
|
this.schematicPorts = circuitJson.filter((el) => el.type === "schematic_port");
|
|
@@ -332000,6 +332144,8 @@ class DiodeResistorAlignmentSolver extends BaseSolver11 {
|
|
|
332000
332144
|
const resistorPort = this.findNearestPort(startFtype === "simple_resistor" ? start : end, schematicSheetId);
|
|
332001
332145
|
if (!diodePort?.center || !resistorPort?.center)
|
|
332002
332146
|
return;
|
|
332147
|
+
if (!this.sourceConnectivity.areIdsConnected(diodePort.source_port_id, resistorPort.source_port_id))
|
|
332148
|
+
return;
|
|
332003
332149
|
const diodeName = diodeBox.sourceComponentName ?? diodeCompId;
|
|
332004
332150
|
const resistorName = resistorBox.sourceComponentName ?? resistorCompId;
|
|
332005
332151
|
const diodePin = diodePort?.display_pin_label ?? diodePort?.pin_number?.toString();
|
|
@@ -332100,8 +332246,8 @@ class DiodeResistorAlignmentSolver extends BaseSolver11 {
|
|
|
332100
332246
|
}
|
|
332101
332247
|
|
|
332102
332248
|
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/FeedbackNetworkPlacementSolver/FeedbackNetworkPlacementSolver.ts
|
|
332103
|
-
import { BaseSolver as
|
|
332104
|
-
class FeedbackNetworkPlacementSolver extends
|
|
332249
|
+
import { BaseSolver as BaseSolver13 } from "@tscircuit/solver-utils";
|
|
332250
|
+
class FeedbackNetworkPlacementSolver extends BaseSolver13 {
|
|
332105
332251
|
static MIN_BODY_GAP = 4;
|
|
332106
332252
|
index;
|
|
332107
332253
|
amplifierIds;
|
|
@@ -332186,8 +332332,8 @@ function distanceBetweenBoxes(a, b) {
|
|
|
332186
332332
|
}
|
|
332187
332333
|
|
|
332188
332334
|
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/PullResistorPlacementSolver/PullResistorPlacementSolver.ts
|
|
332189
|
-
import { BaseSolver as
|
|
332190
|
-
class PullResistorPlacementSolver extends
|
|
332335
|
+
import { BaseSolver as BaseSolver14 } from "@tscircuit/solver-utils";
|
|
332336
|
+
class PullResistorPlacementSolver extends BaseSolver14 {
|
|
332191
332337
|
static MIN_WRONG_SIDE_GAP = 1.5;
|
|
332192
332338
|
index;
|
|
332193
332339
|
resistorIds;
|
|
@@ -332283,12 +332429,13 @@ class PullResistorPlacementSolver extends BaseSolver13 {
|
|
|
332283
332429
|
}
|
|
332284
332430
|
|
|
332285
332431
|
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/TwoPinComponentRailOrientationSolver/TwoPinComponentRailOrientationSolver.ts
|
|
332286
|
-
import { BaseSolver as
|
|
332287
|
-
class TwoPinComponentRailOrientationSolver extends
|
|
332432
|
+
import { BaseSolver as BaseSolver15 } from "@tscircuit/solver-utils";
|
|
332433
|
+
class TwoPinComponentRailOrientationSolver extends BaseSolver15 {
|
|
332288
332434
|
static EPSILON = 0.01;
|
|
332289
332435
|
index;
|
|
332290
332436
|
powerNets;
|
|
332291
332437
|
groundNets;
|
|
332438
|
+
positiveVoltageNets = new Set;
|
|
332292
332439
|
componentIds;
|
|
332293
332440
|
issues;
|
|
332294
332441
|
currentIndex = 0;
|
|
@@ -332302,6 +332449,8 @@ class TwoPinComponentRailOrientationSolver extends BaseSolver14 {
|
|
|
332302
332449
|
this.powerNets = new Set(this.index.powerNets);
|
|
332303
332450
|
this.groundNets = new Set(this.index.groundNets);
|
|
332304
332451
|
for (const element of ctx.circuitJson) {
|
|
332452
|
+
if (element.type === "source_net" && element.is_positive_voltage_source)
|
|
332453
|
+
this.positiveVoltageNets.add(this.index.connected(element.source_net_id));
|
|
332305
332454
|
if (element.type !== "source_port")
|
|
332306
332455
|
continue;
|
|
332307
332456
|
const net = this.index.connected(element.source_port_id);
|
|
@@ -332323,6 +332472,8 @@ class TwoPinComponentRailOrientationSolver extends BaseSolver14 {
|
|
|
332323
332472
|
const nets = index.twoTerminalNets(id);
|
|
332324
332473
|
if (!component || !nets)
|
|
332325
332474
|
return;
|
|
332475
|
+
if (index.components.get(id)?.ftype === "simple_inductor" && !nets.some((net) => this.groundNets.has(net)))
|
|
332476
|
+
return;
|
|
332326
332477
|
if (nets.some((net) => this.powerNets.has(net) && this.groundNets.has(net)))
|
|
332327
332478
|
return;
|
|
332328
332479
|
const railTypes = nets.map((net) => this.powerNets.has(net) ? "power" : this.groundNets.has(net) ? "ground" : undefined);
|
|
@@ -332339,6 +332490,20 @@ class TwoPinComponentRailOrientationSolver extends BaseSolver14 {
|
|
|
332339
332490
|
const otherPort = index.port(otherSourcePort);
|
|
332340
332491
|
if (!railPort || !otherPort)
|
|
332341
332492
|
return;
|
|
332493
|
+
const invertedRails = this.positiveVoltageNets.has(rail) && this.groundNets.has(index.connected(otherSourcePort.source_port_id)) && Math.abs(railPort.center.x - otherPort.center.x) <= TwoPinComponentRailOrientationSolver.EPSILON && railPort.center.y < otherPort.center.y - TwoPinComponentRailOrientationSolver.EPSILON && railPort.facing_direction === "down" && otherPort.facing_direction === "up";
|
|
332494
|
+
if (invertedRails) {
|
|
332495
|
+
this.issues.push({
|
|
332496
|
+
lineItemType: "TwoPinComponentHasInvertedRails",
|
|
332497
|
+
schematicBox: component,
|
|
332498
|
+
railSourcePortId: railSourcePort.source_port_id,
|
|
332499
|
+
railPinName: railSourcePort.name,
|
|
332500
|
+
railType: "power",
|
|
332501
|
+
deltaSchRotation: 180,
|
|
332502
|
+
suggestedRailFacingDirection: "up",
|
|
332503
|
+
message: `rotate ${component.sourceComponentName ?? id} by 180° so its positive-supply pin faces up and its ground pin faces down; preserve pin connections and reroute attached traces`
|
|
332504
|
+
});
|
|
332505
|
+
return;
|
|
332506
|
+
}
|
|
332342
332507
|
const horizontal = Math.abs(railPort.center.y - otherPort.center.y) <= TwoPinComponentRailOrientationSolver.EPSILON && Math.abs(railPort.center.x - otherPort.center.x) > TwoPinComponentRailOrientationSolver.EPSILON && (railPort.facing_direction === "left" && otherPort.facing_direction === "right" || railPort.facing_direction === "right" && otherPort.facing_direction === "left");
|
|
332343
332508
|
if (!horizontal)
|
|
332344
332509
|
return;
|
|
@@ -332363,13 +332528,18 @@ class TwoPinComponentRailOrientationSolver extends BaseSolver14 {
|
|
|
332363
332528
|
addAttr(attrs, "deltaSchRotation", issue.deltaSchRotation);
|
|
332364
332529
|
addAttr(attrs, "suggestedRailFacingDirection", issue.suggestedRailFacingDirection);
|
|
332365
332530
|
addAttr(attrs, "message", issue.message);
|
|
332366
|
-
return
|
|
332531
|
+
return `<${issue.lineItemType} ${attrs.join(" ")} />`;
|
|
332367
332532
|
}
|
|
332368
332533
|
}
|
|
332369
332534
|
|
|
332535
|
+
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/utils/schematic-box-components.ts
|
|
332536
|
+
function getSchematicBoxComponentIds(circuitJson) {
|
|
332537
|
+
return new Set(circuitJson.flatMap((element) => element.type === "schematic_component" && element.is_box_with_pins !== false && !element.symbol_name && !element.schematic_symbol_id ? [element.schematic_component_id] : []));
|
|
332538
|
+
}
|
|
332539
|
+
|
|
332370
332540
|
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/SchematicBoxInnerLabelCollisionSolver/SchematicBoxInnerLabelCollisionSolver.ts
|
|
332371
|
-
import { BaseSolver as
|
|
332372
|
-
class SchematicBoxInnerLabelCollisionSolver extends
|
|
332541
|
+
import { BaseSolver as BaseSolver16 } from "@tscircuit/solver-utils";
|
|
332542
|
+
class SchematicBoxInnerLabelCollisionSolver extends BaseSolver16 {
|
|
332373
332543
|
params;
|
|
332374
332544
|
MESSAGE = "Inner labels are colliding. Increase the schWidth or schHeight.";
|
|
332375
332545
|
PIN_LABEL_EDGE_PADDING = 0.1;
|
|
@@ -332388,9 +332558,8 @@ class SchematicBoxInnerLabelCollisionSolver extends BaseSolver15 {
|
|
|
332388
332558
|
const { circuitJson, componentPlacements } = params2.ctx;
|
|
332389
332559
|
this.placementById = this.getPlacementBySchematicComponentId(componentPlacements);
|
|
332390
332560
|
this.sourcePortById = this.getSourcePortById(circuitJson);
|
|
332391
|
-
|
|
332392
|
-
|
|
332393
|
-
this.entries = this.entries.filter(([id]) => !passiveComponentIds.has(id));
|
|
332561
|
+
const boxIds = getSchematicBoxComponentIds(circuitJson);
|
|
332562
|
+
this.entries = Array.from(this.getPortsBySchematicComponentId(circuitJson)).filter(([id]) => boxIds.has(id));
|
|
332394
332563
|
this.solved = this.entries.length === 0;
|
|
332395
332564
|
}
|
|
332396
332565
|
_step() {
|
|
@@ -332567,8 +332736,8 @@ class SchematicBoxInnerLabelCollisionSolver extends BaseSolver15 {
|
|
|
332567
332736
|
}
|
|
332568
332737
|
|
|
332569
332738
|
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/SchematicBoxOverlapSolver/SchematicBoxOverlapSolver.ts
|
|
332570
|
-
import { BaseSolver as
|
|
332571
|
-
class SchematicBoxOverlapSolver extends
|
|
332739
|
+
import { BaseSolver as BaseSolver17 } from "@tscircuit/solver-utils";
|
|
332740
|
+
class SchematicBoxOverlapSolver extends BaseSolver17 {
|
|
332572
332741
|
params;
|
|
332573
332742
|
placements;
|
|
332574
332743
|
firstIndex = 0;
|
|
@@ -332687,8 +332856,8 @@ class SchematicBoxOverlapSolver extends BaseSolver16 {
|
|
|
332687
332856
|
}
|
|
332688
332857
|
|
|
332689
332858
|
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/SchematicBoxTooWideSolver/SchematicBoxTooWideSolver.ts
|
|
332690
|
-
import { BaseSolver as
|
|
332691
|
-
class SchematicBoxTooWideSolver extends
|
|
332859
|
+
import { BaseSolver as BaseSolver18 } from "@tscircuit/solver-utils";
|
|
332860
|
+
class SchematicBoxTooWideSolver extends BaseSolver18 {
|
|
332692
332861
|
params;
|
|
332693
332862
|
SCHEMATIC_BOX_TOO_WIDE_MESSAGE = "Shrink schematic box width";
|
|
332694
332863
|
PIN_HEADER_MAX_ALLOWED_GAP = 0.1;
|
|
@@ -332709,7 +332878,8 @@ class SchematicBoxTooWideSolver extends BaseSolver17 {
|
|
|
332709
332878
|
this.placementById = this.getPlacementBySchematicComponentId(componentPlacements);
|
|
332710
332879
|
this.sourcePortById = this.getSourcePortById(circuitJson);
|
|
332711
332880
|
this.sourceComponentById = this.getSourceComponentById(circuitJson);
|
|
332712
|
-
|
|
332881
|
+
const boxIds = getSchematicBoxComponentIds(circuitJson);
|
|
332882
|
+
this.entries = Array.from(this.getPortsBySchematicComponentId(circuitJson)).filter(([id]) => boxIds.has(id));
|
|
332713
332883
|
this.solved = this.entries.length === 0;
|
|
332714
332884
|
}
|
|
332715
332885
|
_step() {
|
|
@@ -332723,6 +332893,9 @@ class SchematicBoxTooWideSolver extends BaseSolver17 {
|
|
|
332723
332893
|
const schematicBox = this.placementById.get(schematicComponentId);
|
|
332724
332894
|
if (!schematicBox)
|
|
332725
332895
|
return;
|
|
332896
|
+
const sourceComponent = schematicBox.sourceComponentId ? this.sourceComponentById.get(schematicBox.sourceComponentId) : undefined;
|
|
332897
|
+
if (sourceComponent?.ftype === "simple_connector" && sourceComponent.standard === "usb_c")
|
|
332898
|
+
return;
|
|
332726
332899
|
const bounds = this.getCenteredRectBounds(schematicBox);
|
|
332727
332900
|
const leftCol = this.getLabelColumn("left", ports, this.sourcePortById);
|
|
332728
332901
|
const rightCol = this.getLabelColumn("right", ports, this.sourcePortById);
|
|
@@ -332790,6 +332963,7 @@ class SchematicBoxTooWideSolver extends BaseSolver17 {
|
|
|
332790
332963
|
return {
|
|
332791
332964
|
type: "source_component",
|
|
332792
332965
|
source_component_id: el.source_component_id,
|
|
332966
|
+
standard: "standard" in el && typeof el.standard === "string" ? el.standard : undefined,
|
|
332793
332967
|
ftype: "ftype" in el && typeof el.ftype === "string" ? el.ftype : undefined
|
|
332794
332968
|
};
|
|
332795
332969
|
}
|
|
@@ -332863,8 +333037,8 @@ class SchematicBoxTooWideSolver extends BaseSolver17 {
|
|
|
332863
333037
|
}
|
|
332864
333038
|
|
|
332865
333039
|
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/SchematicPinPaddingToEdgeSolver/SchematicPinPaddingToEdgeSolver.ts
|
|
332866
|
-
import { BaseSolver as
|
|
332867
|
-
class SchematicPinPaddingToEdgeSolver extends
|
|
333040
|
+
import { BaseSolver as BaseSolver19 } from "@tscircuit/solver-utils";
|
|
333041
|
+
class SchematicPinPaddingToEdgeSolver extends BaseSolver19 {
|
|
332868
333042
|
params;
|
|
332869
333043
|
MESSAGE = "Move schematic pins closer to the box edge or change the schematic box";
|
|
332870
333044
|
PIN_NAME_CHARACTER_WIDTH = 0.095;
|
|
@@ -332882,7 +333056,8 @@ class SchematicPinPaddingToEdgeSolver extends BaseSolver18 {
|
|
|
332882
333056
|
this.placementById = this.getPlacementBySchematicComponentId(componentPlacements);
|
|
332883
333057
|
this.schematicComponentById = this.getSchematicComponentById(circuitJson);
|
|
332884
333058
|
this.sourcePortById = this.getSourcePortById(circuitJson);
|
|
332885
|
-
|
|
333059
|
+
const boxIds = getSchematicBoxComponentIds(circuitJson);
|
|
333060
|
+
this.entries = Array.from(this.getPortsBySchematicComponentId(circuitJson)).filter(([id]) => boxIds.has(id));
|
|
332886
333061
|
this.solved = this.entries.length === 0;
|
|
332887
333062
|
}
|
|
332888
333063
|
_step() {
|
|
@@ -332909,7 +333084,10 @@ class SchematicPinPaddingToEdgeSolver extends BaseSolver18 {
|
|
|
332909
333084
|
portsBySide.set(port.side_of_component, sidePorts);
|
|
332910
333085
|
}
|
|
332911
333086
|
const useLabelAwareMaxPadding = this.hasPinsOnAllSides(portsBySide);
|
|
333087
|
+
const candidates = [];
|
|
332912
333088
|
for (const [pinSide, sidePorts] of portsBySide) {
|
|
333089
|
+
if (sidePorts.length === 1)
|
|
333090
|
+
continue;
|
|
332913
333091
|
for (const edgeSide of this.getBoxEdgeSidesForPinSide(pinSide)) {
|
|
332914
333092
|
const outerPin = this.getOuterPinBySide(edgeSide, sidePorts);
|
|
332915
333093
|
if (!outerPin)
|
|
@@ -332918,27 +333096,65 @@ class SchematicPinPaddingToEdgeSolver extends BaseSolver18 {
|
|
|
332918
333096
|
const maxAllowedPadding = useLabelAwareMaxPadding ? this.getMaxAllowedPinPadding(pinSpacing, edgeSide, maxLabelLengthBySide) : pinSpacing;
|
|
332919
333097
|
if (!this.exceedsMaxAllowedGap(measuredPadding, maxAllowedPadding))
|
|
332920
333098
|
continue;
|
|
332921
|
-
|
|
333099
|
+
candidates.push({
|
|
332922
333100
|
schematicBox,
|
|
332923
333101
|
pinSide,
|
|
332924
333102
|
edgeSide,
|
|
332925
333103
|
pinName: this.getPinName(outerPin, this.sourcePortById),
|
|
332926
333104
|
measuredPadding,
|
|
332927
333105
|
maxAllowedPadding
|
|
332928
|
-
})
|
|
333106
|
+
});
|
|
332929
333107
|
}
|
|
332930
333108
|
}
|
|
333109
|
+
if (!candidates.length)
|
|
333110
|
+
return;
|
|
333111
|
+
const details = candidates.map((candidate) => this.createIssue(candidate));
|
|
333112
|
+
const representative = details.reduce((a, b) => b.excessPadding > a.excessPadding ? b : a);
|
|
333113
|
+
const widths = details.flatMap((detail) => detail.suggestedSchWidth === undefined ? [] : [detail.suggestedSchWidth]);
|
|
333114
|
+
const heights = details.flatMap((detail) => detail.suggestedSchHeight === undefined ? [] : [detail.suggestedSchHeight]);
|
|
333115
|
+
const dimensions = [
|
|
333116
|
+
widths.length ? "width" : "",
|
|
333117
|
+
heights.length ? "height" : ""
|
|
333118
|
+
].filter(Boolean).join(" and ");
|
|
333119
|
+
this.params.issues.push({
|
|
333120
|
+
...representative,
|
|
333121
|
+
paddingDetails: details.map(({
|
|
333122
|
+
pinSide,
|
|
333123
|
+
edgeSide,
|
|
333124
|
+
pinName,
|
|
333125
|
+
measuredPadding,
|
|
333126
|
+
maxAllowedPadding,
|
|
333127
|
+
excessPadding
|
|
333128
|
+
}) => ({
|
|
333129
|
+
pinSide,
|
|
333130
|
+
edgeSide,
|
|
333131
|
+
pinName,
|
|
333132
|
+
measuredPadding,
|
|
333133
|
+
maxAllowedPadding,
|
|
333134
|
+
excessPadding
|
|
333135
|
+
})),
|
|
333136
|
+
suggestedSchWidth: widths.length ? Math.max(...widths) : undefined,
|
|
333137
|
+
suggestedSchHeight: heights.length ? Math.max(...heights) : undefined,
|
|
333138
|
+
message: `${this.MESSAGE} ${dimensions}`
|
|
333139
|
+
});
|
|
332931
333140
|
}
|
|
332932
333141
|
static issueToString(issue) {
|
|
332933
333142
|
const attrs = [];
|
|
332934
333143
|
addAttr(attrs, "message", issue.message);
|
|
332935
333144
|
addAttr(attrs, "componentName", issue.schematicBox.sourceComponentName);
|
|
332936
|
-
|
|
332937
|
-
|
|
332938
|
-
|
|
332939
|
-
|
|
332940
|
-
|
|
332941
|
-
|
|
333145
|
+
if (issue.paddingDetails) {
|
|
333146
|
+
addAttr(attrs, "pinSides", [...new Set(issue.paddingDetails.map((detail) => detail.pinSide))].join(","));
|
|
333147
|
+
addAttr(attrs, "edgeSides", [
|
|
333148
|
+
...new Set(issue.paddingDetails.map((detail) => detail.edgeSide))
|
|
333149
|
+
].join(","));
|
|
333150
|
+
} else {
|
|
333151
|
+
addAttr(attrs, "pinSide", issue.pinSide);
|
|
333152
|
+
addAttr(attrs, "edgeSide", issue.edgeSide);
|
|
333153
|
+
addAttr(attrs, "pinName", issue.pinName);
|
|
333154
|
+
addAttr(attrs, "measuredPadding", issue.measuredPadding);
|
|
333155
|
+
addAttr(attrs, "maxAllowedPadding", issue.maxAllowedPadding);
|
|
333156
|
+
addAttr(attrs, "excessPadding", issue.excessPadding);
|
|
333157
|
+
}
|
|
332942
333158
|
addAttr(attrs, "suggestedSchWidth", issue.suggestedSchWidth);
|
|
332943
333159
|
addAttr(attrs, "suggestedSchHeight", issue.suggestedSchHeight);
|
|
332944
333160
|
return `<SchematicPinPaddingToEdgeTooLarge ${attrs.join(" ")} />`;
|
|
@@ -333201,9 +333417,160 @@ var buildSolverContext = (circuitJson) => {
|
|
|
333201
333417
|
return { circuitJson, componentPlacements };
|
|
333202
333418
|
};
|
|
333203
333419
|
|
|
333420
|
+
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/utils/trace-name.ts
|
|
333421
|
+
function getTraceName(circuitJson, trace) {
|
|
333422
|
+
const sourceTrace = circuitJson.find((e) => e.type === "source_trace" && e.source_trace_id === trace.source_trace_id);
|
|
333423
|
+
if (sourceTrace?.type === "source_trace" && sourceTrace.name)
|
|
333424
|
+
return sourceTrace.name;
|
|
333425
|
+
const first = trace.edges[0];
|
|
333426
|
+
const last = trace.edges.at(-1);
|
|
333427
|
+
const endpointName = (point, id) => {
|
|
333428
|
+
const ports = circuitJson.filter((e) => e.type === "schematic_port" && e.schematic_sheet_id === trace.schematic_sheet_id && (id ? e.schematic_port_id === id : Math.hypot(e.center.x - point.x, e.center.y - point.y) <= 0.01));
|
|
333429
|
+
if (ports.length !== 1 || ports[0]?.type !== "schematic_port")
|
|
333430
|
+
return;
|
|
333431
|
+
const port = ports[0];
|
|
333432
|
+
const sourcePort = circuitJson.find((e) => e.type === "source_port" && e.source_port_id === port.source_port_id);
|
|
333433
|
+
const component = circuitJson.find((e) => e.type === "schematic_component" && e.schematic_component_id === port.schematic_component_id);
|
|
333434
|
+
const sourceComponentId = sourcePort?.type === "source_port" ? sourcePort.source_component_id : component?.type === "schematic_component" ? component.source_component_id : undefined;
|
|
333435
|
+
const sourceComponent = circuitJson.find((e) => e.type === "source_component" && e.source_component_id === sourceComponentId);
|
|
333436
|
+
if (sourceComponent?.type !== "source_component" || !sourceComponent.name)
|
|
333437
|
+
return;
|
|
333438
|
+
const pin = sourcePort?.type === "source_port" && sourcePort.name ? sourcePort.name : port.pin_number !== undefined ? `pin${port.pin_number}` : port.display_pin_label;
|
|
333439
|
+
return pin ? `${sourceComponent.name}.${pin}` : sourceComponent.name;
|
|
333440
|
+
};
|
|
333441
|
+
const from = first && endpointName(first.from, first.from_schematic_port_id);
|
|
333442
|
+
const to = last && endpointName(last.to, last.to_schematic_port_id);
|
|
333443
|
+
if (from && to)
|
|
333444
|
+
return `${from} to ${to}`;
|
|
333445
|
+
return sourceTrace?.type === "source_trace" && sourceTrace.display_name || from || to || "trace";
|
|
333446
|
+
}
|
|
333447
|
+
|
|
333204
333448
|
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/TraceSimplificationSolver/TraceSimplificationSolver.ts
|
|
333205
|
-
import {
|
|
333206
|
-
|
|
333449
|
+
import { calculateElbow as calculateElbow3 } from "calculate-elbow/lib";
|
|
333450
|
+
|
|
333451
|
+
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/utils/schematic-text-geometry.ts
|
|
333452
|
+
var rectPolygon = (bounds) => [
|
|
333453
|
+
{ x: bounds.left, y: bounds.bottom },
|
|
333454
|
+
{ x: bounds.right, y: bounds.bottom },
|
|
333455
|
+
{ x: bounds.right, y: bounds.top },
|
|
333456
|
+
{ x: bounds.left, y: bounds.top }
|
|
333457
|
+
];
|
|
333458
|
+
var advance = (character) => {
|
|
333459
|
+
if (/\s/.test(character))
|
|
333460
|
+
return 0.28;
|
|
333461
|
+
if (/[ilI.,:;!'|]/.test(character))
|
|
333462
|
+
return 0.25;
|
|
333463
|
+
if (/[MW@%]/.test(character))
|
|
333464
|
+
return 0.9;
|
|
333465
|
+
if (/[mw]/.test(character))
|
|
333466
|
+
return 0.8;
|
|
333467
|
+
if (/[A-Z]/.test(character))
|
|
333468
|
+
return 0.67;
|
|
333469
|
+
return 0.56;
|
|
333470
|
+
};
|
|
333471
|
+
var widthInEm = (text) => Array.from(text).reduce((width, character) => width + advance(character), 0);
|
|
333472
|
+
function getSchematicTextPolygons(text) {
|
|
333473
|
+
const size = text.font_size;
|
|
333474
|
+
if (!Number.isFinite(size) || size <= 0 || !Number.isFinite(text.rotation) || !Number.isFinite(text.position.x) || !Number.isFinite(text.position.y))
|
|
333475
|
+
return [];
|
|
333476
|
+
const anchor = text.anchor;
|
|
333477
|
+
const horizontal = anchor.includes("left") ? 0 : anchor.includes("right") ? 1 : 0.5;
|
|
333478
|
+
const top = anchor.includes("top") ? 0 : anchor.includes("bottom") ? size : size / 2;
|
|
333479
|
+
const radians = -text.rotation * Math.PI / 180;
|
|
333480
|
+
const cos = Math.cos(radians);
|
|
333481
|
+
const sin = Math.sin(radians);
|
|
333482
|
+
return text.text.split(`
|
|
333483
|
+
`).flatMap((line, index) => {
|
|
333484
|
+
const visible = line.trim();
|
|
333485
|
+
if (!visible)
|
|
333486
|
+
return [];
|
|
333487
|
+
const leading = line.length - line.trimStart().length;
|
|
333488
|
+
const left = (widthInEm(line.slice(0, leading)) - widthInEm(line) * horizontal) * size;
|
|
333489
|
+
const polygon = rectPolygon({
|
|
333490
|
+
left,
|
|
333491
|
+
right: left + widthInEm(visible) * size,
|
|
333492
|
+
top: top - index * size - size * 0.05,
|
|
333493
|
+
bottom: top - (index + 1) * size + size * 0.05
|
|
333494
|
+
});
|
|
333495
|
+
return [
|
|
333496
|
+
polygon.map(({ x, y }) => ({
|
|
333497
|
+
x: text.position.x + x * cos - y * sin,
|
|
333498
|
+
y: text.position.y + x * sin + y * cos
|
|
333499
|
+
}))
|
|
333500
|
+
];
|
|
333501
|
+
});
|
|
333502
|
+
}
|
|
333503
|
+
function polygonsOverlap(a, b) {
|
|
333504
|
+
for (const polygon of [a, b]) {
|
|
333505
|
+
for (let i = 0;i < polygon.length; i++) {
|
|
333506
|
+
const p = polygon[i];
|
|
333507
|
+
const q = polygon[(i + 1) % polygon.length];
|
|
333508
|
+
const length = Math.hypot(q.x - p.x, q.y - p.y);
|
|
333509
|
+
if (length < 0.000000001)
|
|
333510
|
+
continue;
|
|
333511
|
+
const nx = -(q.y - p.y) / length;
|
|
333512
|
+
const ny = (q.x - p.x) / length;
|
|
333513
|
+
const project = (points) => points.map(({ x, y }) => x * nx + y * ny);
|
|
333514
|
+
const pa = project(a);
|
|
333515
|
+
const pb = project(b);
|
|
333516
|
+
if (Math.min(Math.max(...pa), Math.max(...pb)) - Math.max(Math.min(...pa), Math.min(...pb)) <= 0.000001)
|
|
333517
|
+
return false;
|
|
333518
|
+
}
|
|
333519
|
+
}
|
|
333520
|
+
return true;
|
|
333521
|
+
}
|
|
333522
|
+
function traceSegmentPolygon(from, to) {
|
|
333523
|
+
const length = Math.hypot(to.x - from.x, to.y - from.y);
|
|
333524
|
+
if (length < 0.000000001)
|
|
333525
|
+
return;
|
|
333526
|
+
const dx = -(to.y - from.y) / length * 0.01;
|
|
333527
|
+
const dy = (to.x - from.x) / length * 0.01;
|
|
333528
|
+
return [
|
|
333529
|
+
{ x: from.x + dx, y: from.y + dy },
|
|
333530
|
+
{ x: to.x + dx, y: to.y + dy },
|
|
333531
|
+
{ x: to.x - dx, y: to.y - dy },
|
|
333532
|
+
{ x: from.x - dx, y: from.y - dy }
|
|
333533
|
+
];
|
|
333534
|
+
}
|
|
333535
|
+
function segmentCrossesPolygon(from, to, polygon) {
|
|
333536
|
+
if (Math.hypot(to.x - from.x, to.y - from.y) < 0.000000001)
|
|
333537
|
+
return false;
|
|
333538
|
+
let low = 0;
|
|
333539
|
+
let high = 1;
|
|
333540
|
+
for (let i = 0;i < polygon.length; i++) {
|
|
333541
|
+
const p = polygon[i];
|
|
333542
|
+
const q = polygon[(i + 1) % polygon.length];
|
|
333543
|
+
const length = Math.hypot(q.x - p.x, q.y - p.y);
|
|
333544
|
+
if (length < 0.000000001)
|
|
333545
|
+
continue;
|
|
333546
|
+
const nx = -(q.y - p.y) / length;
|
|
333547
|
+
const ny = (q.x - p.x) / length;
|
|
333548
|
+
const start = (from.x - p.x) * nx + (from.y - p.y) * ny - 0.000001;
|
|
333549
|
+
const end = (to.x - p.x) * nx + (to.y - p.y) * ny - 0.000001;
|
|
333550
|
+
if (start <= 0 && end <= 0)
|
|
333551
|
+
return false;
|
|
333552
|
+
if (start <= 0)
|
|
333553
|
+
low = Math.max(low, -start / (end - start));
|
|
333554
|
+
if (end <= 0)
|
|
333555
|
+
high = Math.min(high, -start / (end - start));
|
|
333556
|
+
if (high <= low)
|
|
333557
|
+
return false;
|
|
333558
|
+
}
|
|
333559
|
+
return high > low;
|
|
333560
|
+
}
|
|
333561
|
+
var polygonBounds = (polygons) => {
|
|
333562
|
+
const points = polygons.flat();
|
|
333563
|
+
return {
|
|
333564
|
+
left: Math.min(...points.map((p) => p.x)),
|
|
333565
|
+
right: Math.max(...points.map((p) => p.x)),
|
|
333566
|
+
top: Math.max(...points.map((p) => p.y)),
|
|
333567
|
+
bottom: Math.min(...points.map((p) => p.y))
|
|
333568
|
+
};
|
|
333569
|
+
};
|
|
333570
|
+
|
|
333571
|
+
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/TraceSimplificationSolver/TraceSimplificationSolver.ts
|
|
333572
|
+
import { BaseSolver as BaseSolver20 } from "@tscircuit/solver-utils";
|
|
333573
|
+
class TraceSimplificationSolver extends BaseSolver20 {
|
|
333207
333574
|
static EPSILON = 0.01;
|
|
333208
333575
|
ctx;
|
|
333209
333576
|
out;
|
|
@@ -333245,18 +333612,40 @@ class TraceSimplificationSolver extends BaseSolver19 {
|
|
|
333245
333612
|
placementsByComponentId
|
|
333246
333613
|
})
|
|
333247
333614
|
].filter((candidate) => Boolean(candidate));
|
|
333615
|
+
for (const candidate of [...candidates]) {
|
|
333616
|
+
if (!candidate.target.sourceComponentName?.startsWith("U"))
|
|
333617
|
+
continue;
|
|
333618
|
+
for (const point of [points[0], points.at(-1)]) {
|
|
333619
|
+
const port = this.findPortAtPoint(ports, point, trace.schematic_sheet_id);
|
|
333620
|
+
const target = port?.schematic_component_id ? placementsByComponentId.get(port.schematic_component_id) : undefined;
|
|
333621
|
+
if (!target || !/^[CR]/.test(target.sourceComponentName ?? ""))
|
|
333622
|
+
continue;
|
|
333623
|
+
candidates.push({
|
|
333624
|
+
target,
|
|
333625
|
+
deltaSchX: -candidate.deltaSchX,
|
|
333626
|
+
deltaSchY: -candidate.deltaSchY,
|
|
333627
|
+
currentTurnCount,
|
|
333628
|
+
suggestedTurnCount: candidate.suggestedTurnCount
|
|
333629
|
+
});
|
|
333630
|
+
}
|
|
333631
|
+
}
|
|
333632
|
+
const priority = (candidate) => /^[CR]/.test(candidate.target.sourceComponentName ?? "") ? 0 : candidate.target.sourceComponentName?.startsWith("U") ? 2 : 1;
|
|
333633
|
+
candidates.sort((a, b) => priority(a) - priority(b));
|
|
333248
333634
|
for (const candidate of candidates) {
|
|
333249
333635
|
if (this.wouldOverlapAnotherComponent(candidate))
|
|
333250
333636
|
continue;
|
|
333637
|
+
if (!this.validateMove(trace, candidate, ports))
|
|
333638
|
+
continue;
|
|
333251
333639
|
const moveKey = [
|
|
333252
333640
|
candidate.target.schematicComponentId,
|
|
333253
333641
|
candidate.deltaSchX.toFixed(3),
|
|
333254
333642
|
candidate.deltaSchY.toFixed(3)
|
|
333255
333643
|
].join("\x00");
|
|
333256
333644
|
if (emittedMoves.has(moveKey))
|
|
333257
|
-
|
|
333645
|
+
break;
|
|
333258
333646
|
emittedMoves.add(moveKey);
|
|
333259
333647
|
this.out.push(this.makeIssue(trace, candidate));
|
|
333648
|
+
break;
|
|
333260
333649
|
}
|
|
333261
333650
|
}
|
|
333262
333651
|
this.solved = true;
|
|
@@ -333324,6 +333713,110 @@ class TraceSimplificationSolver extends BaseSolver19 {
|
|
|
333324
333713
|
suggestedTurnCount
|
|
333325
333714
|
};
|
|
333326
333715
|
}
|
|
333716
|
+
validateMove(targetTrace, candidate, ports) {
|
|
333717
|
+
const componentId = candidate.target.schematicComponentId;
|
|
333718
|
+
const sheetId = candidate.target.schematicSheetId;
|
|
333719
|
+
const sheetPorts = ports.filter((p) => p.schematic_sheet_id === sheetId);
|
|
333720
|
+
const movingPorts = sheetPorts.filter((p) => p.schematic_component_id === componentId);
|
|
333721
|
+
const traces = this.ctx.circuitJson.filter((e) => e.type === "schematic_trace" && e.schematic_sheet_id === sheetId);
|
|
333722
|
+
const touchesPort = (trace, port) => trace.edges.some((edge) => edge.from_schematic_port_id === port.schematic_port_id || edge.to_schematic_port_id === port.schematic_port_id || this.pointsEqual(edge.from, port.center) || this.pointsEqual(edge.to, port.center));
|
|
333723
|
+
const affected = traces.filter((trace) => movingPorts.some((port) => touchesPort(trace, port)));
|
|
333724
|
+
if (!affected.includes(targetTrace))
|
|
333725
|
+
return false;
|
|
333726
|
+
if (this.ctx.circuitJson.some((e) => e.type === "schematic_net_label" && e.schematic_sheet_id === sheetId && movingPorts.some((p) => this.pointsEqual(e.anchor_position ?? e.center, p.center))))
|
|
333727
|
+
return false;
|
|
333728
|
+
const shift = (point) => ({
|
|
333729
|
+
x: point.x + candidate.deltaSchX,
|
|
333730
|
+
y: point.y + candidate.deltaSchY
|
|
333731
|
+
});
|
|
333732
|
+
const directions = {
|
|
333733
|
+
left: "x-",
|
|
333734
|
+
right: "x+",
|
|
333735
|
+
up: "y+",
|
|
333736
|
+
down: "y-"
|
|
333737
|
+
};
|
|
333738
|
+
const endpoint = (port, moved) => ({
|
|
333739
|
+
...moved && port.schematic_component_id === componentId ? shift(port.center) : port.center,
|
|
333740
|
+
facingDirection: directions[port.facing_direction]
|
|
333741
|
+
});
|
|
333742
|
+
const length = (points) => points.slice(1).reduce((sum, p, i) => sum + Math.abs(p.x - points[i].x) + Math.abs(p.y - points[i].y), 0);
|
|
333743
|
+
const segments = (points) => points.slice(1).map((to, i) => ({ from: points[i], to }));
|
|
333744
|
+
const movedBounds = centeredRect(candidate.target.schX + candidate.deltaSchX, candidate.target.schY + candidate.deltaSchY, candidate.target.width, candidate.target.height);
|
|
333745
|
+
const unaffected = traces.filter((trace) => !affected.includes(trace));
|
|
333746
|
+
if (unaffected.some((trace) => trace.edges.some((edge) => segmentCrossesPolygon(edge.from, edge.to, rectPolygon(movedBounds)))))
|
|
333747
|
+
return false;
|
|
333748
|
+
const textPolygons = this.ctx.circuitJson.flatMap((e) => {
|
|
333749
|
+
if (e.type === "schematic_net_label" && e.schematic_sheet_id === sheetId)
|
|
333750
|
+
return [rectPolygon(getNetLabelBounds(e))];
|
|
333751
|
+
if (e.type !== "schematic_text" || e.schematic_sheet_id !== sheetId)
|
|
333752
|
+
return [];
|
|
333753
|
+
return getSchematicTextPolygons(e.schematic_component_id === componentId ? { ...e, position: shift(e.position) } : e);
|
|
333754
|
+
});
|
|
333755
|
+
if (textPolygons.some((polygon) => polygonsOverlap(polygon, rectPolygon(movedBounds))))
|
|
333756
|
+
return false;
|
|
333757
|
+
const proposed = [];
|
|
333758
|
+
for (const trace of affected) {
|
|
333759
|
+
const oldPoints = this.getTracePoints(trace);
|
|
333760
|
+
if (oldPoints.length < 2 || trace.junctions?.length)
|
|
333761
|
+
return false;
|
|
333762
|
+
const resolve = (point, id) => {
|
|
333763
|
+
const matches = sheetPorts.filter((p) => id ? p.schematic_port_id === id : this.pointsEqual(p.center, point));
|
|
333764
|
+
return matches.length === 1 && this.pointsEqual(matches[0].center, point) ? matches[0] : undefined;
|
|
333765
|
+
};
|
|
333766
|
+
const start = resolve(oldPoints[0], trace.edges[0].from_schematic_port_id);
|
|
333767
|
+
const end = resolve(oldPoints.at(-1), trace.edges.at(-1).to_schematic_port_id);
|
|
333768
|
+
if (!start?.facing_direction || !end?.facing_direction)
|
|
333769
|
+
return false;
|
|
333770
|
+
if (movingPorts.some((p) => touchesPort(trace, p) && p !== start && p !== end))
|
|
333771
|
+
return false;
|
|
333772
|
+
const isInteriorConnection = (point) => !this.pointsEqual(point, start.center) && !this.pointsEqual(point, end.center) && segments(oldPoints).some(({ from, to }) => Math.abs(Math.hypot(point.x - from.x, point.y - from.y) + Math.hypot(point.x - to.x, point.y - to.y) - Math.hypot(to.x - from.x, to.y - from.y)) < 0.000001);
|
|
333773
|
+
if (traces.some((other) => other !== trace && other.edges.some((edge) => isInteriorConnection(edge.from) || isInteriorConnection(edge.to))))
|
|
333774
|
+
return false;
|
|
333775
|
+
if (this.ctx.circuitJson.some((e) => e.type === "schematic_net_label" && e.schematic_sheet_id === sheetId && isInteriorConnection(e.anchor_position ?? e.center)))
|
|
333776
|
+
return false;
|
|
333777
|
+
const points = calculateElbow3(endpoint(start, true), endpoint(end, true)).filter((point, i, all) => i === 0 || !this.pointsEqual(point, all[i - 1]));
|
|
333778
|
+
const turns = this.countTurns(points);
|
|
333779
|
+
const oldTurns = this.countTurns(oldPoints);
|
|
333780
|
+
if (points.length < 2 || turns === undefined || oldTurns === undefined || turns > oldTurns || length(points) > length(oldPoints) + 0.000001)
|
|
333781
|
+
return false;
|
|
333782
|
+
if (!this.isPointInFacingDirection(points[0], points[1], start.facing_direction) || !this.isPointInFacingDirection(points.at(-1), points.at(-2), end.facing_direction))
|
|
333783
|
+
return false;
|
|
333784
|
+
if (trace === targetTrace) {
|
|
333785
|
+
const baselineTurns = this.countTurns(calculateElbow3(endpoint(start, false), endpoint(end, false)));
|
|
333786
|
+
if (turns >= oldTurns || baselineTurns === undefined || turns >= baselineTurns)
|
|
333787
|
+
return false;
|
|
333788
|
+
candidate.suggestedTurnCount = turns;
|
|
333789
|
+
}
|
|
333790
|
+
for (const segment of segments(points)) {
|
|
333791
|
+
if (textPolygons.some((polygon) => segmentCrossesPolygon(segment.from, segment.to, polygon)))
|
|
333792
|
+
return false;
|
|
333793
|
+
if (this.ctx.componentPlacements.some((p) => {
|
|
333794
|
+
if (p.schematicSheetId !== sheetId)
|
|
333795
|
+
return false;
|
|
333796
|
+
const bounds = p.schematicComponentId === componentId ? movedBounds : centeredRect(p.schX, p.schY, p.width, p.height);
|
|
333797
|
+
return segmentCrossesPolygon(segment.from, segment.to, rectPolygon(bounds));
|
|
333798
|
+
}))
|
|
333799
|
+
return false;
|
|
333800
|
+
const polygon = traceSegmentPolygon(segment.from, segment.to);
|
|
333801
|
+
if (!polygon)
|
|
333802
|
+
continue;
|
|
333803
|
+
const otherSegments = [
|
|
333804
|
+
...unaffected.flatMap((t) => t.edges),
|
|
333805
|
+
...proposed.flatMap((t) => segments(t.points))
|
|
333806
|
+
];
|
|
333807
|
+
if (otherSegments.some((edge) => {
|
|
333808
|
+
if ([start, end].some((port) => port.schematic_component_id !== componentId && [segment.from, segment.to].some((p) => this.pointsEqual(p, port.center)) && [edge.from, edge.to].some((p) => this.pointsEqual(p, port.center))) && this.getAxis(segment.from, segment.to) !== this.getAxis(edge.from, edge.to))
|
|
333809
|
+
return false;
|
|
333810
|
+
const other = traceSegmentPolygon(edge.from, edge.to);
|
|
333811
|
+
return other && polygonsOverlap(polygon, other);
|
|
333812
|
+
}))
|
|
333813
|
+
return false;
|
|
333814
|
+
}
|
|
333815
|
+
proposed.push({ schematicTraceId: trace.schematic_trace_id, points });
|
|
333816
|
+
}
|
|
333817
|
+
candidate.suggestedTraces = proposed;
|
|
333818
|
+
return true;
|
|
333819
|
+
}
|
|
333327
333820
|
getTracePoints(trace) {
|
|
333328
333821
|
const firstEdge = trace.edges[0];
|
|
333329
333822
|
if (!firstEdge)
|
|
@@ -333401,6 +333894,7 @@ class TraceSimplificationSolver extends BaseSolver19 {
|
|
|
333401
333894
|
return {
|
|
333402
333895
|
lineItemType: "TraceCanBeSimplifiedByMovingComponent",
|
|
333403
333896
|
schematicTraceId: trace.schematic_trace_id,
|
|
333897
|
+
traceName: getTraceName(this.ctx.circuitJson, trace),
|
|
333404
333898
|
targetComponent: candidate.target,
|
|
333405
333899
|
deltaSchX: candidate.deltaSchX,
|
|
333406
333900
|
deltaSchY: candidate.deltaSchY,
|
|
@@ -333408,6 +333902,7 @@ class TraceSimplificationSolver extends BaseSolver19 {
|
|
|
333408
333902
|
newSchY,
|
|
333409
333903
|
currentTurnCount: candidate.currentTurnCount,
|
|
333410
333904
|
suggestedTurnCount: candidate.suggestedTurnCount,
|
|
333905
|
+
suggestedTraces: candidate.suggestedTraces,
|
|
333411
333906
|
message: `move ${targetName} ${direction} by ${fmtNumber4(distance)} (to schX=${fmtNumber4(newSchX)}, schY=${fmtNumber4(newSchY)}) to reduce this trace from ${candidate.currentTurnCount} turns to ${candidate.suggestedTurnCount}`
|
|
333412
333907
|
};
|
|
333413
333908
|
}
|
|
@@ -333419,7 +333914,7 @@ class TraceSimplificationSolver extends BaseSolver19 {
|
|
|
333419
333914
|
}
|
|
333420
333915
|
static issueToString(issue) {
|
|
333421
333916
|
const attrs = [];
|
|
333422
|
-
addAttr(attrs, "
|
|
333917
|
+
addAttr(attrs, "traceName", issue.traceName);
|
|
333423
333918
|
addAttr(attrs, "targetComponentName", issue.targetComponent.sourceComponentName);
|
|
333424
333919
|
addAttr(attrs, "deltaSchX", issue.deltaSchX, { formatDelta: true });
|
|
333425
333920
|
addAttr(attrs, "deltaSchY", issue.deltaSchY, { formatDelta: true });
|
|
@@ -333433,12 +333928,12 @@ class TraceSimplificationSolver extends BaseSolver19 {
|
|
|
333433
333928
|
}
|
|
333434
333929
|
|
|
333435
333930
|
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/TwoPinComponentOrientationSolver/TwoPinComponentOrientationSolver.ts
|
|
333436
|
-
import { BaseSolver as
|
|
333931
|
+
import { BaseSolver as BaseSolver21 } from "@tscircuit/solver-utils";
|
|
333437
333932
|
|
|
333438
333933
|
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/TwoPinComponentOrientationSolver/getPowerOrGroundConnectionIds.ts
|
|
333439
333934
|
import {
|
|
333440
333935
|
findConnectedNetworks as findConnectedNetworks3,
|
|
333441
|
-
getSourcePortConnectivityMapFromCircuitJson as
|
|
333936
|
+
getSourcePortConnectivityMapFromCircuitJson as getSourcePortConnectivityMapFromCircuitJson3
|
|
333442
333937
|
} from "circuit-json-to-connectivity-map";
|
|
333443
333938
|
function getPowerOrGroundConnectionIds(circuitJson) {
|
|
333444
333939
|
const powerOrGroundIds = new Set;
|
|
@@ -333457,7 +333952,7 @@ function getPowerOrGroundConnectionIds(circuitJson) {
|
|
|
333457
333952
|
idsByConnectivityKey.set(key, ids);
|
|
333458
333953
|
}
|
|
333459
333954
|
}
|
|
333460
|
-
const sourceConnectivity =
|
|
333955
|
+
const sourceConnectivity = getSourcePortConnectivityMapFromCircuitJson3(circuitJson);
|
|
333461
333956
|
const networks = findConnectedNetworks3([
|
|
333462
333957
|
...Object.values(sourceConnectivity.netMap),
|
|
333463
333958
|
...idsByConnectivityKey.values()
|
|
@@ -333472,7 +333967,7 @@ function getPowerOrGroundConnectionIds(circuitJson) {
|
|
|
333472
333967
|
}
|
|
333473
333968
|
|
|
333474
333969
|
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/TwoPinComponentOrientationSolver/TwoPinComponentOrientationSolver.ts
|
|
333475
|
-
class TwoPinComponentOrientationSolver extends
|
|
333970
|
+
class TwoPinComponentOrientationSolver extends BaseSolver21 {
|
|
333476
333971
|
static EPSILON = 0.01;
|
|
333477
333972
|
ctx;
|
|
333478
333973
|
out;
|
|
@@ -333689,6 +334184,7 @@ class TwoPinComponentOrientationSolver extends BaseSolver20 {
|
|
|
333689
334184
|
return {
|
|
333690
334185
|
lineItemType: "TwoPinComponentCouldBeFlipped",
|
|
333691
334186
|
schematicTraceId: candidate.trace.schematic_trace_id,
|
|
334187
|
+
traceName: getTraceName(this.ctx.circuitJson, candidate.trace),
|
|
333692
334188
|
targetComponent: candidate.targetPlacement,
|
|
333693
334189
|
connectedComponent: candidate.connectedPlacement,
|
|
333694
334190
|
targetPin,
|
|
@@ -333702,7 +334198,7 @@ class TwoPinComponentOrientationSolver extends BaseSolver20 {
|
|
|
333702
334198
|
}
|
|
333703
334199
|
static issueToString(issue) {
|
|
333704
334200
|
const attrs = [];
|
|
333705
|
-
addAttr(attrs, "
|
|
334201
|
+
addAttr(attrs, "traceName", issue.traceName);
|
|
333706
334202
|
addAttr(attrs, "targetComponentName", issue.targetComponent.sourceComponentName);
|
|
333707
334203
|
addAttr(attrs, "connectedComponentName", issue.connectedComponent.sourceComponentName);
|
|
333708
334204
|
addAttr(attrs, "targetPin", issue.targetPin);
|
|
@@ -333717,8 +334213,8 @@ class TwoPinComponentOrientationSolver extends BaseSolver20 {
|
|
|
333717
334213
|
}
|
|
333718
334214
|
|
|
333719
334215
|
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/VerboseNetLabelSolver/VerboseNetLabelSolver.ts
|
|
333720
|
-
import { BaseSolver as
|
|
333721
|
-
class VerboseNetLabelSolver extends
|
|
334216
|
+
import { BaseSolver as BaseSolver22 } from "@tscircuit/solver-utils";
|
|
334217
|
+
class VerboseNetLabelSolver extends BaseSolver22 {
|
|
333722
334218
|
params;
|
|
333723
334219
|
VERBOSE_NET_LABEL_MESSAGE = "Create trace with schDisplayLabel";
|
|
333724
334220
|
netLabels;
|
|
@@ -333827,130 +334323,8 @@ class VerboseNetLabelSolver extends BaseSolver21 {
|
|
|
333827
334323
|
}
|
|
333828
334324
|
|
|
333829
334325
|
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/SchematicTextClearanceSolver/SchematicTextClearanceSolver.ts
|
|
333830
|
-
import { BaseSolver as
|
|
333831
|
-
|
|
333832
|
-
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/utils/schematic-text-geometry.ts
|
|
333833
|
-
var rectPolygon = (bounds) => [
|
|
333834
|
-
{ x: bounds.left, y: bounds.bottom },
|
|
333835
|
-
{ x: bounds.right, y: bounds.bottom },
|
|
333836
|
-
{ x: bounds.right, y: bounds.top },
|
|
333837
|
-
{ x: bounds.left, y: bounds.top }
|
|
333838
|
-
];
|
|
333839
|
-
var advance = (character) => {
|
|
333840
|
-
if (/\s/.test(character))
|
|
333841
|
-
return 0.28;
|
|
333842
|
-
if (/[ilI.,:;!'|]/.test(character))
|
|
333843
|
-
return 0.25;
|
|
333844
|
-
if (/[MW@%]/.test(character))
|
|
333845
|
-
return 0.9;
|
|
333846
|
-
if (/[mw]/.test(character))
|
|
333847
|
-
return 0.8;
|
|
333848
|
-
if (/[A-Z]/.test(character))
|
|
333849
|
-
return 0.67;
|
|
333850
|
-
return 0.56;
|
|
333851
|
-
};
|
|
333852
|
-
var widthInEm = (text) => Array.from(text).reduce((width, character) => width + advance(character), 0);
|
|
333853
|
-
function getSchematicTextPolygons(text) {
|
|
333854
|
-
const size = text.font_size;
|
|
333855
|
-
if (!Number.isFinite(size) || size <= 0 || !Number.isFinite(text.rotation) || !Number.isFinite(text.position.x) || !Number.isFinite(text.position.y))
|
|
333856
|
-
return [];
|
|
333857
|
-
const anchor = text.anchor;
|
|
333858
|
-
const horizontal = anchor.includes("left") ? 0 : anchor.includes("right") ? 1 : 0.5;
|
|
333859
|
-
const top = anchor.includes("top") ? 0 : anchor.includes("bottom") ? size : size / 2;
|
|
333860
|
-
const radians = -text.rotation * Math.PI / 180;
|
|
333861
|
-
const cos = Math.cos(radians);
|
|
333862
|
-
const sin = Math.sin(radians);
|
|
333863
|
-
return text.text.split(`
|
|
333864
|
-
`).flatMap((line, index) => {
|
|
333865
|
-
const visible = line.trim();
|
|
333866
|
-
if (!visible)
|
|
333867
|
-
return [];
|
|
333868
|
-
const leading = line.length - line.trimStart().length;
|
|
333869
|
-
const left = (widthInEm(line.slice(0, leading)) - widthInEm(line) * horizontal) * size;
|
|
333870
|
-
const polygon = rectPolygon({
|
|
333871
|
-
left,
|
|
333872
|
-
right: left + widthInEm(visible) * size,
|
|
333873
|
-
top: top - index * size - size * 0.05,
|
|
333874
|
-
bottom: top - (index + 1) * size + size * 0.05
|
|
333875
|
-
});
|
|
333876
|
-
return [
|
|
333877
|
-
polygon.map(({ x, y }) => ({
|
|
333878
|
-
x: text.position.x + x * cos - y * sin,
|
|
333879
|
-
y: text.position.y + x * sin + y * cos
|
|
333880
|
-
}))
|
|
333881
|
-
];
|
|
333882
|
-
});
|
|
333883
|
-
}
|
|
333884
|
-
function polygonsOverlap(a, b) {
|
|
333885
|
-
for (const polygon of [a, b]) {
|
|
333886
|
-
for (let i = 0;i < polygon.length; i++) {
|
|
333887
|
-
const p = polygon[i];
|
|
333888
|
-
const q = polygon[(i + 1) % polygon.length];
|
|
333889
|
-
const length = Math.hypot(q.x - p.x, q.y - p.y);
|
|
333890
|
-
if (length < 0.000000001)
|
|
333891
|
-
continue;
|
|
333892
|
-
const nx = -(q.y - p.y) / length;
|
|
333893
|
-
const ny = (q.x - p.x) / length;
|
|
333894
|
-
const project = (points) => points.map(({ x, y }) => x * nx + y * ny);
|
|
333895
|
-
const pa = project(a);
|
|
333896
|
-
const pb = project(b);
|
|
333897
|
-
if (Math.min(Math.max(...pa), Math.max(...pb)) - Math.max(Math.min(...pa), Math.min(...pb)) <= 0.000001)
|
|
333898
|
-
return false;
|
|
333899
|
-
}
|
|
333900
|
-
}
|
|
333901
|
-
return true;
|
|
333902
|
-
}
|
|
333903
|
-
function traceSegmentPolygon(from, to) {
|
|
333904
|
-
const length = Math.hypot(to.x - from.x, to.y - from.y);
|
|
333905
|
-
if (length < 0.000000001)
|
|
333906
|
-
return;
|
|
333907
|
-
const dx = -(to.y - from.y) / length * 0.01;
|
|
333908
|
-
const dy = (to.x - from.x) / length * 0.01;
|
|
333909
|
-
return [
|
|
333910
|
-
{ x: from.x + dx, y: from.y + dy },
|
|
333911
|
-
{ x: to.x + dx, y: to.y + dy },
|
|
333912
|
-
{ x: to.x - dx, y: to.y - dy },
|
|
333913
|
-
{ x: from.x - dx, y: from.y - dy }
|
|
333914
|
-
];
|
|
333915
|
-
}
|
|
333916
|
-
function segmentCrossesPolygon(from, to, polygon) {
|
|
333917
|
-
if (Math.hypot(to.x - from.x, to.y - from.y) < 0.000000001)
|
|
333918
|
-
return false;
|
|
333919
|
-
let low = 0;
|
|
333920
|
-
let high = 1;
|
|
333921
|
-
for (let i = 0;i < polygon.length; i++) {
|
|
333922
|
-
const p = polygon[i];
|
|
333923
|
-
const q = polygon[(i + 1) % polygon.length];
|
|
333924
|
-
const length = Math.hypot(q.x - p.x, q.y - p.y);
|
|
333925
|
-
if (length < 0.000000001)
|
|
333926
|
-
continue;
|
|
333927
|
-
const nx = -(q.y - p.y) / length;
|
|
333928
|
-
const ny = (q.x - p.x) / length;
|
|
333929
|
-
const start = (from.x - p.x) * nx + (from.y - p.y) * ny - 0.000001;
|
|
333930
|
-
const end = (to.x - p.x) * nx + (to.y - p.y) * ny - 0.000001;
|
|
333931
|
-
if (start <= 0 && end <= 0)
|
|
333932
|
-
return false;
|
|
333933
|
-
if (start <= 0)
|
|
333934
|
-
low = Math.max(low, -start / (end - start));
|
|
333935
|
-
if (end <= 0)
|
|
333936
|
-
high = Math.min(high, -start / (end - start));
|
|
333937
|
-
if (high <= low)
|
|
333938
|
-
return false;
|
|
333939
|
-
}
|
|
333940
|
-
return high > low;
|
|
333941
|
-
}
|
|
333942
|
-
var polygonBounds = (polygons) => {
|
|
333943
|
-
const points = polygons.flat();
|
|
333944
|
-
return {
|
|
333945
|
-
left: Math.min(...points.map((p) => p.x)),
|
|
333946
|
-
right: Math.max(...points.map((p) => p.x)),
|
|
333947
|
-
top: Math.max(...points.map((p) => p.y)),
|
|
333948
|
-
bottom: Math.min(...points.map((p) => p.y))
|
|
333949
|
-
};
|
|
333950
|
-
};
|
|
333951
|
-
|
|
333952
|
-
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/SchematicTextClearanceSolver/SchematicTextClearanceSolver.ts
|
|
333953
|
-
class SchematicTextClearanceSolver extends BaseSolver22 {
|
|
334326
|
+
import { BaseSolver as BaseSolver23 } from "@tscircuit/solver-utils";
|
|
334327
|
+
class SchematicTextClearanceSolver extends BaseSolver23 {
|
|
333954
334328
|
params;
|
|
333955
334329
|
texts;
|
|
333956
334330
|
obstacles;
|
|
@@ -334101,8 +334475,8 @@ class SchematicTextClearanceSolver extends BaseSolver22 {
|
|
|
334101
334475
|
}
|
|
334102
334476
|
|
|
334103
334477
|
// node_modules/@tscircuit/circuit-json-schematic-placement-analysis/lib/solvers/ResetNetworkGroupingSolver/ResetNetworkGroupingSolver.ts
|
|
334104
|
-
import { BaseSolver as
|
|
334105
|
-
class ResetNetworkGroupingSolver extends
|
|
334478
|
+
import { BaseSolver as BaseSolver24 } from "@tscircuit/solver-utils";
|
|
334479
|
+
class ResetNetworkGroupingSolver extends BaseSolver24 {
|
|
334106
334480
|
params;
|
|
334107
334481
|
static MIN_DISTANCE = 6;
|
|
334108
334482
|
networks;
|
|
@@ -334316,6 +334690,9 @@ class SchematicPlacementPipeline extends BasePipelineSolver2 {
|
|
|
334316
334690
|
]),
|
|
334317
334691
|
definePipelineStep3("ConnectorPlacementSolver", ConnectorPlacementSolver, (p) => [
|
|
334318
334692
|
{ ctx: p.ctx, issues: p.issues }
|
|
334693
|
+
]),
|
|
334694
|
+
definePipelineStep3("LowSideTransistorPlacementSolver", LowSideTransistorPlacementSolver, (p) => [
|
|
334695
|
+
{ ctx: p.ctx, issues: p.issues }
|
|
334319
334696
|
])
|
|
334320
334697
|
];
|
|
334321
334698
|
_setup() {
|
|
@@ -334367,6 +334744,12 @@ var getRelevantPlacementsForIssues = ({
|
|
|
334367
334744
|
};
|
|
334368
334745
|
for (const issue of issues) {
|
|
334369
334746
|
switch (issue.lineItemType) {
|
|
334747
|
+
case "LowSideTransistorNotAlignedWithLoad":
|
|
334748
|
+
addPlacement(issue.transistorSchematicBox);
|
|
334749
|
+
addPlacement(issue.loadSchematicBox);
|
|
334750
|
+
addPlacement(issue.baseResistorSchematicBox);
|
|
334751
|
+
addPlacement(issue.clampDiodeSchematicBox);
|
|
334752
|
+
break;
|
|
334370
334753
|
case "DecouplingCapacitorsNotCloseTogether":
|
|
334371
334754
|
for (const placement of issue.capacitorSchematicBoxes)
|
|
334372
334755
|
addPlacement(placement);
|
|
@@ -334444,6 +334827,7 @@ var getRelevantPlacementsForIssues = ({
|
|
|
334444
334827
|
addPlacement(component);
|
|
334445
334828
|
break;
|
|
334446
334829
|
case "TwoPinComponentShouldBeVertical":
|
|
334830
|
+
case "TwoPinComponentHasInvertedRails":
|
|
334447
334831
|
addPlacement(issue.schematicBox);
|
|
334448
334832
|
break;
|
|
334449
334833
|
case "PullResistorOnWrongSide":
|
|
@@ -334554,8 +334938,10 @@ class SchematicPlacementAnalysis {
|
|
|
334554
334938
|
ResetNetworkNotGrouped: 0,
|
|
334555
334939
|
TwoPinComponentCouldBeFlipped: 0,
|
|
334556
334940
|
TwoPinComponentShouldBeVertical: 0,
|
|
334941
|
+
TwoPinComponentHasInvertedRails: 0,
|
|
334557
334942
|
DecouplingCapacitorsNotCloseTogether: 0,
|
|
334558
|
-
ConnectorPositionCausesTraceDetours: 0
|
|
334943
|
+
ConnectorPositionCausesTraceDetours: 0,
|
|
334944
|
+
LowSideTransistorNotAlignedWithLoad: 0
|
|
334559
334945
|
};
|
|
334560
334946
|
for (const issue of this.getIssues(filter))
|
|
334561
334947
|
counts[issue.lineItemType]++;
|
|
@@ -334604,6 +334990,7 @@ class SchematicPlacementAnalysis {
|
|
|
334604
334990
|
case "FeedbackNetworkNotCompact":
|
|
334605
334991
|
return FeedbackNetworkPlacementSolver.issueToString(issue);
|
|
334606
334992
|
case "TwoPinComponentShouldBeVertical":
|
|
334993
|
+
case "TwoPinComponentHasInvertedRails":
|
|
334607
334994
|
return TwoPinComponentRailOrientationSolver.issueToString(issue);
|
|
334608
334995
|
case "PullResistorOnWrongSide":
|
|
334609
334996
|
return PullResistorPlacementSolver.issueToString(issue);
|
|
@@ -334615,6 +335002,8 @@ class SchematicPlacementAnalysis {
|
|
|
334615
335002
|
return ResetNetworkGroupingSolver.issueToString(issue);
|
|
334616
335003
|
case "ConnectorPositionCausesTraceDetours":
|
|
334617
335004
|
return ConnectorPlacementSolver.issueToString(issue);
|
|
335005
|
+
case "LowSideTransistorNotAlignedWithLoad":
|
|
335006
|
+
return LowSideTransistorPlacementSolver.issueToString(issue);
|
|
334618
335007
|
default:
|
|
334619
335008
|
return "";
|
|
334620
335009
|
}
|
package/dist/lib/index.js
CHANGED
|
@@ -69128,7 +69128,7 @@ var package_default = {
|
|
|
69128
69128
|
"@tscircuit/check-shorts": "https://jscdn.tscircuit.com/@tscircuit/check-shorts/0.0.24.tgz",
|
|
69129
69129
|
"@tscircuit/circuit-json-placement-analysis": "^0.0.15",
|
|
69130
69130
|
"@tscircuit/circuit-json-routing-analysis": "^0.0.8",
|
|
69131
|
-
"@tscircuit/circuit-json-schematic-placement-analysis": "
|
|
69131
|
+
"@tscircuit/circuit-json-schematic-placement-analysis": "https://jscdn.tscircuit.com/@tscircuit/circuit-json-schematic-placement-analysis/0.0.11.tgz",
|
|
69132
69132
|
"@tscircuit/circuit-json-util": "^0.0.113",
|
|
69133
69133
|
"@tscircuit/eval": "0.0.1402",
|
|
69134
69134
|
"@tscircuit/fake-snippets": "^0.0.182",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tscircuit/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2127",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/tscircuit/cli"
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"@tscircuit/check-shorts": "https://jscdn.tscircuit.com/@tscircuit/check-shorts/0.0.24.tgz",
|
|
17
17
|
"@tscircuit/circuit-json-placement-analysis": "^0.0.15",
|
|
18
18
|
"@tscircuit/circuit-json-routing-analysis": "^0.0.8",
|
|
19
|
-
"@tscircuit/circuit-json-schematic-placement-analysis": "
|
|
19
|
+
"@tscircuit/circuit-json-schematic-placement-analysis": "https://jscdn.tscircuit.com/@tscircuit/circuit-json-schematic-placement-analysis/0.0.11.tgz",
|
|
20
20
|
"@tscircuit/circuit-json-util": "^0.0.113",
|
|
21
21
|
"@tscircuit/eval": "0.0.1402",
|
|
22
22
|
"@tscircuit/fake-snippets": "^0.0.182",
|