@tscircuit/core 0.0.2025 → 0.0.2027
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.d.ts +3 -0
- package/dist/index.js +1231 -140
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -6277,10 +6277,10 @@ function addTraceTeardrops(route, contacts) {
|
|
|
6277
6277
|
result.push(start);
|
|
6278
6278
|
continue;
|
|
6279
6279
|
}
|
|
6280
|
-
const atDistance = (
|
|
6280
|
+
const atDistance = (distance25) => ({
|
|
6281
6281
|
route_type: "wire",
|
|
6282
|
-
x: start.x + (end.x - start.x) *
|
|
6283
|
-
y: start.y + (end.y - start.y) *
|
|
6282
|
+
x: start.x + (end.x - start.x) * distance25 / length8,
|
|
6283
|
+
y: start.y + (end.y - start.y) * distance25 / length8,
|
|
6284
6284
|
width: start.width,
|
|
6285
6285
|
layer: start.layer
|
|
6286
6286
|
});
|
|
@@ -6803,11 +6803,11 @@ function Trace_doInitialPcbTraceRender(trace) {
|
|
|
6803
6803
|
const closestNetBPort = getClosest(netAPort, netBPorts);
|
|
6804
6804
|
const netAPortPosition = netAPort._getGlobalPcbPositionBeforeLayout();
|
|
6805
6805
|
const netBPortPosition = closestNetBPort._getGlobalPcbPositionBeforeLayout();
|
|
6806
|
-
const
|
|
6806
|
+
const distance25 = Math.sqrt(
|
|
6807
6807
|
(netAPortPosition.x - netBPortPosition.x) ** 2 + (netAPortPosition.y - netBPortPosition.y) ** 2
|
|
6808
6808
|
);
|
|
6809
|
-
if (
|
|
6810
|
-
closestDistance =
|
|
6809
|
+
if (distance25 < closestDistance) {
|
|
6810
|
+
closestDistance = distance25;
|
|
6811
6811
|
closestPortPair = [netAPort, closestNetBPort];
|
|
6812
6812
|
}
|
|
6813
6813
|
}
|
|
@@ -13018,7 +13018,7 @@ var createComponentsFromCircuitJson = ({
|
|
|
13018
13018
|
const schematicSymbolId = schematicComponent?.schematic_symbol_id;
|
|
13019
13019
|
const parentSymbol = typeof schematicSymbolId === "string" ? schematicSymbolsByImportedId.get(schematicSymbolId) : void 0;
|
|
13020
13020
|
if (parentSymbol && schematicComponent?.is_box_with_pins === true && elm.center && elm.side_of_component) {
|
|
13021
|
-
const
|
|
13021
|
+
const distance25 = elm.distance_from_component_edge;
|
|
13022
13022
|
const facingDirection = getFacingDirectionFromSide(
|
|
13023
13023
|
elm.side_of_component
|
|
13024
13024
|
);
|
|
@@ -13026,8 +13026,8 @@ var createComponentsFromCircuitJson = ({
|
|
|
13026
13026
|
const directionVector = getUnitVectorFromDirection2(facingDirection);
|
|
13027
13027
|
const stemDirection = elm.facing_direction === facingDirection ? 1 : -1;
|
|
13028
13028
|
const portCenter = {
|
|
13029
|
-
x: elm.center.x + directionVector.x *
|
|
13030
|
-
y: elm.center.y + directionVector.y *
|
|
13029
|
+
x: elm.center.x + directionVector.x * distance25 * stemDirection,
|
|
13030
|
+
y: elm.center.y + directionVector.y * distance25 * stemDirection
|
|
13031
13031
|
};
|
|
13032
13032
|
const sourcePort = sourcePortsByImportedId.get(elm.source_port_id);
|
|
13033
13033
|
const aliases = Array.from(
|
|
@@ -17796,15 +17796,15 @@ var Capacitor_addPolarityFabricationSymbols = (capacitor) => {
|
|
|
17796
17796
|
source_port_id: negatives[0].source_port_id
|
|
17797
17797
|
});
|
|
17798
17798
|
if (!positive || !negative) return;
|
|
17799
|
-
const
|
|
17800
|
-
if (
|
|
17799
|
+
const distance25 = Math.hypot(negative.x - positive.x, negative.y - positive.y);
|
|
17800
|
+
if (distance25 < 1e-6) return;
|
|
17801
17801
|
const frame = compose7(
|
|
17802
17802
|
translate5((positive.x + negative.x) / 2, (positive.y + negative.y) / 2),
|
|
17803
17803
|
rotate4(Math.atan2(negative.y - positive.y, negative.x - positive.x))
|
|
17804
17804
|
);
|
|
17805
17805
|
const point6 = (x, y) => applyToPoint26(frame, { x, y });
|
|
17806
|
-
const offset =
|
|
17807
|
-
const halfSize = Math.min(
|
|
17806
|
+
const offset = distance25 / 4;
|
|
17807
|
+
const halfSize = Math.min(distance25 * 0.12, 0.3);
|
|
17808
17808
|
const routes = [
|
|
17809
17809
|
[point6(-offset - halfSize, 0), point6(-offset + halfSize, 0)],
|
|
17810
17810
|
[point6(-offset, -halfSize), point6(-offset, halfSize)],
|
|
@@ -19561,7 +19561,9 @@ function getAutoroutingPhasePcbTracePaths({
|
|
|
19561
19561
|
let exported = false;
|
|
19562
19562
|
for (const routeIndex of remainingRoutes) {
|
|
19563
19563
|
for (const reverse of [false, true]) {
|
|
19564
|
-
const candidates = endpoints[routeIndex][reverse ? 1 : 0]
|
|
19564
|
+
const candidates = endpoints[routeIndex][reverse ? 1 : 0].filter(
|
|
19565
|
+
(terminal2) => terminal2.pcb_port_id
|
|
19566
|
+
);
|
|
19565
19567
|
if (candidates.length !== 1) continue;
|
|
19566
19568
|
const terminal = candidates[0];
|
|
19567
19569
|
if (!terminal.pcb_port_id || degreeByTerminal.get(terminal) !== 1)
|
|
@@ -19629,7 +19631,7 @@ import {
|
|
|
19629
19631
|
groupProps
|
|
19630
19632
|
} from "@tscircuit/props";
|
|
19631
19633
|
import {
|
|
19632
|
-
distance as
|
|
19634
|
+
distance as distance18
|
|
19633
19635
|
} from "circuit-json";
|
|
19634
19636
|
import Debug15 from "debug";
|
|
19635
19637
|
|
|
@@ -38873,9 +38875,9 @@ function getFreeBoundaryTracks(params) {
|
|
|
38873
38875
|
for (const via of vias) {
|
|
38874
38876
|
if (!via.spanLayers.includes(targetLayer2)) continue;
|
|
38875
38877
|
const radius = via.diameter / 2 + traceWidth / 2 + clearance;
|
|
38876
|
-
const
|
|
38877
|
-
if (
|
|
38878
|
-
const extent = Math.sqrt(radius * radius -
|
|
38878
|
+
const distance25 = Math.abs(via.center[across] - edge);
|
|
38879
|
+
if (distance25 >= radius) continue;
|
|
38880
|
+
const extent = Math.sqrt(radius * radius - distance25 * distance25);
|
|
38879
38881
|
blocked.push([via.center[along] - extent, via.center[along] + extent]);
|
|
38880
38882
|
}
|
|
38881
38883
|
const gaps = [];
|
|
@@ -50566,6 +50568,8 @@ function getPresetAutoroutingConfig(autorouterConfig, platformConfig) {
|
|
|
50566
50568
|
};
|
|
50567
50569
|
case "bus-lanes":
|
|
50568
50570
|
return { local: true, groupMode: "subcircuit", preset: "bus_lanes" };
|
|
50571
|
+
case "dogbone":
|
|
50572
|
+
return { local: true, groupMode: "subcircuit", preset: "dogbone" };
|
|
50569
50573
|
case "fanout":
|
|
50570
50574
|
return {
|
|
50571
50575
|
local: true,
|
|
@@ -50628,11 +50632,1027 @@ function getPresetAutoroutingConfig(autorouterConfig, platformConfig) {
|
|
|
50628
50632
|
}
|
|
50629
50633
|
}
|
|
50630
50634
|
|
|
50631
|
-
// node_modules/@tscircuit/
|
|
50635
|
+
// node_modules/@tscircuit/dogbone-solver/lib/dogbone-fanout-solver.ts
|
|
50636
|
+
import { BaseSolver as BaseSolver7 } from "@tscircuit/solver-utils";
|
|
50637
|
+
|
|
50638
|
+
// node_modules/@tscircuit/dogbone-solver/node_modules/@tscircuit/fanout-solver/lib/geometry.ts
|
|
50639
|
+
var EPSILON24 = 1e-9;
|
|
50640
|
+
function obstacleIsCircular2(obstacle) {
|
|
50641
|
+
return obstacle.shape === "circle";
|
|
50642
|
+
}
|
|
50643
|
+
function toObstacleLocalPoint2(point6, obstacle) {
|
|
50644
|
+
const rotationRadians = -(obstacle.ccwRotationDegrees ?? 0) * Math.PI / 180;
|
|
50645
|
+
const dx = point6.x - obstacle.center.x;
|
|
50646
|
+
const dy = point6.y - obstacle.center.y;
|
|
50647
|
+
return {
|
|
50648
|
+
x: dx * Math.cos(rotationRadians) - dy * Math.sin(rotationRadians),
|
|
50649
|
+
y: dx * Math.sin(rotationRadians) + dy * Math.cos(rotationRadians)
|
|
50650
|
+
};
|
|
50651
|
+
}
|
|
50652
|
+
function distance12(a, b) {
|
|
50653
|
+
return Math.hypot(a.x - b.x, a.y - b.y);
|
|
50654
|
+
}
|
|
50655
|
+
function distancePointToSegment2(point6, start, end) {
|
|
50656
|
+
const dx = end.x - start.x;
|
|
50657
|
+
const dy = end.y - start.y;
|
|
50658
|
+
const lengthSquared = dx * dx + dy * dy;
|
|
50659
|
+
const rawT = lengthSquared < EPSILON24 ? 0 : ((point6.x - start.x) * dx + (point6.y - start.y) * dy) / lengthSquared;
|
|
50660
|
+
const t = Math.max(0, Math.min(1, rawT));
|
|
50661
|
+
return Math.hypot(point6.x - (start.x + t * dx), point6.y - (start.y + t * dy));
|
|
50662
|
+
}
|
|
50663
|
+
function cross2(origin, a, b) {
|
|
50664
|
+
return (a.x - origin.x) * (b.y - origin.y) - (a.y - origin.y) * (b.x - origin.x);
|
|
50665
|
+
}
|
|
50666
|
+
function segmentsProperlyCross2(a, b, c, d) {
|
|
50667
|
+
const d1 = cross2(c, d, a);
|
|
50668
|
+
const d2 = cross2(c, d, b);
|
|
50669
|
+
const d3 = cross2(a, b, c);
|
|
50670
|
+
const d4 = cross2(a, b, d);
|
|
50671
|
+
return (d1 > 0 && d2 < 0 || d1 < 0 && d2 > 0) && (d3 > 0 && d4 < 0 || d3 < 0 && d4 > 0);
|
|
50672
|
+
}
|
|
50673
|
+
function distanceSegmentToSegment2(firstStart, firstEnd, secondStart, secondEnd) {
|
|
50674
|
+
if (segmentsProperlyCross2(firstStart, firstEnd, secondStart, secondEnd)) {
|
|
50675
|
+
return 0;
|
|
50676
|
+
}
|
|
50677
|
+
return Math.min(
|
|
50678
|
+
distancePointToSegment2(firstStart, secondStart, secondEnd),
|
|
50679
|
+
distancePointToSegment2(firstEnd, secondStart, secondEnd),
|
|
50680
|
+
distancePointToSegment2(secondStart, firstStart, firstEnd),
|
|
50681
|
+
distancePointToSegment2(secondEnd, firstStart, firstEnd)
|
|
50682
|
+
);
|
|
50683
|
+
}
|
|
50684
|
+
function distancePointToObstacle2(point6, obstacle) {
|
|
50685
|
+
if (obstacleIsCircular2(obstacle)) {
|
|
50686
|
+
return Math.max(0, distance12(point6, obstacle.center) - obstacle.width / 2);
|
|
50687
|
+
}
|
|
50688
|
+
const localPoint = toObstacleLocalPoint2(point6, obstacle);
|
|
50689
|
+
const dx = Math.max(Math.abs(localPoint.x) - obstacle.width / 2, 0);
|
|
50690
|
+
const dy = Math.max(Math.abs(localPoint.y) - obstacle.height / 2, 0);
|
|
50691
|
+
return Math.hypot(dx, dy);
|
|
50692
|
+
}
|
|
50693
|
+
function distanceSegmentToObstacle2(segment2, obstacle) {
|
|
50694
|
+
if (obstacleIsCircular2(obstacle)) {
|
|
50695
|
+
return Math.max(
|
|
50696
|
+
0,
|
|
50697
|
+
distancePointToSegment2(obstacle.center, segment2.start, segment2.end) - obstacle.width / 2
|
|
50698
|
+
);
|
|
50699
|
+
}
|
|
50700
|
+
const localStart = toObstacleLocalPoint2(segment2.start, obstacle);
|
|
50701
|
+
const localEnd = toObstacleLocalPoint2(segment2.end, obstacle);
|
|
50702
|
+
if (Math.abs(localStart.x) <= obstacle.width / 2 + EPSILON24 && Math.abs(localStart.y) <= obstacle.height / 2 + EPSILON24) {
|
|
50703
|
+
return 0;
|
|
50704
|
+
}
|
|
50705
|
+
if (Math.abs(localEnd.x) <= obstacle.width / 2 + EPSILON24 && Math.abs(localEnd.y) <= obstacle.height / 2 + EPSILON24) {
|
|
50706
|
+
return 0;
|
|
50707
|
+
}
|
|
50708
|
+
const minX = -obstacle.width / 2;
|
|
50709
|
+
const maxX = obstacle.width / 2;
|
|
50710
|
+
const minY = -obstacle.height / 2;
|
|
50711
|
+
const maxY = obstacle.height / 2;
|
|
50712
|
+
const corners = [
|
|
50713
|
+
{ x: minX, y: minY },
|
|
50714
|
+
{ x: maxX, y: minY },
|
|
50715
|
+
{ x: maxX, y: maxY },
|
|
50716
|
+
{ x: minX, y: maxY }
|
|
50717
|
+
];
|
|
50718
|
+
let minimumDistance = Number.POSITIVE_INFINITY;
|
|
50719
|
+
for (let index = 0; index < corners.length; index++) {
|
|
50720
|
+
minimumDistance = Math.min(
|
|
50721
|
+
minimumDistance,
|
|
50722
|
+
distanceSegmentToSegment2(
|
|
50723
|
+
localStart,
|
|
50724
|
+
localEnd,
|
|
50725
|
+
corners[index],
|
|
50726
|
+
corners[(index + 1) % corners.length]
|
|
50727
|
+
)
|
|
50728
|
+
);
|
|
50729
|
+
}
|
|
50730
|
+
return minimumDistance;
|
|
50731
|
+
}
|
|
50732
|
+
function segmentsAreClear2(first, second, clearance) {
|
|
50733
|
+
if (first.layer !== second.layer) return true;
|
|
50734
|
+
const requiredDistance = (first.width + second.width) / 2 + clearance;
|
|
50735
|
+
const broadPhaseDistance = requiredDistance + EPSILON24;
|
|
50736
|
+
if (Math.min(first.start.x, first.end.x) - Math.max(second.start.x, second.end.x) > broadPhaseDistance || Math.min(second.start.x, second.end.x) - Math.max(first.start.x, first.end.x) > broadPhaseDistance || Math.min(first.start.y, first.end.y) - Math.max(second.start.y, second.end.y) > broadPhaseDistance || Math.min(second.start.y, second.end.y) - Math.max(first.start.y, first.end.y) > broadPhaseDistance) {
|
|
50737
|
+
return true;
|
|
50738
|
+
}
|
|
50739
|
+
return distanceSegmentToSegment2(
|
|
50740
|
+
first.start,
|
|
50741
|
+
first.end,
|
|
50742
|
+
second.start,
|
|
50743
|
+
second.end
|
|
50744
|
+
) >= requiredDistance - EPSILON24;
|
|
50745
|
+
}
|
|
50746
|
+
|
|
50747
|
+
// node_modules/@tscircuit/dogbone-solver/node_modules/@tscircuit/fanout-solver/lib/match-component-dogbone-via-sites.ts
|
|
50748
|
+
var EPSILON25 = 1e-9;
|
|
50749
|
+
var DEFAULT_MAXIMUM_SEARCH_STATES2 = 1e5;
|
|
50750
|
+
function assertGeometryRules2(rules) {
|
|
50751
|
+
for (const [name, value] of [
|
|
50752
|
+
["viaDiameter", rules.viaDiameter],
|
|
50753
|
+
["traceWidth", rules.traceWidth]
|
|
50754
|
+
]) {
|
|
50755
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
50756
|
+
throw new Error(
|
|
50757
|
+
`FanoutSolver: dogbone ${name} must be a positive finite number, received ${value}`
|
|
50758
|
+
);
|
|
50759
|
+
}
|
|
50760
|
+
}
|
|
50761
|
+
if (!Number.isFinite(rules.clearance) || rules.clearance < 0) {
|
|
50762
|
+
throw new Error(
|
|
50763
|
+
`FanoutSolver: dogbone clearance must be a non-negative finite number, received ${rules.clearance}`
|
|
50764
|
+
);
|
|
50765
|
+
}
|
|
50766
|
+
if (rules.viaHoleDiameter !== void 0 && (!Number.isFinite(rules.viaHoleDiameter) || rules.viaHoleDiameter <= 0)) {
|
|
50767
|
+
throw new Error(
|
|
50768
|
+
`FanoutSolver: dogbone viaHoleDiameter must be a positive finite number, received ${rules.viaHoleDiameter}`
|
|
50769
|
+
);
|
|
50770
|
+
}
|
|
50771
|
+
if (rules.holeToHoleClearance !== void 0 && (!Number.isFinite(rules.holeToHoleClearance) || rules.holeToHoleClearance < 0)) {
|
|
50772
|
+
throw new Error(
|
|
50773
|
+
`FanoutSolver: dogbone holeToHoleClearance must be a non-negative finite number, received ${rules.holeToHoleClearance}`
|
|
50774
|
+
);
|
|
50775
|
+
}
|
|
50776
|
+
if (rules.holeToHoleClearance !== void 0 && rules.viaHoleDiameter === void 0) {
|
|
50777
|
+
throw new Error(
|
|
50778
|
+
"FanoutSolver: dogbone holeToHoleClearance requires viaHoleDiameter"
|
|
50779
|
+
);
|
|
50780
|
+
}
|
|
50781
|
+
const maximumSearchStates = rules.maximumSearchStates ?? DEFAULT_MAXIMUM_SEARCH_STATES2;
|
|
50782
|
+
if (!Number.isInteger(maximumSearchStates) || maximumSearchStates < 1) {
|
|
50783
|
+
throw new Error(
|
|
50784
|
+
`FanoutSolver: dogbone maximumSearchStates must be a positive integer, received ${maximumSearchStates}`
|
|
50785
|
+
);
|
|
50786
|
+
}
|
|
50787
|
+
return maximumSearchStates;
|
|
50788
|
+
}
|
|
50789
|
+
function uniqueSortedCoordinates2(values) {
|
|
50790
|
+
const result = [];
|
|
50791
|
+
for (const value of values.toSorted((first, second) => first - second)) {
|
|
50792
|
+
if (!Number.isFinite(value)) continue;
|
|
50793
|
+
if (result.length === 0 || Math.abs(result.at(-1) - value) > EPSILON25) {
|
|
50794
|
+
result.push(value);
|
|
50795
|
+
}
|
|
50796
|
+
}
|
|
50797
|
+
return result;
|
|
50798
|
+
}
|
|
50799
|
+
function getComponentMatchingInputs2(preparedBuses) {
|
|
50800
|
+
const byComponent = /* @__PURE__ */ new Map();
|
|
50801
|
+
const componentByConnectionIndex = /* @__PURE__ */ new Map();
|
|
50802
|
+
const obstacleSetByComponentId = /* @__PURE__ */ new Map();
|
|
50803
|
+
for (const bus of preparedBuses) {
|
|
50804
|
+
let component = byComponent.get(bus.componentId);
|
|
50805
|
+
if (!component) {
|
|
50806
|
+
component = {
|
|
50807
|
+
componentId: bus.componentId,
|
|
50808
|
+
connections: [],
|
|
50809
|
+
obstacles: [],
|
|
50810
|
+
xCoordinates: [],
|
|
50811
|
+
yCoordinates: [],
|
|
50812
|
+
pitchX: Number.POSITIVE_INFINITY,
|
|
50813
|
+
pitchY: Number.POSITIVE_INFINITY
|
|
50814
|
+
};
|
|
50815
|
+
byComponent.set(bus.componentId, component);
|
|
50816
|
+
obstacleSetByComponentId.set(bus.componentId, /* @__PURE__ */ new Set());
|
|
50817
|
+
}
|
|
50818
|
+
component.xCoordinates.push(...bus.xCoordinates);
|
|
50819
|
+
component.yCoordinates.push(...bus.yCoordinates);
|
|
50820
|
+
if (Number.isFinite(bus.pitchX) && bus.pitchX > EPSILON25) {
|
|
50821
|
+
component.pitchX = Math.min(component.pitchX, bus.pitchX);
|
|
50822
|
+
}
|
|
50823
|
+
if (Number.isFinite(bus.pitchY) && bus.pitchY > EPSILON25) {
|
|
50824
|
+
component.pitchY = Math.min(component.pitchY, bus.pitchY);
|
|
50825
|
+
}
|
|
50826
|
+
const obstacleSet = obstacleSetByComponentId.get(bus.componentId);
|
|
50827
|
+
for (const obstacle of bus.componentObstacles) {
|
|
50828
|
+
if (!obstacleSet.has(obstacle)) {
|
|
50829
|
+
obstacleSet.add(obstacle);
|
|
50830
|
+
component.obstacles.push(obstacle);
|
|
50831
|
+
}
|
|
50832
|
+
}
|
|
50833
|
+
for (const preparedConnection of bus.connections) {
|
|
50834
|
+
const existingComponent = componentByConnectionIndex.get(
|
|
50835
|
+
preparedConnection.connectionIndex
|
|
50836
|
+
);
|
|
50837
|
+
if (existingComponent !== void 0) {
|
|
50838
|
+
if (existingComponent !== bus.componentId) {
|
|
50839
|
+
throw new Error(
|
|
50840
|
+
`FanoutSolver: connection index ${preparedConnection.connectionIndex} belongs to multiple components`
|
|
50841
|
+
);
|
|
50842
|
+
}
|
|
50843
|
+
continue;
|
|
50844
|
+
}
|
|
50845
|
+
componentByConnectionIndex.set(
|
|
50846
|
+
preparedConnection.connectionIndex,
|
|
50847
|
+
bus.componentId
|
|
50848
|
+
);
|
|
50849
|
+
component.connections.push({
|
|
50850
|
+
preparedConnection,
|
|
50851
|
+
busId: bus.busId,
|
|
50852
|
+
direction: bus.direction,
|
|
50853
|
+
terminationType: bus.termination.type
|
|
50854
|
+
});
|
|
50855
|
+
}
|
|
50856
|
+
}
|
|
50857
|
+
return [...byComponent.values()].map((component) => ({
|
|
50858
|
+
...component,
|
|
50859
|
+
connections: component.connections.toSorted(
|
|
50860
|
+
(first, second) => first.preparedConnection.connectionIndex - second.preparedConnection.connectionIndex
|
|
50861
|
+
),
|
|
50862
|
+
xCoordinates: uniqueSortedCoordinates2(component.xCoordinates),
|
|
50863
|
+
yCoordinates: uniqueSortedCoordinates2(component.yCoordinates)
|
|
50864
|
+
})).toSorted(
|
|
50865
|
+
(first, second) => first.componentId.localeCompare(second.componentId)
|
|
50866
|
+
);
|
|
50867
|
+
}
|
|
50868
|
+
function getInterstitialCoordinates2(params) {
|
|
50869
|
+
const { coordinates, pitch } = params;
|
|
50870
|
+
if (coordinates.length === 0 || !Number.isFinite(pitch) || pitch <= EPSILON25) {
|
|
50871
|
+
return [];
|
|
50872
|
+
}
|
|
50873
|
+
const interstitialCoordinates = [coordinates[0] - pitch / 2];
|
|
50874
|
+
for (let index = 1; index < coordinates.length; index++) {
|
|
50875
|
+
interstitialCoordinates.push(
|
|
50876
|
+
(coordinates[index - 1] + coordinates[index]) / 2
|
|
50877
|
+
);
|
|
50878
|
+
}
|
|
50879
|
+
interstitialCoordinates.push(coordinates.at(-1) + pitch / 2);
|
|
50880
|
+
return uniqueSortedCoordinates2(interstitialCoordinates);
|
|
50881
|
+
}
|
|
50882
|
+
function getAdjacentInterstitialCoordinates2(params) {
|
|
50883
|
+
const { sourceCoordinate, coordinates, pitch } = params;
|
|
50884
|
+
const interstitialCoordinates = getInterstitialCoordinates2({
|
|
50885
|
+
coordinates,
|
|
50886
|
+
pitch
|
|
50887
|
+
});
|
|
50888
|
+
const before = interstitialCoordinates.filter((coordinate) => coordinate < sourceCoordinate - EPSILON25).at(-1);
|
|
50889
|
+
const after = interstitialCoordinates.find(
|
|
50890
|
+
(coordinate) => coordinate > sourceCoordinate + EPSILON25
|
|
50891
|
+
);
|
|
50892
|
+
return [before, after].filter(
|
|
50893
|
+
(coordinate) => coordinate !== void 0
|
|
50894
|
+
);
|
|
50895
|
+
}
|
|
50896
|
+
function directSegmentIsStraightOr452(start, end) {
|
|
50897
|
+
const absoluteX = Math.abs(end.x - start.x);
|
|
50898
|
+
const absoluteY = Math.abs(end.y - start.y);
|
|
50899
|
+
return absoluteX <= EPSILON25 || absoluteY <= EPSILON25 || Math.abs(absoluteX - absoluteY) <= EPSILON25;
|
|
50900
|
+
}
|
|
50901
|
+
function getOutwardRank2(params) {
|
|
50902
|
+
const { source, site, direction } = params;
|
|
50903
|
+
const outwardDisplacement = direction === "right" ? site.x - source.x : direction === "left" ? source.x - site.x : direction === "up" ? site.y - source.y : source.y - site.y;
|
|
50904
|
+
return outwardDisplacement > EPSILON25 ? 0 : Math.abs(outwardDisplacement) <= EPSILON25 ? 1 : 2;
|
|
50905
|
+
}
|
|
50906
|
+
function viaSiteClearsObstacles2(params) {
|
|
50907
|
+
const { point: point6, obstacles, viaDiameter, clearance } = params;
|
|
50908
|
+
const requiredClearance = viaDiameter / 2 + clearance;
|
|
50909
|
+
return obstacles.every(
|
|
50910
|
+
(obstacle) => distancePointToObstacle2(point6, obstacle) >= requiredClearance - EPSILON25
|
|
50911
|
+
);
|
|
50912
|
+
}
|
|
50913
|
+
function sourceSegmentClearsOtherObstacles2(params) {
|
|
50914
|
+
const { segment: segment2, sourceObstacle, obstacles, clearance } = params;
|
|
50915
|
+
const requiredClearance = segment2.width / 2 + clearance;
|
|
50916
|
+
return obstacles.every(
|
|
50917
|
+
(obstacle) => obstacle === sourceObstacle || distanceSegmentToObstacle2(segment2, obstacle) >= requiredClearance - EPSILON25
|
|
50918
|
+
);
|
|
50919
|
+
}
|
|
50920
|
+
function getConnectionCandidates2(params) {
|
|
50921
|
+
const { connection, component, rules } = params;
|
|
50922
|
+
const { preparedConnection, direction } = connection;
|
|
50923
|
+
const obstacles = rules.additionalObstacles ? [.../* @__PURE__ */ new Set([...component.obstacles, ...rules.additionalObstacles])] : component.obstacles;
|
|
50924
|
+
const source = {
|
|
50925
|
+
x: preparedConnection.sourcePoint.x,
|
|
50926
|
+
y: preparedConnection.sourcePoint.y
|
|
50927
|
+
};
|
|
50928
|
+
const adjacentX = getAdjacentInterstitialCoordinates2({
|
|
50929
|
+
sourceCoordinate: source.x,
|
|
50930
|
+
coordinates: component.xCoordinates,
|
|
50931
|
+
pitch: component.pitchX
|
|
50932
|
+
});
|
|
50933
|
+
const adjacentY = getAdjacentInterstitialCoordinates2({
|
|
50934
|
+
sourceCoordinate: source.y,
|
|
50935
|
+
coordinates: component.yCoordinates,
|
|
50936
|
+
pitch: component.pitchY
|
|
50937
|
+
});
|
|
50938
|
+
const rawPoints = [
|
|
50939
|
+
...adjacentX.map((x) => ({ x, y: source.y })),
|
|
50940
|
+
...adjacentY.map((y) => ({ x: source.x, y })),
|
|
50941
|
+
...adjacentX.flatMap((x) => adjacentY.map((y) => ({ x, y })))
|
|
50942
|
+
];
|
|
50943
|
+
const uniquePoints2 = [];
|
|
50944
|
+
for (const point6 of rawPoints) {
|
|
50945
|
+
if (!uniquePoints2.some((candidate) => distance12(candidate, point6) <= EPSILON25)) {
|
|
50946
|
+
uniquePoints2.push(point6);
|
|
50947
|
+
}
|
|
50948
|
+
}
|
|
50949
|
+
const fixedViaPoint = rules.fixedViaPointsByConnectionIndex?.get(
|
|
50950
|
+
preparedConnection.connectionIndex
|
|
50951
|
+
);
|
|
50952
|
+
const candidatePoints = fixedViaPoint ? [fixedViaPoint] : uniquePoints2;
|
|
50953
|
+
const candidates = [];
|
|
50954
|
+
for (const point6 of candidatePoints) {
|
|
50955
|
+
if (connection.terminationType === "plane" && !directSegmentIsStraightOr452(source, point6)) {
|
|
50956
|
+
continue;
|
|
50957
|
+
}
|
|
50958
|
+
if (!viaSiteClearsObstacles2({
|
|
50959
|
+
point: point6,
|
|
50960
|
+
obstacles,
|
|
50961
|
+
viaDiameter: rules.viaDiameter,
|
|
50962
|
+
clearance: rules.clearance
|
|
50963
|
+
})) {
|
|
50964
|
+
continue;
|
|
50965
|
+
}
|
|
50966
|
+
const sourceSegment = {
|
|
50967
|
+
start: source,
|
|
50968
|
+
end: point6,
|
|
50969
|
+
width: rules.traceWidth,
|
|
50970
|
+
layer: preparedConnection.sourceLayer
|
|
50971
|
+
};
|
|
50972
|
+
if (!sourceSegmentClearsOtherObstacles2({
|
|
50973
|
+
segment: sourceSegment,
|
|
50974
|
+
sourceObstacle: preparedConnection.sourceObstacle,
|
|
50975
|
+
obstacles,
|
|
50976
|
+
clearance: rules.clearance
|
|
50977
|
+
})) {
|
|
50978
|
+
continue;
|
|
50979
|
+
}
|
|
50980
|
+
const candidateClearsRoutedCopper = (rules.blockingSegments ?? []).every(
|
|
50981
|
+
(blocker) => {
|
|
50982
|
+
if (blocker.connectionIndex === preparedConnection.connectionIndex) {
|
|
50983
|
+
return true;
|
|
50984
|
+
}
|
|
50985
|
+
if (rules.canShareCopper?.(
|
|
50986
|
+
preparedConnection.connectionIndex,
|
|
50987
|
+
blocker.connectionIndex
|
|
50988
|
+
)) {
|
|
50989
|
+
return true;
|
|
50990
|
+
}
|
|
50991
|
+
const viaToTraceClearance = rules.viaDiameter / 2 + blocker.segment.width / 2 + rules.clearance;
|
|
50992
|
+
if (distancePointToSegment2(
|
|
50993
|
+
point6,
|
|
50994
|
+
blocker.segment.start,
|
|
50995
|
+
blocker.segment.end
|
|
50996
|
+
) < viaToTraceClearance - EPSILON25) {
|
|
50997
|
+
return false;
|
|
50998
|
+
}
|
|
50999
|
+
return blocker.segment.layer !== sourceSegment.layer || segmentsAreClear2(sourceSegment, blocker.segment, rules.clearance);
|
|
51000
|
+
}
|
|
51001
|
+
);
|
|
51002
|
+
if (!candidateClearsRoutedCopper) continue;
|
|
51003
|
+
const candidateClearsRoutedVias = (rules.blockingVias ?? []).every(
|
|
51004
|
+
(blocker) => {
|
|
51005
|
+
if (blocker.connectionIndex === preparedConnection.connectionIndex) {
|
|
51006
|
+
return true;
|
|
51007
|
+
}
|
|
51008
|
+
if (distance12(point6, blocker.center) < (rules.viaDiameter + blocker.diameter) / 2 + rules.clearance - EPSILON25) {
|
|
51009
|
+
return false;
|
|
51010
|
+
}
|
|
51011
|
+
if (blocker.spanLayers.includes(sourceSegment.layer) && distancePointToSegment2(
|
|
51012
|
+
blocker.center,
|
|
51013
|
+
sourceSegment.start,
|
|
51014
|
+
sourceSegment.end
|
|
51015
|
+
) < blocker.diameter / 2 + sourceSegment.width / 2 + rules.clearance - EPSILON25) {
|
|
51016
|
+
return false;
|
|
51017
|
+
}
|
|
51018
|
+
return true;
|
|
51019
|
+
}
|
|
51020
|
+
);
|
|
51021
|
+
if (!candidateClearsRoutedVias) continue;
|
|
51022
|
+
candidates.push({
|
|
51023
|
+
connectionIndex: preparedConnection.connectionIndex,
|
|
51024
|
+
point: point6,
|
|
51025
|
+
sourceSegment,
|
|
51026
|
+
outwardRank: getOutwardRank2({ source, site: point6, direction })
|
|
51027
|
+
});
|
|
51028
|
+
}
|
|
51029
|
+
const perpendicularCoordinates = direction === "left" || direction === "right" ? component.yCoordinates : component.xCoordinates;
|
|
51030
|
+
const sourcePerpendicularCoordinate = direction === "left" || direction === "right" ? source.y : source.x;
|
|
51031
|
+
const perpendicularGridIndex = perpendicularCoordinates.findIndex(
|
|
51032
|
+
(coordinate) => Math.abs(coordinate - sourcePerpendicularCoordinate) <= EPSILON25
|
|
51033
|
+
);
|
|
51034
|
+
const planeCheckerboardSide = perpendicularGridIndex >= 0 ? perpendicularGridIndex % 2 === 0 ? 1 : -1 : void 0;
|
|
51035
|
+
const preferredPerpendicularSide = connection.terminationType === "boundary" ? rules.preferredBoundaryPerpendicularSideByBusId?.get(connection.busId) : rules.preferPlaneCheckerboardSites && connection.terminationType === "plane" && (direction === "left" || direction === "right") ? planeCheckerboardSide : void 0;
|
|
51036
|
+
const preferOutward = connection.terminationType === "boundary" ? rules.preferBoundaryOutwardByBusId?.get(connection.busId) ?? true : true;
|
|
51037
|
+
const preferredViaPoint = rules.preferredViaPointsByConnectionIndex?.get(
|
|
51038
|
+
preparedConnection.connectionIndex
|
|
51039
|
+
);
|
|
51040
|
+
const getPerpendicularPreferenceRank = (candidate) => {
|
|
51041
|
+
if (preferredPerpendicularSide === void 0) return 0;
|
|
51042
|
+
const displacement = direction === "left" || direction === "right" ? candidate.point.y - source.y : candidate.point.x - source.x;
|
|
51043
|
+
return displacement * preferredPerpendicularSide > EPSILON25 ? 0 : Math.abs(displacement) <= EPSILON25 ? 1 : 2;
|
|
51044
|
+
};
|
|
51045
|
+
return candidates.toSorted(
|
|
51046
|
+
(first, second) => (preferredViaPoint ? Number(distance12(first.point, preferredViaPoint) > EPSILON25) - Number(distance12(second.point, preferredViaPoint) > EPSILON25) : 0) || (preferOutward ? first.outwardRank - second.outwardRank : second.outwardRank - first.outwardRank) || getPerpendicularPreferenceRank(first) - getPerpendicularPreferenceRank(second) || distance12(source, first.point) - distance12(source, second.point) || first.point.x - second.point.x || first.point.y - second.point.y
|
|
51047
|
+
);
|
|
51048
|
+
}
|
|
51049
|
+
function candidatesAreMutuallyClear2(params) {
|
|
51050
|
+
const { first, second, rules } = params;
|
|
51051
|
+
const canShareCopper = rules.canShareCopper?.(first.connectionIndex, second.connectionIndex) ?? false;
|
|
51052
|
+
const requiredHoleSeparation = rules.viaHoleDiameter ? rules.viaHoleDiameter + (rules.holeToHoleClearance ?? rules.clearance) : 0;
|
|
51053
|
+
const requiredViaSeparation = canShareCopper ? requiredHoleSeparation : Math.max(rules.viaDiameter + rules.clearance, requiredHoleSeparation);
|
|
51054
|
+
if (distance12(first.point, second.point) < requiredViaSeparation - EPSILON25) {
|
|
51055
|
+
return false;
|
|
51056
|
+
}
|
|
51057
|
+
const requiredViaToTraceClearance = rules.viaDiameter / 2 + rules.traceWidth / 2 + rules.clearance;
|
|
51058
|
+
if (!canShareCopper) {
|
|
51059
|
+
if (distancePointToSegment2(
|
|
51060
|
+
first.point,
|
|
51061
|
+
second.sourceSegment.start,
|
|
51062
|
+
second.sourceSegment.end
|
|
51063
|
+
) < requiredViaToTraceClearance - EPSILON25 || distancePointToSegment2(
|
|
51064
|
+
second.point,
|
|
51065
|
+
first.sourceSegment.start,
|
|
51066
|
+
first.sourceSegment.end
|
|
51067
|
+
) < requiredViaToTraceClearance - EPSILON25) {
|
|
51068
|
+
return false;
|
|
51069
|
+
}
|
|
51070
|
+
}
|
|
51071
|
+
if (canShareCopper) return true;
|
|
51072
|
+
return segmentsAreClear2(
|
|
51073
|
+
first.sourceSegment,
|
|
51074
|
+
second.sourceSegment,
|
|
51075
|
+
rules.clearance
|
|
51076
|
+
);
|
|
51077
|
+
}
|
|
51078
|
+
function matchComponent2(params) {
|
|
51079
|
+
const { component, rules, consumeSearchState } = params;
|
|
51080
|
+
const entries = component.connections.map(
|
|
51081
|
+
(connection) => ({
|
|
51082
|
+
connection,
|
|
51083
|
+
candidates: getConnectionCandidates2({ connection, component, rules })
|
|
51084
|
+
})
|
|
51085
|
+
);
|
|
51086
|
+
if (entries.some((entry) => entry.candidates.length === 0)) return null;
|
|
51087
|
+
const compatibilityCache = /* @__PURE__ */ new Map();
|
|
51088
|
+
const candidatesAreCompatible = (first, second) => {
|
|
51089
|
+
const cached = compatibilityCache.get(first)?.get(second);
|
|
51090
|
+
if (cached !== void 0) return cached;
|
|
51091
|
+
const compatible = candidatesAreMutuallyClear2({ first, second, rules });
|
|
51092
|
+
const firstCache = compatibilityCache.get(first) ?? /* @__PURE__ */ new Map();
|
|
51093
|
+
firstCache.set(second, compatible);
|
|
51094
|
+
compatibilityCache.set(first, firstCache);
|
|
51095
|
+
const secondCache = compatibilityCache.get(second) ?? /* @__PURE__ */ new Map();
|
|
51096
|
+
secondCache.set(first, compatible);
|
|
51097
|
+
compatibilityCache.set(second, secondCache);
|
|
51098
|
+
return compatible;
|
|
51099
|
+
};
|
|
51100
|
+
const forcedCandidates = entries.flatMap(
|
|
51101
|
+
(entry) => entry.candidates.length === 1 ? [entry.candidates[0]] : []
|
|
51102
|
+
);
|
|
51103
|
+
for (let candidateIndex = 0; candidateIndex < forcedCandidates.length; candidateIndex++) {
|
|
51104
|
+
const candidate = forcedCandidates[candidateIndex];
|
|
51105
|
+
for (let previousIndex = 0; previousIndex < candidateIndex; previousIndex++) {
|
|
51106
|
+
if (!candidatesAreCompatible(candidate, forcedCandidates[previousIndex])) {
|
|
51107
|
+
return null;
|
|
51108
|
+
}
|
|
51109
|
+
}
|
|
51110
|
+
}
|
|
51111
|
+
const assignedCandidates = new Map(
|
|
51112
|
+
forcedCandidates.map((candidate) => [candidate.connectionIndex, candidate])
|
|
51113
|
+
);
|
|
51114
|
+
const remaining = new Set(
|
|
51115
|
+
entries.flatMap(
|
|
51116
|
+
(entry) => entry.candidates.length > 1 ? [entry.connection.preparedConnection.connectionIndex] : []
|
|
51117
|
+
)
|
|
51118
|
+
);
|
|
51119
|
+
const entryByConnectionIndex = new Map(
|
|
51120
|
+
entries.map((entry) => [
|
|
51121
|
+
entry.connection.preparedConnection.connectionIndex,
|
|
51122
|
+
entry
|
|
51123
|
+
])
|
|
51124
|
+
);
|
|
51125
|
+
if (remaining.size === 0) {
|
|
51126
|
+
return new Map(
|
|
51127
|
+
[...assignedCandidates.entries()].map(([connectionIndex, candidate]) => [
|
|
51128
|
+
connectionIndex,
|
|
51129
|
+
{ ...candidate.point }
|
|
51130
|
+
])
|
|
51131
|
+
);
|
|
51132
|
+
}
|
|
51133
|
+
const getViableCandidates = (entry) => entry.candidates.filter(
|
|
51134
|
+
(candidate) => [...assignedCandidates.values()].every(
|
|
51135
|
+
(assignedCandidate) => candidatesAreCompatible(candidate, assignedCandidate)
|
|
51136
|
+
)
|
|
51137
|
+
);
|
|
51138
|
+
const augmentMatching = () => {
|
|
51139
|
+
if (!consumeSearchState()) return false;
|
|
51140
|
+
if (remaining.size === 0) return true;
|
|
51141
|
+
let selectedEntry;
|
|
51142
|
+
let selectedCandidates = [];
|
|
51143
|
+
for (const connectionIndex2 of [...remaining].toSorted(
|
|
51144
|
+
(first, second) => first - second
|
|
51145
|
+
)) {
|
|
51146
|
+
const entry = entryByConnectionIndex.get(connectionIndex2);
|
|
51147
|
+
const viableCandidates = getViableCandidates(entry);
|
|
51148
|
+
if (viableCandidates.length === 0) return false;
|
|
51149
|
+
if (!selectedEntry || viableCandidates.length < selectedCandidates.length || viableCandidates.length === selectedCandidates.length && connectionIndex2 < selectedEntry.connection.preparedConnection.connectionIndex) {
|
|
51150
|
+
selectedEntry = entry;
|
|
51151
|
+
selectedCandidates = viableCandidates;
|
|
51152
|
+
}
|
|
51153
|
+
}
|
|
51154
|
+
const connectionIndex = selectedEntry.connection.preparedConnection.connectionIndex;
|
|
51155
|
+
remaining.delete(connectionIndex);
|
|
51156
|
+
for (const candidate of selectedCandidates) {
|
|
51157
|
+
assignedCandidates.set(connectionIndex, candidate);
|
|
51158
|
+
if (augmentMatching()) return true;
|
|
51159
|
+
assignedCandidates.delete(connectionIndex);
|
|
51160
|
+
}
|
|
51161
|
+
remaining.add(connectionIndex);
|
|
51162
|
+
return false;
|
|
51163
|
+
};
|
|
51164
|
+
if (!augmentMatching()) return null;
|
|
51165
|
+
return new Map(
|
|
51166
|
+
[...assignedCandidates.entries()].toSorted(([first], [second]) => first - second).map(([connectionIndex, candidate]) => [
|
|
51167
|
+
connectionIndex,
|
|
51168
|
+
{ ...candidate.point }
|
|
51169
|
+
])
|
|
51170
|
+
);
|
|
51171
|
+
}
|
|
51172
|
+
function matchComponentDogboneViaSites2(preparedBuses, rules) {
|
|
51173
|
+
const maximumSearchStates = assertGeometryRules2(rules);
|
|
51174
|
+
if (preparedBuses.length === 0) return /* @__PURE__ */ new Map();
|
|
51175
|
+
let consumedSearchStates = 0;
|
|
51176
|
+
const consumeSearchState = () => {
|
|
51177
|
+
consumedSearchStates++;
|
|
51178
|
+
return consumedSearchStates <= maximumSearchStates;
|
|
51179
|
+
};
|
|
51180
|
+
const result = /* @__PURE__ */ new Map();
|
|
51181
|
+
for (const component of getComponentMatchingInputs2(preparedBuses)) {
|
|
51182
|
+
const componentResult = matchComponent2({
|
|
51183
|
+
component,
|
|
51184
|
+
rules,
|
|
51185
|
+
consumeSearchState
|
|
51186
|
+
});
|
|
51187
|
+
if (!componentResult) return null;
|
|
51188
|
+
for (const [connectionIndex, point6] of componentResult) {
|
|
51189
|
+
result.set(connectionIndex, point6);
|
|
51190
|
+
}
|
|
51191
|
+
}
|
|
51192
|
+
return result;
|
|
51193
|
+
}
|
|
51194
|
+
|
|
51195
|
+
// node_modules/@tscircuit/dogbone-solver/node_modules/@tscircuit/fanout-solver/lib/route-reserved-via-buses.ts
|
|
51196
|
+
import {
|
|
51197
|
+
PortfolioSingleIntraNodeSolver as PortfolioSingleIntraNodeSolver2
|
|
51198
|
+
} from "@tscircuit/capacity-autorouter";
|
|
50632
51199
|
import { BaseSolver as BaseSolver4 } from "@tscircuit/solver-utils";
|
|
50633
51200
|
|
|
51201
|
+
// node_modules/@tscircuit/dogbone-solver/node_modules/@tscircuit/fanout-solver/lib/subsolver-request.ts
|
|
51202
|
+
import { BaseSolver as BaseSolver5 } from "@tscircuit/solver-utils";
|
|
51203
|
+
|
|
51204
|
+
// node_modules/@tscircuit/dogbone-solver/node_modules/@tscircuit/fanout-solver/lib/fanout-solver.ts
|
|
51205
|
+
import { BaseSolver as BaseSolver6 } from "@tscircuit/solver-utils";
|
|
51206
|
+
import { mergeGraphics as mergeGraphics2 } from "graphics-debug";
|
|
51207
|
+
|
|
51208
|
+
// node_modules/@tscircuit/dogbone-solver/node_modules/@tscircuit/fanout-solver/lib/match-angularly-ordered-local-vias.ts
|
|
51209
|
+
var TAU2 = Math.PI * 2;
|
|
51210
|
+
|
|
51211
|
+
// node_modules/@tscircuit/dogbone-solver/node_modules/@tscircuit/fanout-solver/lib/route-single-layer-adaptive-exits.ts
|
|
51212
|
+
var FANOUT_FLOW_DEBUG_ENABLED2 = globalThis.process?.env?.FANOUT_FLOW_DEBUG === "1";
|
|
51213
|
+
|
|
51214
|
+
// node_modules/@tscircuit/dogbone-solver/node_modules/@tscircuit/fanout-solver/lib/runtime-process.ts
|
|
51215
|
+
var getRuntimeProcess2 = (runtime) => runtime.process ?? { env: {} };
|
|
51216
|
+
|
|
51217
|
+
// node_modules/@tscircuit/dogbone-solver/node_modules/@tscircuit/fanout-solver/lib/fanout-solver.ts
|
|
51218
|
+
var process2 = getRuntimeProcess2(globalThis);
|
|
51219
|
+
|
|
51220
|
+
// node_modules/@tscircuit/dogbone-solver/lib/dogbone-fanout-solver.ts
|
|
51221
|
+
import { layer_ref as layer_ref3 } from "circuit-json";
|
|
51222
|
+
|
|
51223
|
+
// node_modules/@tscircuit/dogbone-solver/lib/get-via-board-layers.ts
|
|
51224
|
+
function getViaBoardLayers2(layerCount) {
|
|
51225
|
+
if (layerCount <= 1) return ["top"];
|
|
51226
|
+
return [
|
|
51227
|
+
"top",
|
|
51228
|
+
...Array.from(
|
|
51229
|
+
{ length: layerCount - 2 },
|
|
51230
|
+
(_, index) => `inner${index + 1}`
|
|
51231
|
+
),
|
|
51232
|
+
"bottom"
|
|
51233
|
+
];
|
|
51234
|
+
}
|
|
51235
|
+
|
|
51236
|
+
// node_modules/@tscircuit/dogbone-solver/lib/dogbone-fanout-solver.ts
|
|
51237
|
+
var DogboneFanoutSolver = class extends BaseSolver7 {
|
|
51238
|
+
constructor(params) {
|
|
51239
|
+
super();
|
|
51240
|
+
this.params = params;
|
|
51241
|
+
this.MAX_ITERATIONS = params.input.connections.length * 2 + 10;
|
|
51242
|
+
this.steps = this.solveSteps();
|
|
51243
|
+
}
|
|
51244
|
+
params;
|
|
51245
|
+
phase = "preparing";
|
|
51246
|
+
sources = [];
|
|
51247
|
+
sites = /* @__PURE__ */ new Map();
|
|
51248
|
+
traces = [];
|
|
51249
|
+
steps;
|
|
51250
|
+
getConstructorParams() {
|
|
51251
|
+
return [this.params];
|
|
51252
|
+
}
|
|
51253
|
+
_step() {
|
|
51254
|
+
try {
|
|
51255
|
+
if (this.steps.next().done) {
|
|
51256
|
+
this.phase = "complete";
|
|
51257
|
+
this.progress = 1;
|
|
51258
|
+
this.solved = true;
|
|
51259
|
+
}
|
|
51260
|
+
} catch (error) {
|
|
51261
|
+
this.error = error instanceof Error ? error.message : String(error);
|
|
51262
|
+
this.failed = true;
|
|
51263
|
+
}
|
|
51264
|
+
}
|
|
51265
|
+
getOutput() {
|
|
51266
|
+
if (!this.solved)
|
|
51267
|
+
throw new Error(this.error ?? "Dogbone fanout is not solved");
|
|
51268
|
+
return this.traces;
|
|
51269
|
+
}
|
|
51270
|
+
visualize() {
|
|
51271
|
+
return {
|
|
51272
|
+
rects: this.params.input.obstacles.filter((pad) => pad.shape !== "circle").map((pad) => ({
|
|
51273
|
+
center: pad.center,
|
|
51274
|
+
width: pad.width,
|
|
51275
|
+
height: pad.height,
|
|
51276
|
+
fill: "rgba(200,40,40,0.3)"
|
|
51277
|
+
})),
|
|
51278
|
+
circles: [
|
|
51279
|
+
...this.params.input.obstacles.filter((pad) => pad.shape === "circle").map((pad) => ({
|
|
51280
|
+
center: pad.center,
|
|
51281
|
+
radius: pad.width / 2,
|
|
51282
|
+
fill: "rgba(200,40,40,0.3)"
|
|
51283
|
+
})),
|
|
51284
|
+
...[...this.sites.values()].map((center) => ({
|
|
51285
|
+
center,
|
|
51286
|
+
radius: (this.params.input.minViaPadDiameter ?? this.params.input.minViaDiameter ?? 0.6) / 2,
|
|
51287
|
+
fill: "orange"
|
|
51288
|
+
}))
|
|
51289
|
+
],
|
|
51290
|
+
lines: [...this.sites].map(([index, via]) => ({
|
|
51291
|
+
points: [this.sources[index].port, via],
|
|
51292
|
+
strokeColor: "orange",
|
|
51293
|
+
strokeWidth: this.params.input.minTraceWidth
|
|
51294
|
+
}))
|
|
51295
|
+
};
|
|
51296
|
+
}
|
|
51297
|
+
*solveSteps() {
|
|
51298
|
+
const { input, fanoutRoutingLayers } = this.params;
|
|
51299
|
+
const traceWidth = input.minTraceWidth;
|
|
51300
|
+
const clearance = input.minTraceToPadEdgeClearance ?? 0.1;
|
|
51301
|
+
const viaDiameter = input.minViaPadDiameter ?? input.minViaDiameter ?? 0.6;
|
|
51302
|
+
const holeDiameter = input.minViaHoleDiameter ?? 0.3;
|
|
51303
|
+
const viaClearance = input.minViaEdgeToPadEdgeClearance ?? clearance;
|
|
51304
|
+
const boardEdgeClearance = input.minBoardEdgeClearance ?? clearance;
|
|
51305
|
+
const holeClearance = input.minViaHoleEdgeToViaHoleEdgeClearance ?? clearance;
|
|
51306
|
+
this.sources = input.connections.map((connection) => {
|
|
51307
|
+
const point6 = connection.pointsToConnect.find(
|
|
51308
|
+
(point7) => point7.pcb_port_id && input.obstacles.some(
|
|
51309
|
+
(pad2) => pad2.componentId && Math.hypot(pad2.center.x - point7.x, pad2.center.y - point7.y) < 1e-6
|
|
51310
|
+
)
|
|
51311
|
+
);
|
|
51312
|
+
if (!point6?.pcb_port_id)
|
|
51313
|
+
throw new Error(
|
|
51314
|
+
`Dogbone connection ${connection.name} has no source pad`
|
|
51315
|
+
);
|
|
51316
|
+
const pad = input.obstacles.find(
|
|
51317
|
+
(pad2) => pad2.componentId && Math.hypot(pad2.center.x - point6.x, pad2.center.y - point6.y) < 1e-6
|
|
51318
|
+
);
|
|
51319
|
+
return {
|
|
51320
|
+
port: {
|
|
51321
|
+
pcb_port_id: point6.pcb_port_id,
|
|
51322
|
+
pcb_component_id: pad.componentId,
|
|
51323
|
+
x: point6.x,
|
|
51324
|
+
y: point6.y,
|
|
51325
|
+
layers: [layer_ref3.parse(point6.layer)]
|
|
51326
|
+
},
|
|
51327
|
+
sourceTraceId: connection.source_trace_id
|
|
51328
|
+
};
|
|
51329
|
+
});
|
|
51330
|
+
const sources = this.sources;
|
|
51331
|
+
const layers = getViaBoardLayers2(input.layerCount);
|
|
51332
|
+
const allowedLayers = fanoutRoutingLayers ?? layers;
|
|
51333
|
+
if (allowedLayers.some(
|
|
51334
|
+
(layer) => !layers.some((boardLayer) => boardLayer === layer)
|
|
51335
|
+
))
|
|
51336
|
+
throw new Error("Dogbone fanout targets an unavailable board layer");
|
|
51337
|
+
const buses = [];
|
|
51338
|
+
const targets = sources.map(({ port, sourceTraceId }, connectionIndex) => {
|
|
51339
|
+
const sourceObstacle = input.obstacles.find(
|
|
51340
|
+
(obstacle) => obstacle.componentId === port.pcb_component_id && Math.hypot(obstacle.center.x - port.x, obstacle.center.y - port.y) < 1e-6
|
|
51341
|
+
);
|
|
51342
|
+
if (!sourceObstacle)
|
|
51343
|
+
throw new Error(
|
|
51344
|
+
"Dogbone fanout requires a component pad at each source port"
|
|
51345
|
+
);
|
|
51346
|
+
if (port.layers.length !== 1 || !layers.includes(port.layers[0])) {
|
|
51347
|
+
throw new Error("Dogbone fanout requires a single-layer SMT source pad");
|
|
51348
|
+
}
|
|
51349
|
+
const sourceLayer = port.layers[0];
|
|
51350
|
+
const targetLayer2 = allowedLayers.find((layer) => layer !== sourceLayer);
|
|
51351
|
+
if (!targetLayer2)
|
|
51352
|
+
throw new Error(
|
|
51353
|
+
"Dogbone fanout requires a legal layer distinct from the source pad"
|
|
51354
|
+
);
|
|
51355
|
+
let bus = buses.find(
|
|
51356
|
+
(bus2) => bus2.componentId === sourceObstacle.componentId
|
|
51357
|
+
);
|
|
51358
|
+
if (!bus) {
|
|
51359
|
+
const pads = input.obstacles.filter(
|
|
51360
|
+
(obstacle) => obstacle.componentId === sourceObstacle.componentId
|
|
51361
|
+
);
|
|
51362
|
+
const xs = [
|
|
51363
|
+
...new Set(pads.map((pad) => Math.round(pad.center.x * 1e6) / 1e6))
|
|
51364
|
+
].sort((a, b) => a - b);
|
|
51365
|
+
const ys = [
|
|
51366
|
+
...new Set(pads.map((pad) => Math.round(pad.center.y * 1e6) / 1e6))
|
|
51367
|
+
].sort((a, b) => a - b);
|
|
51368
|
+
if (xs.length < 2 || ys.length < 2)
|
|
51369
|
+
throw new Error("Dogbone fanout requires a two-dimensional pad grid");
|
|
51370
|
+
const pitch = (coordinates) => Math.min(...coordinates.slice(1).map((v, i) => v - coordinates[i]));
|
|
51371
|
+
bus = {
|
|
51372
|
+
busId: sourceObstacle.componentId,
|
|
51373
|
+
componentId: sourceObstacle.componentId,
|
|
51374
|
+
componentObstacles: pads,
|
|
51375
|
+
connections: [],
|
|
51376
|
+
direction: "down",
|
|
51377
|
+
termination: { type: "boundary" },
|
|
51378
|
+
componentBounds: {
|
|
51379
|
+
minX: xs[0],
|
|
51380
|
+
maxX: xs.at(-1),
|
|
51381
|
+
minY: ys[0],
|
|
51382
|
+
maxY: ys.at(-1)
|
|
51383
|
+
},
|
|
51384
|
+
sharedBoundary: input.bounds,
|
|
51385
|
+
xCoordinates: xs,
|
|
51386
|
+
yCoordinates: ys,
|
|
51387
|
+
pitchX: pitch(xs),
|
|
51388
|
+
pitchY: pitch(ys)
|
|
51389
|
+
};
|
|
51390
|
+
buses.push(bus);
|
|
51391
|
+
}
|
|
51392
|
+
const sourcePoint = {
|
|
51393
|
+
x: port.x,
|
|
51394
|
+
y: port.y,
|
|
51395
|
+
layer: sourceLayer,
|
|
51396
|
+
pcb_port_id: port.pcb_port_id
|
|
51397
|
+
};
|
|
51398
|
+
bus.connections.push({
|
|
51399
|
+
connectionIndex,
|
|
51400
|
+
connection: { name: port.pcb_port_id, pointsToConnect: [sourcePoint] },
|
|
51401
|
+
sourcePoint,
|
|
51402
|
+
sourcePointIndex: 0,
|
|
51403
|
+
sourceLayer,
|
|
51404
|
+
sourceObstacle,
|
|
51405
|
+
targetPoint: sourcePoint
|
|
51406
|
+
});
|
|
51407
|
+
return { sourceTraceId, port, sourceLayer, targetLayer: targetLayer2 };
|
|
51408
|
+
});
|
|
51409
|
+
const sites = this.sites;
|
|
51410
|
+
const blockingSegments = [];
|
|
51411
|
+
const blockingVias = [];
|
|
51412
|
+
for (const bus of buses) {
|
|
51413
|
+
this.phase = "assigning_sites";
|
|
51414
|
+
yield;
|
|
51415
|
+
const assignment = matchComponentDogboneViaSites2([bus], {
|
|
51416
|
+
traceWidth,
|
|
51417
|
+
clearance: Math.max(clearance, viaClearance),
|
|
51418
|
+
viaDiameter,
|
|
51419
|
+
viaHoleDiameter: holeDiameter,
|
|
51420
|
+
holeToHoleClearance: holeClearance,
|
|
51421
|
+
additionalObstacles: input.obstacles,
|
|
51422
|
+
blockingSegments,
|
|
51423
|
+
blockingVias
|
|
51424
|
+
});
|
|
51425
|
+
if (!assignment || assignment.size !== bus.connections.length)
|
|
51426
|
+
throw new Error(
|
|
51427
|
+
"No complete local dogbone assignment within clearance/search limits"
|
|
51428
|
+
);
|
|
51429
|
+
for (const connection of bus.connections) {
|
|
51430
|
+
const connectionIndex = connection.connectionIndex;
|
|
51431
|
+
const via = assignment.get(connectionIndex);
|
|
51432
|
+
sites.set(connectionIndex, via);
|
|
51433
|
+
blockingSegments.push({
|
|
51434
|
+
connectionIndex,
|
|
51435
|
+
segment: {
|
|
51436
|
+
start: connection.sourcePoint,
|
|
51437
|
+
end: via,
|
|
51438
|
+
width: traceWidth,
|
|
51439
|
+
layer: connection.sourceLayer
|
|
51440
|
+
}
|
|
51441
|
+
});
|
|
51442
|
+
blockingVias.push({
|
|
51443
|
+
connectionIndex,
|
|
51444
|
+
center: via,
|
|
51445
|
+
diameter: viaDiameter,
|
|
51446
|
+
spanLayers: layers
|
|
51447
|
+
});
|
|
51448
|
+
}
|
|
51449
|
+
}
|
|
51450
|
+
this.phase = "creating_traces";
|
|
51451
|
+
for (const [
|
|
51452
|
+
index,
|
|
51453
|
+
{ sourceTraceId, port, sourceLayer, targetLayer: targetLayer2 }
|
|
51454
|
+
] of targets.entries()) {
|
|
51455
|
+
const via = sites.get(index);
|
|
51456
|
+
const dx = Math.abs(via.x - port.x), dy = Math.abs(via.y - port.y);
|
|
51457
|
+
if (dx > 1e-6 && dy > 1e-6 && Math.abs(dx - dy) > 1e-6)
|
|
51458
|
+
throw new Error(
|
|
51459
|
+
"Dogbone fanout requires straight or 45-degree local escapes"
|
|
51460
|
+
);
|
|
51461
|
+
const margin = viaDiameter / 2 + boardEdgeClearance;
|
|
51462
|
+
if (via.x < input.bounds.minX + margin || via.x > input.bounds.maxX - margin || via.y < input.bounds.minY + margin || via.y > input.bounds.maxY - margin)
|
|
51463
|
+
throw new Error("Dogbone via violates board-edge clearance");
|
|
51464
|
+
this.traces.push({
|
|
51465
|
+
type: "pcb_trace",
|
|
51466
|
+
pcb_trace_id: `dogbone_${port.pcb_port_id}`,
|
|
51467
|
+
source_trace_id: sourceTraceId,
|
|
51468
|
+
connectsTo: [port.pcb_port_id],
|
|
51469
|
+
route: [
|
|
51470
|
+
{
|
|
51471
|
+
route_type: "wire",
|
|
51472
|
+
x: port.x,
|
|
51473
|
+
y: port.y,
|
|
51474
|
+
layer: sourceLayer,
|
|
51475
|
+
width: traceWidth
|
|
51476
|
+
},
|
|
51477
|
+
{ route_type: "wire", ...via, layer: sourceLayer, width: traceWidth },
|
|
51478
|
+
{
|
|
51479
|
+
route_type: "via",
|
|
51480
|
+
...via,
|
|
51481
|
+
from_layer: sourceLayer,
|
|
51482
|
+
to_layer: targetLayer2,
|
|
51483
|
+
via_diameter: viaDiameter,
|
|
51484
|
+
via_hole_diameter: holeDiameter,
|
|
51485
|
+
layers
|
|
51486
|
+
},
|
|
51487
|
+
{ route_type: "wire", ...via, layer: targetLayer2, width: traceWidth },
|
|
51488
|
+
{ route_type: "wire", ...via, layer: targetLayer2, width: traceWidth }
|
|
51489
|
+
]
|
|
51490
|
+
});
|
|
51491
|
+
this.progress = (index + 1) / targets.length;
|
|
51492
|
+
yield;
|
|
51493
|
+
}
|
|
51494
|
+
}
|
|
51495
|
+
};
|
|
51496
|
+
|
|
51497
|
+
// node_modules/@tscircuit/dogbone-solver/lib/dogbone-autorouter.ts
|
|
51498
|
+
var DogboneAutorouter = class {
|
|
51499
|
+
constructor(params, callbacks = {}) {
|
|
51500
|
+
this.params = params;
|
|
51501
|
+
this.callbacks = callbacks;
|
|
51502
|
+
this.solver = new DogboneFanoutSolver(params);
|
|
51503
|
+
}
|
|
51504
|
+
params;
|
|
51505
|
+
callbacks;
|
|
51506
|
+
get input() {
|
|
51507
|
+
return this.params.input;
|
|
51508
|
+
}
|
|
51509
|
+
isRouting = false;
|
|
51510
|
+
solver;
|
|
51511
|
+
timer;
|
|
51512
|
+
listeners = [];
|
|
51513
|
+
finishSolver() {
|
|
51514
|
+
this.callbacks.onSolverEnded?.({
|
|
51515
|
+
solverName: "DogboneFanoutSolver",
|
|
51516
|
+
solved: this.solver.solved,
|
|
51517
|
+
failed: this.solver.failed,
|
|
51518
|
+
iterations: this.solver.iterations,
|
|
51519
|
+
error: this.solver.error
|
|
51520
|
+
});
|
|
51521
|
+
}
|
|
51522
|
+
getTraces() {
|
|
51523
|
+
return this.solver.getOutput().map((trace) => {
|
|
51524
|
+
const connection = this.params.input.connections.find(
|
|
51525
|
+
(connection2) => connection2.pointsToConnect.some(
|
|
51526
|
+
(point6) => point6.pcb_port_id && trace.connectsTo?.includes(point6.pcb_port_id)
|
|
51527
|
+
)
|
|
51528
|
+
);
|
|
51529
|
+
if (!connection)
|
|
51530
|
+
throw new Error("Dogbone fanout lost its source connection");
|
|
51531
|
+
return {
|
|
51532
|
+
...trace,
|
|
51533
|
+
connection_name: connection.name,
|
|
51534
|
+
source_trace_id: connection.source_trace_id,
|
|
51535
|
+
connectsTo: [
|
|
51536
|
+
.../* @__PURE__ */ new Set([
|
|
51537
|
+
...trace.connectsTo ?? [],
|
|
51538
|
+
...connection.routingPcbGroupId ? connection.pointsToConnect.flatMap(
|
|
51539
|
+
(point6) => !point6.pcb_port_id && point6.pointId ? [point6.pointId] : []
|
|
51540
|
+
) : [`${trace.pcb_trace_id}_exit`]
|
|
51541
|
+
])
|
|
51542
|
+
]
|
|
51543
|
+
};
|
|
51544
|
+
});
|
|
51545
|
+
}
|
|
51546
|
+
getOutputSimpleRouteJson() {
|
|
51547
|
+
const traces = this.getTraces();
|
|
51548
|
+
return {
|
|
51549
|
+
...this.params.input,
|
|
51550
|
+
traces,
|
|
51551
|
+
connections: this.params.input.connections.map((connection) => {
|
|
51552
|
+
const trace = traces.find(
|
|
51553
|
+
(trace2) => trace2.connection_name === connection.name
|
|
51554
|
+
);
|
|
51555
|
+
if (!trace) return connection;
|
|
51556
|
+
const exit = trace.route.at(-1);
|
|
51557
|
+
if (exit.route_type !== "wire")
|
|
51558
|
+
throw new Error("Dogbone fanout lost its exit");
|
|
51559
|
+
return {
|
|
51560
|
+
...connection,
|
|
51561
|
+
pointsToConnect: connection.pointsToConnect.map((point6) => {
|
|
51562
|
+
const isHandoff = !point6.pcb_port_id;
|
|
51563
|
+
const relocate = connection.routingPcbGroupId ? isHandoff : Boolean(
|
|
51564
|
+
point6.pcb_port_id && trace.connectsTo?.includes(point6.pcb_port_id)
|
|
51565
|
+
);
|
|
51566
|
+
if (!relocate) return point6;
|
|
51567
|
+
if (connection.routingPcbGroupId)
|
|
51568
|
+
return { ...point6, x: exit.x, y: exit.y, layer: exit.layer };
|
|
51569
|
+
const { pcb_port_id: _port, ...handoff } = point6;
|
|
51570
|
+
return {
|
|
51571
|
+
...handoff,
|
|
51572
|
+
pointId: `${trace.pcb_trace_id}_exit`,
|
|
51573
|
+
x: exit.x,
|
|
51574
|
+
y: exit.y,
|
|
51575
|
+
layer: exit.layer
|
|
51576
|
+
};
|
|
51577
|
+
})
|
|
51578
|
+
};
|
|
51579
|
+
})
|
|
51580
|
+
};
|
|
51581
|
+
}
|
|
51582
|
+
on(event, callback) {
|
|
51583
|
+
this.listeners.push({
|
|
51584
|
+
event,
|
|
51585
|
+
callback
|
|
51586
|
+
});
|
|
51587
|
+
}
|
|
51588
|
+
emit(event) {
|
|
51589
|
+
for (const listener of this.listeners)
|
|
51590
|
+
if (listener.event === event.type) listener.callback(event);
|
|
51591
|
+
}
|
|
51592
|
+
start() {
|
|
51593
|
+
if (this.isRouting) return;
|
|
51594
|
+
this.isRouting = true;
|
|
51595
|
+
this.callbacks.onSolverStarted?.({
|
|
51596
|
+
solverName: "DogboneFanoutSolver",
|
|
51597
|
+
solverParams: this.params,
|
|
51598
|
+
solverConstructorArgs: this.solver.getConstructorParams()
|
|
51599
|
+
});
|
|
51600
|
+
const tick = () => {
|
|
51601
|
+
if (!this.isRouting) return;
|
|
51602
|
+
try {
|
|
51603
|
+
for (let i = 0; i < 16 && !this.solver.solved && !this.solver.failed; i++)
|
|
51604
|
+
this.solver.step();
|
|
51605
|
+
this.emit({
|
|
51606
|
+
type: "progress",
|
|
51607
|
+
steps: this.solver.iterations,
|
|
51608
|
+
progress: this.solver.progress,
|
|
51609
|
+
phase: this.solver.phase,
|
|
51610
|
+
debugGraphics: this.solver.visualize()
|
|
51611
|
+
});
|
|
51612
|
+
if (!this.isRouting) return;
|
|
51613
|
+
if (this.solver.failed) {
|
|
51614
|
+
this.finishSolver();
|
|
51615
|
+
this.isRouting = false;
|
|
51616
|
+
this.emit({
|
|
51617
|
+
type: "error",
|
|
51618
|
+
error: new Error(this.solver.error ?? "Dogbone routing failed")
|
|
51619
|
+
});
|
|
51620
|
+
return;
|
|
51621
|
+
}
|
|
51622
|
+
if (this.solver.solved) {
|
|
51623
|
+
this.finishSolver();
|
|
51624
|
+
this.isRouting = false;
|
|
51625
|
+
this.emit({ type: "complete", traces: this.getTraces() });
|
|
51626
|
+
return;
|
|
51627
|
+
}
|
|
51628
|
+
this.timer = setTimeout(tick, 0);
|
|
51629
|
+
} catch (error) {
|
|
51630
|
+
this.isRouting = false;
|
|
51631
|
+
this.emit({
|
|
51632
|
+
type: "error",
|
|
51633
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
51634
|
+
});
|
|
51635
|
+
}
|
|
51636
|
+
};
|
|
51637
|
+
this.timer = setTimeout(tick, 0);
|
|
51638
|
+
}
|
|
51639
|
+
stop() {
|
|
51640
|
+
this.isRouting = false;
|
|
51641
|
+
if (this.timer) clearTimeout(this.timer);
|
|
51642
|
+
}
|
|
51643
|
+
solveSync() {
|
|
51644
|
+
this.solver.solve();
|
|
51645
|
+
if (this.solver.failed)
|
|
51646
|
+
throw new Error(this.solver.error ?? "Dogbone routing failed");
|
|
51647
|
+
return this.getTraces();
|
|
51648
|
+
}
|
|
51649
|
+
};
|
|
51650
|
+
|
|
51651
|
+
// node_modules/@tscircuit/bus-lanes-solver/lib/bus-lanes-solver.ts
|
|
51652
|
+
import { BaseSolver as BaseSolver8 } from "@tscircuit/solver-utils";
|
|
51653
|
+
|
|
50634
51654
|
// node_modules/@tscircuit/bus-lanes-solver/lib/geometry.ts
|
|
50635
|
-
var
|
|
51655
|
+
var distance14 = (a, b) => Math.hypot(a.x - b.x, a.y - b.y);
|
|
50636
51656
|
function pointSegmentDistance(p, edge) {
|
|
50637
51657
|
const [a, b] = edge, dx = b.x - a.x, dy = b.y - a.y, t = Math.max(
|
|
50638
51658
|
0,
|
|
@@ -50643,10 +51663,10 @@ function pointSegmentDistance(p, edge) {
|
|
|
50643
51663
|
);
|
|
50644
51664
|
return Math.hypot(p.x - a.x - t * dx, p.y - a.y - t * dy);
|
|
50645
51665
|
}
|
|
50646
|
-
var
|
|
51666
|
+
var cross3 = (a, b, c) => (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
|
|
50647
51667
|
function segmentDistance(ab, cd) {
|
|
50648
51668
|
const [a, b] = ab, [c, d] = cd;
|
|
50649
|
-
if (Math.max(a.x, b.x) >= Math.min(c.x, d.x) && Math.max(c.x, d.x) >= Math.min(a.x, b.x) && Math.max(a.y, b.y) >= Math.min(c.y, d.y) && Math.max(c.y, d.y) >= Math.min(a.y, b.y) &&
|
|
51669
|
+
if (Math.max(a.x, b.x) >= Math.min(c.x, d.x) && Math.max(c.x, d.x) >= Math.min(a.x, b.x) && Math.max(a.y, b.y) >= Math.min(c.y, d.y) && Math.max(c.y, d.y) >= Math.min(a.y, b.y) && cross3(a, b, c) * cross3(a, b, d) <= 0 && cross3(c, d, a) * cross3(c, d, b) <= 0)
|
|
50650
51670
|
return 0;
|
|
50651
51671
|
return Math.min(
|
|
50652
51672
|
pointSegmentDistance(a, cd),
|
|
@@ -50655,10 +51675,10 @@ function segmentDistance(ab, cd) {
|
|
|
50655
51675
|
pointSegmentDistance(d, ab)
|
|
50656
51676
|
);
|
|
50657
51677
|
}
|
|
50658
|
-
var length = (path) => path.slice(1).reduce((sum, p, i) => sum +
|
|
51678
|
+
var length = (path) => path.slice(1).reduce((sum, p, i) => sum + distance14(path[i], p), 0);
|
|
50659
51679
|
function simplify(path) {
|
|
50660
51680
|
return path.filter(
|
|
50661
|
-
(p, i) => !i || i === path.length - 1 || Math.abs(
|
|
51681
|
+
(p, i) => !i || i === path.length - 1 || Math.abs(cross3(path[i - 1], p, path[i + 1])) > 1e-9
|
|
50662
51682
|
);
|
|
50663
51683
|
}
|
|
50664
51684
|
|
|
@@ -50702,7 +51722,7 @@ function fixedCopper(input) {
|
|
|
50702
51722
|
throw Error("Fixed trace changes layer without a via");
|
|
50703
51723
|
result.push({ a: p, b: q, radius: p.width / 2, layer: p.layer, owners });
|
|
50704
51724
|
}
|
|
50705
|
-
if (q && p.route_type !== q.route_type &&
|
|
51725
|
+
if (q && p.route_type !== q.route_type && distance14(p, q) > 1e-10) {
|
|
50706
51726
|
const wire = p.route_type === "wire" ? p : q;
|
|
50707
51727
|
result.push({
|
|
50708
51728
|
a: p,
|
|
@@ -50822,7 +51842,7 @@ var VectorScene = class {
|
|
|
50822
51842
|
);
|
|
50823
51843
|
} else {
|
|
50824
51844
|
const r = c.radius + this.margin + epsilon;
|
|
50825
|
-
for (const p of
|
|
51845
|
+
for (const p of distance14(c.a, c.b) < 1e-9 ? [c.a] : [c.a, c.b])
|
|
50826
51846
|
for (const [x, y] of [
|
|
50827
51847
|
[1, k],
|
|
50828
51848
|
[k, 1],
|
|
@@ -50910,7 +51930,7 @@ var VectorVisibilitySearch = class {
|
|
|
50910
51930
|
this.start = start;
|
|
50911
51931
|
this.end = end;
|
|
50912
51932
|
this.vertices = [start, end];
|
|
50913
|
-
this.open.push({ id: 0, g: 0, f:
|
|
51933
|
+
this.open.push({ id: 0, g: 0, f: distance14(start, end) });
|
|
50914
51934
|
this.best.set(0, 0);
|
|
50915
51935
|
}
|
|
50916
51936
|
scene;
|
|
@@ -50970,7 +51990,7 @@ var VectorVisibilitySearch = class {
|
|
|
50970
51990
|
const from = this.vertices[cur.id];
|
|
50971
51991
|
for (let id = 1; id < this.vertices.length; id++) {
|
|
50972
51992
|
if (id === cur.id) continue;
|
|
50973
|
-
const to = this.vertices[id], lower = cur.g +
|
|
51993
|
+
const to = this.vertices[id], lower = cur.g + distance14(from, to);
|
|
50974
51994
|
if (lower >= (this.best.get(id) ?? Infinity) - 1e-9) continue;
|
|
50975
51995
|
const candidates = connectors(from, to).sort(
|
|
50976
51996
|
(a, b) => length(a) - length(b)
|
|
@@ -50983,7 +52003,7 @@ var VectorVisibilitySearch = class {
|
|
|
50983
52003
|
this.open.push({
|
|
50984
52004
|
id,
|
|
50985
52005
|
g,
|
|
50986
|
-
f: g +
|
|
52006
|
+
f: g + distance14(to, this.end),
|
|
50987
52007
|
parent: cur,
|
|
50988
52008
|
edge: path
|
|
50989
52009
|
});
|
|
@@ -51225,9 +52245,9 @@ function tuneLengths(input, traces, targets) {
|
|
|
51225
52245
|
const clearance = input.minTraceToPadEdgeClearance ?? input.defaultObstacleMargin ?? 0.075;
|
|
51226
52246
|
const returnSpacing = Math.max(width + clearance, 3 * width);
|
|
51227
52247
|
const pitch = 2 * (returnSpacing + 2 * width);
|
|
51228
|
-
const segments = t.route.slice(1).map((p, i) => ({ i, span:
|
|
52248
|
+
const segments = t.route.slice(1).map((p, i) => ({ i, span: distance14(t.route[i], p) })).sort((a, b) => b.span - a.span);
|
|
51229
52249
|
for (const { i } of segments) {
|
|
51230
|
-
const a = t.route[i], b = t.route[i + 1], span =
|
|
52250
|
+
const a = t.route[i], b = t.route[i + 1], span = distance14(a, b);
|
|
51231
52251
|
if (span < 0.01) continue;
|
|
51232
52252
|
const ux = (b.x - a.x) / span, uy = (b.y - a.y) / span;
|
|
51233
52253
|
const maximumTeeth = Math.floor(span * 0.9 / pitch);
|
|
@@ -51327,7 +52347,7 @@ function tuneLengths(input, traces, targets) {
|
|
|
51327
52347
|
function tuningPathIsSelfClear(path, required) {
|
|
51328
52348
|
const cumulative = [0];
|
|
51329
52349
|
for (let i = 1; i < path.length; i++)
|
|
51330
|
-
cumulative.push(cumulative[i - 1] +
|
|
52350
|
+
cumulative.push(cumulative[i - 1] + distance14(path[i - 1], path[i]));
|
|
51331
52351
|
for (let i = 0; i < path.length - 1; i++)
|
|
51332
52352
|
for (let j = i + 2; j < path.length - 1; j++) {
|
|
51333
52353
|
if (cumulative[j] - cumulative[i + 1] <= required + 1e-8) continue;
|
|
@@ -51365,7 +52385,7 @@ var layerColors = {
|
|
|
51365
52385
|
var layerColor = (layer) => layerColors[layer] ?? "#64748b";
|
|
51366
52386
|
|
|
51367
52387
|
// node_modules/@tscircuit/bus-lanes-solver/lib/bus-lanes-solver.ts
|
|
51368
|
-
var BusLanesSolver = class extends
|
|
52388
|
+
var BusLanesSolver = class extends BaseSolver8 {
|
|
51369
52389
|
input;
|
|
51370
52390
|
options;
|
|
51371
52391
|
phase = "validate";
|
|
@@ -51575,7 +52595,7 @@ var BusLanesSolver = class extends BaseSolver4 {
|
|
|
51575
52595
|
const t = this.traces.find((t2) => t2.connection_name === c.name);
|
|
51576
52596
|
if (!t) throw Error("Missing lane");
|
|
51577
52597
|
const scene = this.scene(c);
|
|
51578
|
-
if (
|
|
52598
|
+
if (distance14(t.route[0], c.pointsToConnect[0]) > 1e-8 || distance14(t.route.at(-1), c.pointsToConnect[1]) > 1e-8)
|
|
51579
52599
|
throw Error("Broken lane endpoints");
|
|
51580
52600
|
for (let i = 1; i < t.route.length; i++) {
|
|
51581
52601
|
const a = t.route[i - 1], b = t.route[i], dx = Math.abs(a.x - b.x), dy = Math.abs(a.y - b.y);
|
|
@@ -51640,7 +52660,7 @@ var BusLanesSolver = class extends BaseSolver4 {
|
|
|
51640
52660
|
});
|
|
51641
52661
|
continue;
|
|
51642
52662
|
}
|
|
51643
|
-
if (
|
|
52663
|
+
if (distance14(c.a, c.b) < 1e-9)
|
|
51644
52664
|
circles.push({
|
|
51645
52665
|
center: c.a,
|
|
51646
52666
|
radius: c.radius,
|
|
@@ -51801,7 +52821,7 @@ import { CreateFdmEnclosureSolver } from "@tscircuit/create-fdm-enclosure";
|
|
|
51801
52821
|
// node_modules/@tscircuit/implicit-copper-pour-solver/lib/implicit-copper-pour-pipeline-solver.ts
|
|
51802
52822
|
import {
|
|
51803
52823
|
BasePipelineSolver,
|
|
51804
|
-
BaseSolver as
|
|
52824
|
+
BaseSolver as BaseSolver9,
|
|
51805
52825
|
definePipelineStep
|
|
51806
52826
|
} from "@tscircuit/solver-utils";
|
|
51807
52827
|
|
|
@@ -51819,7 +52839,7 @@ import { applyToPoint as applyToPoint30, compose as compose11, scale as scale2,
|
|
|
51819
52839
|
// node_modules/@tscircuit/implicit-copper-pour-solver/lib/geometry.ts
|
|
51820
52840
|
import {
|
|
51821
52841
|
clamp,
|
|
51822
|
-
distance as
|
|
52842
|
+
distance as distance15,
|
|
51823
52843
|
doBoundsOverlap as doBoundsOverlap2,
|
|
51824
52844
|
getBoundsFromPoints as getBoundsFromPoints3,
|
|
51825
52845
|
getUnitVectorFromPointAToB as getUnitVectorFromPointAToB2,
|
|
@@ -51868,7 +52888,7 @@ var distanceToPolygon = (point6, polygon) => {
|
|
|
51868
52888
|
var distanceToPrimitive = (primitive, px, py) => {
|
|
51869
52889
|
const point6 = { x: px, y: py };
|
|
51870
52890
|
if (primitive.kind === "circle") {
|
|
51871
|
-
return Math.max(
|
|
52891
|
+
return Math.max(distance15(point6, primitive) - primitive.radius, 0);
|
|
51872
52892
|
}
|
|
51873
52893
|
if (primitive.kind === "segment") {
|
|
51874
52894
|
return Math.max(
|
|
@@ -51919,7 +52939,7 @@ var getClosestPointOnPrimitive = (primitive, point6) => {
|
|
|
51919
52939
|
const start = primitive.points[index];
|
|
51920
52940
|
const end = primitive.points[(index + 1) % primitive.points.length];
|
|
51921
52941
|
const candidate = pointToSegmentClosestPoint(point6, start, end);
|
|
51922
|
-
const candidateDistance =
|
|
52942
|
+
const candidateDistance = distance15(point6, candidate);
|
|
51923
52943
|
if (candidateDistance < bestDistance) {
|
|
51924
52944
|
bestDistance = candidateDistance;
|
|
51925
52945
|
closestPoint = candidate;
|
|
@@ -52975,7 +53995,7 @@ var prepareCircuitJson = (input) => {
|
|
|
52975
53995
|
|
|
52976
53996
|
// node_modules/@tscircuit/implicit-copper-pour-solver/lib/simplify-polygon-edges.ts
|
|
52977
53997
|
import {
|
|
52978
|
-
distance as
|
|
53998
|
+
distance as distance16,
|
|
52979
53999
|
doSegmentsIntersect,
|
|
52980
54000
|
onSegment,
|
|
52981
54001
|
pointToSegmentDistance as pointToSegmentDistance2
|
|
@@ -53038,8 +54058,8 @@ var simplifyOpenPath = (points, tolerance) => {
|
|
|
53038
54058
|
const point6 = points[index];
|
|
53039
54059
|
const next = points[index + 1];
|
|
53040
54060
|
const shortestLeg = Math.min(
|
|
53041
|
-
|
|
53042
|
-
|
|
54061
|
+
distance16(point6, previous),
|
|
54062
|
+
distance16(next, point6)
|
|
53043
54063
|
);
|
|
53044
54064
|
if (repeatsTurnDirection || shortestLeg > tolerance) {
|
|
53045
54065
|
anchorIndices.push(index);
|
|
@@ -53088,8 +54108,8 @@ var normalizePolygon = (polygon) => {
|
|
|
53088
54108
|
};
|
|
53089
54109
|
var isPointStrictlyInsideSegment = (point6, start, end) => {
|
|
53090
54110
|
if (pointsEqual(point6, start) || pointsEqual(point6, end)) return false;
|
|
53091
|
-
const
|
|
53092
|
-
if (Math.abs(
|
|
54111
|
+
const cross5 = crossProduct(start, end, point6);
|
|
54112
|
+
if (Math.abs(cross5) > 1e-9) return false;
|
|
53093
54113
|
return onSegment(start, point6, end);
|
|
53094
54114
|
};
|
|
53095
54115
|
var splitEdgesAtVertices = (polygon, allVertices) => {
|
|
@@ -53441,7 +54461,7 @@ var mergeSolverGraphics = (source, overlay) => {
|
|
|
53441
54461
|
};
|
|
53442
54462
|
|
|
53443
54463
|
// node_modules/@tscircuit/implicit-copper-pour-solver/lib/implicit-copper-pour-pipeline-solver.ts
|
|
53444
|
-
var PrepareCircuitJsonSolver = class extends
|
|
54464
|
+
var PrepareCircuitJsonSolver = class extends BaseSolver9 {
|
|
53445
54465
|
constructor(input) {
|
|
53446
54466
|
super();
|
|
53447
54467
|
this.input = input;
|
|
@@ -53457,7 +54477,7 @@ var PrepareCircuitJsonSolver = class extends BaseSolver5 {
|
|
|
53457
54477
|
return this.output;
|
|
53458
54478
|
}
|
|
53459
54479
|
};
|
|
53460
|
-
var AssignGridCellsSolver = class extends
|
|
54480
|
+
var AssignGridCellsSolver = class extends BaseSolver9 {
|
|
53461
54481
|
constructor(input) {
|
|
53462
54482
|
super();
|
|
53463
54483
|
this.input = input;
|
|
@@ -53480,7 +54500,7 @@ var AssignGridCellsSolver = class extends BaseSolver5 {
|
|
|
53480
54500
|
return this.output;
|
|
53481
54501
|
}
|
|
53482
54502
|
};
|
|
53483
|
-
var TracePowerPolygonsSolver = class extends
|
|
54503
|
+
var TracePowerPolygonsSolver = class extends BaseSolver9 {
|
|
53484
54504
|
constructor(input) {
|
|
53485
54505
|
super();
|
|
53486
54506
|
this.input = input;
|
|
@@ -53516,7 +54536,7 @@ var TracePowerPolygonsSolver = class extends BaseSolver5 {
|
|
|
53516
54536
|
};
|
|
53517
54537
|
}
|
|
53518
54538
|
};
|
|
53519
|
-
var SimplifyPolygonEdgesSolver = class extends
|
|
54539
|
+
var SimplifyPolygonEdgesSolver = class extends BaseSolver9 {
|
|
53520
54540
|
constructor(input) {
|
|
53521
54541
|
super();
|
|
53522
54542
|
this.input = input;
|
|
@@ -53654,13 +54674,13 @@ import { LayoutPipelineSolver } from "@tscircuit/matchpack";
|
|
|
53654
54674
|
import { SchematicTracePipelineSolver } from "@tscircuit/schematic-trace-solver";
|
|
53655
54675
|
|
|
53656
54676
|
// node_modules/@tscircuit/via-stitch-solver/lib/solvers/ViaStitchSolver.ts
|
|
53657
|
-
import { BaseSolver as
|
|
54677
|
+
import { BaseSolver as BaseSolver10 } from "@tscircuit/solver-utils";
|
|
53658
54678
|
|
|
53659
54679
|
// node_modules/@tscircuit/via-stitch-solver/lib/geometry/brep-point-containment.ts
|
|
53660
54680
|
var POINT_EPSILON = 1e-8;
|
|
53661
54681
|
var isPointOnSegment = (point6, start, end) => {
|
|
53662
|
-
const
|
|
53663
|
-
if (Math.abs(
|
|
54682
|
+
const cross5 = (point6.y - start.y) * (end.x - start.x) - (point6.x - start.x) * (end.y - start.y);
|
|
54683
|
+
if (Math.abs(cross5) > POINT_EPSILON) return false;
|
|
53664
54684
|
const dot = (point6.x - start.x) * (end.x - start.x) + (point6.y - start.y) * (end.y - start.y);
|
|
53665
54685
|
if (dot < -POINT_EPSILON) return false;
|
|
53666
54686
|
const squaredLength = (end.x - start.x) ** 2 + (end.y - start.y) ** 2;
|
|
@@ -53981,7 +55001,7 @@ var getGridCoordinates = ({
|
|
|
53981
55001
|
}
|
|
53982
55002
|
return coordinates;
|
|
53983
55003
|
};
|
|
53984
|
-
var ViaStitchSolver = class extends
|
|
55004
|
+
var ViaStitchSolver = class extends BaseSolver10 {
|
|
53985
55005
|
constructor(input) {
|
|
53986
55006
|
super();
|
|
53987
55007
|
this.input = input;
|
|
@@ -54128,6 +55148,7 @@ var ViaStitchSolver = class extends BaseSolver6 {
|
|
|
54128
55148
|
// lib/solvers.ts
|
|
54129
55149
|
import { PackSolver2 } from "calculate-packing";
|
|
54130
55150
|
var SOLVERS = {
|
|
55151
|
+
DogboneFanoutSolver,
|
|
54131
55152
|
BusLanesSolver,
|
|
54132
55153
|
PackSolver2,
|
|
54133
55154
|
LayoutPipelineSolver,
|
|
@@ -54591,6 +55612,27 @@ var localAutorouterStrategies = /* @__PURE__ */ new Map([
|
|
|
54591
55612
|
createFanoutAutorouterStrategy("single_layer_fanout")
|
|
54592
55613
|
],
|
|
54593
55614
|
["fanout", createFanoutAutorouterStrategy("fanout")],
|
|
55615
|
+
[
|
|
55616
|
+
"dogbone",
|
|
55617
|
+
{
|
|
55618
|
+
name: "dogbone",
|
|
55619
|
+
preserveOutputTraces: true,
|
|
55620
|
+
followUpAutorouter: "default",
|
|
55621
|
+
cacheable: false,
|
|
55622
|
+
getSolverName: () => "DogboneFanoutSolver",
|
|
55623
|
+
create: ({
|
|
55624
|
+
simpleRouteJson,
|
|
55625
|
+
fanoutRoutingLayers,
|
|
55626
|
+
onSolverStarted,
|
|
55627
|
+
onSolverEnded
|
|
55628
|
+
}) => {
|
|
55629
|
+
return new DogboneAutorouter(
|
|
55630
|
+
{ input: simpleRouteJson, fanoutRoutingLayers },
|
|
55631
|
+
{ onSolverStarted, onSolverEnded }
|
|
55632
|
+
);
|
|
55633
|
+
}
|
|
55634
|
+
}
|
|
55635
|
+
],
|
|
54594
55636
|
[
|
|
54595
55637
|
"bus_lanes",
|
|
54596
55638
|
{
|
|
@@ -61067,19 +62109,19 @@ import Debug12 from "debug";
|
|
|
61067
62109
|
import { isValidElement as isValidElement2 } from "react";
|
|
61068
62110
|
|
|
61069
62111
|
// lib/components/primitive-components/Group/Group_doInitialSchematicTraceRender/segment-intersection.ts
|
|
61070
|
-
var
|
|
62112
|
+
var cross4 = (ax, ay, bx, by) => {
|
|
61071
62113
|
return ax * by - ay * bx;
|
|
61072
62114
|
};
|
|
61073
62115
|
function segmentIntersection(p1, p2, q1, q2, tol) {
|
|
61074
62116
|
const r = { x: p2.x - p1.x, y: p2.y - p1.y };
|
|
61075
62117
|
const s = { x: q2.x - q1.x, y: q2.y - q1.y };
|
|
61076
|
-
const rxs =
|
|
62118
|
+
const rxs = cross4(r.x, r.y, s.x, s.y);
|
|
61077
62119
|
const q_p = { x: q1.x - p1.x, y: q1.y - p1.y };
|
|
61078
|
-
const q_pxr =
|
|
62120
|
+
const q_pxr = cross4(q_p.x, q_p.y, r.x, r.y);
|
|
61079
62121
|
if (Math.abs(rxs) < tol && Math.abs(q_pxr) < tol) return null;
|
|
61080
62122
|
if (Math.abs(rxs) < tol && Math.abs(q_pxr) >= tol) return null;
|
|
61081
|
-
const t =
|
|
61082
|
-
const u =
|
|
62123
|
+
const t = cross4(q_p.x, q_p.y, s.x, s.y) / rxs;
|
|
62124
|
+
const u = cross4(q_p.x, q_p.y, r.x, r.y) / rxs;
|
|
61083
62125
|
if (t < -tol || t > 1 + tol || u < -tol || u > 1 + tol) return null;
|
|
61084
62126
|
return { x: p1.x + t * r.x, y: p1.y + t * r.y };
|
|
61085
62127
|
}
|
|
@@ -61272,8 +62314,8 @@ function isParallel(e1, e2, tol = TOL2) {
|
|
|
61272
62314
|
const L1 = Math.hypot(v1.x, v1.y);
|
|
61273
62315
|
const L2 = Math.hypot(v2.x, v2.y);
|
|
61274
62316
|
if (L1 < tol || L2 < tol) return true;
|
|
61275
|
-
const
|
|
61276
|
-
return Math.abs(
|
|
62317
|
+
const cross5 = v1.x * v2.y - v1.y * v2.x;
|
|
62318
|
+
return Math.abs(cross5) <= tol * L1 * L2;
|
|
61277
62319
|
}
|
|
61278
62320
|
function incidentEdgesAtPoint(trace, p, tol = TOL2) {
|
|
61279
62321
|
return trace.edges.filter(
|
|
@@ -64540,6 +65582,16 @@ function Group_getRoutingPhasePlans(group) {
|
|
|
64540
65582
|
nets: nets.filter((net) => breakoutByNet.get(net) === breakout),
|
|
64541
65583
|
traces: breakoutTraces
|
|
64542
65584
|
};
|
|
65585
|
+
if (breakout.isDogboneFanout && breakoutProps2.pcbTracePaths === void 0) {
|
|
65586
|
+
breakoutPlans.push({
|
|
65587
|
+
...breakoutPlan,
|
|
65588
|
+
// Keep the local fanout outline while allowing dogbone sites outside
|
|
65589
|
+
// the pad bounding box to use the full board routing bounds.
|
|
65590
|
+
routingBounds: void 0,
|
|
65591
|
+
fanoutBounds: routingBounds
|
|
65592
|
+
});
|
|
65593
|
+
continue;
|
|
65594
|
+
}
|
|
64543
65595
|
if (breakout._parsedProps.pcbTracePaths !== void 0) {
|
|
64544
65596
|
breakoutPlans.push({
|
|
64545
65597
|
...breakoutPlan,
|
|
@@ -64612,7 +65664,7 @@ function Group_getRoutingPhasePlans(group) {
|
|
|
64612
65664
|
var package_default = {
|
|
64613
65665
|
name: "@tscircuit/core",
|
|
64614
65666
|
type: "module",
|
|
64615
|
-
version: "0.0.
|
|
65667
|
+
version: "0.0.2026",
|
|
64616
65668
|
types: "dist/index.d.ts",
|
|
64617
65669
|
main: "dist/index.js",
|
|
64618
65670
|
module: "dist/index.js",
|
|
@@ -64653,6 +65705,7 @@ var package_default = {
|
|
|
64653
65705
|
"@tscircuit/common": "^0.0.20",
|
|
64654
65706
|
"@tscircuit/copper-pour-solver": "^0.0.62",
|
|
64655
65707
|
"@tscircuit/create-fdm-enclosure": "0.0.4",
|
|
65708
|
+
"@tscircuit/dogbone-solver": "https://jscdn.tscircuit.com/@tscircuit/dogbone-solver/0.0.1.tgz",
|
|
64656
65709
|
"@tscircuit/fanout-solver": "0.0.78",
|
|
64657
65710
|
"@tscircuit/flex-utils": "https://jscdn.tscircuit.com/@tscircuit/flex-utils/0.0.5.tgz",
|
|
64658
65711
|
"@tscircuit/footprinter": "^0.0.426",
|
|
@@ -65080,7 +66133,6 @@ function Group_syncFanoutExitsWithGlobalConnections({
|
|
|
65080
66133
|
) ? [{ globalConnection, pointIndex, previousPoint }] : []
|
|
65081
66134
|
)
|
|
65082
66135
|
);
|
|
65083
|
-
if (globalPointMatches.length === 0) continue;
|
|
65084
66136
|
const changedPointIndex = outputConnection.pointsToConnect.findIndex(
|
|
65085
66137
|
(outputPoint, pointIndex) => {
|
|
65086
66138
|
const inputPoint = inputConnection.pointsToConnect[pointIndex];
|
|
@@ -65089,6 +66141,14 @@ function Group_syncFanoutExitsWithGlobalConnections({
|
|
|
65089
66141
|
);
|
|
65090
66142
|
if (changedPointIndex < 0) continue;
|
|
65091
66143
|
const fanoutExitPoint = outputConnection.pointsToConnect[changedPointIndex];
|
|
66144
|
+
if (globalPointMatches.length === 0) {
|
|
66145
|
+
synchronizedBreakoutPoints.push({
|
|
66146
|
+
sourceTraceId: inputConnection.source_trace_id,
|
|
66147
|
+
routingPcbGroupId,
|
|
66148
|
+
previousPoint: inputConnection.pointsToConnect[changedPointIndex],
|
|
66149
|
+
fanoutExitPoint
|
|
66150
|
+
});
|
|
66151
|
+
}
|
|
65092
66152
|
for (const {
|
|
65093
66153
|
globalConnection,
|
|
65094
66154
|
pointIndex,
|
|
@@ -65349,7 +66409,7 @@ function getAccumulatedPcbTracesWithStageOutputReplacements({
|
|
|
65349
66409
|
}
|
|
65350
66410
|
|
|
65351
66411
|
// lib/components/primitive-components/Group/get-source-trace-id-for-routed-trace.ts
|
|
65352
|
-
import { distance as
|
|
66412
|
+
import { distance as distance17, pointToSegmentDistance as pointToSegmentDistance3 } from "@tscircuit/math-utils";
|
|
65353
66413
|
import { ConnectivityMap as ConnectivityMap5 } from "circuit-json-to-connectivity-map";
|
|
65354
66414
|
var POINT_EPSILON2 = 1e-6;
|
|
65355
66415
|
function isPointOnWireSegment({
|
|
@@ -65371,7 +66431,7 @@ function isPointInSmtPad({
|
|
|
65371
66431
|
return Math.abs(point6.x - pad.x) <= pad.width / 2 + traceWidth / 2 && Math.abs(point6.y - pad.y) <= pad.height / 2 + traceWidth / 2;
|
|
65372
66432
|
}
|
|
65373
66433
|
if (pad.shape === "circle") {
|
|
65374
|
-
return
|
|
66434
|
+
return distance17(point6, pad) <= pad.radius + traceWidth / 2;
|
|
65375
66435
|
}
|
|
65376
66436
|
return false;
|
|
65377
66437
|
}
|
|
@@ -65380,7 +66440,7 @@ function isPointInPlatedHole({
|
|
|
65380
66440
|
hole,
|
|
65381
66441
|
traceWidth = 0
|
|
65382
66442
|
}) {
|
|
65383
|
-
return
|
|
66443
|
+
return distance17(point6, hole) <= (hole.outer_diameter ?? hole.hole_diameter ?? 0) / 2 + traceWidth / 2;
|
|
65384
66444
|
}
|
|
65385
66445
|
function getEndpointSourcePortIdsFromGeometry(db, trace) {
|
|
65386
66446
|
const sourcePortIds = /* @__PURE__ */ new Set();
|
|
@@ -65393,7 +66453,7 @@ function getEndpointSourcePortIdsFromGeometry(db, trace) {
|
|
|
65393
66453
|
if (!pcbPort.source_port_id) continue;
|
|
65394
66454
|
if (endpoint.layer && pcbPort.layers && !pcbPort.layers.includes(endpoint.layer))
|
|
65395
66455
|
continue;
|
|
65396
|
-
if (
|
|
66456
|
+
if (distance17(endpoint, pcbPort) <= 0.01) {
|
|
65397
66457
|
sourcePortIds.add(pcbPort.source_port_id);
|
|
65398
66458
|
}
|
|
65399
66459
|
}
|
|
@@ -66077,8 +67137,8 @@ var Group5 = class extends NormalComponent {
|
|
|
66077
67137
|
const groupProps2 = props;
|
|
66078
67138
|
const hasOutline = groupProps2.outline && groupProps2.outline.length > 0;
|
|
66079
67139
|
const numericOutline = hasOutline ? groupProps2.outline.map((point6) => ({
|
|
66080
|
-
x:
|
|
66081
|
-
y:
|
|
67140
|
+
x: distance18.parse(point6.x),
|
|
67141
|
+
y: distance18.parse(point6.y)
|
|
66082
67142
|
})) : void 0;
|
|
66083
67143
|
const ctx = this.props;
|
|
66084
67144
|
const anchorPosition = this._getGlobalPcbPositionBeforeLayout();
|
|
@@ -66116,8 +67176,8 @@ var Group5 = class extends NormalComponent {
|
|
|
66116
67176
|
const hasExplicitPositioning = this._parsedProps.pcbX !== void 0 || this._parsedProps.pcbY !== void 0;
|
|
66117
67177
|
if (hasOutline) {
|
|
66118
67178
|
const numericOutline = props.outline.map((point6) => ({
|
|
66119
|
-
x:
|
|
66120
|
-
y:
|
|
67179
|
+
x: distance18.parse(point6.x),
|
|
67180
|
+
y: distance18.parse(point6.y)
|
|
66121
67181
|
}));
|
|
66122
67182
|
const outlineBounds = getBoundsFromPoints9(numericOutline);
|
|
66123
67183
|
if (!outlineBounds) return;
|
|
@@ -66518,7 +67578,9 @@ var Group5 = class extends NormalComponent {
|
|
|
66518
67578
|
routingPhaseDebugLabels.set(plan, `${label} ${ordinal}`);
|
|
66519
67579
|
}
|
|
66520
67580
|
const hasFanoutStage = routingStages.some(
|
|
66521
|
-
({ autorouterConfig: autorouterConfig2 }) => ["fanout", "single_layer_fanout"].includes(
|
|
67581
|
+
({ autorouterConfig: autorouterConfig2 }) => ["fanout", "single_layer_fanout", "dogbone"].includes(
|
|
67582
|
+
autorouterConfig2.preset ?? ""
|
|
67583
|
+
)
|
|
66522
67584
|
);
|
|
66523
67585
|
const fanoutPourNetMap = hasFanoutStage ? Group_getFanoutPourNetMap(this, routingPhasePlans) : void 0;
|
|
66524
67586
|
let { simpleRouteJson: baseSimpleRouteJson } = getSimpleRouteJsonFromCircuitJson({
|
|
@@ -66941,6 +68003,11 @@ var Group5 = class extends NormalComponent {
|
|
|
66941
68003
|
} else {
|
|
66942
68004
|
autorouter = localAutorouterStrategy.create({
|
|
66943
68005
|
simpleRouteJson,
|
|
68006
|
+
onSolverEnded: (event) => this.root?.emit("solver:ended", {
|
|
68007
|
+
...event,
|
|
68008
|
+
type: "solver:ended",
|
|
68009
|
+
componentName: this.getString()
|
|
68010
|
+
}),
|
|
66944
68011
|
commonAutorouterOptions,
|
|
66945
68012
|
busFanoutDirections: routingPhasePlan.busFanoutDirections,
|
|
66946
68013
|
fanoutBounds: routingPhasePlan.fanoutBounds,
|
|
@@ -66996,7 +68063,7 @@ var Group5 = class extends NormalComponent {
|
|
|
66996
68063
|
traces = await routingPromise;
|
|
66997
68064
|
}
|
|
66998
68065
|
let transformedSimpleRouteJson = precomputedOutputSimpleRouteJson ?? autorouter?.getOutputSimpleRouteJson?.();
|
|
66999
|
-
if (transformedSimpleRouteJson && !usesPreviousStageOutput && ["fanout", "single_layer_fanout"].includes(
|
|
68066
|
+
if (transformedSimpleRouteJson && !usesPreviousStageOutput && ["fanout", "single_layer_fanout", "dogbone"].includes(
|
|
67000
68067
|
phaseAutorouterConfig.preset ?? ""
|
|
67001
68068
|
) && routingPhasePlan.routingPcbGroupId) {
|
|
67002
68069
|
const synchronizedFanout = Group_syncFanoutExitsWithGlobalConnections(
|
|
@@ -67016,10 +68083,14 @@ var Group5 = class extends NormalComponent {
|
|
|
67016
68083
|
if (!breakoutPoint) continue;
|
|
67017
68084
|
db.pcb_breakout_point.update(breakoutPoint.pcb_breakout_point_id, {
|
|
67018
68085
|
x: synchronizedPoint.fanoutExitPoint.x,
|
|
67019
|
-
y: synchronizedPoint.fanoutExitPoint.y
|
|
68086
|
+
y: synchronizedPoint.fanoutExitPoint.y,
|
|
68087
|
+
layer: synchronizedPoint.fanoutExitPoint.layer
|
|
67020
68088
|
});
|
|
67021
68089
|
}
|
|
67022
68090
|
}
|
|
68091
|
+
if (localAutorouterStrategy.preserveOutputTraces) {
|
|
68092
|
+
for (const trace of traces) fixedTraceIds.add(trace.pcb_trace_id);
|
|
68093
|
+
}
|
|
67023
68094
|
let stageOutputTraces = traces;
|
|
67024
68095
|
if (transformedSimpleRouteJson?.traces) {
|
|
67025
68096
|
stageOutputTraces = transformedSimpleRouteJson.traces;
|
|
@@ -67052,11 +68123,13 @@ var Group5 = class extends NormalComponent {
|
|
|
67052
68123
|
});
|
|
67053
68124
|
}
|
|
67054
68125
|
const savedPhasePaths = getAutoroutingPhasePcbTracePaths({
|
|
67055
|
-
group:
|
|
68126
|
+
group: this.selectAll("group").find(
|
|
68127
|
+
(group) => group.pcb_group_id === routingPhasePlan.fanoutRegionPcbGroupId
|
|
68128
|
+
) ?? routingPhasePlan.autoroutingPhase?.getGroup() ?? this,
|
|
67056
68129
|
subcircuit: this,
|
|
67057
68130
|
input: simpleRouteJson,
|
|
67058
68131
|
traces,
|
|
67059
|
-
isFanout: ["fanout", "single_layer_fanout"].includes(
|
|
68132
|
+
isFanout: ["fanout", "single_layer_fanout", "dogbone"].includes(
|
|
67060
68133
|
phaseAutorouterConfig.preset ?? ""
|
|
67061
68134
|
)
|
|
67062
68135
|
});
|
|
@@ -67989,8 +69062,8 @@ var Led_addPolarityFabricationSymbol = (led) => {
|
|
|
67989
69062
|
const a = db.pcb_port.getWhere({ source_port_id: anode.source_port_id });
|
|
67990
69063
|
const k = db.pcb_port.getWhere({ source_port_id: cathode.source_port_id });
|
|
67991
69064
|
if (!a || !k) return;
|
|
67992
|
-
const
|
|
67993
|
-
if (
|
|
69065
|
+
const distance25 = Math.hypot(k.x - a.x, k.y - a.y);
|
|
69066
|
+
if (distance25 < 1e-6) return;
|
|
67994
69067
|
const angle = Math.atan2(k.y - a.y, k.x - a.x);
|
|
67995
69068
|
const frame = compose15(
|
|
67996
69069
|
translate15((a.x + k.x) / 2, (a.y + k.y) / 2),
|
|
@@ -68004,10 +69077,10 @@ var Led_addPolarityFabricationSymbol = (led) => {
|
|
|
68004
69077
|
};
|
|
68005
69078
|
const notes = [];
|
|
68006
69079
|
generatedNotes.set(led, notes);
|
|
68007
|
-
const halfLength = Math.min(
|
|
69080
|
+
const halfLength = Math.min(distance25 * 0.2, 0.4);
|
|
68008
69081
|
const halfHeight = halfLength * 0.75;
|
|
68009
69082
|
const routes = [
|
|
68010
|
-
[point6(-
|
|
69083
|
+
[point6(-distance25 / 2, 0), point6(-halfLength, 0)],
|
|
68011
69084
|
[
|
|
68012
69085
|
point6(-halfLength, -halfHeight),
|
|
68013
69086
|
point6(halfLength, 0),
|
|
@@ -68015,7 +69088,7 @@ var Led_addPolarityFabricationSymbol = (led) => {
|
|
|
68015
69088
|
point6(-halfLength, -halfHeight)
|
|
68016
69089
|
],
|
|
68017
69090
|
[point6(halfLength, -halfHeight), point6(halfLength, halfHeight)],
|
|
68018
|
-
[point6(halfLength, 0), point6(
|
|
69091
|
+
[point6(halfLength, 0), point6(distance25 / 2, 0)]
|
|
68019
69092
|
];
|
|
68020
69093
|
for (const route of routes) {
|
|
68021
69094
|
notes.push(
|
|
@@ -69949,7 +71022,7 @@ var Board_doInitialPcbPlacementDesignRuleChecks = (board) => {
|
|
|
69949
71022
|
|
|
69950
71023
|
// lib/components/normal-components/Board/board-castellated-hole.ts
|
|
69951
71024
|
import {
|
|
69952
|
-
distance as
|
|
71025
|
+
distance as distance19
|
|
69953
71026
|
} from "circuit-json";
|
|
69954
71027
|
var CASTELLATED_HOLE_ENDPOINT_TOLERANCE_MM = 1e-6;
|
|
69955
71028
|
var getConnectionTargets2 = (connectsTo) => {
|
|
@@ -69970,8 +71043,8 @@ var BoardCastellatedHole = class _BoardCastellatedHole extends PlatedHole {
|
|
|
69970
71043
|
constructor(outlinePoint, outlinePointIndex) {
|
|
69971
71044
|
const name = `castellated_hole_${outlinePointIndex + 1}`;
|
|
69972
71045
|
const connectionTargets = getConnectionTargets2(outlinePoint.connectsTo);
|
|
69973
|
-
const holeDiameter =
|
|
69974
|
-
const padDiameter =
|
|
71046
|
+
const holeDiameter = distance19.parse(outlinePoint.holeDiameter);
|
|
71047
|
+
const padDiameter = distance19.parse(outlinePoint.padDiameter);
|
|
69975
71048
|
super({
|
|
69976
71049
|
shape: "circle",
|
|
69977
71050
|
holeDiameter,
|
|
@@ -70721,11 +71794,11 @@ var MountedBoard = class extends Subcircuit {
|
|
|
70721
71794
|
|
|
70722
71795
|
// lib/components/normal-components/Panel.ts
|
|
70723
71796
|
import { panelProps } from "@tscircuit/props";
|
|
70724
|
-
import { distance as
|
|
71797
|
+
import { distance as distance23 } from "circuit-json";
|
|
70725
71798
|
|
|
70726
71799
|
// lib/components/normal-components/Subpanel.ts
|
|
70727
71800
|
import { subpanelProps } from "@tscircuit/props";
|
|
70728
|
-
import { distance as
|
|
71801
|
+
import { distance as distance22 } from "circuit-json";
|
|
70729
71802
|
import { compose as compose17, identity as identity9, translate as translate17 } from "transformation-matrix";
|
|
70730
71803
|
|
|
70731
71804
|
// lib/utils/panels/generate-panel-tabs-and-mouse-bites.ts
|
|
@@ -70989,15 +72062,15 @@ function generatePanelOutlineRoutingCutouts(boards, options) {
|
|
|
70989
72062
|
}
|
|
70990
72063
|
|
|
70991
72064
|
// lib/utils/panels/pack-into-grid.ts
|
|
70992
|
-
import { distance as
|
|
72065
|
+
import { distance as distance21 } from "circuit-json";
|
|
70993
72066
|
|
|
70994
72067
|
// lib/utils/panels/get-board-dimensions-from-props.ts
|
|
70995
72068
|
import { getBoundsFromPoints as getBoundsFromPoints11 } from "@tscircuit/math-utils";
|
|
70996
|
-
import { distance as
|
|
72069
|
+
import { distance as distance20 } from "circuit-json";
|
|
70997
72070
|
var getBoardDimensionsFromProps = (board) => {
|
|
70998
72071
|
const props = board._parsedProps;
|
|
70999
|
-
let width = props.width != null ?
|
|
71000
|
-
let height = props.height != null ?
|
|
72072
|
+
let width = props.width != null ? distance20.parse(props.width) : void 0;
|
|
72073
|
+
let height = props.height != null ? distance20.parse(props.height) : void 0;
|
|
71001
72074
|
if ((width === void 0 || height === void 0) && props.outline?.length) {
|
|
71002
72075
|
const outlineBounds = getBoundsFromPoints11(props.outline);
|
|
71003
72076
|
if (outlineBounds) {
|
|
@@ -71041,8 +72114,8 @@ function packIntoGrid({
|
|
|
71041
72114
|
}
|
|
71042
72115
|
let cols;
|
|
71043
72116
|
let rows;
|
|
71044
|
-
const minCellWidth = cellWidth ?
|
|
71045
|
-
const minCellHeight = cellHeight ?
|
|
72117
|
+
const minCellWidth = cellWidth ? distance21.parse(cellWidth) : 0;
|
|
72118
|
+
const minCellHeight = cellHeight ? distance21.parse(cellHeight) : 0;
|
|
71046
72119
|
if (col !== void 0) {
|
|
71047
72120
|
cols = col;
|
|
71048
72121
|
rows = row ?? Math.ceil(itemsWithDims.length / cols);
|
|
@@ -71141,8 +72214,8 @@ function getItemDimensions(item, db) {
|
|
|
71141
72214
|
const props = subpanel._parsedProps;
|
|
71142
72215
|
if (props.width !== void 0 && props.height !== void 0) {
|
|
71143
72216
|
return {
|
|
71144
|
-
width:
|
|
71145
|
-
height:
|
|
72217
|
+
width: distance21.parse(props.width),
|
|
72218
|
+
height: distance21.parse(props.height)
|
|
71146
72219
|
};
|
|
71147
72220
|
}
|
|
71148
72221
|
const directBoards = subpanel._getDirectBoardChildren();
|
|
@@ -71169,7 +72242,7 @@ function getItemDimensions(item, db) {
|
|
|
71169
72242
|
return getBoardDimensionsFromProps(directBoards[0]);
|
|
71170
72243
|
}
|
|
71171
72244
|
if (subpanel._cachedGridWidth > 0 && subpanel._cachedGridHeight > 0) {
|
|
71172
|
-
const edgePadding =
|
|
72245
|
+
const edgePadding = distance21.parse(props.edgePadding ?? 5);
|
|
71173
72246
|
return {
|
|
71174
72247
|
width: subpanel._cachedGridWidth + edgePadding * 2,
|
|
71175
72248
|
height: subpanel._cachedGridHeight + edgePadding * 2
|
|
@@ -71327,17 +72400,17 @@ var Subpanel = class _Subpanel extends Group5 {
|
|
|
71327
72400
|
edgePaddingTop: edgePaddingTopProp,
|
|
71328
72401
|
edgePaddingBottom: edgePaddingBottomProp
|
|
71329
72402
|
} = this._parsedProps;
|
|
71330
|
-
const edgePadding =
|
|
71331
|
-
const edgePaddingLeft =
|
|
71332
|
-
const edgePaddingRight =
|
|
72403
|
+
const edgePadding = distance22.parse(edgePaddingProp ?? 5);
|
|
72404
|
+
const edgePaddingLeft = distance22.parse(edgePaddingLeftProp ?? edgePadding);
|
|
72405
|
+
const edgePaddingRight = distance22.parse(
|
|
71333
72406
|
edgePaddingRightProp ?? edgePadding
|
|
71334
72407
|
);
|
|
71335
|
-
const edgePaddingTop =
|
|
71336
|
-
const edgePaddingBottom =
|
|
72408
|
+
const edgePaddingTop = distance22.parse(edgePaddingTopProp ?? edgePadding);
|
|
72409
|
+
const edgePaddingBottom = distance22.parse(
|
|
71337
72410
|
edgePaddingBottomProp ?? edgePadding
|
|
71338
72411
|
);
|
|
71339
|
-
const panelWidth =
|
|
71340
|
-
const panelHeight =
|
|
72412
|
+
const panelWidth = distance22.parse(this._parsedProps.width);
|
|
72413
|
+
const panelHeight = distance22.parse(this._parsedProps.height);
|
|
71341
72414
|
availablePanelWidth = panelWidth - edgePaddingLeft - edgePaddingRight;
|
|
71342
72415
|
availablePanelHeight = panelHeight - edgePaddingTop - edgePaddingBottom;
|
|
71343
72416
|
}
|
|
@@ -71412,8 +72485,8 @@ var Subpanel = class _Subpanel extends Group5 {
|
|
|
71412
72485
|
if (!this.pcb_group_id) return;
|
|
71413
72486
|
if (hasExplicitWidth && hasExplicitHeight) {
|
|
71414
72487
|
db.pcb_group.update(this.pcb_group_id, {
|
|
71415
|
-
width:
|
|
71416
|
-
height:
|
|
72488
|
+
width: distance22.parse(this._parsedProps.width),
|
|
72489
|
+
height: distance22.parse(this._parsedProps.height)
|
|
71417
72490
|
});
|
|
71418
72491
|
} else if (gridWidth > 0 || gridHeight > 0) {
|
|
71419
72492
|
const {
|
|
@@ -71423,18 +72496,18 @@ var Subpanel = class _Subpanel extends Group5 {
|
|
|
71423
72496
|
edgePaddingTop: edgePaddingTopProp,
|
|
71424
72497
|
edgePaddingBottom: edgePaddingBottomProp
|
|
71425
72498
|
} = this._parsedProps;
|
|
71426
|
-
const edgePadding =
|
|
71427
|
-
const edgePaddingLeft =
|
|
71428
|
-
const edgePaddingRight =
|
|
72499
|
+
const edgePadding = distance22.parse(edgePaddingProp ?? 5);
|
|
72500
|
+
const edgePaddingLeft = distance22.parse(edgePaddingLeftProp ?? edgePadding);
|
|
72501
|
+
const edgePaddingRight = distance22.parse(
|
|
71429
72502
|
edgePaddingRightProp ?? edgePadding
|
|
71430
72503
|
);
|
|
71431
|
-
const edgePaddingTop =
|
|
71432
|
-
const edgePaddingBottom =
|
|
72504
|
+
const edgePaddingTop = distance22.parse(edgePaddingTopProp ?? edgePadding);
|
|
72505
|
+
const edgePaddingBottom = distance22.parse(
|
|
71433
72506
|
edgePaddingBottomProp ?? edgePadding
|
|
71434
72507
|
);
|
|
71435
72508
|
db.pcb_group.update(this.pcb_group_id, {
|
|
71436
|
-
width: hasExplicitWidth ?
|
|
71437
|
-
height: hasExplicitHeight ?
|
|
72509
|
+
width: hasExplicitWidth ? distance22.parse(this._parsedProps.width) : gridWidth + edgePaddingLeft + edgePaddingRight,
|
|
72510
|
+
height: hasExplicitHeight ? distance22.parse(this._parsedProps.height) : gridHeight + edgePaddingTop + edgePaddingBottom
|
|
71438
72511
|
});
|
|
71439
72512
|
}
|
|
71440
72513
|
}
|
|
@@ -71522,8 +72595,8 @@ var Panel = class extends Subpanel {
|
|
|
71522
72595
|
const { db } = this.root;
|
|
71523
72596
|
const props = this._parsedProps;
|
|
71524
72597
|
const inserted = db.pcb_panel.insert({
|
|
71525
|
-
width: props.width !== void 0 ?
|
|
71526
|
-
height: props.height !== void 0 ?
|
|
72598
|
+
width: props.width !== void 0 ? distance23.parse(props.width) : 0,
|
|
72599
|
+
height: props.height !== void 0 ? distance23.parse(props.height) : 0,
|
|
71527
72600
|
thickness: 1.6,
|
|
71528
72601
|
center: this._getGlobalPcbPositionBeforeLayout(),
|
|
71529
72602
|
covered_with_solder_mask: !(props.noSolderMask ?? false)
|
|
@@ -71542,8 +72615,8 @@ var Panel = class extends Subpanel {
|
|
|
71542
72615
|
if (!this.pcb_panel_id) return;
|
|
71543
72616
|
if (hasExplicitWidth && hasExplicitHeight) {
|
|
71544
72617
|
db.pcb_panel.update(this.pcb_panel_id, {
|
|
71545
|
-
width:
|
|
71546
|
-
height:
|
|
72618
|
+
width: distance23.parse(this._parsedProps.width),
|
|
72619
|
+
height: distance23.parse(this._parsedProps.height)
|
|
71547
72620
|
});
|
|
71548
72621
|
} else if (gridWidth > 0 || gridHeight > 0) {
|
|
71549
72622
|
const {
|
|
@@ -71553,18 +72626,18 @@ var Panel = class extends Subpanel {
|
|
|
71553
72626
|
edgePaddingTop: edgePaddingTopProp,
|
|
71554
72627
|
edgePaddingBottom: edgePaddingBottomProp
|
|
71555
72628
|
} = this._parsedProps;
|
|
71556
|
-
const edgePadding =
|
|
71557
|
-
const edgePaddingLeft =
|
|
71558
|
-
const edgePaddingRight =
|
|
72629
|
+
const edgePadding = distance23.parse(edgePaddingProp ?? 5);
|
|
72630
|
+
const edgePaddingLeft = distance23.parse(edgePaddingLeftProp ?? edgePadding);
|
|
72631
|
+
const edgePaddingRight = distance23.parse(
|
|
71559
72632
|
edgePaddingRightProp ?? edgePadding
|
|
71560
72633
|
);
|
|
71561
|
-
const edgePaddingTop =
|
|
71562
|
-
const edgePaddingBottom =
|
|
72634
|
+
const edgePaddingTop = distance23.parse(edgePaddingTopProp ?? edgePadding);
|
|
72635
|
+
const edgePaddingBottom = distance23.parse(
|
|
71563
72636
|
edgePaddingBottomProp ?? edgePadding
|
|
71564
72637
|
);
|
|
71565
72638
|
db.pcb_panel.update(this.pcb_panel_id, {
|
|
71566
|
-
width: hasExplicitWidth ?
|
|
71567
|
-
height: hasExplicitHeight ?
|
|
72639
|
+
width: hasExplicitWidth ? distance23.parse(this._parsedProps.width) : gridWidth + edgePaddingLeft + edgePaddingRight,
|
|
72640
|
+
height: hasExplicitHeight ? distance23.parse(this._parsedProps.height) : gridHeight + edgePaddingTop + edgePaddingBottom
|
|
71568
72641
|
});
|
|
71569
72642
|
}
|
|
71570
72643
|
}
|
|
@@ -71575,8 +72648,8 @@ var Panel = class extends Subpanel {
|
|
|
71575
72648
|
const props = this._parsedProps;
|
|
71576
72649
|
const currentPanel = db.pcb_panel.get(this.pcb_panel_id);
|
|
71577
72650
|
db.pcb_panel.update(this.pcb_panel_id, {
|
|
71578
|
-
width: props.width !== void 0 ?
|
|
71579
|
-
height: props.height !== void 0 ?
|
|
72651
|
+
width: props.width !== void 0 ? distance23.parse(props.width) : currentPanel?.width,
|
|
72652
|
+
height: props.height !== void 0 ? distance23.parse(props.height) : currentPanel?.height,
|
|
71580
72653
|
center: this._getGlobalPcbPositionBeforeLayout(),
|
|
71581
72654
|
covered_with_solder_mask: !(props.noSolderMask ?? false)
|
|
71582
72655
|
});
|
|
@@ -73398,7 +74471,7 @@ var PcbNoteDimension = class extends PrimitiveComponent2 {
|
|
|
73398
74471
|
import { breakoutProps } from "@tscircuit/props";
|
|
73399
74472
|
|
|
73400
74473
|
// lib/components/primitive-components/AutoplacedBreakoutPoint.ts
|
|
73401
|
-
import { layer_ref as
|
|
74474
|
+
import { layer_ref as layer_ref4 } from "circuit-json";
|
|
73402
74475
|
var AutoplacedBreakoutPoint = class extends BaseBreakoutPoint {
|
|
73403
74476
|
get config() {
|
|
73404
74477
|
return {
|
|
@@ -73412,7 +74485,7 @@ var AutoplacedBreakoutPoint = class extends BaseBreakoutPoint {
|
|
|
73412
74485
|
position
|
|
73413
74486
|
}) {
|
|
73414
74487
|
this.matchedSourceTraceId = sourceTraceId;
|
|
73415
|
-
this._renderPcbBreakoutPoint({ layer:
|
|
74488
|
+
this._renderPcbBreakoutPoint({ layer: layer_ref4.parse(layer) });
|
|
73416
74489
|
this._setPositionFromLayout(position);
|
|
73417
74490
|
}
|
|
73418
74491
|
};
|
|
@@ -74124,7 +75197,7 @@ var validateWindingBreakoutInput = (input) => {
|
|
|
74124
75197
|
};
|
|
74125
75198
|
|
|
74126
75199
|
// node_modules/@tscircuit/winding-breakout-point-solver/lib/solvers/GatePlacementSolver.ts
|
|
74127
|
-
import { BaseSolver as
|
|
75200
|
+
import { BaseSolver as BaseSolver11 } from "@tscircuit/solver-utils";
|
|
74128
75201
|
|
|
74129
75202
|
// node_modules/@tscircuit/winding-breakout-point-solver/lib/gate-placement/place-breakout-gates.ts
|
|
74130
75203
|
var GEOMETRY_EPSILON = 1e-9;
|
|
@@ -74654,7 +75727,7 @@ var getSharedGateSlotCount = (points) => new Set(
|
|
|
74654
75727
|
(point6) => `${point6.regionId}:${point6.x.toFixed(9)}:${point6.y.toFixed(9)}`
|
|
74655
75728
|
)
|
|
74656
75729
|
).size;
|
|
74657
|
-
var GatePlacementSolver = class extends
|
|
75730
|
+
var GatePlacementSolver = class extends BaseSolver11 {
|
|
74658
75731
|
constructor(params) {
|
|
74659
75732
|
super();
|
|
74660
75733
|
this.params = params;
|
|
@@ -74793,7 +75866,7 @@ var GatePlacementSolver = class extends BaseSolver7 {
|
|
|
74793
75866
|
};
|
|
74794
75867
|
|
|
74795
75868
|
// node_modules/@tscircuit/winding-breakout-point-solver/lib/solvers/ReferenceOrderingSolver.ts
|
|
74796
|
-
import { BaseSolver as
|
|
75869
|
+
import { BaseSolver as BaseSolver12 } from "@tscircuit/solver-utils";
|
|
74797
75870
|
|
|
74798
75871
|
// node_modules/@tscircuit/winding-breakout-point-solver/lib/ordering/get-natural-winding-order.ts
|
|
74799
75872
|
var getNaturalWindingOrder = (region, connections) => connections.map((connection) => {
|
|
@@ -74860,7 +75933,7 @@ var getReferenceWindingOrder = (naturalOrder, atomicGroups, buses) => {
|
|
|
74860
75933
|
};
|
|
74861
75934
|
|
|
74862
75935
|
// node_modules/@tscircuit/winding-breakout-point-solver/lib/solvers/ReferenceOrderingSolver.ts
|
|
74863
|
-
var ReferenceOrderingSolver = class extends
|
|
75936
|
+
var ReferenceOrderingSolver = class extends BaseSolver12 {
|
|
74864
75937
|
constructor(params) {
|
|
74865
75938
|
super();
|
|
74866
75939
|
this.params = params;
|
|
@@ -75912,6 +76985,10 @@ var solveImplicitBreakoutPoints = (breakout, solverFn) => {
|
|
|
75912
76985
|
|
|
75913
76986
|
// lib/components/primitive-components/Breakout/Breakout.ts
|
|
75914
76987
|
var Breakout = class extends Group5 {
|
|
76988
|
+
get isDogboneFanout() {
|
|
76989
|
+
const autorouter = this._parsedProps.autorouter;
|
|
76990
|
+
return (typeof autorouter === "string" ? autorouter : autorouter?.preset) === "dogbone";
|
|
76991
|
+
}
|
|
75915
76992
|
get isRoutingDirective() {
|
|
75916
76993
|
return true;
|
|
75917
76994
|
}
|
|
@@ -75970,7 +77047,7 @@ var Breakout = class extends Group5 {
|
|
|
75970
77047
|
for (const port of result.ports) {
|
|
75971
77048
|
const isInside = breakoutPortSet.has(port);
|
|
75972
77049
|
const hasOutsidePort = result.ports.some((p) => !breakoutPortSet.has(p));
|
|
75973
|
-
if (!isInside || !hasOutsidePort) continue;
|
|
77050
|
+
if (!isInside || !hasOutsidePort && !this.isDogboneFanout) continue;
|
|
75974
77051
|
if (manuallyMappedPorts.has(port)) continue;
|
|
75975
77052
|
if (autoPlacedPorts.has(port)) continue;
|
|
75976
77053
|
autoPlacedPorts.add(port);
|
|
@@ -75983,6 +77060,20 @@ var Breakout = class extends Group5 {
|
|
|
75983
77060
|
}
|
|
75984
77061
|
doInitialPcbAutoplaceBreakoutPoints() {
|
|
75985
77062
|
if (this.root?.pcbDisabled) return;
|
|
77063
|
+
if (this.isDogboneFanout && this._parsedProps.pcbTracePaths === void 0) {
|
|
77064
|
+
for (const point6 of this.children) {
|
|
77065
|
+
if (!(point6 instanceof AutoplacedBreakoutPoint)) continue;
|
|
77066
|
+
const port = this.root.db.pcb_port.get(
|
|
77067
|
+
point6.matchedPort.pcb_port_id
|
|
77068
|
+
);
|
|
77069
|
+
point6._applySolvedBreakoutPoint({
|
|
77070
|
+
sourceTraceId: point6.matchedSourceTraceId,
|
|
77071
|
+
layer: port.layers[0],
|
|
77072
|
+
position: port
|
|
77073
|
+
});
|
|
77074
|
+
}
|
|
77075
|
+
return;
|
|
77076
|
+
}
|
|
75986
77077
|
const ownAutorouter = this.props.autorouter;
|
|
75987
77078
|
const inheritedAutorouter = ownAutorouter === void 0 ? this.parent?.getInheritedProperty("autorouter") : void 0;
|
|
75988
77079
|
const implicitBreakoutPointSolverFn = typeof ownAutorouter === "object" ? ownAutorouter.implicitBreakoutPointSolverFn : typeof inheritedAutorouter === "object" ? inheritedAutorouter.implicitBreakoutPointSolverFn : void 0;
|
|
@@ -76205,7 +77296,7 @@ var SilkscreenGraphic = class extends PrimitiveComponent2 {
|
|
|
76205
77296
|
|
|
76206
77297
|
// lib/components/primitive-components/Fiducial.ts
|
|
76207
77298
|
import "zod";
|
|
76208
|
-
import { distance as
|
|
77299
|
+
import { distance as distance24 } from "circuit-json";
|
|
76209
77300
|
import { fiducialProps as fiducialProps2 } from "@tscircuit/props";
|
|
76210
77301
|
var Fiducial = class extends PrimitiveComponent2 {
|
|
76211
77302
|
pcb_smtpad_id = null;
|
|
@@ -76230,15 +77321,15 @@ var Fiducial = class extends PrimitiveComponent2 {
|
|
|
76230
77321
|
shape: "circle",
|
|
76231
77322
|
x: position.x,
|
|
76232
77323
|
y: position.y,
|
|
76233
|
-
radius:
|
|
76234
|
-
soldermask_margin: props.soldermaskPullback ?
|
|
77324
|
+
radius: distance24.parse(props.padDiameter) / 2,
|
|
77325
|
+
soldermask_margin: props.soldermaskPullback ? distance24.parse(props.soldermaskPullback) : distance24.parse(props.padDiameter) / 2,
|
|
76235
77326
|
is_covered_with_solder_mask: true
|
|
76236
77327
|
});
|
|
76237
77328
|
this.pcb_smtpad_id = pcb_smtpad.pcb_smtpad_id;
|
|
76238
77329
|
}
|
|
76239
77330
|
getPcbSize() {
|
|
76240
77331
|
const { _parsedProps: props } = this;
|
|
76241
|
-
const d =
|
|
77332
|
+
const d = distance24.parse(props.padDiameter);
|
|
76242
77333
|
return { width: d, height: d };
|
|
76243
77334
|
}
|
|
76244
77335
|
_setPositionFromLayout(newCenter) {
|
|
@@ -76282,15 +77373,15 @@ import {
|
|
|
76282
77373
|
} from "@tscircuit/copper-pour-solver";
|
|
76283
77374
|
|
|
76284
77375
|
// lib/components/primitive-components/CopperPour/utils/mark-trace-segments-inside-copper-pour.ts
|
|
76285
|
-
var
|
|
77376
|
+
var EPSILON26 = 1e-9;
|
|
76286
77377
|
var isWireRoutePoint = (routePoint) => routePoint.route_type === "wire";
|
|
76287
77378
|
var isPointOnSegment2 = (p, a, b) => {
|
|
76288
|
-
const
|
|
76289
|
-
if (Math.abs(
|
|
77379
|
+
const cross5 = (p.y - a.y) * (b.x - a.x) - (p.x - a.x) * (b.y - a.y);
|
|
77380
|
+
if (Math.abs(cross5) > EPSILON26) return false;
|
|
76290
77381
|
const dot = (p.x - a.x) * (b.x - a.x) + (p.y - a.y) * (b.y - a.y);
|
|
76291
|
-
if (dot < -
|
|
77382
|
+
if (dot < -EPSILON26) return false;
|
|
76292
77383
|
const squaredLength = (b.x - a.x) ** 2 + (b.y - a.y) ** 2;
|
|
76293
|
-
if (dot - squaredLength >
|
|
77384
|
+
if (dot - squaredLength > EPSILON26) return false;
|
|
76294
77385
|
return true;
|
|
76295
77386
|
};
|
|
76296
77387
|
var isPointInRing2 = (point6, ring) => {
|
|
@@ -76314,7 +77405,7 @@ var isPointInRectPour = (p, pour) => {
|
|
|
76314
77405
|
const dy = p.y - center.y;
|
|
76315
77406
|
const localX = dx * cosR - dy * sinR;
|
|
76316
77407
|
const localY = dx * sinR + dy * cosR;
|
|
76317
|
-
return Math.abs(localX) <= width / 2 +
|
|
77408
|
+
return Math.abs(localX) <= width / 2 + EPSILON26 && Math.abs(localY) <= height / 2 + EPSILON26;
|
|
76318
77409
|
};
|
|
76319
77410
|
var isPointInBrepPour = (p, pour) => {
|
|
76320
77411
|
const outerRing = pour.brep_shape.outer_ring.vertices.map((v) => ({
|
|
@@ -76348,7 +77439,7 @@ var isSegmentFullyInsideCopperPour = (start, end, pour) => {
|
|
|
76348
77439
|
const dx = end.x - start.x;
|
|
76349
77440
|
const dy = end.y - start.y;
|
|
76350
77441
|
const length8 = Math.hypot(dx, dy);
|
|
76351
|
-
if (length8 <=
|
|
77442
|
+
if (length8 <= EPSILON26) return false;
|
|
76352
77443
|
const samples = [0, 0.25, 0.5, 0.75, 1];
|
|
76353
77444
|
return samples.every(
|
|
76354
77445
|
(t) => isPointInCopperPour(
|