@tscircuit/core 0.0.1914 → 0.0.1916
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 +4 -0
- package/dist/index.js +1390 -204
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -6119,11 +6119,11 @@ function Trace_doInitialPcbTraceRender(trace) {
|
|
|
6119
6119
|
const closestNetBPort = getClosest(netAPort, netBPorts);
|
|
6120
6120
|
const netAPortPosition = netAPort._getGlobalPcbPositionBeforeLayout();
|
|
6121
6121
|
const netBPortPosition = closestNetBPort._getGlobalPcbPositionBeforeLayout();
|
|
6122
|
-
const
|
|
6122
|
+
const distance23 = Math.sqrt(
|
|
6123
6123
|
(netAPortPosition.x - netBPortPosition.x) ** 2 + (netAPortPosition.y - netBPortPosition.y) ** 2
|
|
6124
6124
|
);
|
|
6125
|
-
if (
|
|
6126
|
-
closestDistance =
|
|
6125
|
+
if (distance23 < closestDistance) {
|
|
6126
|
+
closestDistance = distance23;
|
|
6127
6127
|
closestPortPair = [netAPort, closestNetBPort];
|
|
6128
6128
|
}
|
|
6129
6129
|
}
|
|
@@ -7283,7 +7283,7 @@ var getMaxLengthFromConnectedComponents = (ports, { db }) => {
|
|
|
7283
7283
|
return sourceComponent.max_decoupling_trace_length;
|
|
7284
7284
|
}
|
|
7285
7285
|
return null;
|
|
7286
|
-
}).filter((
|
|
7286
|
+
}).filter((length8) => typeof length8 === "number");
|
|
7287
7287
|
if (componentMaxLengths.length === 0) return void 0;
|
|
7288
7288
|
return Math.min(...componentMaxLengths);
|
|
7289
7289
|
};
|
|
@@ -10130,11 +10130,11 @@ import { schematicPathProps } from "@tscircuit/props";
|
|
|
10130
10130
|
import SVGPathCommander from "svg-path-commander";
|
|
10131
10131
|
function sampleCurveSegment(segmentPath, samplesPerUnit) {
|
|
10132
10132
|
const commander = new SVGPathCommander(segmentPath);
|
|
10133
|
-
const
|
|
10134
|
-
const numSamples = Math.max(2, Math.ceil(
|
|
10133
|
+
const length8 = commander.getTotalLength();
|
|
10134
|
+
const numSamples = Math.max(2, Math.ceil(length8 * samplesPerUnit));
|
|
10135
10135
|
const points = [];
|
|
10136
10136
|
for (let i = 1; i <= numSamples; i++) {
|
|
10137
|
-
const t = i / numSamples *
|
|
10137
|
+
const t = i / numSamples * length8;
|
|
10138
10138
|
const point6 = commander.getPointAtLength(t);
|
|
10139
10139
|
points.push({ x: point6.x, y: point6.y });
|
|
10140
10140
|
}
|
|
@@ -12303,7 +12303,7 @@ var createComponentsFromCircuitJson = ({
|
|
|
12303
12303
|
const schematicSymbolId = schematicComponent?.schematic_symbol_id;
|
|
12304
12304
|
const parentSymbol = typeof schematicSymbolId === "string" ? schematicSymbolsByImportedId.get(schematicSymbolId) : void 0;
|
|
12305
12305
|
if (parentSymbol && schematicComponent?.is_box_with_pins === true && elm.center && elm.side_of_component) {
|
|
12306
|
-
const
|
|
12306
|
+
const distance23 = elm.distance_from_component_edge;
|
|
12307
12307
|
const facingDirection = getFacingDirectionFromSide(
|
|
12308
12308
|
elm.side_of_component
|
|
12309
12309
|
);
|
|
@@ -12311,8 +12311,8 @@ var createComponentsFromCircuitJson = ({
|
|
|
12311
12311
|
const directionVector = getUnitVectorFromDirection2(facingDirection);
|
|
12312
12312
|
const stemDirection = elm.facing_direction === facingDirection ? 1 : -1;
|
|
12313
12313
|
const portCenter = {
|
|
12314
|
-
x: elm.center.x + directionVector.x *
|
|
12315
|
-
y: elm.center.y + directionVector.y *
|
|
12314
|
+
x: elm.center.x + directionVector.x * distance23 * stemDirection,
|
|
12315
|
+
y: elm.center.y + directionVector.y * distance23 * stemDirection
|
|
12316
12316
|
};
|
|
12317
12317
|
const sourcePort = sourcePortsByImportedId.get(elm.source_port_id);
|
|
12318
12318
|
const aliases = Array.from(
|
|
@@ -13543,9 +13543,9 @@ var getLabelPlacementAlongRoute = (route) => {
|
|
|
13543
13543
|
for (let pointIndex = 1; pointIndex < route.length; pointIndex++) {
|
|
13544
13544
|
const from = route[pointIndex - 1];
|
|
13545
13545
|
const to = route[pointIndex];
|
|
13546
|
-
const
|
|
13547
|
-
if (
|
|
13548
|
-
longestSegment = { from, to, length:
|
|
13546
|
+
const length8 = Math.hypot(to.x - from.x, to.y - from.y);
|
|
13547
|
+
if (length8 > longestSegment.length) {
|
|
13548
|
+
longestSegment = { from, to, length: length8 };
|
|
13549
13549
|
}
|
|
13550
13550
|
}
|
|
13551
13551
|
const deltaX = longestSegment.to.x - longestSegment.from.x;
|
|
@@ -16770,15 +16770,15 @@ var Capacitor_addPolarityFabricationSymbols = (capacitor) => {
|
|
|
16770
16770
|
source_port_id: negatives[0].source_port_id
|
|
16771
16771
|
});
|
|
16772
16772
|
if (!positive || !negative) return;
|
|
16773
|
-
const
|
|
16774
|
-
if (
|
|
16773
|
+
const distance23 = Math.hypot(negative.x - positive.x, negative.y - positive.y);
|
|
16774
|
+
if (distance23 < 1e-6) return;
|
|
16775
16775
|
const frame = compose6(
|
|
16776
16776
|
translate4((positive.x + negative.x) / 2, (positive.y + negative.y) / 2),
|
|
16777
16777
|
rotate3(Math.atan2(negative.y - positive.y, negative.x - positive.x))
|
|
16778
16778
|
);
|
|
16779
16779
|
const point6 = (x, y) => applyToPoint25(frame, { x, y });
|
|
16780
|
-
const offset =
|
|
16781
|
-
const halfSize = Math.min(
|
|
16780
|
+
const offset = distance23 / 4;
|
|
16781
|
+
const halfSize = Math.min(distance23 * 0.12, 0.3);
|
|
16782
16782
|
const routes = [
|
|
16783
16783
|
[point6(-offset - halfSize, 0), point6(-offset + halfSize, 0)],
|
|
16784
16784
|
[point6(-offset, -halfSize), point6(-offset, halfSize)],
|
|
@@ -18270,7 +18270,7 @@ import {
|
|
|
18270
18270
|
groupProps
|
|
18271
18271
|
} from "@tscircuit/props";
|
|
18272
18272
|
import {
|
|
18273
|
-
distance as
|
|
18273
|
+
distance as distance16
|
|
18274
18274
|
} from "circuit-json";
|
|
18275
18275
|
import Debug15 from "debug";
|
|
18276
18276
|
|
|
@@ -18977,7 +18977,7 @@ function validateOriginalEndpointConnectivity(params) {
|
|
|
18977
18977
|
representativeConnection.name
|
|
18978
18978
|
)
|
|
18979
18979
|
).map((obstacle) => ({ type: "obstacle", obstacle }));
|
|
18980
|
-
const
|
|
18980
|
+
const routeCopper2 = (routedSrj.traces ?? []).filter(
|
|
18981
18981
|
(trace) => traceBelongsToNet(inputSrj, trace, representativeConnection)
|
|
18982
18982
|
).flatMap((trace) => extractTraceCopper(trace, layerNames));
|
|
18983
18983
|
const planeCopper = [
|
|
@@ -18994,7 +18994,7 @@ function validateOriginalEndpointConnectivity(params) {
|
|
|
18994
18994
|
const copper = [
|
|
18995
18995
|
...endpointCopper,
|
|
18996
18996
|
...obstacleCopper,
|
|
18997
|
-
...
|
|
18997
|
+
...routeCopper2,
|
|
18998
18998
|
...planeCopper
|
|
18999
18999
|
];
|
|
19000
19000
|
const connectedCopper = new DisjointSet(copper.length);
|
|
@@ -19469,8 +19469,8 @@ function getTerminalDirections(params) {
|
|
|
19469
19469
|
x: plan.targetPoint.x - plan.sourcePoint.x,
|
|
19470
19470
|
y: plan.targetPoint.y - plan.sourcePoint.y
|
|
19471
19471
|
};
|
|
19472
|
-
const
|
|
19473
|
-
const outward =
|
|
19472
|
+
const length8 = Math.hypot(rawOutward.x, rawOutward.y);
|
|
19473
|
+
const outward = length8 > EPSILON4 ? { x: rawOutward.x / length8, y: rawOutward.y / length8 } : { x: 1, y: 0 };
|
|
19474
19474
|
return {
|
|
19475
19475
|
outward,
|
|
19476
19476
|
perpendicular: { x: -outward.y, y: outward.x }
|
|
@@ -19759,7 +19759,7 @@ function runLocalCompletionPass(params) {
|
|
|
19759
19759
|
};
|
|
19760
19760
|
}
|
|
19761
19761
|
function traceLength(trace) {
|
|
19762
|
-
let
|
|
19762
|
+
let length8 = 0;
|
|
19763
19763
|
let previousWire;
|
|
19764
19764
|
for (const point6 of trace.route) {
|
|
19765
19765
|
if (point6.route_type !== "wire") {
|
|
@@ -19767,10 +19767,10 @@ function traceLength(trace) {
|
|
|
19767
19767
|
continue;
|
|
19768
19768
|
}
|
|
19769
19769
|
if (previousWire?.layer === point6.layer)
|
|
19770
|
-
|
|
19770
|
+
length8 += distance9(previousWire, point6);
|
|
19771
19771
|
previousWire = point6;
|
|
19772
19772
|
}
|
|
19773
|
-
return
|
|
19773
|
+
return length8;
|
|
19774
19774
|
}
|
|
19775
19775
|
function trimCompletedFanoutTails(params) {
|
|
19776
19776
|
const { fanoutSrj, completionTraces } = params;
|
|
@@ -20480,8 +20480,8 @@ function* getMultiSegmentTuningWindows(params) {
|
|
|
20480
20480
|
for (const [index, segment2] of plan.segments.entries()) {
|
|
20481
20481
|
if (segment2.layer !== plan.targetLayer || index < (plan.sourceEscapeSegmentCount ?? 1))
|
|
20482
20482
|
continue;
|
|
20483
|
-
const
|
|
20484
|
-
const steps = Math.max(1, Math.ceil(
|
|
20483
|
+
const length8 = distance9(segment2.start, segment2.end);
|
|
20484
|
+
const steps = Math.max(1, Math.ceil(length8 / (segment2.width / 2)));
|
|
20485
20485
|
for (let step = 0; step <= steps; step++) {
|
|
20486
20486
|
consumeWork();
|
|
20487
20487
|
const fraction = step / steps;
|
|
@@ -26416,7 +26416,7 @@ function hasValidTurns(segments) {
|
|
|
26416
26416
|
const segment2 = segments[i];
|
|
26417
26417
|
const dx = segment2.end.x - segment2.start.x;
|
|
26418
26418
|
const dy = segment2.end.y - segment2.start.y;
|
|
26419
|
-
const
|
|
26419
|
+
const length8 = Math.hypot(dx, dy);
|
|
26420
26420
|
if (Math.min(
|
|
26421
26421
|
Math.abs(dx),
|
|
26422
26422
|
Math.abs(dy),
|
|
@@ -26425,12 +26425,12 @@ function hasValidTurns(segments) {
|
|
|
26425
26425
|
return false;
|
|
26426
26426
|
const next = segments[i + 1];
|
|
26427
26427
|
if (next && distance9(segment2.end, next.start) > EPSILON8) return false;
|
|
26428
|
-
if (!next || next.layer !== segment2.layer ||
|
|
26428
|
+
if (!next || next.layer !== segment2.layer || length8 < EPSILON8) continue;
|
|
26429
26429
|
const nx = next.end.x - next.start.x;
|
|
26430
26430
|
const ny = next.end.y - next.start.y;
|
|
26431
26431
|
const nextLength = Math.hypot(nx, ny);
|
|
26432
26432
|
if (nextLength < EPSILON8) continue;
|
|
26433
|
-
if ((dx * nx + dy * ny) / (
|
|
26433
|
+
if ((dx * nx + dy * ny) / (length8 * nextLength) < Math.SQRT1_2 - EPSILON8)
|
|
26434
26434
|
return false;
|
|
26435
26435
|
}
|
|
26436
26436
|
return true;
|
|
@@ -26751,7 +26751,7 @@ function normalizeFanoutPlanCorners(params) {
|
|
|
26751
26751
|
0
|
|
26752
26752
|
)
|
|
26753
26753
|
);
|
|
26754
|
-
if (lengths.some((
|
|
26754
|
+
if (lengths.some((length8) => !Number.isFinite(length8)) || Math.abs(lengths[0] - lengths[1]) > pair.lengthTolerance + EPSILON8)
|
|
26755
26755
|
return null;
|
|
26756
26756
|
}
|
|
26757
26757
|
if (params.inputSrj.traces?.length && plans.length) {
|
|
@@ -26990,7 +26990,7 @@ function rebuildTraceRoute(plan, segments) {
|
|
|
26990
26990
|
function createPlanWithSegments(plan, segments, updateSourceEscapeCount = false) {
|
|
26991
26991
|
const route = rebuildTraceRoute(plan, segments);
|
|
26992
26992
|
if (!route) return null;
|
|
26993
|
-
const
|
|
26993
|
+
const length8 = [...segments, ...plan.planeEndpointSegments ?? []].reduce(
|
|
26994
26994
|
(total, segment2) => total + distance9(segment2.start, segment2.end),
|
|
26995
26995
|
0
|
|
26996
26996
|
);
|
|
@@ -27002,7 +27002,7 @@ function createPlanWithSegments(plan, segments, updateSourceEscapeCount = false)
|
|
|
27002
27002
|
...updateSourceEscapeCount && plan.sourceEscapeSegmentCount !== void 0 && sourceEscapeSegmentCount >= 0 ? { sourceEscapeSegmentCount } : {},
|
|
27003
27003
|
trace: { ...plan.trace, route },
|
|
27004
27004
|
segments,
|
|
27005
|
-
length:
|
|
27005
|
+
length: length8
|
|
27006
27006
|
};
|
|
27007
27007
|
}
|
|
27008
27008
|
function addedTuningViasAreSelfClear(plan, addedVias, clearance) {
|
|
@@ -27532,11 +27532,11 @@ function* createExtendedFoldCandidates(params) {
|
|
|
27532
27532
|
continue;
|
|
27533
27533
|
} else if (start.layer !== plan.targetLayer && (!params.allowTransitLayerMatching || !(bus.allowedLayers ?? [plan.targetLayer]).includes(start.layer) || !(bus.routableEscapeLayers ?? bus.allowedLayers ?? [plan.targetLayer]).includes(start.layer)))
|
|
27534
27534
|
continue;
|
|
27535
|
-
const
|
|
27536
|
-
if (
|
|
27535
|
+
const length8 = distance9(start.start, start.end);
|
|
27536
|
+
if (length8 <= EPSILON9) continue;
|
|
27537
27537
|
const direction = {
|
|
27538
|
-
x: (start.end.x - start.start.x) /
|
|
27539
|
-
y: (start.end.y - start.start.y) /
|
|
27538
|
+
x: (start.end.x - start.start.x) / length8,
|
|
27539
|
+
y: (start.end.y - start.start.y) / length8
|
|
27540
27540
|
};
|
|
27541
27541
|
for (let last = first + 2; last < Math.min(plan.segments.length, first + 16); last++) {
|
|
27542
27542
|
const span = plan.segments.slice(first, last + 1);
|
|
@@ -27613,19 +27613,19 @@ function* createSpreadLaneCandidates(plan, clearance, workBudget) {
|
|
|
27613
27613
|
for (const { segment: segment2, index } of plan.segments.map((segment3, index2) => ({ segment: segment3, index: index2 })).filter(({ segment: segment3 }) => segment3.layer === plan.targetLayer).toSorted(
|
|
27614
27614
|
(a, b) => distance9(b.segment.start, b.segment.end) - distance9(a.segment.start, a.segment.end)
|
|
27615
27615
|
)) {
|
|
27616
|
-
const
|
|
27617
|
-
if (
|
|
27616
|
+
const length8 = distance9(segment2.start, segment2.end);
|
|
27617
|
+
if (length8 <= EPSILON9) continue;
|
|
27618
27618
|
const dx = Math.abs(segment2.end.x - segment2.start.x);
|
|
27619
27619
|
const dy = Math.abs(segment2.end.y - segment2.start.y);
|
|
27620
27620
|
if (dx > EPSILON9 && dy > EPSILON9 && Math.abs(dx - dy) > EPSILON9) continue;
|
|
27621
27621
|
const tangent = {
|
|
27622
|
-
x: (segment2.end.x - segment2.start.x) /
|
|
27623
|
-
y: (segment2.end.y - segment2.start.y) /
|
|
27622
|
+
x: (segment2.end.x - segment2.start.x) / length8,
|
|
27623
|
+
y: (segment2.end.y - segment2.start.y) / length8
|
|
27624
27624
|
};
|
|
27625
27625
|
const pitch = segment2.width + clearance;
|
|
27626
27626
|
for (const multiple of [2, 3, 4, 6]) {
|
|
27627
27627
|
const offset = pitch * multiple;
|
|
27628
|
-
if (
|
|
27628
|
+
if (length8 < 2 * offset + pitch) continue;
|
|
27629
27629
|
for (const sign of [1, -1]) {
|
|
27630
27630
|
consumeMatchingWork(workBudget);
|
|
27631
27631
|
const normal = { x: -tangent.y * sign, y: tangent.x * sign };
|
|
@@ -28395,15 +28395,15 @@ function sourceOriginRouteIsSelfClear(params) {
|
|
|
28395
28395
|
const radius = (viaDiameter + traceWidth) / 2 + clearance;
|
|
28396
28396
|
const incident = /* @__PURE__ */ new Set();
|
|
28397
28397
|
for (const direction of [-1, 1]) {
|
|
28398
|
-
let point6 = via.center,
|
|
28398
|
+
let point6 = via.center, length8 = 0;
|
|
28399
28399
|
const z18 = direction === -1 ? via.fromZ : via.toZ;
|
|
28400
28400
|
for (let edge = via.edge + direction; edge >= 0 && edge + 1 < points.length; edge += direction) {
|
|
28401
28401
|
const a = points[edge], b = points[edge + 1];
|
|
28402
28402
|
const near = direction === -1 ? b : a, far = direction === -1 ? a : b;
|
|
28403
|
-
if (a.z !== z18 || b.z !== z18 || distance9(point6, near) > 1e-7 ||
|
|
28403
|
+
if (a.z !== z18 || b.z !== z18 || distance9(point6, near) > 1e-7 || length8 > radius + 1e-7)
|
|
28404
28404
|
break;
|
|
28405
28405
|
incident.add(edge);
|
|
28406
|
-
|
|
28406
|
+
length8 += distance9(near, far);
|
|
28407
28407
|
point6 = far;
|
|
28408
28408
|
}
|
|
28409
28409
|
}
|
|
@@ -28466,10 +28466,10 @@ function shortcutSection(points, width, clear) {
|
|
|
28466
28466
|
const lowerBound = Math.max(dx, dy) + (Math.SQRT2 - 1) * Math.min(dx, dy);
|
|
28467
28467
|
if (cost[i] + lowerBound >= cost[j] - EPSILON10) continue;
|
|
28468
28468
|
for (const path of connectorVariants(a, b)) {
|
|
28469
|
-
const
|
|
28470
|
-
if (cost[i] +
|
|
28469
|
+
const length8 = path.slice(1).reduce((sum, p, index) => sum + distance9(path[index], p), 0);
|
|
28470
|
+
if (cost[i] + length8 >= cost[j] - EPSILON10 || !path.slice(1).every((p, index) => clear(path[index], p)))
|
|
28471
28471
|
continue;
|
|
28472
|
-
cost[j] = cost[i] +
|
|
28472
|
+
cost[j] = cost[i] + length8;
|
|
28473
28473
|
edges[j] = { previous: i, points: path };
|
|
28474
28474
|
}
|
|
28475
28475
|
}
|
|
@@ -28814,14 +28814,14 @@ var intersectsRegion = (regions, a, b = a) => regions.some(
|
|
|
28814
28814
|
);
|
|
28815
28815
|
function terminalSuffixAt(segments, point6, layer) {
|
|
28816
28816
|
const positions = [];
|
|
28817
|
-
let
|
|
28817
|
+
let length8 = 0;
|
|
28818
28818
|
for (const [index2, segment2] of segments.entries()) {
|
|
28819
28819
|
if (segment2.layer === layer && distancePointToSegment(point6, segment2.start, segment2.end) < 1e-8) {
|
|
28820
|
-
const offset =
|
|
28820
|
+
const offset = length8 + distance9(segment2.start, point6);
|
|
28821
28821
|
if (!positions.some((p) => Math.abs(p.offset - offset) < 1e-8))
|
|
28822
28822
|
positions.push({ index: index2, offset });
|
|
28823
28823
|
}
|
|
28824
|
-
|
|
28824
|
+
length8 += distance9(segment2.start, segment2.end);
|
|
28825
28825
|
}
|
|
28826
28826
|
if (positions.length !== 1) return null;
|
|
28827
28827
|
let index = positions[0].index;
|
|
@@ -28884,12 +28884,12 @@ function boundaryTerminalPlanIsSelfClear(params) {
|
|
|
28884
28884
|
if (Math.abs(ux * vy - uy * vx) >= 1e-10 || ux * vx + uy * vy < 0) break;
|
|
28885
28885
|
runStart = previous.start;
|
|
28886
28886
|
}
|
|
28887
|
-
const
|
|
28888
|
-
if (
|
|
28889
|
-
const trim = Math.min(maximumJoinLength,
|
|
28887
|
+
const length8 = distance9(runStart, cut);
|
|
28888
|
+
if (length8 < 1e-10) return false;
|
|
28889
|
+
const trim = Math.min(maximumJoinLength, length8 / 3);
|
|
28890
28890
|
cut = {
|
|
28891
|
-
x: cut.x + (runStart.x - cut.x) * trim /
|
|
28892
|
-
y: cut.y + (runStart.y - cut.y) * trim /
|
|
28891
|
+
x: cut.x + (runStart.x - cut.x) * trim / length8,
|
|
28892
|
+
y: cut.y + (runStart.y - cut.y) * trim / length8
|
|
28893
28893
|
};
|
|
28894
28894
|
}
|
|
28895
28895
|
const suffix = terminalSuffixAt(plan.segments, cut, start.layer);
|
|
@@ -33562,13 +33562,13 @@ function* sourcePrefixFoldShortcuts(plan, clearance) {
|
|
|
33562
33562
|
if (first < 0) return;
|
|
33563
33563
|
const pitch = prefix[first].width + clearance;
|
|
33564
33564
|
for (let start = first; start >= Math.max(0, first - 3); start--) {
|
|
33565
|
-
let
|
|
33565
|
+
let length8 = 0;
|
|
33566
33566
|
for (let end = start; end < Math.min(prefix.length, first + 8); end++) {
|
|
33567
33567
|
const segment2 = prefix[end];
|
|
33568
33568
|
if (segment2.layer !== plan.sourceLayer || end > start && distance9(prefix[end - 1].end, segment2.start) > 1e-7)
|
|
33569
33569
|
break;
|
|
33570
|
-
|
|
33571
|
-
if (
|
|
33570
|
+
length8 += distance9(segment2.start, segment2.end);
|
|
33571
|
+
if (length8 > 4 * pitch + 1e-7) break;
|
|
33572
33572
|
if (end <= first) continue;
|
|
33573
33573
|
const a = prefix[start].start, b = segment2.end, dx = b.x - a.x, dy = b.y - a.y, diagonal = Math.min(Math.abs(dx), Math.abs(dy));
|
|
33574
33574
|
for (const bend of [
|
|
@@ -33581,7 +33581,7 @@ function* sourcePrefixFoldShortcuts(plan, clearance) {
|
|
|
33581
33581
|
y: b.y - Math.sign(dy) * diagonal
|
|
33582
33582
|
}
|
|
33583
33583
|
]) {
|
|
33584
|
-
if (distance9(a, bend) + distance9(bend, b) >=
|
|
33584
|
+
if (distance9(a, bend) + distance9(bend, b) >= length8 - 1e-7) continue;
|
|
33585
33585
|
yield [
|
|
33586
33586
|
prefix[0].start,
|
|
33587
33587
|
...prefix.slice(0, start).map((s) => s.end),
|
|
@@ -33711,8 +33711,8 @@ function repairSourcePadReentries(params) {
|
|
|
33711
33711
|
const key = JSON.stringify([anchor, points]);
|
|
33712
33712
|
if (seen.has(key)) continue;
|
|
33713
33713
|
seen.add(key);
|
|
33714
|
-
const
|
|
33715
|
-
proposals.push({ anchor, points, length:
|
|
33714
|
+
const length8 = points.slice(1).reduce((sum, p, i) => sum + distance9(points[i], p), 0) + prefix.slice(anchor).reduce((sum, s) => sum + distance9(s.start, s.end), 0);
|
|
33715
|
+
proposals.push({ anchor, points, length: length8 });
|
|
33716
33716
|
}
|
|
33717
33717
|
}
|
|
33718
33718
|
}
|
|
@@ -37514,9 +37514,9 @@ function getFreeBoundaryTracks(params) {
|
|
|
37514
37514
|
for (const via of vias) {
|
|
37515
37515
|
if (!via.spanLayers.includes(targetLayer2)) continue;
|
|
37516
37516
|
const radius = via.diameter / 2 + traceWidth / 2 + clearance;
|
|
37517
|
-
const
|
|
37518
|
-
if (
|
|
37519
|
-
const extent = Math.sqrt(radius * radius -
|
|
37517
|
+
const distance23 = Math.abs(via.center[across] - edge);
|
|
37518
|
+
if (distance23 >= radius) continue;
|
|
37519
|
+
const extent = Math.sqrt(radius * radius - distance23 * distance23);
|
|
37520
37520
|
blocked.push([via.center[along] - extent, via.center[along] + extent]);
|
|
37521
37521
|
}
|
|
37522
37522
|
const gaps = [];
|
|
@@ -38731,8 +38731,8 @@ var LayerRoutingAttempts = class {
|
|
|
38731
38731
|
|
|
38732
38732
|
// node_modules/@tscircuit/fanout-solver/lib/get-boundary-approach-reservations.ts
|
|
38733
38733
|
function getBoundaryApproachReservations(params) {
|
|
38734
|
-
const
|
|
38735
|
-
if (!Number.isFinite(
|
|
38734
|
+
const length8 = params.traceWidth + params.clearance;
|
|
38735
|
+
if (!Number.isFinite(length8) || !(params.traceWidth > 0) || params.clearance < 0)
|
|
38736
38736
|
throw new Error("Boundary approach reservations require valid trace rules");
|
|
38737
38737
|
return params.buses.filter(
|
|
38738
38738
|
(bus) => bus.termination.type === "boundary" && !params.excludedBusIds.has(bus.busId)
|
|
@@ -38749,10 +38749,10 @@ function getBoundaryApproachReservations(params) {
|
|
|
38749
38749
|
`Missing boundary approach target for ${connection.connectionIndex}`
|
|
38750
38750
|
);
|
|
38751
38751
|
const start = { ...end };
|
|
38752
|
-
if (bus.exitEdge === "bottom") start.y +=
|
|
38753
|
-
else if (bus.exitEdge === "top") start.y -=
|
|
38754
|
-
else if (bus.exitEdge === "left") start.x +=
|
|
38755
|
-
else start.x -=
|
|
38752
|
+
if (bus.exitEdge === "bottom") start.y += length8;
|
|
38753
|
+
else if (bus.exitEdge === "top") start.y -= length8;
|
|
38754
|
+
else if (bus.exitEdge === "left") start.x += length8;
|
|
38755
|
+
else start.x -= length8;
|
|
38756
38756
|
return {
|
|
38757
38757
|
type: "pcb_trace",
|
|
38758
38758
|
pcb_trace_id: `fanout-approach-reservation:${connection.connectionIndex}`,
|
|
@@ -43010,7 +43010,7 @@ function validateDifferentialPairs(inputSrj, plansByConnection, issues) {
|
|
|
43010
43010
|
0
|
|
43011
43011
|
)
|
|
43012
43012
|
);
|
|
43013
|
-
if (lengths.some((
|
|
43013
|
+
if (lengths.some((length8) => !Number.isFinite(length8))) {
|
|
43014
43014
|
addIssue2(
|
|
43015
43015
|
issues,
|
|
43016
43016
|
"invalid-differential-pair",
|
|
@@ -49205,6 +49205,8 @@ function getPresetAutoroutingConfig(autorouterConfig, platformConfig) {
|
|
|
49205
49205
|
groupMode: "subcircuit",
|
|
49206
49206
|
preset: "single_layer_fanout"
|
|
49207
49207
|
};
|
|
49208
|
+
case "bus-lanes":
|
|
49209
|
+
return { local: true, groupMode: "subcircuit", preset: "bus_lanes" };
|
|
49208
49210
|
case "fanout":
|
|
49209
49211
|
return {
|
|
49210
49212
|
local: true,
|
|
@@ -49267,6 +49269,1153 @@ function getPresetAutoroutingConfig(autorouterConfig, platformConfig) {
|
|
|
49267
49269
|
}
|
|
49268
49270
|
}
|
|
49269
49271
|
|
|
49272
|
+
// node_modules/@tscircuit/bus-lanes-solver/lib/bus-lanes-solver.ts
|
|
49273
|
+
import { BaseSolver as BaseSolver4 } from "@tscircuit/solver-utils";
|
|
49274
|
+
|
|
49275
|
+
// node_modules/@tscircuit/bus-lanes-solver/lib/geometry.ts
|
|
49276
|
+
var distance12 = (a, b) => Math.hypot(a.x - b.x, a.y - b.y);
|
|
49277
|
+
function pointSegmentDistance(p, edge) {
|
|
49278
|
+
const [a, b] = edge, dx = b.x - a.x, dy = b.y - a.y, t = Math.max(
|
|
49279
|
+
0,
|
|
49280
|
+
Math.min(
|
|
49281
|
+
1,
|
|
49282
|
+
((p.x - a.x) * dx + (p.y - a.y) * dy) / (dx * dx + dy * dy || 1)
|
|
49283
|
+
)
|
|
49284
|
+
);
|
|
49285
|
+
return Math.hypot(p.x - a.x - t * dx, p.y - a.y - t * dy);
|
|
49286
|
+
}
|
|
49287
|
+
var cross2 = (a, b, c) => (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
|
|
49288
|
+
function segmentDistance(ab, cd) {
|
|
49289
|
+
const [a, b] = ab, [c, d] = cd;
|
|
49290
|
+
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) && cross2(a, b, c) * cross2(a, b, d) <= 0 && cross2(c, d, a) * cross2(c, d, b) <= 0)
|
|
49291
|
+
return 0;
|
|
49292
|
+
return Math.min(
|
|
49293
|
+
pointSegmentDistance(a, cd),
|
|
49294
|
+
pointSegmentDistance(b, cd),
|
|
49295
|
+
pointSegmentDistance(c, ab),
|
|
49296
|
+
pointSegmentDistance(d, ab)
|
|
49297
|
+
);
|
|
49298
|
+
}
|
|
49299
|
+
var length = (path) => path.slice(1).reduce((sum, p, i) => sum + distance12(path[i], p), 0);
|
|
49300
|
+
function simplify(path) {
|
|
49301
|
+
return path.filter(
|
|
49302
|
+
(p, i) => !i || i === path.length - 1 || Math.abs(cross2(path[i - 1], p, path[i + 1])) > 1e-9
|
|
49303
|
+
);
|
|
49304
|
+
}
|
|
49305
|
+
|
|
49306
|
+
// node_modules/@tscircuit/bus-lanes-solver/lib/vector-scene.ts
|
|
49307
|
+
function fixedCopper(input) {
|
|
49308
|
+
const result = [];
|
|
49309
|
+
for (const o of input.obstacles)
|
|
49310
|
+
for (const layer of o.layers)
|
|
49311
|
+
result.push({
|
|
49312
|
+
a: o.center,
|
|
49313
|
+
b: o.center,
|
|
49314
|
+
radius: 0,
|
|
49315
|
+
layer,
|
|
49316
|
+
owners: o.connectedTo,
|
|
49317
|
+
rect: {
|
|
49318
|
+
minX: o.center.x - o.width / 2,
|
|
49319
|
+
maxX: o.center.x + o.width / 2,
|
|
49320
|
+
minY: o.center.y - o.height / 2,
|
|
49321
|
+
maxY: o.center.y + o.height / 2
|
|
49322
|
+
}
|
|
49323
|
+
});
|
|
49324
|
+
const layers = Array.from(
|
|
49325
|
+
{ length: input.layerCount },
|
|
49326
|
+
(_, i) => i === 0 ? "top" : i === input.layerCount - 1 ? "bottom" : `inner${i}`
|
|
49327
|
+
);
|
|
49328
|
+
for (const t of input.traces ?? [])
|
|
49329
|
+
for (let i = 0; i < t.route.length; i++) {
|
|
49330
|
+
const p = t.route[i], q = t.route[i + 1], owners = [t.connection_name ?? "", t.source_trace_id ?? ""];
|
|
49331
|
+
if (p.route_type === "via") {
|
|
49332
|
+
const a = layers.indexOf(p.from_layer), b = layers.indexOf(p.to_layer);
|
|
49333
|
+
for (const layer of p.layers ?? layers.slice(Math.min(a, b), Math.max(a, b) + 1))
|
|
49334
|
+
result.push({
|
|
49335
|
+
a: p,
|
|
49336
|
+
b: p,
|
|
49337
|
+
radius: (p.via_diameter ?? 0.3) / 2,
|
|
49338
|
+
layer,
|
|
49339
|
+
owners
|
|
49340
|
+
});
|
|
49341
|
+
} else if (q?.route_type === "wire") {
|
|
49342
|
+
if (p.layer !== q.layer)
|
|
49343
|
+
throw Error("Fixed trace changes layer without a via");
|
|
49344
|
+
result.push({ a: p, b: q, radius: p.width / 2, layer: p.layer, owners });
|
|
49345
|
+
}
|
|
49346
|
+
if (q && p.route_type !== q.route_type && distance12(p, q) > 1e-10) {
|
|
49347
|
+
const wire = p.route_type === "wire" ? p : q;
|
|
49348
|
+
result.push({
|
|
49349
|
+
a: p,
|
|
49350
|
+
b: q,
|
|
49351
|
+
radius: wire.width / 2,
|
|
49352
|
+
layer: wire.layer,
|
|
49353
|
+
owners
|
|
49354
|
+
});
|
|
49355
|
+
}
|
|
49356
|
+
}
|
|
49357
|
+
return result;
|
|
49358
|
+
}
|
|
49359
|
+
function routeCopper(t) {
|
|
49360
|
+
return t.route.slice(1).map((p, i) => ({
|
|
49361
|
+
a: t.route[i],
|
|
49362
|
+
b: p,
|
|
49363
|
+
radius: p.width / 2,
|
|
49364
|
+
layer: p.layer,
|
|
49365
|
+
owners: [t.connection_name ?? ""]
|
|
49366
|
+
}));
|
|
49367
|
+
}
|
|
49368
|
+
var intersectsRect = (a, b, r) => {
|
|
49369
|
+
let t0 = 0, t1 = 1;
|
|
49370
|
+
for (const [origin, delta, min, max] of [
|
|
49371
|
+
[a.x, b.x - a.x, r.minX, r.maxX],
|
|
49372
|
+
[a.y, b.y - a.y, r.minY, r.maxY]
|
|
49373
|
+
]) {
|
|
49374
|
+
if (Math.abs(delta) < 1e-12) {
|
|
49375
|
+
if (origin < min || origin > max) return false;
|
|
49376
|
+
continue;
|
|
49377
|
+
}
|
|
49378
|
+
let lo = (min - origin) / delta, hi = (max - origin) / delta;
|
|
49379
|
+
if (lo > hi) [lo, hi] = [hi, lo];
|
|
49380
|
+
t0 = Math.max(t0, lo);
|
|
49381
|
+
t1 = Math.min(t1, hi);
|
|
49382
|
+
if (t0 > t1) return false;
|
|
49383
|
+
}
|
|
49384
|
+
return true;
|
|
49385
|
+
};
|
|
49386
|
+
function clearanceToCopper(a, b, c) {
|
|
49387
|
+
if (!c.rect) return segmentDistance([a, b], [c.a, c.b]) - c.radius;
|
|
49388
|
+
const r = c.rect;
|
|
49389
|
+
if (intersectsRect(a, b, r)) return 0;
|
|
49390
|
+
const corners = [
|
|
49391
|
+
{ x: r.minX, y: r.minY },
|
|
49392
|
+
{ x: r.maxX, y: r.minY },
|
|
49393
|
+
{ x: r.maxX, y: r.maxY },
|
|
49394
|
+
{ x: r.minX, y: r.maxY }
|
|
49395
|
+
];
|
|
49396
|
+
return Math.min(
|
|
49397
|
+
...corners.map(
|
|
49398
|
+
(p, i) => segmentDistance([a, b], [p, corners[(i + 1) % 4]])
|
|
49399
|
+
)
|
|
49400
|
+
);
|
|
49401
|
+
}
|
|
49402
|
+
var VectorScene = class {
|
|
49403
|
+
constructor(input, connection, width, all) {
|
|
49404
|
+
this.input = input;
|
|
49405
|
+
this.connection = connection;
|
|
49406
|
+
this.width = width;
|
|
49407
|
+
this.owners = new Set(
|
|
49408
|
+
[
|
|
49409
|
+
connection.name,
|
|
49410
|
+
connection.source_trace_id,
|
|
49411
|
+
...connection.pointsToConnect.flatMap((p) => [
|
|
49412
|
+
p.pointId,
|
|
49413
|
+
p.pcb_port_id
|
|
49414
|
+
])
|
|
49415
|
+
].filter((s) => !!s)
|
|
49416
|
+
);
|
|
49417
|
+
this.copper = all.filter(
|
|
49418
|
+
(c) => c.layer === connection.pointsToConnect[0].layer && !c.owners.some((n) => this.owners.has(n))
|
|
49419
|
+
);
|
|
49420
|
+
this.margin = width / 2 + (input.minTraceToPadEdgeClearance ?? input.defaultObstacleMargin ?? 0.075);
|
|
49421
|
+
}
|
|
49422
|
+
input;
|
|
49423
|
+
connection;
|
|
49424
|
+
width;
|
|
49425
|
+
copper;
|
|
49426
|
+
owners;
|
|
49427
|
+
margin;
|
|
49428
|
+
visible(a, b) {
|
|
49429
|
+
const m = this.width / 2 + (this.input.minBoardEdgeClearance ?? 0), r = this.input.bounds;
|
|
49430
|
+
if ([a, b].some(
|
|
49431
|
+
(p) => p.x < r.minX + m - 1e-9 || p.x > r.maxX - m + 1e-9 || p.y < r.minY + m - 1e-9 || p.y > r.maxY - m + 1e-9
|
|
49432
|
+
))
|
|
49433
|
+
return false;
|
|
49434
|
+
const minX = Math.min(a.x, b.x) - this.margin, maxX = Math.max(a.x, b.x) + this.margin, minY = Math.min(a.y, b.y) - this.margin, maxY = Math.max(a.y, b.y) + this.margin;
|
|
49435
|
+
for (const c of this.copper) {
|
|
49436
|
+
const r2 = c.rect ?? {
|
|
49437
|
+
minX: Math.min(c.a.x, c.b.x) - c.radius,
|
|
49438
|
+
maxX: Math.max(c.a.x, c.b.x) + c.radius,
|
|
49439
|
+
minY: Math.min(c.a.y, c.b.y) - c.radius,
|
|
49440
|
+
maxY: Math.max(c.a.y, c.b.y) + c.radius
|
|
49441
|
+
};
|
|
49442
|
+
if (r2.minX > maxX || r2.maxX < minX || r2.minY > maxY || r2.maxY < minY)
|
|
49443
|
+
continue;
|
|
49444
|
+
if (clearanceToCopper(a, b, c) < this.margin - 1e-8) return false;
|
|
49445
|
+
}
|
|
49446
|
+
return true;
|
|
49447
|
+
}
|
|
49448
|
+
pathVisible(path) {
|
|
49449
|
+
return path.slice(1).every((b, i) => this.visible(path[i], b));
|
|
49450
|
+
}
|
|
49451
|
+
/** Vertices of circumscribed octagonal Minkowski offsets. Their edges are
|
|
49452
|
+
* horizontal, vertical or 45 degrees, including circular vias and trace caps. */
|
|
49453
|
+
vertices() {
|
|
49454
|
+
const result = [], k = Math.SQRT2 - 1, epsilon = 1e-5;
|
|
49455
|
+
for (const c of this.copper) {
|
|
49456
|
+
if (c.rect) {
|
|
49457
|
+
const r = c.rect, m = this.margin + epsilon;
|
|
49458
|
+
result.push(
|
|
49459
|
+
{ x: r.minX - m, y: r.minY - m },
|
|
49460
|
+
{ x: r.minX - m, y: r.maxY + m },
|
|
49461
|
+
{ x: r.maxX + m, y: r.minY - m },
|
|
49462
|
+
{ x: r.maxX + m, y: r.maxY + m }
|
|
49463
|
+
);
|
|
49464
|
+
} else {
|
|
49465
|
+
const r = c.radius + this.margin + epsilon;
|
|
49466
|
+
for (const p of distance12(c.a, c.b) < 1e-9 ? [c.a] : [c.a, c.b])
|
|
49467
|
+
for (const [x, y] of [
|
|
49468
|
+
[1, k],
|
|
49469
|
+
[k, 1],
|
|
49470
|
+
[-k, 1],
|
|
49471
|
+
[-1, k],
|
|
49472
|
+
[-1, -k],
|
|
49473
|
+
[-k, -1],
|
|
49474
|
+
[k, -1],
|
|
49475
|
+
[1, -k]
|
|
49476
|
+
])
|
|
49477
|
+
result.push({ x: p.x + x * r, y: p.y + y * r });
|
|
49478
|
+
}
|
|
49479
|
+
}
|
|
49480
|
+
const seen = /* @__PURE__ */ new Set();
|
|
49481
|
+
return result.filter((p) => {
|
|
49482
|
+
const key = `${p.x.toFixed(9)},${p.y.toFixed(9)}`;
|
|
49483
|
+
if (seen.has(key)) return false;
|
|
49484
|
+
seen.add(key);
|
|
49485
|
+
return this.visible(p, p);
|
|
49486
|
+
});
|
|
49487
|
+
}
|
|
49488
|
+
};
|
|
49489
|
+
|
|
49490
|
+
// node_modules/@tscircuit/bus-lanes-solver/lib/min-heap.ts
|
|
49491
|
+
var MinHeap2 = class {
|
|
49492
|
+
entries = [];
|
|
49493
|
+
sequence = 0;
|
|
49494
|
+
get length() {
|
|
49495
|
+
return this.entries.length;
|
|
49496
|
+
}
|
|
49497
|
+
values() {
|
|
49498
|
+
return this.entries.map((e) => e.value);
|
|
49499
|
+
}
|
|
49500
|
+
before(a, b) {
|
|
49501
|
+
return a.value.f < b.value.f || a.value.f === b.value.f && a.sequence < b.sequence;
|
|
49502
|
+
}
|
|
49503
|
+
push(value) {
|
|
49504
|
+
const entry = { value, sequence: this.sequence++ };
|
|
49505
|
+
let i = this.entries.length;
|
|
49506
|
+
this.entries.push(entry);
|
|
49507
|
+
while (i > 0) {
|
|
49508
|
+
const parent = i - 1 >> 1;
|
|
49509
|
+
if (!this.before(entry, this.entries[parent])) break;
|
|
49510
|
+
this.entries[i] = this.entries[parent];
|
|
49511
|
+
i = parent;
|
|
49512
|
+
}
|
|
49513
|
+
this.entries[i] = entry;
|
|
49514
|
+
}
|
|
49515
|
+
pop() {
|
|
49516
|
+
const first = this.entries[0], last = this.entries.pop();
|
|
49517
|
+
if (this.entries.length) {
|
|
49518
|
+
let i = 0;
|
|
49519
|
+
while (i * 2 + 1 < this.entries.length) {
|
|
49520
|
+
let child = i * 2 + 1;
|
|
49521
|
+
if (child + 1 < this.entries.length && this.before(this.entries[child + 1], this.entries[child]))
|
|
49522
|
+
child++;
|
|
49523
|
+
if (!this.before(this.entries[child], last)) break;
|
|
49524
|
+
this.entries[i] = this.entries[child];
|
|
49525
|
+
i = child;
|
|
49526
|
+
}
|
|
49527
|
+
this.entries[i] = last;
|
|
49528
|
+
}
|
|
49529
|
+
return first.value;
|
|
49530
|
+
}
|
|
49531
|
+
};
|
|
49532
|
+
|
|
49533
|
+
// node_modules/@tscircuit/bus-lanes-solver/lib/vector-visibility.ts
|
|
49534
|
+
function connectors(a, b) {
|
|
49535
|
+
const dx = b.x - a.x, dy = b.y - a.y, sx = Math.sign(dx), sy = Math.sign(dy), d = Math.min(Math.abs(dx), Math.abs(dy));
|
|
49536
|
+
if (Math.min(Math.abs(dx), Math.abs(dy)) < 1e-10 || Math.abs(Math.abs(dx) - Math.abs(dy)) < 1e-10)
|
|
49537
|
+
return [[a, b]];
|
|
49538
|
+
const lead = (Math.max(Math.abs(dx), Math.abs(dy)) - d) / 2;
|
|
49539
|
+
const centered = Math.abs(dx) > Math.abs(dy) ? [a, { x: a.x + sx * lead, y: a.y }, { x: b.x - sx * lead, y: b.y }, b] : [a, { x: a.x, y: a.y + sy * lead }, { x: b.x, y: b.y - sy * lead }, b];
|
|
49540
|
+
return [
|
|
49541
|
+
centered,
|
|
49542
|
+
[a, { x: a.x + sx * d, y: a.y + sy * d }, b],
|
|
49543
|
+
[a, { x: b.x - sx * d, y: b.y - sy * d }, b],
|
|
49544
|
+
[a, { x: a.x, y: b.y }, b],
|
|
49545
|
+
[a, { x: b.x, y: a.y }, b]
|
|
49546
|
+
];
|
|
49547
|
+
}
|
|
49548
|
+
var VectorVisibilitySearch = class {
|
|
49549
|
+
constructor(scene, start, end) {
|
|
49550
|
+
this.scene = scene;
|
|
49551
|
+
this.start = start;
|
|
49552
|
+
this.end = end;
|
|
49553
|
+
this.vertices = [start, end];
|
|
49554
|
+
this.open.push({ id: 0, g: 0, f: distance12(start, end) });
|
|
49555
|
+
this.best.set(0, 0);
|
|
49556
|
+
}
|
|
49557
|
+
scene;
|
|
49558
|
+
start;
|
|
49559
|
+
end;
|
|
49560
|
+
vertices;
|
|
49561
|
+
open = new MinHeap2();
|
|
49562
|
+
best = /* @__PURE__ */ new Map();
|
|
49563
|
+
expanded = 0;
|
|
49564
|
+
failed = false;
|
|
49565
|
+
solved = false;
|
|
49566
|
+
result = [];
|
|
49567
|
+
geometryLoaded = false;
|
|
49568
|
+
current;
|
|
49569
|
+
visibleEdges = [];
|
|
49570
|
+
step() {
|
|
49571
|
+
if (!this.geometryLoaded) {
|
|
49572
|
+
this.geometryLoaded = true;
|
|
49573
|
+
const lowerBound = Math.max(
|
|
49574
|
+
Math.abs(this.end.x - this.start.x),
|
|
49575
|
+
Math.abs(this.end.y - this.start.y)
|
|
49576
|
+
) + (Math.SQRT2 - 1) * Math.min(
|
|
49577
|
+
Math.abs(this.end.x - this.start.x),
|
|
49578
|
+
Math.abs(this.end.y - this.start.y)
|
|
49579
|
+
);
|
|
49580
|
+
for (const path of connectors(this.start, this.end)) {
|
|
49581
|
+
if (length(path) > lowerBound + 1e-9 || !this.scene.pathVisible(path))
|
|
49582
|
+
continue;
|
|
49583
|
+
this.visibleEdges = [path];
|
|
49584
|
+
this.result = simplify(path);
|
|
49585
|
+
this.solved = true;
|
|
49586
|
+
this.expanded = 1;
|
|
49587
|
+
return;
|
|
49588
|
+
}
|
|
49589
|
+
this.vertices.push(...this.scene.vertices());
|
|
49590
|
+
}
|
|
49591
|
+
if (!this.open.length) {
|
|
49592
|
+
this.failed = true;
|
|
49593
|
+
return;
|
|
49594
|
+
}
|
|
49595
|
+
const cur = this.open.pop();
|
|
49596
|
+
if (cur.g > (this.best.get(cur.id) ?? Infinity) + 1e-9) return;
|
|
49597
|
+
this.current = cur;
|
|
49598
|
+
this.expanded++;
|
|
49599
|
+
this.visibleEdges = [];
|
|
49600
|
+
if (cur.id === 1) {
|
|
49601
|
+
const edges = [];
|
|
49602
|
+
for (let c = cur; c?.parent; c = c.parent)
|
|
49603
|
+
edges.push(c.edge);
|
|
49604
|
+
this.result = simplify([
|
|
49605
|
+
this.start,
|
|
49606
|
+
...edges.reverse().flatMap((p) => p.slice(1))
|
|
49607
|
+
]);
|
|
49608
|
+
this.solved = true;
|
|
49609
|
+
return;
|
|
49610
|
+
}
|
|
49611
|
+
const from = this.vertices[cur.id];
|
|
49612
|
+
for (let id = 1; id < this.vertices.length; id++) {
|
|
49613
|
+
if (id === cur.id) continue;
|
|
49614
|
+
const to = this.vertices[id], lower = cur.g + distance12(from, to);
|
|
49615
|
+
if (lower >= (this.best.get(id) ?? Infinity) - 1e-9) continue;
|
|
49616
|
+
const candidates = connectors(from, to).sort(
|
|
49617
|
+
(a, b) => length(a) - length(b)
|
|
49618
|
+
);
|
|
49619
|
+
for (const path of candidates) {
|
|
49620
|
+
const g = cur.g + length(path);
|
|
49621
|
+
if (g >= (this.best.get(id) ?? Infinity) - 1e-9) continue;
|
|
49622
|
+
if (!this.scene.pathVisible(path)) continue;
|
|
49623
|
+
this.best.set(id, g);
|
|
49624
|
+
this.open.push({
|
|
49625
|
+
id,
|
|
49626
|
+
g,
|
|
49627
|
+
f: g + distance12(to, this.end),
|
|
49628
|
+
parent: cur,
|
|
49629
|
+
edge: path
|
|
49630
|
+
});
|
|
49631
|
+
if (this.visibleEdges.length < 100) this.visibleEdges.push(path);
|
|
49632
|
+
break;
|
|
49633
|
+
}
|
|
49634
|
+
}
|
|
49635
|
+
}
|
|
49636
|
+
currentPath() {
|
|
49637
|
+
const edges = [];
|
|
49638
|
+
for (let c = this.current; c?.parent; c = c.parent) edges.push(c.edge);
|
|
49639
|
+
return [this.start, ...edges.reverse().flatMap((e) => e.slice(1))];
|
|
49640
|
+
}
|
|
49641
|
+
};
|
|
49642
|
+
|
|
49643
|
+
// node_modules/@tscircuit/bus-lanes-solver/lib/winding-orders.ts
|
|
49644
|
+
function windingOrders(connections) {
|
|
49645
|
+
const orders = [];
|
|
49646
|
+
const seen = /* @__PURE__ */ new Set();
|
|
49647
|
+
const add = (order) => {
|
|
49648
|
+
const key = order.map((c) => c.name).join("\0");
|
|
49649
|
+
if (!seen.has(key)) {
|
|
49650
|
+
seen.add(key);
|
|
49651
|
+
orders.push(order);
|
|
49652
|
+
}
|
|
49653
|
+
};
|
|
49654
|
+
const direction = connections.reduce(
|
|
49655
|
+
(v, c) => ({
|
|
49656
|
+
x: v.x + c.pointsToConnect[1].x - c.pointsToConnect[0].x,
|
|
49657
|
+
y: v.y + c.pointsToConnect[1].y - c.pointsToConnect[0].y
|
|
49658
|
+
}),
|
|
49659
|
+
{ x: 0, y: 0 }
|
|
49660
|
+
);
|
|
49661
|
+
const transverse = (c) => -direction.y * c.pointsToConnect[0].x + direction.x * c.pointsToConnect[0].y;
|
|
49662
|
+
const sweep = [...connections].sort(
|
|
49663
|
+
(a, b) => a.pointsToConnect[0].layer.localeCompare(b.pointsToConnect[0].layer) || transverse(a) - transverse(b) || a.name.localeCompare(b.name)
|
|
49664
|
+
);
|
|
49665
|
+
const span = (endpoint, axis) => Math.max(...connections.map((c) => c.pointsToConnect[endpoint][axis])) - Math.min(...connections.map((c) => c.pointsToConnect[endpoint][axis]));
|
|
49666
|
+
const transverseAxis = span(0, "x") < 1e-7 && span(1, "x") < 1e-7 ? "y" : span(0, "y") < 1e-7 && span(1, "y") < 1e-7 ? "x" : void 0;
|
|
49667
|
+
if (transverseAxis) {
|
|
49668
|
+
const drift = connections.reduce(
|
|
49669
|
+
(s, c) => s + c.pointsToConnect[1][transverseAxis] - c.pointsToConnect[0][transverseAxis],
|
|
49670
|
+
0
|
|
49671
|
+
);
|
|
49672
|
+
if (Math.abs(drift) > 1e-7)
|
|
49673
|
+
add(
|
|
49674
|
+
[...connections].sort(
|
|
49675
|
+
(a, b) => a.pointsToConnect[0].layer.localeCompare(
|
|
49676
|
+
b.pointsToConnect[0].layer
|
|
49677
|
+
) || -Math.sign(drift) * (a.pointsToConnect[0][transverseAxis] - b.pointsToConnect[0][transverseAxis]) || a.name.localeCompare(b.name)
|
|
49678
|
+
)
|
|
49679
|
+
);
|
|
49680
|
+
}
|
|
49681
|
+
add(sweep);
|
|
49682
|
+
add([...sweep].reverse());
|
|
49683
|
+
add(connections);
|
|
49684
|
+
for (const endpoint of [1, 0]) {
|
|
49685
|
+
const center = connections.reduce(
|
|
49686
|
+
(p, c) => ({
|
|
49687
|
+
x: p.x + c.pointsToConnect[endpoint].x / connections.length,
|
|
49688
|
+
y: p.y + c.pointsToConnect[endpoint].y / connections.length
|
|
49689
|
+
}),
|
|
49690
|
+
{ x: 0, y: 0 }
|
|
49691
|
+
);
|
|
49692
|
+
const angle = (c) => Math.atan2(
|
|
49693
|
+
c.pointsToConnect[endpoint].y - center.y,
|
|
49694
|
+
c.pointsToConnect[endpoint].x - center.x
|
|
49695
|
+
);
|
|
49696
|
+
const angular = [...connections].sort(
|
|
49697
|
+
(a, b) => angle(a) - angle(b) || a.name.localeCompare(b.name)
|
|
49698
|
+
);
|
|
49699
|
+
add(angular);
|
|
49700
|
+
add([...angular].reverse());
|
|
49701
|
+
for (const axis of ["x", "y"]) {
|
|
49702
|
+
const other = axis === "x" ? "y" : "x";
|
|
49703
|
+
const sorted = [...connections].sort(
|
|
49704
|
+
(a, b) => a.pointsToConnect[endpoint][axis] - b.pointsToConnect[endpoint][axis] || a.pointsToConnect[endpoint][other] - b.pointsToConnect[endpoint][other]
|
|
49705
|
+
);
|
|
49706
|
+
add(sorted);
|
|
49707
|
+
add([...sorted].reverse());
|
|
49708
|
+
}
|
|
49709
|
+
for (let i = 1; i < angular.length; i++) {
|
|
49710
|
+
const rotated = [...angular.slice(i), ...angular.slice(0, i)];
|
|
49711
|
+
add(rotated);
|
|
49712
|
+
add([...rotated].reverse());
|
|
49713
|
+
}
|
|
49714
|
+
}
|
|
49715
|
+
return orders;
|
|
49716
|
+
}
|
|
49717
|
+
|
|
49718
|
+
// node_modules/@tscircuit/bus-lanes-solver/lib/route-lengths.ts
|
|
49719
|
+
function fixedRouteLength(input, name) {
|
|
49720
|
+
const connection = input.connections.find((c) => c.name === name);
|
|
49721
|
+
return (input.traces ?? []).filter(
|
|
49722
|
+
(t) => t.connection_name === name || t.source_trace_id === (connection?.source_trace_id ?? name)
|
|
49723
|
+
).reduce((sum, t) => sum + length(t.route), 0);
|
|
49724
|
+
}
|
|
49725
|
+
function busLengthReports(input, traces) {
|
|
49726
|
+
return (input.buses ?? []).map((bus) => {
|
|
49727
|
+
const lengths = bus.connectionNames.map((name) => {
|
|
49728
|
+
const route = traces.find((t) => t.connection_name === name);
|
|
49729
|
+
return {
|
|
49730
|
+
name,
|
|
49731
|
+
carrierLengthMm: route ? length(route.route) : null,
|
|
49732
|
+
fixedLengthMm: fixedRouteLength(input, name),
|
|
49733
|
+
totalLengthMm: route ? length(route.route) + fixedRouteLength(input, name) : null
|
|
49734
|
+
};
|
|
49735
|
+
});
|
|
49736
|
+
const complete = lengths.every((l) => l.totalLengthMm !== null);
|
|
49737
|
+
const values = lengths.map((l) => l.totalLengthMm ?? 0);
|
|
49738
|
+
const skewMm = complete && values.length ? Math.max(...values) - Math.min(...values) : null;
|
|
49739
|
+
return {
|
|
49740
|
+
busId: bus.busId,
|
|
49741
|
+
toleranceMm: bus.maxLengthSkew ?? null,
|
|
49742
|
+
skewMm,
|
|
49743
|
+
matched: bus.maxLengthSkew !== void 0 && skewMm !== null && skewMm <= bus.maxLengthSkew + 1e-7,
|
|
49744
|
+
lengths
|
|
49745
|
+
};
|
|
49746
|
+
});
|
|
49747
|
+
}
|
|
49748
|
+
function lengthConstraints(input) {
|
|
49749
|
+
return [
|
|
49750
|
+
...(input.buses ?? []).filter((b) => b.maxLengthSkew !== void 0).map((b) => ({
|
|
49751
|
+
names: b.connectionNames,
|
|
49752
|
+
tolerance: b.maxLengthSkew
|
|
49753
|
+
})),
|
|
49754
|
+
...(input.differentialPairs ?? []).map((p) => ({
|
|
49755
|
+
names: p.connectionNames,
|
|
49756
|
+
tolerance: p.lengthTolerance
|
|
49757
|
+
}))
|
|
49758
|
+
];
|
|
49759
|
+
}
|
|
49760
|
+
function minimumLengthTargets(input, traces) {
|
|
49761
|
+
const targets = new Map(
|
|
49762
|
+
traces.map((t) => [
|
|
49763
|
+
t.connection_name,
|
|
49764
|
+
length(t.route) + fixedRouteLength(input, t.connection_name)
|
|
49765
|
+
])
|
|
49766
|
+
);
|
|
49767
|
+
const constraints = lengthConstraints(input);
|
|
49768
|
+
for (let pass = 0; pass < targets.size; pass++) {
|
|
49769
|
+
let changed = false;
|
|
49770
|
+
for (const { names, tolerance } of constraints) {
|
|
49771
|
+
const floor = Math.max(...names.map((n) => targets.get(n))) - tolerance;
|
|
49772
|
+
for (const name of names)
|
|
49773
|
+
if (targets.get(name) < floor - 1e-9) {
|
|
49774
|
+
targets.set(name, floor);
|
|
49775
|
+
changed = true;
|
|
49776
|
+
}
|
|
49777
|
+
}
|
|
49778
|
+
if (!changed) break;
|
|
49779
|
+
}
|
|
49780
|
+
return targets;
|
|
49781
|
+
}
|
|
49782
|
+
function pairLengthReports(input, traces) {
|
|
49783
|
+
return busLengthReports(
|
|
49784
|
+
{
|
|
49785
|
+
...input,
|
|
49786
|
+
buses: (input.differentialPairs ?? []).map((p, i) => ({
|
|
49787
|
+
busId: `pair_${i}`,
|
|
49788
|
+
connectionNames: p.connectionNames,
|
|
49789
|
+
maxLengthSkew: p.lengthTolerance
|
|
49790
|
+
}))
|
|
49791
|
+
},
|
|
49792
|
+
traces
|
|
49793
|
+
);
|
|
49794
|
+
}
|
|
49795
|
+
|
|
49796
|
+
// node_modules/@tscircuit/bus-lanes-solver/lib/spread-tuning-lanes.ts
|
|
49797
|
+
function spreadTuningLanes(input, traces, pitch) {
|
|
49798
|
+
const dx = traces.reduce((s, t) => s + t.route.at(-1).x - t.route[0].x, 0);
|
|
49799
|
+
const dy = traces.reduce((s, t) => s + t.route.at(-1).y - t.route[0].y, 0);
|
|
49800
|
+
const angle = Math.round(Math.atan2(dy, dx) / (Math.PI / 4)) * Math.PI / 4, ux = Math.cos(angle), uy = Math.sin(angle);
|
|
49801
|
+
const uv = (p) => ({ u: p.x * ux + p.y * uy, v: -p.x * uy + p.y * ux });
|
|
49802
|
+
const xy = (u, v) => ({
|
|
49803
|
+
x: u * ux - v * uy,
|
|
49804
|
+
y: u * uy + v * ux
|
|
49805
|
+
});
|
|
49806
|
+
const result = [];
|
|
49807
|
+
for (const layer of new Set(traces.map((t) => t.route[0].layer))) {
|
|
49808
|
+
const group = traces.filter((t) => t.route[0].layer === layer).sort((a, b) => uv(a.route[0]).v - uv(b.route[0]).v);
|
|
49809
|
+
const center = group.reduce(
|
|
49810
|
+
(s, t) => s + (uv(t.route[0]).v + uv(t.route.at(-1)).v) / 2,
|
|
49811
|
+
0
|
|
49812
|
+
) / group.length;
|
|
49813
|
+
for (const [index, t] of group.entries()) {
|
|
49814
|
+
const a = uv(t.route[0]), b = uv(t.route.at(-1)), v = center + (index - (group.length - 1) / 2) * pitch;
|
|
49815
|
+
const da = Math.abs(v - a.v), db = Math.abs(v - b.v), space = b.u - a.u - da - db;
|
|
49816
|
+
if (space < 1) return null;
|
|
49817
|
+
const lead = space * 0.15;
|
|
49818
|
+
const points = simplify([
|
|
49819
|
+
xy(a.u, a.v),
|
|
49820
|
+
xy(a.u + lead, a.v),
|
|
49821
|
+
xy(a.u + lead + da, v),
|
|
49822
|
+
xy(b.u - lead - db, v),
|
|
49823
|
+
xy(b.u - lead, b.v),
|
|
49824
|
+
xy(b.u, b.v)
|
|
49825
|
+
]);
|
|
49826
|
+
result.push({
|
|
49827
|
+
...t,
|
|
49828
|
+
route: points.map((p) => ({
|
|
49829
|
+
...p,
|
|
49830
|
+
route_type: "wire",
|
|
49831
|
+
layer,
|
|
49832
|
+
width: t.route[0].width
|
|
49833
|
+
}))
|
|
49834
|
+
});
|
|
49835
|
+
}
|
|
49836
|
+
}
|
|
49837
|
+
const copper = [...fixedCopper(input), ...result.flatMap(routeCopper)];
|
|
49838
|
+
for (const t of result) {
|
|
49839
|
+
const c = input.connections.find((c2) => c2.name === t.connection_name);
|
|
49840
|
+
if (!new VectorScene(
|
|
49841
|
+
input,
|
|
49842
|
+
c,
|
|
49843
|
+
t.route[0].width,
|
|
49844
|
+
copper
|
|
49845
|
+
).pathVisible(t.route))
|
|
49846
|
+
return null;
|
|
49847
|
+
}
|
|
49848
|
+
return traces.map(
|
|
49849
|
+
(t) => result.find((r) => r.connection_name === t.connection_name)
|
|
49850
|
+
);
|
|
49851
|
+
}
|
|
49852
|
+
|
|
49853
|
+
// node_modules/@tscircuit/bus-lanes-solver/lib/length-tuning.ts
|
|
49854
|
+
function tuneLengths(input, traces, targets) {
|
|
49855
|
+
const fixed = fixedCopper(input);
|
|
49856
|
+
function* candidates(t, scene) {
|
|
49857
|
+
const connection = input.connections.find(
|
|
49858
|
+
(c) => c.name === t.connection_name
|
|
49859
|
+
);
|
|
49860
|
+
const width = t.route[0].width;
|
|
49861
|
+
const delta = targets.get(connection.name) - length(t.route) - fixedRouteLength(input, connection.name);
|
|
49862
|
+
if (delta < 1e-8) {
|
|
49863
|
+
yield t;
|
|
49864
|
+
return;
|
|
49865
|
+
}
|
|
49866
|
+
const clearance = input.minTraceToPadEdgeClearance ?? input.defaultObstacleMargin ?? 0.075;
|
|
49867
|
+
const returnSpacing = Math.max(width + clearance, 3 * width);
|
|
49868
|
+
const pitch = 2 * (returnSpacing + 2 * width);
|
|
49869
|
+
const segments = t.route.slice(1).map((p, i) => ({ i, span: distance12(t.route[i], p) })).sort((a, b) => b.span - a.span);
|
|
49870
|
+
for (const { i } of segments) {
|
|
49871
|
+
const a = t.route[i], b = t.route[i + 1], span = distance12(a, b);
|
|
49872
|
+
if (span < 0.01) continue;
|
|
49873
|
+
const ux = (b.x - a.x) / span, uy = (b.y - a.y) / span;
|
|
49874
|
+
const maximumTeeth = Math.floor(span * 0.9 / pitch);
|
|
49875
|
+
const preferredTeeth = Math.min(
|
|
49876
|
+
maximumTeeth,
|
|
49877
|
+
Math.max(2, Math.ceil(delta / (12 * width)))
|
|
49878
|
+
);
|
|
49879
|
+
const counts = Array.from({ length: maximumTeeth }, (_, i2) => i2 + 1).sort(
|
|
49880
|
+
(a2, b2) => Math.abs(a2 - preferredTeeth) - Math.abs(b2 - preferredTeeth) || b2 - a2
|
|
49881
|
+
);
|
|
49882
|
+
for (const teeth of counts) {
|
|
49883
|
+
for (const fraction of [0.9, 0.65, 0.4]) {
|
|
49884
|
+
const w = span * fraction / teeth;
|
|
49885
|
+
if (w < pitch) continue;
|
|
49886
|
+
const c = Math.min(
|
|
49887
|
+
delta / (2 * teeth),
|
|
49888
|
+
w / 10,
|
|
49889
|
+
(w / 2 - returnSpacing) / 2
|
|
49890
|
+
);
|
|
49891
|
+
const h = delta / (2 * teeth) + 2 * c * (2 - Math.SQRT2);
|
|
49892
|
+
for (const phase of [0.5, 0, 1])
|
|
49893
|
+
for (const side of [1, -1]) {
|
|
49894
|
+
const at = (x, y) => ({
|
|
49895
|
+
x: a.x + ux * x - uy * y * side,
|
|
49896
|
+
y: a.y + uy * x + ux * y * side
|
|
49897
|
+
});
|
|
49898
|
+
const bump = [at(0, 0)];
|
|
49899
|
+
for (let tooth = 0; tooth < teeth; tooth++) {
|
|
49900
|
+
const offset = span * (1 - fraction) * (0.05 + 0.9 * phase) + tooth * w, gap = w * 0.5;
|
|
49901
|
+
bump.push(
|
|
49902
|
+
...[
|
|
49903
|
+
[offset, 0],
|
|
49904
|
+
[offset + c, c],
|
|
49905
|
+
[offset + c, h - c],
|
|
49906
|
+
[offset + 2 * c, h],
|
|
49907
|
+
[offset + gap - 2 * c, h],
|
|
49908
|
+
[offset + gap - c, h - c],
|
|
49909
|
+
[offset + gap - c, c],
|
|
49910
|
+
[offset + gap, 0]
|
|
49911
|
+
].map(([x, y]) => at(x, y))
|
|
49912
|
+
);
|
|
49913
|
+
}
|
|
49914
|
+
bump.push(at(span, 0));
|
|
49915
|
+
if (!scene.pathVisible(bump)) continue;
|
|
49916
|
+
const next = simplify([
|
|
49917
|
+
...t.route.slice(0, i),
|
|
49918
|
+
...bump,
|
|
49919
|
+
...t.route.slice(i + 2)
|
|
49920
|
+
]);
|
|
49921
|
+
if (Math.abs(
|
|
49922
|
+
length(next) + fixedRouteLength(input, connection.name) - targets.get(connection.name)
|
|
49923
|
+
) > 1e-6)
|
|
49924
|
+
continue;
|
|
49925
|
+
if (!tuningPathIsSelfClear(next, returnSpacing)) continue;
|
|
49926
|
+
yield {
|
|
49927
|
+
...t,
|
|
49928
|
+
route: next.map((p) => ({
|
|
49929
|
+
...p,
|
|
49930
|
+
route_type: "wire",
|
|
49931
|
+
layer: connection.pointsToConnect[0].layer,
|
|
49932
|
+
width
|
|
49933
|
+
}))
|
|
49934
|
+
};
|
|
49935
|
+
}
|
|
49936
|
+
}
|
|
49937
|
+
}
|
|
49938
|
+
}
|
|
49939
|
+
}
|
|
49940
|
+
const result = [...traces];
|
|
49941
|
+
const pending = new Set(traces.map((_, i) => i));
|
|
49942
|
+
let changed = true;
|
|
49943
|
+
while (pending.size && changed) {
|
|
49944
|
+
changed = false;
|
|
49945
|
+
for (const index of pending) {
|
|
49946
|
+
const connection = input.connections.find(
|
|
49947
|
+
(c) => c.name === traces[index].connection_name
|
|
49948
|
+
);
|
|
49949
|
+
const scene = new VectorScene(
|
|
49950
|
+
input,
|
|
49951
|
+
connection,
|
|
49952
|
+
traces[index].route[0].width,
|
|
49953
|
+
[...fixed, ...result.flatMap(routeCopper)]
|
|
49954
|
+
);
|
|
49955
|
+
const next = candidates(traces[index], scene).next().value;
|
|
49956
|
+
if (!next) continue;
|
|
49957
|
+
result[index] = next;
|
|
49958
|
+
pending.delete(index);
|
|
49959
|
+
changed = true;
|
|
49960
|
+
}
|
|
49961
|
+
}
|
|
49962
|
+
if (pending.size)
|
|
49963
|
+
throw Error(
|
|
49964
|
+
`Insufficient tuning clearance for ${[...pending].map((i) => traces[i].connection_name).join(", ")}`
|
|
49965
|
+
);
|
|
49966
|
+
return result;
|
|
49967
|
+
}
|
|
49968
|
+
function tuningPathIsSelfClear(path, required) {
|
|
49969
|
+
const cumulative = [0];
|
|
49970
|
+
for (let i = 1; i < path.length; i++)
|
|
49971
|
+
cumulative.push(cumulative[i - 1] + distance12(path[i - 1], path[i]));
|
|
49972
|
+
for (let i = 0; i < path.length - 1; i++)
|
|
49973
|
+
for (let j = i + 2; j < path.length - 1; j++) {
|
|
49974
|
+
if (cumulative[j] - cumulative[i + 1] <= required + 1e-8) continue;
|
|
49975
|
+
const a = path[i], b = path[i + 1], c = path[j], d = path[j + 1];
|
|
49976
|
+
if (Math.max(a.x, b.x) + required < Math.min(c.x, d.x) || Math.max(c.x, d.x) + required < Math.min(a.x, b.x) || Math.max(a.y, b.y) + required < Math.min(c.y, d.y) || Math.max(c.y, d.y) + required < Math.min(a.y, b.y))
|
|
49977
|
+
continue;
|
|
49978
|
+
if (segmentDistance([a, b], [c, d]) >= required - 1e-8) continue;
|
|
49979
|
+
let sx = 0, sy = 0;
|
|
49980
|
+
for (let k = i; k <= j; k++) {
|
|
49981
|
+
const dx = path[k + 1].x - path[k].x, dy = path[k + 1].y - path[k].y;
|
|
49982
|
+
if (Math.abs(dx) > 1e-8) {
|
|
49983
|
+
if (sx && sx !== Math.sign(dx)) return false;
|
|
49984
|
+
sx = Math.sign(dx);
|
|
49985
|
+
}
|
|
49986
|
+
if (Math.abs(dy) > 1e-8) {
|
|
49987
|
+
if (sy && sy !== Math.sign(dy)) return false;
|
|
49988
|
+
sy = Math.sign(dy);
|
|
49989
|
+
}
|
|
49990
|
+
}
|
|
49991
|
+
}
|
|
49992
|
+
return true;
|
|
49993
|
+
}
|
|
49994
|
+
|
|
49995
|
+
// node_modules/@tscircuit/bus-lanes-solver/lib/layer-colors.ts
|
|
49996
|
+
var layerColors = {
|
|
49997
|
+
top: "#dc2626",
|
|
49998
|
+
inner1: "#ca8a04",
|
|
49999
|
+
inner2: "#16a34a",
|
|
50000
|
+
inner3: "#0891b2",
|
|
50001
|
+
inner4: "#9333ea",
|
|
50002
|
+
inner5: "#ea580c",
|
|
50003
|
+
inner6: "#db2777",
|
|
50004
|
+
bottom: "#2563eb"
|
|
50005
|
+
};
|
|
50006
|
+
var layerColor = (layer) => layerColors[layer] ?? "#64748b";
|
|
50007
|
+
|
|
50008
|
+
// node_modules/@tscircuit/bus-lanes-solver/lib/bus-lanes-solver.ts
|
|
50009
|
+
var BusLanesSolver = class extends BaseSolver4 {
|
|
50010
|
+
input;
|
|
50011
|
+
options;
|
|
50012
|
+
phase = "validate";
|
|
50013
|
+
failureCode = null;
|
|
50014
|
+
traces = [];
|
|
50015
|
+
widths = /* @__PURE__ */ new Map();
|
|
50016
|
+
fixed = [];
|
|
50017
|
+
orders = [];
|
|
50018
|
+
attempt = 0;
|
|
50019
|
+
lane = 0;
|
|
50020
|
+
search;
|
|
50021
|
+
bestPartial = [];
|
|
50022
|
+
constructor(input, options = {}) {
|
|
50023
|
+
super();
|
|
50024
|
+
this.input = structuredClone(input);
|
|
50025
|
+
this.options = options;
|
|
50026
|
+
this.MAX_ITERATIONS = options.maxSearchIterations ?? 2e5;
|
|
50027
|
+
}
|
|
50028
|
+
getConstructorParams() {
|
|
50029
|
+
return [this.input, this.options];
|
|
50030
|
+
}
|
|
50031
|
+
getOutput() {
|
|
50032
|
+
if (!this.solved) throw Error(this.error ?? "Bus lanes are not solved");
|
|
50033
|
+
return {
|
|
50034
|
+
...this.input,
|
|
50035
|
+
traces: [...this.input.traces ?? [], ...this.traces]
|
|
50036
|
+
};
|
|
50037
|
+
}
|
|
50038
|
+
fail(code, message) {
|
|
50039
|
+
this.failureCode = code;
|
|
50040
|
+
this.error = message;
|
|
50041
|
+
this.failed = true;
|
|
50042
|
+
this.phase = "failed";
|
|
50043
|
+
}
|
|
50044
|
+
tryFinalAcceptance() {
|
|
50045
|
+
if (!this.solved)
|
|
50046
|
+
this.fail(
|
|
50047
|
+
"search_budget_exhausted",
|
|
50048
|
+
"Vector visibility search budget exhausted"
|
|
50049
|
+
);
|
|
50050
|
+
}
|
|
50051
|
+
initialize() {
|
|
50052
|
+
const input = this.input;
|
|
50053
|
+
if (input.outline?.length) {
|
|
50054
|
+
this.fail("unsupported_outline", "Custom board outlines are unsupported");
|
|
50055
|
+
return;
|
|
50056
|
+
}
|
|
50057
|
+
if (input.differentialPairs?.some(
|
|
50058
|
+
(p) => p.traceGap !== void 0 || p.maxUncoupledLength !== void 0
|
|
50059
|
+
)) {
|
|
50060
|
+
this.fail(
|
|
50061
|
+
"unsupported_coupling",
|
|
50062
|
+
"Coupled differential geometry is not supported"
|
|
50063
|
+
);
|
|
50064
|
+
return;
|
|
50065
|
+
}
|
|
50066
|
+
const names = /* @__PURE__ */ new Set();
|
|
50067
|
+
for (const c of input.connections) {
|
|
50068
|
+
if (names.has(c.name)) throw Error(`Duplicate connection ${c.name}`);
|
|
50069
|
+
names.add(c.name);
|
|
50070
|
+
if (c.pointsToConnect.length !== 2) {
|
|
50071
|
+
this.fail(
|
|
50072
|
+
"invalid_terminals",
|
|
50073
|
+
`${c.name}: exactly two terminals required`
|
|
50074
|
+
);
|
|
50075
|
+
return;
|
|
50076
|
+
}
|
|
50077
|
+
const [a, b] = c.pointsToConnect;
|
|
50078
|
+
if (a.layers || b.layers || a.layer !== b.layer) {
|
|
50079
|
+
this.fail(
|
|
50080
|
+
"layer_change_required",
|
|
50081
|
+
`${c.name}: ${a.layer} \u2192 ${b.layer}; a common fixed layer is required; fanout handoff layers must agree`
|
|
50082
|
+
);
|
|
50083
|
+
return;
|
|
50084
|
+
}
|
|
50085
|
+
if (![a.x, a.y, b.x, b.y].every(Number.isFinite))
|
|
50086
|
+
throw Error("Nonfinite terminal");
|
|
50087
|
+
this.widths.set(
|
|
50088
|
+
c.name,
|
|
50089
|
+
c.nominalTraceWidth ?? c.width ?? input.minTraceWidth
|
|
50090
|
+
);
|
|
50091
|
+
}
|
|
50092
|
+
for (const b of input.buses ?? [])
|
|
50093
|
+
if (b.maxLengthSkew !== void 0 && (!Number.isFinite(b.maxLengthSkew) || b.maxLengthSkew < 0))
|
|
50094
|
+
throw Error("Invalid maximum length skew");
|
|
50095
|
+
for (const { names: members, tolerance } of lengthConstraints(input)) {
|
|
50096
|
+
if (!Number.isFinite(tolerance) || tolerance < 0)
|
|
50097
|
+
throw Error("Invalid maximum length skew");
|
|
50098
|
+
if (members.length < 1 || new Set(members).size !== members.length || members.some((n) => !names.has(n)))
|
|
50099
|
+
throw Error("Invalid length matching members");
|
|
50100
|
+
}
|
|
50101
|
+
const claimed = /* @__PURE__ */ new Set();
|
|
50102
|
+
for (const b of input.buses ?? [])
|
|
50103
|
+
for (const name of b.connectionNames) {
|
|
50104
|
+
const c = input.connections.find((c2) => c2.name === name);
|
|
50105
|
+
if (!c || claimed.has(name))
|
|
50106
|
+
throw Error(`Missing or duplicated bus member ${name}`);
|
|
50107
|
+
claimed.add(name);
|
|
50108
|
+
const layer = c.pointsToConnect[0].layer;
|
|
50109
|
+
if (b.allowedLayers && !b.allowedLayers.includes(layer))
|
|
50110
|
+
throw Error(`${b.busId}: forbidden layer ${layer}`);
|
|
50111
|
+
const width = b.traceWidth;
|
|
50112
|
+
if (width !== void 0) this.widths.set(name, width);
|
|
50113
|
+
}
|
|
50114
|
+
for (const width of this.widths.values())
|
|
50115
|
+
if (!Number.isFinite(width) || width <= 0 || width < input.minTraceWidth)
|
|
50116
|
+
throw Error("Invalid trace width");
|
|
50117
|
+
this.fixed = fixedCopper(input);
|
|
50118
|
+
for (const c of input.connections)
|
|
50119
|
+
for (const p of c.pointsToConnect)
|
|
50120
|
+
this.fixed.push({
|
|
50121
|
+
a: p,
|
|
50122
|
+
b: p,
|
|
50123
|
+
layer: p.layer,
|
|
50124
|
+
radius: this.widths.get(c.name) / 2,
|
|
50125
|
+
owners: [c.name]
|
|
50126
|
+
});
|
|
50127
|
+
this.orders = windingOrders(input.connections);
|
|
50128
|
+
if (!input.connections.length) {
|
|
50129
|
+
this.solved = true;
|
|
50130
|
+
this.phase = "solved";
|
|
50131
|
+
return;
|
|
50132
|
+
}
|
|
50133
|
+
this.phase = "route";
|
|
50134
|
+
this.startLane();
|
|
50135
|
+
}
|
|
50136
|
+
scene(c) {
|
|
50137
|
+
return new VectorScene(this.input, c, this.widths.get(c.name), [
|
|
50138
|
+
...this.fixed,
|
|
50139
|
+
...this.traces.flatMap(routeCopper)
|
|
50140
|
+
]);
|
|
50141
|
+
}
|
|
50142
|
+
startLane() {
|
|
50143
|
+
if (this.lane === this.input.connections.length) {
|
|
50144
|
+
this.phase = "match";
|
|
50145
|
+
return;
|
|
50146
|
+
}
|
|
50147
|
+
const c = this.orders[this.attempt][this.lane], [a, b] = c.pointsToConnect;
|
|
50148
|
+
this.search = new VectorVisibilitySearch(this.scene(c), a, b);
|
|
50149
|
+
}
|
|
50150
|
+
retry() {
|
|
50151
|
+
if (this.traces.length > this.bestPartial.length)
|
|
50152
|
+
this.bestPartial = structuredClone(this.traces);
|
|
50153
|
+
this.attempt++;
|
|
50154
|
+
if (this.attempt >= this.orders.length) {
|
|
50155
|
+
this.traces = this.bestPartial;
|
|
50156
|
+
this.fail(
|
|
50157
|
+
"no_planar_route",
|
|
50158
|
+
"No collision-free routing found in the vector visibility graph"
|
|
50159
|
+
);
|
|
50160
|
+
return;
|
|
50161
|
+
}
|
|
50162
|
+
this.traces = [];
|
|
50163
|
+
this.lane = 0;
|
|
50164
|
+
this.startLane();
|
|
50165
|
+
}
|
|
50166
|
+
route() {
|
|
50167
|
+
const s = this.search;
|
|
50168
|
+
s.step();
|
|
50169
|
+
if (s.solved) {
|
|
50170
|
+
const c = this.orders[this.attempt][this.lane];
|
|
50171
|
+
this.traces.push({
|
|
50172
|
+
type: "pcb_trace",
|
|
50173
|
+
pcb_trace_id: `bus_lane_${c.name}`,
|
|
50174
|
+
connection_name: c.name,
|
|
50175
|
+
source_trace_id: c.source_trace_id ?? c.name,
|
|
50176
|
+
route: s.result.map((p) => ({
|
|
50177
|
+
route_type: "wire",
|
|
50178
|
+
x: p.x,
|
|
50179
|
+
y: p.y,
|
|
50180
|
+
layer: c.pointsToConnect[0].layer,
|
|
50181
|
+
width: this.widths.get(c.name)
|
|
50182
|
+
}))
|
|
50183
|
+
});
|
|
50184
|
+
this.lane++;
|
|
50185
|
+
this.startLane();
|
|
50186
|
+
} else if (s.failed || s.expanded >= (this.options.maxLaneIterations ?? 4e3))
|
|
50187
|
+
this.retry();
|
|
50188
|
+
}
|
|
50189
|
+
match() {
|
|
50190
|
+
const original = this.traces;
|
|
50191
|
+
const input = this.input;
|
|
50192
|
+
function* candidates() {
|
|
50193
|
+
yield original;
|
|
50194
|
+
const width = Math.max(...original.map((t) => t.route[0].width));
|
|
50195
|
+
for (const multiplier of [16, 24, 28, 32]) {
|
|
50196
|
+
const spread = spreadTuningLanes(input, original, width * multiplier);
|
|
50197
|
+
if (spread) yield spread;
|
|
50198
|
+
}
|
|
50199
|
+
}
|
|
50200
|
+
let error;
|
|
50201
|
+
for (const candidate of candidates()) {
|
|
50202
|
+
const targets = minimumLengthTargets(input, candidate);
|
|
50203
|
+
try {
|
|
50204
|
+
this.traces = tuneLengths(input, candidate, targets);
|
|
50205
|
+
this.phase = "validate_output";
|
|
50206
|
+
return;
|
|
50207
|
+
} catch (e) {
|
|
50208
|
+
error = e;
|
|
50209
|
+
}
|
|
50210
|
+
}
|
|
50211
|
+
this.fail("length_matching_failed", String(error));
|
|
50212
|
+
return;
|
|
50213
|
+
}
|
|
50214
|
+
validateOutput() {
|
|
50215
|
+
for (const c of this.input.connections) {
|
|
50216
|
+
const t = this.traces.find((t2) => t2.connection_name === c.name);
|
|
50217
|
+
if (!t) throw Error("Missing lane");
|
|
50218
|
+
const scene = this.scene(c);
|
|
50219
|
+
if (distance12(t.route[0], c.pointsToConnect[0]) > 1e-8 || distance12(t.route.at(-1), c.pointsToConnect[1]) > 1e-8)
|
|
50220
|
+
throw Error("Broken lane endpoints");
|
|
50221
|
+
for (let i = 1; i < t.route.length; i++) {
|
|
50222
|
+
const a = t.route[i - 1], b = t.route[i], dx = Math.abs(a.x - b.x), dy = Math.abs(a.y - b.y);
|
|
50223
|
+
if (a.route_type !== "wire" || b.route_type !== "wire" || a.layer !== b.layer)
|
|
50224
|
+
throw Error("Forbidden layer transition");
|
|
50225
|
+
if (Math.min(dx, dy) > 1e-8 && Math.abs(dx - dy) > 1e-8)
|
|
50226
|
+
throw Error("Non-octilinear segment");
|
|
50227
|
+
if (!scene.visible(a, b))
|
|
50228
|
+
throw Error("Final copper clearance violation");
|
|
50229
|
+
}
|
|
50230
|
+
}
|
|
50231
|
+
if ([
|
|
50232
|
+
...busLengthReports(this.input, this.traces),
|
|
50233
|
+
...pairLengthReports(this.input, this.traces)
|
|
50234
|
+
].some((b) => b.toleranceMm !== null && !b.matched))
|
|
50235
|
+
throw Error("Final bus length skew violation");
|
|
50236
|
+
this.phase = "solved";
|
|
50237
|
+
this.solved = true;
|
|
50238
|
+
}
|
|
50239
|
+
_step() {
|
|
50240
|
+
try {
|
|
50241
|
+
if (this.phase === "validate") this.initialize();
|
|
50242
|
+
else if (this.phase === "route") this.route();
|
|
50243
|
+
else if (this.phase === "match") this.match();
|
|
50244
|
+
else if (this.phase === "validate_output") this.validateOutput();
|
|
50245
|
+
} catch (e) {
|
|
50246
|
+
this.fail("constraint_error", String(e));
|
|
50247
|
+
}
|
|
50248
|
+
this.progress = this.lane / Math.max(1, this.input.connections.length);
|
|
50249
|
+
this.stats = {
|
|
50250
|
+
busLengths: busLengthReports(this.input, this.traces),
|
|
50251
|
+
pairLengths: pairLengthReports(this.input, this.traces),
|
|
50252
|
+
phase: this.phase,
|
|
50253
|
+
algorithm: "octilinear_visibility",
|
|
50254
|
+
attempt: this.attempt,
|
|
50255
|
+
lane: this.lane,
|
|
50256
|
+
totalLanes: this.input.connections.length,
|
|
50257
|
+
vertices: this.search?.vertices.length ?? 0,
|
|
50258
|
+
expandedVertices: this.search?.expanded ?? 0,
|
|
50259
|
+
frontier: this.search?.open.length ?? 0,
|
|
50260
|
+
failureCode: this.failureCode,
|
|
50261
|
+
traceLengthsMm: this.traces.map((t) => ({
|
|
50262
|
+
name: t.connection_name,
|
|
50263
|
+
length: length(t.route)
|
|
50264
|
+
}))
|
|
50265
|
+
};
|
|
50266
|
+
}
|
|
50267
|
+
visualize() {
|
|
50268
|
+
const lines = [], points = [], rects = [], circles = [];
|
|
50269
|
+
for (const c of fixedCopper(this.input)) {
|
|
50270
|
+
if (c.rect) {
|
|
50271
|
+
rects.push({
|
|
50272
|
+
center: {
|
|
50273
|
+
x: (c.rect.minX + c.rect.maxX) / 2,
|
|
50274
|
+
y: (c.rect.minY + c.rect.maxY) / 2
|
|
50275
|
+
},
|
|
50276
|
+
width: c.rect.maxX - c.rect.minX,
|
|
50277
|
+
height: c.rect.maxY - c.rect.minY,
|
|
50278
|
+
layer: c.layer,
|
|
50279
|
+
fill: `${layerColor(c.layer)}30`,
|
|
50280
|
+
stroke: layerColor(c.layer)
|
|
50281
|
+
});
|
|
50282
|
+
continue;
|
|
50283
|
+
}
|
|
50284
|
+
if (distance12(c.a, c.b) < 1e-9)
|
|
50285
|
+
circles.push({
|
|
50286
|
+
center: c.a,
|
|
50287
|
+
radius: c.radius,
|
|
50288
|
+
layer: c.layer,
|
|
50289
|
+
fill: "transparent",
|
|
50290
|
+
stroke: layerColor(c.layer)
|
|
50291
|
+
});
|
|
50292
|
+
else
|
|
50293
|
+
lines.push({
|
|
50294
|
+
points: [
|
|
50295
|
+
{ x: c.a.x, y: c.a.y },
|
|
50296
|
+
{ x: c.b.x, y: c.b.y }
|
|
50297
|
+
],
|
|
50298
|
+
strokeWidth: c.radius * 2,
|
|
50299
|
+
strokeColor: layerColor(c.layer),
|
|
50300
|
+
layer: c.layer,
|
|
50301
|
+
label: `Fixed fanout [${c.layer}]`
|
|
50302
|
+
});
|
|
50303
|
+
}
|
|
50304
|
+
for (const t of this.traces)
|
|
50305
|
+
lines.push({
|
|
50306
|
+
points: t.route.map(({ x, y }) => ({ x, y })),
|
|
50307
|
+
strokeWidth: t.route[0].width,
|
|
50308
|
+
strokeColor: layerColor(t.route[0].layer),
|
|
50309
|
+
layer: t.route[0].layer,
|
|
50310
|
+
label: t.connection_name
|
|
50311
|
+
});
|
|
50312
|
+
for (const c of this.input.connections)
|
|
50313
|
+
for (const [i, p] of c.pointsToConnect.entries())
|
|
50314
|
+
points.push({
|
|
50315
|
+
...p,
|
|
50316
|
+
color: i ? "#d97706" : "#2563eb",
|
|
50317
|
+
label: `${c.name} ${i ? "target" : "source"} [${p.layer}]`
|
|
50318
|
+
});
|
|
50319
|
+
if (this.search && this.phase === "route") {
|
|
50320
|
+
const layer = this.orders[this.attempt][this.lane]?.pointsToConnect[0].layer;
|
|
50321
|
+
for (const edge of this.search.visibleEdges)
|
|
50322
|
+
lines.push({
|
|
50323
|
+
points: edge,
|
|
50324
|
+
strokeWidth: 0.02,
|
|
50325
|
+
strokeColor: "#67e8f980",
|
|
50326
|
+
layer
|
|
50327
|
+
});
|
|
50328
|
+
for (const n of this.search.open.values().slice(0, 80))
|
|
50329
|
+
points.push({ ...this.search.vertices[n.id], color: "#06b6d4", layer });
|
|
50330
|
+
lines.push({
|
|
50331
|
+
points: this.search.currentPath(),
|
|
50332
|
+
strokeColor: "#f43f5e",
|
|
50333
|
+
strokeWidth: 0.09,
|
|
50334
|
+
layer
|
|
50335
|
+
});
|
|
50336
|
+
}
|
|
50337
|
+
return {
|
|
50338
|
+
title: `Vector bus lanes \xB7 ${this.phase}`,
|
|
50339
|
+
lines,
|
|
50340
|
+
points,
|
|
50341
|
+
rects,
|
|
50342
|
+
circles
|
|
50343
|
+
};
|
|
50344
|
+
}
|
|
50345
|
+
};
|
|
50346
|
+
|
|
50347
|
+
// lib/utils/autorouting/BusLanesAutorouter.ts
|
|
50348
|
+
var BusLanesAutorouter = class {
|
|
50349
|
+
constructor(input) {
|
|
50350
|
+
this.input = input;
|
|
50351
|
+
this.solver = new BusLanesSolver(input);
|
|
50352
|
+
}
|
|
50353
|
+
input;
|
|
50354
|
+
isRouting = false;
|
|
50355
|
+
solver;
|
|
50356
|
+
timer;
|
|
50357
|
+
listeners = [];
|
|
50358
|
+
on(event, callback) {
|
|
50359
|
+
this.listeners.push({
|
|
50360
|
+
event,
|
|
50361
|
+
callback
|
|
50362
|
+
});
|
|
50363
|
+
}
|
|
50364
|
+
emit(event) {
|
|
50365
|
+
for (const listener of this.listeners)
|
|
50366
|
+
if (listener.event === event.type) listener.callback(event);
|
|
50367
|
+
}
|
|
50368
|
+
start() {
|
|
50369
|
+
if (this.isRouting) return;
|
|
50370
|
+
this.isRouting = true;
|
|
50371
|
+
const tick = () => {
|
|
50372
|
+
if (!this.isRouting) return;
|
|
50373
|
+
try {
|
|
50374
|
+
for (let i = 0; i < 200 && !this.solver.solved && !this.solver.failed; i++)
|
|
50375
|
+
this.solver.step();
|
|
50376
|
+
if (this.solver.failed) {
|
|
50377
|
+
this.isRouting = false;
|
|
50378
|
+
this.emit({
|
|
50379
|
+
type: "error",
|
|
50380
|
+
error: new Error(this.solver.error ?? "Bus lanes routing failed")
|
|
50381
|
+
});
|
|
50382
|
+
return;
|
|
50383
|
+
}
|
|
50384
|
+
if (this.solver.solved) {
|
|
50385
|
+
this.isRouting = false;
|
|
50386
|
+
this.emit({ type: "complete", traces: this.solver.traces });
|
|
50387
|
+
return;
|
|
50388
|
+
}
|
|
50389
|
+
this.emit({
|
|
50390
|
+
type: "progress",
|
|
50391
|
+
steps: this.solver.iterations,
|
|
50392
|
+
progress: this.solver.progress,
|
|
50393
|
+
phase: this.solver.phase,
|
|
50394
|
+
debugGraphics: this.solver.visualize()
|
|
50395
|
+
});
|
|
50396
|
+
this.timer = setTimeout(tick, 0);
|
|
50397
|
+
} catch (error) {
|
|
50398
|
+
this.isRouting = false;
|
|
50399
|
+
this.emit({
|
|
50400
|
+
type: "error",
|
|
50401
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
50402
|
+
});
|
|
50403
|
+
}
|
|
50404
|
+
};
|
|
50405
|
+
this.timer = setTimeout(tick, 0);
|
|
50406
|
+
}
|
|
50407
|
+
stop() {
|
|
50408
|
+
this.isRouting = false;
|
|
50409
|
+
if (this.timer) clearTimeout(this.timer);
|
|
50410
|
+
}
|
|
50411
|
+
solveSync() {
|
|
50412
|
+
this.solver.solve();
|
|
50413
|
+
if (this.solver.failed)
|
|
50414
|
+
throw new Error(this.solver.error ?? "Bus lanes routing failed");
|
|
50415
|
+
return this.solver.traces;
|
|
50416
|
+
}
|
|
50417
|
+
};
|
|
50418
|
+
|
|
49270
50419
|
// lib/utils/autorouting/CapacityMeshAutorouter.ts
|
|
49271
50420
|
import {
|
|
49272
50421
|
AutoroutingPipelineSolver9_Networked as AutoroutingPipelineSolver9_Networked2
|
|
@@ -49293,7 +50442,7 @@ import { CreateFdmEnclosureSolver } from "@tscircuit/create-fdm-enclosure";
|
|
|
49293
50442
|
// node_modules/@tscircuit/implicit-copper-pour-solver/lib/implicit-copper-pour-pipeline-solver.ts
|
|
49294
50443
|
import {
|
|
49295
50444
|
BasePipelineSolver,
|
|
49296
|
-
BaseSolver as
|
|
50445
|
+
BaseSolver as BaseSolver5,
|
|
49297
50446
|
definePipelineStep
|
|
49298
50447
|
} from "@tscircuit/solver-utils";
|
|
49299
50448
|
|
|
@@ -49311,7 +50460,7 @@ import { applyToPoint as applyToPoint27, compose as compose9, scale as scale2, t
|
|
|
49311
50460
|
// node_modules/@tscircuit/implicit-copper-pour-solver/lib/geometry.ts
|
|
49312
50461
|
import {
|
|
49313
50462
|
clamp,
|
|
49314
|
-
distance as
|
|
50463
|
+
distance as distance13,
|
|
49315
50464
|
doBoundsOverlap as doBoundsOverlap2,
|
|
49316
50465
|
getBoundsFromPoints as getBoundsFromPoints3,
|
|
49317
50466
|
getUnitVectorFromPointAToB as getUnitVectorFromPointAToB2,
|
|
@@ -49360,7 +50509,7 @@ var distanceToPolygon = (point6, polygon) => {
|
|
|
49360
50509
|
var distanceToPrimitive = (primitive, px, py) => {
|
|
49361
50510
|
const point6 = { x: px, y: py };
|
|
49362
50511
|
if (primitive.kind === "circle") {
|
|
49363
|
-
return Math.max(
|
|
50512
|
+
return Math.max(distance13(point6, primitive) - primitive.radius, 0);
|
|
49364
50513
|
}
|
|
49365
50514
|
if (primitive.kind === "segment") {
|
|
49366
50515
|
return Math.max(
|
|
@@ -49411,7 +50560,7 @@ var getClosestPointOnPrimitive = (primitive, point6) => {
|
|
|
49411
50560
|
const start = primitive.points[index];
|
|
49412
50561
|
const end = primitive.points[(index + 1) % primitive.points.length];
|
|
49413
50562
|
const candidate = pointToSegmentClosestPoint(point6, start, end);
|
|
49414
|
-
const candidateDistance =
|
|
50563
|
+
const candidateDistance = distance13(point6, candidate);
|
|
49415
50564
|
if (candidateDistance < bestDistance) {
|
|
49416
50565
|
bestDistance = candidateDistance;
|
|
49417
50566
|
closestPoint = candidate;
|
|
@@ -50467,7 +51616,7 @@ var prepareCircuitJson = (input) => {
|
|
|
50467
51616
|
|
|
50468
51617
|
// node_modules/@tscircuit/implicit-copper-pour-solver/lib/simplify-polygon-edges.ts
|
|
50469
51618
|
import {
|
|
50470
|
-
distance as
|
|
51619
|
+
distance as distance14,
|
|
50471
51620
|
doSegmentsIntersect,
|
|
50472
51621
|
onSegment,
|
|
50473
51622
|
pointToSegmentDistance as pointToSegmentDistance2
|
|
@@ -50486,13 +51635,13 @@ var simplifyRdpPath = (points, tolerance) => {
|
|
|
50486
51635
|
let furthestIndex = -1;
|
|
50487
51636
|
let furthestDistance = tolerance;
|
|
50488
51637
|
for (let index = firstIndex + 1; index < lastIndex; index++) {
|
|
50489
|
-
const
|
|
51638
|
+
const segmentDistance2 = pointToSegmentDistance2(
|
|
50490
51639
|
points[index],
|
|
50491
51640
|
first,
|
|
50492
51641
|
last
|
|
50493
51642
|
);
|
|
50494
|
-
if (
|
|
50495
|
-
furthestDistance =
|
|
51643
|
+
if (segmentDistance2 > furthestDistance) {
|
|
51644
|
+
furthestDistance = segmentDistance2;
|
|
50496
51645
|
furthestIndex = index;
|
|
50497
51646
|
}
|
|
50498
51647
|
}
|
|
@@ -50530,8 +51679,8 @@ var simplifyOpenPath = (points, tolerance) => {
|
|
|
50530
51679
|
const point6 = points[index];
|
|
50531
51680
|
const next = points[index + 1];
|
|
50532
51681
|
const shortestLeg = Math.min(
|
|
50533
|
-
|
|
50534
|
-
|
|
51682
|
+
distance14(point6, previous),
|
|
51683
|
+
distance14(next, point6)
|
|
50535
51684
|
);
|
|
50536
51685
|
if (repeatsTurnDirection || shortestLeg > tolerance) {
|
|
50537
51686
|
anchorIndices.push(index);
|
|
@@ -50580,8 +51729,8 @@ var normalizePolygon = (polygon) => {
|
|
|
50580
51729
|
};
|
|
50581
51730
|
var isPointStrictlyInsideSegment = (point6, start, end) => {
|
|
50582
51731
|
if (pointsEqual(point6, start) || pointsEqual(point6, end)) return false;
|
|
50583
|
-
const
|
|
50584
|
-
if (Math.abs(
|
|
51732
|
+
const cross4 = crossProduct(start, end, point6);
|
|
51733
|
+
if (Math.abs(cross4) > 1e-9) return false;
|
|
50585
51734
|
return onSegment(start, point6, end);
|
|
50586
51735
|
};
|
|
50587
51736
|
var splitEdgesAtVertices = (polygon, allVertices) => {
|
|
@@ -50933,7 +52082,7 @@ var mergeSolverGraphics = (source, overlay) => {
|
|
|
50933
52082
|
};
|
|
50934
52083
|
|
|
50935
52084
|
// node_modules/@tscircuit/implicit-copper-pour-solver/lib/implicit-copper-pour-pipeline-solver.ts
|
|
50936
|
-
var PrepareCircuitJsonSolver = class extends
|
|
52085
|
+
var PrepareCircuitJsonSolver = class extends BaseSolver5 {
|
|
50937
52086
|
constructor(input) {
|
|
50938
52087
|
super();
|
|
50939
52088
|
this.input = input;
|
|
@@ -50949,7 +52098,7 @@ var PrepareCircuitJsonSolver = class extends BaseSolver4 {
|
|
|
50949
52098
|
return this.output;
|
|
50950
52099
|
}
|
|
50951
52100
|
};
|
|
50952
|
-
var AssignGridCellsSolver = class extends
|
|
52101
|
+
var AssignGridCellsSolver = class extends BaseSolver5 {
|
|
50953
52102
|
constructor(input) {
|
|
50954
52103
|
super();
|
|
50955
52104
|
this.input = input;
|
|
@@ -50972,7 +52121,7 @@ var AssignGridCellsSolver = class extends BaseSolver4 {
|
|
|
50972
52121
|
return this.output;
|
|
50973
52122
|
}
|
|
50974
52123
|
};
|
|
50975
|
-
var TracePowerPolygonsSolver = class extends
|
|
52124
|
+
var TracePowerPolygonsSolver = class extends BaseSolver5 {
|
|
50976
52125
|
constructor(input) {
|
|
50977
52126
|
super();
|
|
50978
52127
|
this.input = input;
|
|
@@ -51008,7 +52157,7 @@ var TracePowerPolygonsSolver = class extends BaseSolver4 {
|
|
|
51008
52157
|
};
|
|
51009
52158
|
}
|
|
51010
52159
|
};
|
|
51011
|
-
var SimplifyPolygonEdgesSolver = class extends
|
|
52160
|
+
var SimplifyPolygonEdgesSolver = class extends BaseSolver5 {
|
|
51012
52161
|
constructor(input) {
|
|
51013
52162
|
super();
|
|
51014
52163
|
this.input = input;
|
|
@@ -51146,13 +52295,13 @@ import { LayoutPipelineSolver } from "@tscircuit/matchpack";
|
|
|
51146
52295
|
import { SchematicTracePipelineSolver } from "@tscircuit/schematic-trace-solver";
|
|
51147
52296
|
|
|
51148
52297
|
// node_modules/@tscircuit/via-stitch-solver/lib/solvers/ViaStitchSolver.ts
|
|
51149
|
-
import { BaseSolver as
|
|
52298
|
+
import { BaseSolver as BaseSolver6 } from "@tscircuit/solver-utils";
|
|
51150
52299
|
|
|
51151
52300
|
// node_modules/@tscircuit/via-stitch-solver/lib/geometry/brep-point-containment.ts
|
|
51152
52301
|
var POINT_EPSILON = 1e-8;
|
|
51153
52302
|
var isPointOnSegment = (point6, start, end) => {
|
|
51154
|
-
const
|
|
51155
|
-
if (Math.abs(
|
|
52303
|
+
const cross4 = (point6.y - start.y) * (end.x - start.x) - (point6.x - start.x) * (end.y - start.y);
|
|
52304
|
+
if (Math.abs(cross4) > POINT_EPSILON) return false;
|
|
51156
52305
|
const dot = (point6.x - start.x) * (end.x - start.x) + (point6.y - start.y) * (end.y - start.y);
|
|
51157
52306
|
if (dot < -POINT_EPSILON) return false;
|
|
51158
52307
|
const squaredLength = (end.x - start.x) ** 2 + (end.y - start.y) ** 2;
|
|
@@ -51473,7 +52622,7 @@ var getGridCoordinates = ({
|
|
|
51473
52622
|
}
|
|
51474
52623
|
return coordinates;
|
|
51475
52624
|
};
|
|
51476
|
-
var ViaStitchSolver = class extends
|
|
52625
|
+
var ViaStitchSolver = class extends BaseSolver6 {
|
|
51477
52626
|
constructor(input) {
|
|
51478
52627
|
super();
|
|
51479
52628
|
this.input = input;
|
|
@@ -51620,6 +52769,7 @@ var ViaStitchSolver = class extends BaseSolver5 {
|
|
|
51620
52769
|
// lib/solvers.ts
|
|
51621
52770
|
import { PackSolver2 } from "calculate-packing";
|
|
51622
52771
|
var SOLVERS = {
|
|
52772
|
+
BusLanesSolver,
|
|
51623
52773
|
PackSolver2,
|
|
51624
52774
|
LayoutPipelineSolver,
|
|
51625
52775
|
AutoroutingPipelineSolver,
|
|
@@ -52082,6 +53232,22 @@ var localAutorouterStrategies = /* @__PURE__ */ new Map([
|
|
|
52082
53232
|
createFanoutAutorouterStrategy("single_layer_fanout")
|
|
52083
53233
|
],
|
|
52084
53234
|
["fanout", createFanoutAutorouterStrategy("fanout")],
|
|
53235
|
+
[
|
|
53236
|
+
"bus_lanes",
|
|
53237
|
+
{
|
|
53238
|
+
name: "bus_lanes",
|
|
53239
|
+
cacheable: false,
|
|
53240
|
+
getSolverName: () => "BusLanesSolver",
|
|
53241
|
+
create: ({ simpleRouteJson, onSolverStarted }) => {
|
|
53242
|
+
onSolverStarted?.({
|
|
53243
|
+
solverName: "BusLanesSolver",
|
|
53244
|
+
solverParams: simpleRouteJson,
|
|
53245
|
+
solverConstructorArgs: [simpleRouteJson]
|
|
53246
|
+
});
|
|
53247
|
+
return new BusLanesAutorouter(simpleRouteJson);
|
|
53248
|
+
}
|
|
53249
|
+
}
|
|
53250
|
+
],
|
|
52085
53251
|
["simplify", simplificationLocalAutorouterStrategy]
|
|
52086
53252
|
]);
|
|
52087
53253
|
var getLocalAutorouterStrategy = (preset) => localAutorouterStrategies.get(preset ?? "") ?? defaultLocalAutorouterStrategy;
|
|
@@ -54640,7 +55806,7 @@ function Group_doInitialPcbComponentAnchorAlignment(group) {
|
|
|
54640
55806
|
// lib/components/primitive-components/Group/Group_doInitialPcbLayoutFlex.ts
|
|
54641
55807
|
import { getMinimumFlexContainer } from "@tscircuit/circuit-json-util";
|
|
54642
55808
|
import { RootFlexBox } from "@tscircuit/miniflex";
|
|
54643
|
-
import { length } from "circuit-json";
|
|
55809
|
+
import { length as length2 } from "circuit-json";
|
|
54644
55810
|
var Group_doInitialPcbLayoutFlex = (group) => {
|
|
54645
55811
|
const { db } = group.root;
|
|
54646
55812
|
const { _parsedProps: props } = group;
|
|
@@ -54692,8 +55858,8 @@ var Group_doInitialPcbLayoutFlex = (group) => {
|
|
|
54692
55858
|
rowGap = rawGap;
|
|
54693
55859
|
columnGap = rawGap;
|
|
54694
55860
|
} else if (typeof rawGap === "string") {
|
|
54695
|
-
rowGap =
|
|
54696
|
-
columnGap =
|
|
55861
|
+
rowGap = length2.parse(rawGap);
|
|
55862
|
+
columnGap = length2.parse(rawGap);
|
|
54697
55863
|
}
|
|
54698
55864
|
let minFlexContainer;
|
|
54699
55865
|
let width = props.width ?? props.pcbWidth ?? void 0;
|
|
@@ -54773,7 +55939,7 @@ import {
|
|
|
54773
55939
|
repositionPcbComponentTo as repositionPcbComponentTo2,
|
|
54774
55940
|
repositionPcbGroupTo as repositionPcbGroupTo2
|
|
54775
55941
|
} from "@tscircuit/circuit-json-util";
|
|
54776
|
-
import { length as
|
|
55942
|
+
import { length as length3 } from "circuit-json";
|
|
54777
55943
|
import { CssGrid } from "minicssgrid";
|
|
54778
55944
|
var MIN_GAP = 1;
|
|
54779
55945
|
function Group_doInitialPcbLayoutGrid(group) {
|
|
@@ -54835,7 +56001,7 @@ function parseGridConfiguration(props) {
|
|
|
54835
56001
|
const templateRows = props.pcbGridTemplateRows;
|
|
54836
56002
|
const parseGap = (gapValue) => {
|
|
54837
56003
|
if (gapValue === void 0) return MIN_GAP;
|
|
54838
|
-
return typeof gapValue === "number" ? gapValue :
|
|
56004
|
+
return typeof gapValue === "number" ? gapValue : length3.parse(gapValue);
|
|
54839
56005
|
};
|
|
54840
56006
|
const gridGapOption = props.pcbGridGap ?? props.gridGap ?? props.pcbLayout?.gridGap;
|
|
54841
56007
|
const rowGapOption = props.pcbGridRowGap ?? props.gridRowGap ?? props.pcbLayout?.gridRowGap;
|
|
@@ -54986,7 +56152,7 @@ import {
|
|
|
54986
56152
|
convertPackOutputToPackInput,
|
|
54987
56153
|
getGraphicsFromPackOutput
|
|
54988
56154
|
} from "calculate-packing";
|
|
54989
|
-
import { length as
|
|
56155
|
+
import { length as length4 } from "circuit-json";
|
|
54990
56156
|
import Debug6 from "debug";
|
|
54991
56157
|
|
|
54992
56158
|
// lib/utils/packing/solvePackSolverWithTimeout.ts
|
|
@@ -55495,16 +56661,16 @@ var Group_doInitialPcbLayoutPack = (group) => {
|
|
|
55495
56661
|
pcbPackGap
|
|
55496
56662
|
} = props;
|
|
55497
56663
|
const gap = pcbPackGap ?? pcbGap ?? gapProp;
|
|
55498
|
-
const gapMm =
|
|
56664
|
+
const gapMm = length4.parse(gap ?? DEFAULT_MIN_GAP);
|
|
55499
56665
|
const chipMarginsMap = {};
|
|
55500
56666
|
const staticPcbComponentIds = /* @__PURE__ */ new Set();
|
|
55501
56667
|
const collectMargins = (comp) => {
|
|
55502
56668
|
if (comp?.pcb_component_id && comp?._parsedProps) {
|
|
55503
56669
|
const props2 = comp._parsedProps;
|
|
55504
|
-
const left =
|
|
55505
|
-
const right =
|
|
55506
|
-
const top =
|
|
55507
|
-
const bottom =
|
|
56670
|
+
const left = length4.parse(props2.pcbMarginLeft ?? props2.pcbMarginX ?? 0);
|
|
56671
|
+
const right = length4.parse(props2.pcbMarginRight ?? props2.pcbMarginX ?? 0);
|
|
56672
|
+
const top = length4.parse(props2.pcbMarginTop ?? props2.pcbMarginY ?? 0);
|
|
56673
|
+
const bottom = length4.parse(
|
|
55508
56674
|
props2.pcbMarginBottom ?? props2.pcbMarginY ?? 0
|
|
55509
56675
|
);
|
|
55510
56676
|
if (left || right || top || bottom) {
|
|
@@ -55553,8 +56719,8 @@ var Group_doInitialPcbLayoutPack = (group) => {
|
|
|
55553
56719
|
const filteredCircuitJson = db.toArray();
|
|
55554
56720
|
let bounds;
|
|
55555
56721
|
if (props.width !== void 0 && props.height !== void 0) {
|
|
55556
|
-
const widthMm =
|
|
55557
|
-
const heightMm =
|
|
56722
|
+
const widthMm = length4.parse(props.width);
|
|
56723
|
+
const heightMm = length4.parse(props.height);
|
|
55558
56724
|
bounds = {
|
|
55559
56725
|
minX: -widthMm / 2,
|
|
55560
56726
|
maxX: widthMm / 2,
|
|
@@ -55859,7 +57025,7 @@ import {
|
|
|
55859
57025
|
repositionSchematicGroupTo
|
|
55860
57026
|
} from "@tscircuit/circuit-json-util";
|
|
55861
57027
|
import { RootFlexBox as RootFlexBox2 } from "@tscircuit/miniflex";
|
|
55862
|
-
import { length as
|
|
57028
|
+
import { length as length5 } from "circuit-json";
|
|
55863
57029
|
var getSizeOfTreeNodeChild = (db, child) => {
|
|
55864
57030
|
const { sourceComponent, sourceGroup } = child;
|
|
55865
57031
|
if (child.nodeType === "component") {
|
|
@@ -55952,8 +57118,8 @@ var Group_doInitialSchematicLayoutFlex = (group) => {
|
|
|
55952
57118
|
rowGap = rawGap;
|
|
55953
57119
|
columnGap = rawGap;
|
|
55954
57120
|
} else if (typeof rawGap === "string") {
|
|
55955
|
-
rowGap =
|
|
55956
|
-
columnGap =
|
|
57121
|
+
rowGap = length5.parse(rawGap);
|
|
57122
|
+
columnGap = length5.parse(rawGap);
|
|
55957
57123
|
}
|
|
55958
57124
|
let minFlexContainer;
|
|
55959
57125
|
let width = props.width ?? props.schWidth ?? void 0;
|
|
@@ -56047,7 +57213,7 @@ var Group_doInitialSchematicLayoutFlex = (group) => {
|
|
|
56047
57213
|
};
|
|
56048
57214
|
|
|
56049
57215
|
// lib/components/primitive-components/Group/Group_doInitialSchematicLayoutGrid.ts
|
|
56050
|
-
import { length as
|
|
57216
|
+
import { length as length6 } from "circuit-json";
|
|
56051
57217
|
|
|
56052
57218
|
// lib/components/primitive-components/Group/utils/updateSchematicPrimitivesForLayoutShift.ts
|
|
56053
57219
|
function updateSchematicPrimitivesForLayoutShift({
|
|
@@ -56151,7 +57317,7 @@ function Group_doInitialSchematicLayoutGrid(group) {
|
|
|
56151
57317
|
let gridGapY;
|
|
56152
57318
|
const parseGap = (val) => {
|
|
56153
57319
|
if (val === void 0) return void 0;
|
|
56154
|
-
return typeof val === "number" ? val :
|
|
57320
|
+
return typeof val === "number" ? val : length6.parse(val);
|
|
56155
57321
|
};
|
|
56156
57322
|
if (gridRowGapOption !== void 0 || gridColumnGapOption !== void 0) {
|
|
56157
57323
|
const fallbackX = typeof gridGapOption === "object" && gridGapOption !== null ? gridGapOption.x : gridGapOption;
|
|
@@ -56162,14 +57328,14 @@ function Group_doInitialSchematicLayoutGrid(group) {
|
|
|
56162
57328
|
gridGapX = gridGapOption;
|
|
56163
57329
|
gridGapY = gridGapOption;
|
|
56164
57330
|
} else if (typeof gridGapOption === "string") {
|
|
56165
|
-
const parsed =
|
|
57331
|
+
const parsed = length6.parse(gridGapOption);
|
|
56166
57332
|
gridGapX = parsed;
|
|
56167
57333
|
gridGapY = parsed;
|
|
56168
57334
|
} else if (typeof gridGapOption === "object" && gridGapOption !== null) {
|
|
56169
57335
|
const xRaw = gridGapOption.x;
|
|
56170
57336
|
const yRaw = gridGapOption.y;
|
|
56171
|
-
gridGapX = typeof xRaw === "number" ? xRaw :
|
|
56172
|
-
gridGapY = typeof yRaw === "number" ? yRaw :
|
|
57337
|
+
gridGapX = typeof xRaw === "number" ? xRaw : length6.parse(xRaw ?? "0mm");
|
|
57338
|
+
gridGapY = typeof yRaw === "number" ? yRaw : length6.parse(yRaw ?? "0mm");
|
|
56173
57339
|
} else {
|
|
56174
57340
|
gridGapX = 1;
|
|
56175
57341
|
gridGapY = 1;
|
|
@@ -58402,19 +59568,19 @@ import Debug12 from "debug";
|
|
|
58402
59568
|
import { isValidElement as isValidElement2 } from "react";
|
|
58403
59569
|
|
|
58404
59570
|
// lib/components/primitive-components/Group/Group_doInitialSchematicTraceRender/segment-intersection.ts
|
|
58405
|
-
var
|
|
59571
|
+
var cross3 = (ax, ay, bx, by) => {
|
|
58406
59572
|
return ax * by - ay * bx;
|
|
58407
59573
|
};
|
|
58408
59574
|
function segmentIntersection(p1, p2, q1, q2, tol) {
|
|
58409
59575
|
const r = { x: p2.x - p1.x, y: p2.y - p1.y };
|
|
58410
59576
|
const s = { x: q2.x - q1.x, y: q2.y - q1.y };
|
|
58411
|
-
const rxs =
|
|
59577
|
+
const rxs = cross3(r.x, r.y, s.x, s.y);
|
|
58412
59578
|
const q_p = { x: q1.x - p1.x, y: q1.y - p1.y };
|
|
58413
|
-
const q_pxr =
|
|
59579
|
+
const q_pxr = cross3(q_p.x, q_p.y, r.x, r.y);
|
|
58414
59580
|
if (Math.abs(rxs) < tol && Math.abs(q_pxr) < tol) return null;
|
|
58415
59581
|
if (Math.abs(rxs) < tol && Math.abs(q_pxr) >= tol) return null;
|
|
58416
|
-
const t =
|
|
58417
|
-
const u =
|
|
59582
|
+
const t = cross3(q_p.x, q_p.y, s.x, s.y) / rxs;
|
|
59583
|
+
const u = cross3(q_p.x, q_p.y, r.x, r.y) / rxs;
|
|
58418
59584
|
if (t < -tol || t > 1 + tol || u < -tol || u > 1 + tol) return null;
|
|
58419
59585
|
return { x: p1.x + t * r.x, y: p1.y + t * r.y };
|
|
58420
59586
|
}
|
|
@@ -58426,14 +59592,14 @@ function isHorizontalEdge(edge) {
|
|
|
58426
59592
|
const dy = Math.abs(edge.to.y - edge.from.y);
|
|
58427
59593
|
return dx >= dy;
|
|
58428
59594
|
}
|
|
58429
|
-
function
|
|
59595
|
+
function length7(a, b) {
|
|
58430
59596
|
return Math.hypot(b.x - a.x, b.y - a.y);
|
|
58431
59597
|
}
|
|
58432
59598
|
function pointAt(a, b, t) {
|
|
58433
59599
|
return { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t };
|
|
58434
59600
|
}
|
|
58435
59601
|
function paramAlong(a, b, p) {
|
|
58436
|
-
const L =
|
|
59602
|
+
const L = length7(a, b);
|
|
58437
59603
|
if (L < TOL) return 0;
|
|
58438
59604
|
const t = ((p.x - a.x) * (b.x - a.x) + (p.y - a.y) * (b.y - a.y)) / ((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y));
|
|
58439
59605
|
return Math.max(0, Math.min(1, t)) * L;
|
|
@@ -58456,7 +59622,7 @@ function mergeIntervals(intervals, tol = TOL) {
|
|
|
58456
59622
|
return merged;
|
|
58457
59623
|
}
|
|
58458
59624
|
function splitEdgeByCrossings(edge, crossingDistances, crossLen) {
|
|
58459
|
-
const L =
|
|
59625
|
+
const L = length7(edge.from, edge.to);
|
|
58460
59626
|
if (L < TOL || crossingDistances.length === 0) return [edge];
|
|
58461
59627
|
const half = crossLen / 2;
|
|
58462
59628
|
const rawIntervals = crossingDistances.map((d) => ({
|
|
@@ -58508,8 +59674,8 @@ function computeCrossings(traces, opts = {}) {
|
|
|
58508
59674
|
}
|
|
58509
59675
|
const P = segmentIntersection(eA.from, eA.to, eB.from, eB.to, tol);
|
|
58510
59676
|
if (!P) continue;
|
|
58511
|
-
const LA =
|
|
58512
|
-
const LB =
|
|
59677
|
+
const LA = length7(eA.from, eA.to);
|
|
59678
|
+
const LB = length7(eB.from, eB.to);
|
|
58513
59679
|
if (LA < tol || LB < tol) continue;
|
|
58514
59680
|
const dA = paramAlong(eA.from, eA.to, P);
|
|
58515
59681
|
const dB = paramAlong(eB.from, eB.to, P);
|
|
@@ -58607,8 +59773,8 @@ function isParallel(e1, e2, tol = TOL2) {
|
|
|
58607
59773
|
const L1 = Math.hypot(v1.x, v1.y);
|
|
58608
59774
|
const L2 = Math.hypot(v2.x, v2.y);
|
|
58609
59775
|
if (L1 < tol || L2 < tol) return true;
|
|
58610
|
-
const
|
|
58611
|
-
return Math.abs(
|
|
59776
|
+
const cross4 = v1.x * v2.y - v1.y * v2.x;
|
|
59777
|
+
return Math.abs(cross4) <= tol * L1 * L2;
|
|
58612
59778
|
}
|
|
58613
59779
|
function incidentEdgesAtPoint(trace, p, tol = TOL2) {
|
|
58614
59780
|
return trace.edges.filter(
|
|
@@ -58758,7 +59924,7 @@ function isCollinear(a, b, tol = TOL3) {
|
|
|
58758
59924
|
function splitEdgeAroundIntervals(edge, intervals) {
|
|
58759
59925
|
const merged = mergeIntervals(intervals);
|
|
58760
59926
|
if (merged.length === 0) return [edge];
|
|
58761
|
-
const edgeLength =
|
|
59927
|
+
const edgeLength = length7(edge.from, edge.to);
|
|
58762
59928
|
if (edgeLength <= TOL3) return [edge];
|
|
58763
59929
|
const result = [];
|
|
58764
59930
|
let cursor = 0;
|
|
@@ -58792,7 +59958,7 @@ function removeOverlappingSameNetCrossingSegments(traces) {
|
|
|
58792
59958
|
const crossingTrace = traces[crossingTraceIndex];
|
|
58793
59959
|
if (!crossingTrace.connectivity_key) continue;
|
|
58794
59960
|
for (const crossingEdge of crossingTrace.edges) {
|
|
58795
|
-
if (!crossingEdge.is_crossing ||
|
|
59961
|
+
if (!crossingEdge.is_crossing || length7(crossingEdge.from, crossingEdge.to) <= TOL3)
|
|
58796
59962
|
continue;
|
|
58797
59963
|
for (let traceIndex = 0; traceIndex < traces.length; traceIndex++) {
|
|
58798
59964
|
const candidateTrace = traces[traceIndex];
|
|
@@ -58801,7 +59967,7 @@ function removeOverlappingSameNetCrossingSegments(traces) {
|
|
|
58801
59967
|
}
|
|
58802
59968
|
for (let edgeIndex = 0; edgeIndex < candidateTrace.edges.length; edgeIndex++) {
|
|
58803
59969
|
const candidateEdge = candidateTrace.edges[edgeIndex];
|
|
58804
|
-
const candidateLength =
|
|
59970
|
+
const candidateLength = length7(candidateEdge.from, candidateEdge.to);
|
|
58805
59971
|
if (candidateEdge.is_crossing || candidateLength <= TOL3) continue;
|
|
58806
59972
|
if (!isCollinear(candidateEdge, crossingEdge)) continue;
|
|
58807
59973
|
const start = Math.max(
|
|
@@ -61976,6 +63142,7 @@ function Group_getRoutingPhasePlans(group) {
|
|
|
61976
63142
|
for (const plan of plans) {
|
|
61977
63143
|
plan.autorouter = autoroutersByPhaseIndex.get(plan.routingPhaseIndex);
|
|
61978
63144
|
const phaseProps = phasePropsByPhaseIndex.get(plan.routingPhaseIndex);
|
|
63145
|
+
plan.isImplicitRemainingPhase = plan.routingPhaseIndex === null && phaseProps === void 0;
|
|
61979
63146
|
plan.phaseName = phaseProps?.name;
|
|
61980
63147
|
plan.reroute = phaseProps?.reroute;
|
|
61981
63148
|
plan.region = phaseProps?.region;
|
|
@@ -62101,6 +63268,7 @@ function Group_getRoutingPhasePlans(group) {
|
|
|
62101
63268
|
...breakoutPlans,
|
|
62102
63269
|
{
|
|
62103
63270
|
routingPhaseIndex: null,
|
|
63271
|
+
isImplicitRemainingPhase: true,
|
|
62104
63272
|
nets: [...reroutePlan.nets],
|
|
62105
63273
|
traces: [...reroutePlan.traces]
|
|
62106
63274
|
},
|
|
@@ -62114,7 +63282,7 @@ function Group_getRoutingPhasePlans(group) {
|
|
|
62114
63282
|
var package_default = {
|
|
62115
63283
|
name: "@tscircuit/core",
|
|
62116
63284
|
type: "module",
|
|
62117
|
-
version: "0.0.
|
|
63285
|
+
version: "0.0.1915",
|
|
62118
63286
|
types: "dist/index.d.ts",
|
|
62119
63287
|
main: "dist/index.js",
|
|
62120
63288
|
module: "dist/index.js",
|
|
@@ -62148,6 +63316,7 @@ var package_default = {
|
|
|
62148
63316
|
"@tsci/tscircuit.ti": "github:tscircuit/ti#57e314be4b2b06bc546d4def7453e619604d1157",
|
|
62149
63317
|
"@tscircuit/alphabet": "0.0.25",
|
|
62150
63318
|
"@tscircuit/bga-fanout-solver": "github:tscircuit/bga-fanout-solver#247c835cb8d69b65e53891dcf869731079415b39",
|
|
63319
|
+
"@tscircuit/bus-lanes-solver": "github:tscircuit/bus-lanes-solver#0bc8d071241b18a3e7465a878881abe4998f6384",
|
|
62151
63320
|
"@tscircuit/capacity-autorouter": "^0.0.900",
|
|
62152
63321
|
"@tscircuit/checks": "^0.0.192",
|
|
62153
63322
|
"@tscircuit/circuit-json-util": "^0.0.113",
|
|
@@ -62846,7 +64015,7 @@ function getAccumulatedPcbTracesWithStageOutputReplacements({
|
|
|
62846
64015
|
}
|
|
62847
64016
|
|
|
62848
64017
|
// lib/components/primitive-components/Group/get-source-trace-id-for-routed-trace.ts
|
|
62849
|
-
import { distance as
|
|
64018
|
+
import { distance as distance15, pointToSegmentDistance as pointToSegmentDistance3 } from "@tscircuit/math-utils";
|
|
62850
64019
|
import { ConnectivityMap as ConnectivityMap5 } from "circuit-json-to-connectivity-map";
|
|
62851
64020
|
var POINT_EPSILON2 = 1e-6;
|
|
62852
64021
|
function isPointOnWireSegment({
|
|
@@ -62868,7 +64037,7 @@ function isPointInSmtPad({
|
|
|
62868
64037
|
return Math.abs(point6.x - pad.x) <= pad.width / 2 + traceWidth / 2 && Math.abs(point6.y - pad.y) <= pad.height / 2 + traceWidth / 2;
|
|
62869
64038
|
}
|
|
62870
64039
|
if (pad.shape === "circle") {
|
|
62871
|
-
return
|
|
64040
|
+
return distance15(point6, pad) <= pad.radius + traceWidth / 2;
|
|
62872
64041
|
}
|
|
62873
64042
|
return false;
|
|
62874
64043
|
}
|
|
@@ -62877,7 +64046,7 @@ function isPointInPlatedHole({
|
|
|
62877
64046
|
hole,
|
|
62878
64047
|
traceWidth = 0
|
|
62879
64048
|
}) {
|
|
62880
|
-
return
|
|
64049
|
+
return distance15(point6, hole) <= (hole.outer_diameter ?? hole.hole_diameter ?? 0) / 2 + traceWidth / 2;
|
|
62881
64050
|
}
|
|
62882
64051
|
function getEndpointSourcePortIdsFromGeometry(db, trace) {
|
|
62883
64052
|
const sourcePortIds = /* @__PURE__ */ new Set();
|
|
@@ -62890,7 +64059,7 @@ function getEndpointSourcePortIdsFromGeometry(db, trace) {
|
|
|
62890
64059
|
if (!pcbPort.source_port_id) continue;
|
|
62891
64060
|
if (endpoint.layer && pcbPort.layers && !pcbPort.layers.includes(endpoint.layer))
|
|
62892
64061
|
continue;
|
|
62893
|
-
if (
|
|
64062
|
+
if (distance15(endpoint, pcbPort) <= 0.01) {
|
|
62894
64063
|
sourcePortIds.add(pcbPort.source_port_id);
|
|
62895
64064
|
}
|
|
62896
64065
|
}
|
|
@@ -63574,8 +64743,8 @@ var Group5 = class extends NormalComponent3 {
|
|
|
63574
64743
|
const groupProps2 = props;
|
|
63575
64744
|
const hasOutline = groupProps2.outline && groupProps2.outline.length > 0;
|
|
63576
64745
|
const numericOutline = hasOutline ? groupProps2.outline.map((point6) => ({
|
|
63577
|
-
x:
|
|
63578
|
-
y:
|
|
64746
|
+
x: distance16.parse(point6.x),
|
|
64747
|
+
y: distance16.parse(point6.y)
|
|
63579
64748
|
})) : void 0;
|
|
63580
64749
|
const ctx = this.props;
|
|
63581
64750
|
const anchorPosition = this._getGlobalPcbPositionBeforeLayout();
|
|
@@ -63613,8 +64782,8 @@ var Group5 = class extends NormalComponent3 {
|
|
|
63613
64782
|
const hasExplicitPositioning = this._parsedProps.pcbX !== void 0 || this._parsedProps.pcbY !== void 0;
|
|
63614
64783
|
if (hasOutline) {
|
|
63615
64784
|
const numericOutline = props.outline.map((point6) => ({
|
|
63616
|
-
x:
|
|
63617
|
-
y:
|
|
64785
|
+
x: distance16.parse(point6.x),
|
|
64786
|
+
y: distance16.parse(point6.y)
|
|
63618
64787
|
}));
|
|
63619
64788
|
const outlineBounds = getBoundsFromPoints9(numericOutline);
|
|
63620
64789
|
if (!outlineBounds) return;
|
|
@@ -64136,6 +65305,7 @@ var Group5 = class extends NormalComponent3 {
|
|
|
64136
65305
|
};
|
|
64137
65306
|
const fixedFanoutTraceIds = /* @__PURE__ */ new Set();
|
|
64138
65307
|
let previousStageOutputSimpleRouteJson;
|
|
65308
|
+
const skippedRemainingPhases = /* @__PURE__ */ new Set();
|
|
64139
65309
|
for (const [
|
|
64140
65310
|
routingStageIndex,
|
|
64141
65311
|
{
|
|
@@ -64147,6 +65317,7 @@ var Group5 = class extends NormalComponent3 {
|
|
|
64147
65317
|
phaseStageCount
|
|
64148
65318
|
}
|
|
64149
65319
|
] of routingStages.entries()) {
|
|
65320
|
+
if (skippedRemainingPhases.has(routingPhasePlan)) continue;
|
|
64150
65321
|
if (!usesPreviousStageOutput) {
|
|
64151
65322
|
previousStageOutputSimpleRouteJson = void 0;
|
|
64152
65323
|
}
|
|
@@ -64238,16 +65409,31 @@ var Group5 = class extends NormalComponent3 {
|
|
|
64238
65409
|
})
|
|
64239
65410
|
};
|
|
64240
65411
|
}
|
|
64241
|
-
|
|
64242
|
-
simpleRouteJson
|
|
64243
|
-
|
|
64244
|
-
|
|
65412
|
+
if (phaseAutorouterConfig.preset !== "bus_lanes") {
|
|
65413
|
+
simpleRouteJson = withFixedFanoutTraces(
|
|
65414
|
+
simpleRouteJson,
|
|
65415
|
+
fixedFanoutTraceIds
|
|
65416
|
+
);
|
|
65417
|
+
}
|
|
64245
65418
|
simpleRouteJson = Group_applyDrcTolerancesToSimpleRouteJson(
|
|
64246
65419
|
simpleRouteJson,
|
|
64247
65420
|
routingPhasePlan.drcTolerances
|
|
64248
65421
|
);
|
|
64249
65422
|
simpleRouteJson.allowViaInPad = phaseAutorouterConfig.allowViaInPad;
|
|
64250
65423
|
const getPrecomputedRoutingResult = usesPreviousStageOutput ? void 0 : routingPhasePlan.getPrecomputedRoutingResult;
|
|
65424
|
+
const preflightRoutingCheckPolicy = this.getInheritedProperty(
|
|
65425
|
+
"preflightRoutingCheckPolicy"
|
|
65426
|
+
);
|
|
65427
|
+
if (routingPhasePlan.isImplicitRemainingPhase && phaseStageIndex === 0 && this.getInheritedProperty("routeRemaining") === void 0 && (preflightRoutingCheckPolicy === "basic" || preflightRoutingCheckPolicy === "conservative") && simpleRouteJson.connections.length > 50) {
|
|
65428
|
+
skippedRemainingPhases.add(routingPhasePlan);
|
|
65429
|
+
db.pcb_autorouting_error.insert({
|
|
65430
|
+
pcb_error_id: `pcb_autorouting_error_remaining_routes_${this.subcircuit_id}`,
|
|
65431
|
+
subcircuit_id: this.subcircuit_id ?? void 0,
|
|
65432
|
+
error_type: "pcb_autorouting_error",
|
|
65433
|
+
message: `Remaining routes left unrouted (over 50 traces remaining and preflightRoutingCheckPolicy="${preflightRoutingCheckPolicy}"). Set <board routeRemaining={true} /> or create <autoroutingphase /> elements for specific connections in the order you'd like to route them. The autorouter may hang unless you create autorouting phases incrementally.`
|
|
65434
|
+
});
|
|
65435
|
+
continue;
|
|
65436
|
+
}
|
|
64251
65437
|
const simplificationHasNoTraceInput = Boolean(
|
|
64252
65438
|
isTraceSimplificationPhase && simpleRouteJson.traces?.length === 0
|
|
64253
65439
|
);
|
|
@@ -65413,8 +66599,8 @@ var Led_addPolarityFabricationSymbol = (led) => {
|
|
|
65413
66599
|
const a = db.pcb_port.getWhere({ source_port_id: anode.source_port_id });
|
|
65414
66600
|
const k = db.pcb_port.getWhere({ source_port_id: cathode.source_port_id });
|
|
65415
66601
|
if (!a || !k) return;
|
|
65416
|
-
const
|
|
65417
|
-
if (
|
|
66602
|
+
const distance23 = Math.hypot(k.x - a.x, k.y - a.y);
|
|
66603
|
+
if (distance23 < 1e-6) return;
|
|
65418
66604
|
const angle = Math.atan2(k.y - a.y, k.x - a.x);
|
|
65419
66605
|
const frame = compose14(
|
|
65420
66606
|
translate14((a.x + k.x) / 2, (a.y + k.y) / 2),
|
|
@@ -65428,10 +66614,10 @@ var Led_addPolarityFabricationSymbol = (led) => {
|
|
|
65428
66614
|
};
|
|
65429
66615
|
const notes = [];
|
|
65430
66616
|
generatedNotes.set(led, notes);
|
|
65431
|
-
const halfLength = Math.min(
|
|
66617
|
+
const halfLength = Math.min(distance23 * 0.2, 0.4);
|
|
65432
66618
|
const halfHeight = halfLength * 0.75;
|
|
65433
66619
|
const routes = [
|
|
65434
|
-
[point6(-
|
|
66620
|
+
[point6(-distance23 / 2, 0), point6(-halfLength, 0)],
|
|
65435
66621
|
[
|
|
65436
66622
|
point6(-halfLength, -halfHeight),
|
|
65437
66623
|
point6(halfLength, 0),
|
|
@@ -65439,7 +66625,7 @@ var Led_addPolarityFabricationSymbol = (led) => {
|
|
|
65439
66625
|
point6(-halfLength, -halfHeight)
|
|
65440
66626
|
],
|
|
65441
66627
|
[point6(halfLength, -halfHeight), point6(halfLength, halfHeight)],
|
|
65442
|
-
[point6(halfLength, 0), point6(
|
|
66628
|
+
[point6(halfLength, 0), point6(distance23 / 2, 0)]
|
|
65443
66629
|
];
|
|
65444
66630
|
for (const route of routes) {
|
|
65445
66631
|
notes.push(
|
|
@@ -67163,8 +68349,8 @@ import {
|
|
|
67163
68349
|
var EPSILON24 = 1e-9;
|
|
67164
68350
|
var isWireRoutePoint = (routePoint) => routePoint.route_type === "wire";
|
|
67165
68351
|
var isPointOnSegment2 = (p, a, b) => {
|
|
67166
|
-
const
|
|
67167
|
-
if (Math.abs(
|
|
68352
|
+
const cross4 = (p.y - a.y) * (b.x - a.x) - (p.x - a.x) * (b.y - a.y);
|
|
68353
|
+
if (Math.abs(cross4) > EPSILON24) return false;
|
|
67168
68354
|
const dot = (p.x - a.x) * (b.x - a.x) + (p.y - a.y) * (b.y - a.y);
|
|
67169
68355
|
if (dot < -EPSILON24) return false;
|
|
67170
68356
|
const squaredLength = (b.x - a.x) ** 2 + (b.y - a.y) ** 2;
|
|
@@ -67225,8 +68411,8 @@ var isTraceConnectedToSourceNet = (trace, sourceNetId, sourceTraceById) => {
|
|
|
67225
68411
|
var isSegmentFullyInsideCopperPour = (start, end, pour) => {
|
|
67226
68412
|
const dx = end.x - start.x;
|
|
67227
68413
|
const dy = end.y - start.y;
|
|
67228
|
-
const
|
|
67229
|
-
if (
|
|
68414
|
+
const length8 = Math.hypot(dx, dy);
|
|
68415
|
+
if (length8 <= EPSILON24) return false;
|
|
67230
68416
|
const samples = [0, 0.25, 0.5, 0.75, 1];
|
|
67231
68417
|
return samples.every(
|
|
67232
68418
|
(t) => isPointInCopperPour(
|
|
@@ -67694,13 +68880,13 @@ var getPlatedHolePolygon = (pad, componentRotation = 0) => {
|
|
|
67694
68880
|
);
|
|
67695
68881
|
};
|
|
67696
68882
|
var getTraceSegmentPolygon = (start, end, startWidth, endWidth = startWidth) => {
|
|
67697
|
-
const
|
|
68883
|
+
const length8 = Math.hypot(end.x - start.x, end.y - start.y);
|
|
67698
68884
|
const r1 = startWidth / 2;
|
|
67699
68885
|
const r2 = endWidth / 2;
|
|
67700
|
-
if (
|
|
68886
|
+
if (length8 <= Math.abs(r2 - r1))
|
|
67701
68887
|
return circlePolygon(r1 >= r2 ? start : end, Math.max(r1, r2));
|
|
67702
68888
|
const angle = Math.atan2(end.y - start.y, end.x - start.x);
|
|
67703
|
-
const tangent = Math.acos((r1 - r2) /
|
|
68889
|
+
const tangent = Math.acos((r1 - r2) / length8);
|
|
67704
68890
|
const first = new Arc(
|
|
67705
68891
|
new Point(start.x, start.y),
|
|
67706
68892
|
r1,
|
|
@@ -68005,7 +69191,7 @@ var Board_doInitialPcbPlacementDesignRuleChecks = (board) => {
|
|
|
68005
69191
|
|
|
68006
69192
|
// lib/components/normal-components/board-castellated-hole.ts
|
|
68007
69193
|
import {
|
|
68008
|
-
distance as
|
|
69194
|
+
distance as distance17
|
|
68009
69195
|
} from "circuit-json";
|
|
68010
69196
|
var CASTELLATED_HOLE_ENDPOINT_TOLERANCE_MM = 1e-6;
|
|
68011
69197
|
var getConnectionTargets2 = (connectsTo) => {
|
|
@@ -68026,8 +69212,8 @@ var BoardCastellatedHole = class _BoardCastellatedHole extends PlatedHole {
|
|
|
68026
69212
|
constructor(outlinePoint, outlinePointIndex) {
|
|
68027
69213
|
const name = `castellated_hole_${outlinePointIndex + 1}`;
|
|
68028
69214
|
const connectionTargets = getConnectionTargets2(outlinePoint.connectsTo);
|
|
68029
|
-
const holeDiameter =
|
|
68030
|
-
const padDiameter =
|
|
69215
|
+
const holeDiameter = distance17.parse(outlinePoint.holeDiameter);
|
|
69216
|
+
const padDiameter = distance17.parse(outlinePoint.padDiameter);
|
|
68031
69217
|
super({
|
|
68032
69218
|
shape: "circle",
|
|
68033
69219
|
holeDiameter,
|
|
@@ -68871,11 +70057,11 @@ var MountedBoard = class extends Subcircuit {
|
|
|
68871
70057
|
|
|
68872
70058
|
// lib/components/normal-components/Panel.ts
|
|
68873
70059
|
import { panelProps } from "@tscircuit/props";
|
|
68874
|
-
import { distance as
|
|
70060
|
+
import { distance as distance21 } from "circuit-json";
|
|
68875
70061
|
|
|
68876
70062
|
// lib/components/normal-components/Subpanel.ts
|
|
68877
70063
|
import { subpanelProps } from "@tscircuit/props";
|
|
68878
|
-
import { distance as
|
|
70064
|
+
import { distance as distance20 } from "circuit-json";
|
|
68879
70065
|
import { compose as compose17, identity as identity8, translate as translate17 } from "transformation-matrix";
|
|
68880
70066
|
|
|
68881
70067
|
// lib/utils/panels/generate-panel-tabs-and-mouse-bites.ts
|
|
@@ -69139,15 +70325,15 @@ function generatePanelOutlineRoutingCutouts(boards, options) {
|
|
|
69139
70325
|
}
|
|
69140
70326
|
|
|
69141
70327
|
// lib/utils/panels/pack-into-grid.ts
|
|
69142
|
-
import { distance as
|
|
70328
|
+
import { distance as distance19 } from "circuit-json";
|
|
69143
70329
|
|
|
69144
70330
|
// lib/utils/panels/get-board-dimensions-from-props.ts
|
|
69145
70331
|
import { getBoundsFromPoints as getBoundsFromPoints11 } from "@tscircuit/math-utils";
|
|
69146
|
-
import { distance as
|
|
70332
|
+
import { distance as distance18 } from "circuit-json";
|
|
69147
70333
|
var getBoardDimensionsFromProps = (board) => {
|
|
69148
70334
|
const props = board._parsedProps;
|
|
69149
|
-
let width = props.width != null ?
|
|
69150
|
-
let height = props.height != null ?
|
|
70335
|
+
let width = props.width != null ? distance18.parse(props.width) : void 0;
|
|
70336
|
+
let height = props.height != null ? distance18.parse(props.height) : void 0;
|
|
69151
70337
|
if ((width === void 0 || height === void 0) && props.outline?.length) {
|
|
69152
70338
|
const outlineBounds = getBoundsFromPoints11(props.outline);
|
|
69153
70339
|
if (outlineBounds) {
|
|
@@ -69191,8 +70377,8 @@ function packIntoGrid({
|
|
|
69191
70377
|
}
|
|
69192
70378
|
let cols;
|
|
69193
70379
|
let rows;
|
|
69194
|
-
const minCellWidth = cellWidth ?
|
|
69195
|
-
const minCellHeight = cellHeight ?
|
|
70380
|
+
const minCellWidth = cellWidth ? distance19.parse(cellWidth) : 0;
|
|
70381
|
+
const minCellHeight = cellHeight ? distance19.parse(cellHeight) : 0;
|
|
69196
70382
|
if (col !== void 0) {
|
|
69197
70383
|
cols = col;
|
|
69198
70384
|
rows = row ?? Math.ceil(itemsWithDims.length / cols);
|
|
@@ -69291,8 +70477,8 @@ function getItemDimensions(item, db) {
|
|
|
69291
70477
|
const props = subpanel._parsedProps;
|
|
69292
70478
|
if (props.width !== void 0 && props.height !== void 0) {
|
|
69293
70479
|
return {
|
|
69294
|
-
width:
|
|
69295
|
-
height:
|
|
70480
|
+
width: distance19.parse(props.width),
|
|
70481
|
+
height: distance19.parse(props.height)
|
|
69296
70482
|
};
|
|
69297
70483
|
}
|
|
69298
70484
|
const directBoards = subpanel._getDirectBoardChildren();
|
|
@@ -69319,7 +70505,7 @@ function getItemDimensions(item, db) {
|
|
|
69319
70505
|
return getBoardDimensionsFromProps(directBoards[0]);
|
|
69320
70506
|
}
|
|
69321
70507
|
if (subpanel._cachedGridWidth > 0 && subpanel._cachedGridHeight > 0) {
|
|
69322
|
-
const edgePadding =
|
|
70508
|
+
const edgePadding = distance19.parse(props.edgePadding ?? 5);
|
|
69323
70509
|
return {
|
|
69324
70510
|
width: subpanel._cachedGridWidth + edgePadding * 2,
|
|
69325
70511
|
height: subpanel._cachedGridHeight + edgePadding * 2
|
|
@@ -69477,17 +70663,17 @@ var Subpanel = class _Subpanel extends Group5 {
|
|
|
69477
70663
|
edgePaddingTop: edgePaddingTopProp,
|
|
69478
70664
|
edgePaddingBottom: edgePaddingBottomProp
|
|
69479
70665
|
} = this._parsedProps;
|
|
69480
|
-
const edgePadding =
|
|
69481
|
-
const edgePaddingLeft =
|
|
69482
|
-
const edgePaddingRight =
|
|
70666
|
+
const edgePadding = distance20.parse(edgePaddingProp ?? 5);
|
|
70667
|
+
const edgePaddingLeft = distance20.parse(edgePaddingLeftProp ?? edgePadding);
|
|
70668
|
+
const edgePaddingRight = distance20.parse(
|
|
69483
70669
|
edgePaddingRightProp ?? edgePadding
|
|
69484
70670
|
);
|
|
69485
|
-
const edgePaddingTop =
|
|
69486
|
-
const edgePaddingBottom =
|
|
70671
|
+
const edgePaddingTop = distance20.parse(edgePaddingTopProp ?? edgePadding);
|
|
70672
|
+
const edgePaddingBottom = distance20.parse(
|
|
69487
70673
|
edgePaddingBottomProp ?? edgePadding
|
|
69488
70674
|
);
|
|
69489
|
-
const panelWidth =
|
|
69490
|
-
const panelHeight =
|
|
70675
|
+
const panelWidth = distance20.parse(this._parsedProps.width);
|
|
70676
|
+
const panelHeight = distance20.parse(this._parsedProps.height);
|
|
69491
70677
|
availablePanelWidth = panelWidth - edgePaddingLeft - edgePaddingRight;
|
|
69492
70678
|
availablePanelHeight = panelHeight - edgePaddingTop - edgePaddingBottom;
|
|
69493
70679
|
}
|
|
@@ -69562,8 +70748,8 @@ var Subpanel = class _Subpanel extends Group5 {
|
|
|
69562
70748
|
if (!this.pcb_group_id) return;
|
|
69563
70749
|
if (hasExplicitWidth && hasExplicitHeight) {
|
|
69564
70750
|
db.pcb_group.update(this.pcb_group_id, {
|
|
69565
|
-
width:
|
|
69566
|
-
height:
|
|
70751
|
+
width: distance20.parse(this._parsedProps.width),
|
|
70752
|
+
height: distance20.parse(this._parsedProps.height)
|
|
69567
70753
|
});
|
|
69568
70754
|
} else if (gridWidth > 0 || gridHeight > 0) {
|
|
69569
70755
|
const {
|
|
@@ -69573,18 +70759,18 @@ var Subpanel = class _Subpanel extends Group5 {
|
|
|
69573
70759
|
edgePaddingTop: edgePaddingTopProp,
|
|
69574
70760
|
edgePaddingBottom: edgePaddingBottomProp
|
|
69575
70761
|
} = this._parsedProps;
|
|
69576
|
-
const edgePadding =
|
|
69577
|
-
const edgePaddingLeft =
|
|
69578
|
-
const edgePaddingRight =
|
|
70762
|
+
const edgePadding = distance20.parse(edgePaddingProp ?? 5);
|
|
70763
|
+
const edgePaddingLeft = distance20.parse(edgePaddingLeftProp ?? edgePadding);
|
|
70764
|
+
const edgePaddingRight = distance20.parse(
|
|
69579
70765
|
edgePaddingRightProp ?? edgePadding
|
|
69580
70766
|
);
|
|
69581
|
-
const edgePaddingTop =
|
|
69582
|
-
const edgePaddingBottom =
|
|
70767
|
+
const edgePaddingTop = distance20.parse(edgePaddingTopProp ?? edgePadding);
|
|
70768
|
+
const edgePaddingBottom = distance20.parse(
|
|
69583
70769
|
edgePaddingBottomProp ?? edgePadding
|
|
69584
70770
|
);
|
|
69585
70771
|
db.pcb_group.update(this.pcb_group_id, {
|
|
69586
|
-
width: hasExplicitWidth ?
|
|
69587
|
-
height: hasExplicitHeight ?
|
|
70772
|
+
width: hasExplicitWidth ? distance20.parse(this._parsedProps.width) : gridWidth + edgePaddingLeft + edgePaddingRight,
|
|
70773
|
+
height: hasExplicitHeight ? distance20.parse(this._parsedProps.height) : gridHeight + edgePaddingTop + edgePaddingBottom
|
|
69588
70774
|
});
|
|
69589
70775
|
}
|
|
69590
70776
|
}
|
|
@@ -69672,8 +70858,8 @@ var Panel = class extends Subpanel {
|
|
|
69672
70858
|
const { db } = this.root;
|
|
69673
70859
|
const props = this._parsedProps;
|
|
69674
70860
|
const inserted = db.pcb_panel.insert({
|
|
69675
|
-
width: props.width !== void 0 ?
|
|
69676
|
-
height: props.height !== void 0 ?
|
|
70861
|
+
width: props.width !== void 0 ? distance21.parse(props.width) : 0,
|
|
70862
|
+
height: props.height !== void 0 ? distance21.parse(props.height) : 0,
|
|
69677
70863
|
thickness: 1.6,
|
|
69678
70864
|
center: this._getGlobalPcbPositionBeforeLayout(),
|
|
69679
70865
|
covered_with_solder_mask: !(props.noSolderMask ?? false)
|
|
@@ -69692,8 +70878,8 @@ var Panel = class extends Subpanel {
|
|
|
69692
70878
|
if (!this.pcb_panel_id) return;
|
|
69693
70879
|
if (hasExplicitWidth && hasExplicitHeight) {
|
|
69694
70880
|
db.pcb_panel.update(this.pcb_panel_id, {
|
|
69695
|
-
width:
|
|
69696
|
-
height:
|
|
70881
|
+
width: distance21.parse(this._parsedProps.width),
|
|
70882
|
+
height: distance21.parse(this._parsedProps.height)
|
|
69697
70883
|
});
|
|
69698
70884
|
} else if (gridWidth > 0 || gridHeight > 0) {
|
|
69699
70885
|
const {
|
|
@@ -69703,18 +70889,18 @@ var Panel = class extends Subpanel {
|
|
|
69703
70889
|
edgePaddingTop: edgePaddingTopProp,
|
|
69704
70890
|
edgePaddingBottom: edgePaddingBottomProp
|
|
69705
70891
|
} = this._parsedProps;
|
|
69706
|
-
const edgePadding =
|
|
69707
|
-
const edgePaddingLeft =
|
|
69708
|
-
const edgePaddingRight =
|
|
70892
|
+
const edgePadding = distance21.parse(edgePaddingProp ?? 5);
|
|
70893
|
+
const edgePaddingLeft = distance21.parse(edgePaddingLeftProp ?? edgePadding);
|
|
70894
|
+
const edgePaddingRight = distance21.parse(
|
|
69709
70895
|
edgePaddingRightProp ?? edgePadding
|
|
69710
70896
|
);
|
|
69711
|
-
const edgePaddingTop =
|
|
69712
|
-
const edgePaddingBottom =
|
|
70897
|
+
const edgePaddingTop = distance21.parse(edgePaddingTopProp ?? edgePadding);
|
|
70898
|
+
const edgePaddingBottom = distance21.parse(
|
|
69713
70899
|
edgePaddingBottomProp ?? edgePadding
|
|
69714
70900
|
);
|
|
69715
70901
|
db.pcb_panel.update(this.pcb_panel_id, {
|
|
69716
|
-
width: hasExplicitWidth ?
|
|
69717
|
-
height: hasExplicitHeight ?
|
|
70902
|
+
width: hasExplicitWidth ? distance21.parse(this._parsedProps.width) : gridWidth + edgePaddingLeft + edgePaddingRight,
|
|
70903
|
+
height: hasExplicitHeight ? distance21.parse(this._parsedProps.height) : gridHeight + edgePaddingTop + edgePaddingBottom
|
|
69718
70904
|
});
|
|
69719
70905
|
}
|
|
69720
70906
|
}
|
|
@@ -69725,8 +70911,8 @@ var Panel = class extends Subpanel {
|
|
|
69725
70911
|
const props = this._parsedProps;
|
|
69726
70912
|
const currentPanel = db.pcb_panel.get(this.pcb_panel_id);
|
|
69727
70913
|
db.pcb_panel.update(this.pcb_panel_id, {
|
|
69728
|
-
width: props.width !== void 0 ?
|
|
69729
|
-
height: props.height !== void 0 ?
|
|
70914
|
+
width: props.width !== void 0 ? distance21.parse(props.width) : currentPanel?.width,
|
|
70915
|
+
height: props.height !== void 0 ? distance21.parse(props.height) : currentPanel?.height,
|
|
69730
70916
|
center: this._getGlobalPcbPositionBeforeLayout(),
|
|
69731
70917
|
covered_with_solder_mask: !(props.noSolderMask ?? false)
|
|
69732
70918
|
});
|
|
@@ -72032,7 +73218,7 @@ var validateWindingBreakoutInput = (input) => {
|
|
|
72032
73218
|
};
|
|
72033
73219
|
|
|
72034
73220
|
// node_modules/@tscircuit/winding-breakout-point-solver/lib/solvers/GatePlacementSolver.ts
|
|
72035
|
-
import { BaseSolver as
|
|
73221
|
+
import { BaseSolver as BaseSolver7 } from "@tscircuit/solver-utils";
|
|
72036
73222
|
|
|
72037
73223
|
// node_modules/@tscircuit/winding-breakout-point-solver/lib/gate-placement/place-breakout-gates.ts
|
|
72038
73224
|
var GEOMETRY_EPSILON = 1e-9;
|
|
@@ -72562,7 +73748,7 @@ var getSharedGateSlotCount = (points) => new Set(
|
|
|
72562
73748
|
(point6) => `${point6.regionId}:${point6.x.toFixed(9)}:${point6.y.toFixed(9)}`
|
|
72563
73749
|
)
|
|
72564
73750
|
).size;
|
|
72565
|
-
var GatePlacementSolver = class extends
|
|
73751
|
+
var GatePlacementSolver = class extends BaseSolver7 {
|
|
72566
73752
|
constructor(params) {
|
|
72567
73753
|
super();
|
|
72568
73754
|
this.params = params;
|
|
@@ -72701,7 +73887,7 @@ var GatePlacementSolver = class extends BaseSolver6 {
|
|
|
72701
73887
|
};
|
|
72702
73888
|
|
|
72703
73889
|
// node_modules/@tscircuit/winding-breakout-point-solver/lib/solvers/ReferenceOrderingSolver.ts
|
|
72704
|
-
import { BaseSolver as
|
|
73890
|
+
import { BaseSolver as BaseSolver8 } from "@tscircuit/solver-utils";
|
|
72705
73891
|
|
|
72706
73892
|
// node_modules/@tscircuit/winding-breakout-point-solver/lib/ordering/get-natural-winding-order.ts
|
|
72707
73893
|
var getNaturalWindingOrder = (region, connections) => connections.map((connection) => {
|
|
@@ -72768,7 +73954,7 @@ var getReferenceWindingOrder = (naturalOrder, atomicGroups, buses) => {
|
|
|
72768
73954
|
};
|
|
72769
73955
|
|
|
72770
73956
|
// node_modules/@tscircuit/winding-breakout-point-solver/lib/solvers/ReferenceOrderingSolver.ts
|
|
72771
|
-
var ReferenceOrderingSolver = class extends
|
|
73957
|
+
var ReferenceOrderingSolver = class extends BaseSolver8 {
|
|
72772
73958
|
constructor(params) {
|
|
72773
73959
|
super();
|
|
72774
73960
|
this.params = params;
|
|
@@ -74113,7 +75299,7 @@ var SilkscreenGraphic = class extends PrimitiveComponent2 {
|
|
|
74113
75299
|
|
|
74114
75300
|
// lib/components/primitive-components/Fiducial.ts
|
|
74115
75301
|
import "zod";
|
|
74116
|
-
import { distance as
|
|
75302
|
+
import { distance as distance22 } from "circuit-json";
|
|
74117
75303
|
import { fiducialProps as fiducialProps2 } from "@tscircuit/props";
|
|
74118
75304
|
var Fiducial = class extends PrimitiveComponent2 {
|
|
74119
75305
|
pcb_smtpad_id = null;
|
|
@@ -74138,15 +75324,15 @@ var Fiducial = class extends PrimitiveComponent2 {
|
|
|
74138
75324
|
shape: "circle",
|
|
74139
75325
|
x: position.x,
|
|
74140
75326
|
y: position.y,
|
|
74141
|
-
radius:
|
|
74142
|
-
soldermask_margin: props.soldermaskPullback ?
|
|
75327
|
+
radius: distance22.parse(props.padDiameter) / 2,
|
|
75328
|
+
soldermask_margin: props.soldermaskPullback ? distance22.parse(props.soldermaskPullback) : distance22.parse(props.padDiameter) / 2,
|
|
74143
75329
|
is_covered_with_solder_mask: true
|
|
74144
75330
|
});
|
|
74145
75331
|
this.pcb_smtpad_id = pcb_smtpad.pcb_smtpad_id;
|
|
74146
75332
|
}
|
|
74147
75333
|
getPcbSize() {
|
|
74148
75334
|
const { _parsedProps: props } = this;
|
|
74149
|
-
const d =
|
|
75335
|
+
const d = distance22.parse(props.padDiameter);
|
|
74150
75336
|
return { width: d, height: d };
|
|
74151
75337
|
}
|
|
74152
75338
|
_setPositionFromLayout(newCenter) {
|