@tscircuit/core 0.0.1281 → 0.0.1282
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +734 -8
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3843,7 +3843,7 @@ var Trace_doInitialSchematicTraceRender = (trace) => {
|
|
|
3843
3843
|
elbowEdges.push({ from: path[j], to: path[j + 1] });
|
|
3844
3844
|
}
|
|
3845
3845
|
}
|
|
3846
|
-
const
|
|
3846
|
+
const doesSegmentIntersectRect2 = (edge, rect) => {
|
|
3847
3847
|
const halfW = rect.width / 2;
|
|
3848
3848
|
const halfH = rect.height / 2;
|
|
3849
3849
|
const left = rect.center.x - halfW;
|
|
@@ -3876,7 +3876,7 @@ var Trace_doInitialSchematicTraceRender = (trace) => {
|
|
|
3876
3876
|
};
|
|
3877
3877
|
for (const edge of elbowEdges) {
|
|
3878
3878
|
for (const obstacle of obstacles) {
|
|
3879
|
-
if (
|
|
3879
|
+
if (doesSegmentIntersectRect2(edge, obstacle)) {
|
|
3880
3880
|
return null;
|
|
3881
3881
|
}
|
|
3882
3882
|
}
|
|
@@ -21867,7 +21867,7 @@ import { identity as identity5 } from "transformation-matrix";
|
|
|
21867
21867
|
var package_default = {
|
|
21868
21868
|
name: "@tscircuit/core",
|
|
21869
21869
|
type: "module",
|
|
21870
|
-
version: "0.0.
|
|
21870
|
+
version: "0.0.1281",
|
|
21871
21871
|
types: "dist/index.d.ts",
|
|
21872
21872
|
main: "dist/index.js",
|
|
21873
21873
|
module: "dist/index.js",
|
|
@@ -24866,7 +24866,733 @@ var PcbNoteDimension = class extends PrimitiveComponent2 {
|
|
|
24866
24866
|
|
|
24867
24867
|
// lib/components/primitive-components/Breakout/Breakout.ts
|
|
24868
24868
|
import "@tscircuit/props";
|
|
24869
|
-
|
|
24869
|
+
|
|
24870
|
+
// node_modules/@tscircuit/breakout-point-solver/lib/BreakoutPointSolver.ts
|
|
24871
|
+
import { BaseSolver } from "@tscircuit/solver-utils";
|
|
24872
|
+
|
|
24873
|
+
// node_modules/@tscircuit/breakout-point-solver/lib/boundary/get-breakout-boundary-intersection.ts
|
|
24874
|
+
import {
|
|
24875
|
+
distance as distance14,
|
|
24876
|
+
getSegmentIntersection
|
|
24877
|
+
} from "@tscircuit/math-utils";
|
|
24878
|
+
var getBreakoutBoundaryIntersection = ({
|
|
24879
|
+
from,
|
|
24880
|
+
to,
|
|
24881
|
+
bounds
|
|
24882
|
+
}) => {
|
|
24883
|
+
if (from.x === to.x && from.y === to.y) return null;
|
|
24884
|
+
const boundarySegments = [
|
|
24885
|
+
[
|
|
24886
|
+
{ x: bounds.minX, y: bounds.minY },
|
|
24887
|
+
{ x: bounds.maxX, y: bounds.minY }
|
|
24888
|
+
],
|
|
24889
|
+
[
|
|
24890
|
+
{ x: bounds.maxX, y: bounds.minY },
|
|
24891
|
+
{ x: bounds.maxX, y: bounds.maxY }
|
|
24892
|
+
],
|
|
24893
|
+
[
|
|
24894
|
+
{ x: bounds.maxX, y: bounds.maxY },
|
|
24895
|
+
{ x: bounds.minX, y: bounds.maxY }
|
|
24896
|
+
],
|
|
24897
|
+
[
|
|
24898
|
+
{ x: bounds.minX, y: bounds.maxY },
|
|
24899
|
+
{ x: bounds.minX, y: bounds.minY }
|
|
24900
|
+
]
|
|
24901
|
+
];
|
|
24902
|
+
const candidates = boundarySegments.map(([start, end]) => getSegmentIntersection(from, to, start, end)).filter((point6) => point6 !== null);
|
|
24903
|
+
candidates.sort((a, b) => distance14(from, a) - distance14(from, b));
|
|
24904
|
+
return candidates[0] ?? null;
|
|
24905
|
+
};
|
|
24906
|
+
|
|
24907
|
+
// node_modules/@tscircuit/breakout-point-solver/lib/boundary/get-available-breakout-boundary-point.ts
|
|
24908
|
+
import { distance as distance15 } from "@tscircuit/math-utils";
|
|
24909
|
+
|
|
24910
|
+
// node_modules/@tscircuit/breakout-point-solver/lib/pad/breakout-pad-collisions.ts
|
|
24911
|
+
import {
|
|
24912
|
+
doesSegmentIntersectRect,
|
|
24913
|
+
getBoundFromCenteredRect
|
|
24914
|
+
} from "@tscircuit/math-utils";
|
|
24915
|
+
var degreesToRadians = (degrees) => degrees * Math.PI / 180;
|
|
24916
|
+
var rotatePoint = (point6, radians) => {
|
|
24917
|
+
const cos = Math.cos(radians);
|
|
24918
|
+
const sin = Math.sin(radians);
|
|
24919
|
+
return {
|
|
24920
|
+
x: point6.x * cos - point6.y * sin,
|
|
24921
|
+
y: point6.x * sin + point6.y * cos
|
|
24922
|
+
};
|
|
24923
|
+
};
|
|
24924
|
+
var getLocalPadPoint = (point6, pad) => {
|
|
24925
|
+
const translatedPoint = {
|
|
24926
|
+
x: point6.x - pad.center.x,
|
|
24927
|
+
y: point6.y - pad.center.y
|
|
24928
|
+
};
|
|
24929
|
+
return rotatePoint(
|
|
24930
|
+
translatedPoint,
|
|
24931
|
+
-degreesToRadians(pad.ccwRotationDegrees ?? 0)
|
|
24932
|
+
);
|
|
24933
|
+
};
|
|
24934
|
+
var getInflatedPadRect = (pad) => {
|
|
24935
|
+
const clearance = pad.clearance ?? 0;
|
|
24936
|
+
return getBoundFromCenteredRect({
|
|
24937
|
+
center: { x: 0, y: 0 },
|
|
24938
|
+
width: pad.width + clearance * 2,
|
|
24939
|
+
height: pad.height + clearance * 2
|
|
24940
|
+
});
|
|
24941
|
+
};
|
|
24942
|
+
var isBreakoutPadIgnoredForSourcePort = ({
|
|
24943
|
+
pad,
|
|
24944
|
+
sourcePortId
|
|
24945
|
+
}) => {
|
|
24946
|
+
if (!pad.sourcePortIds) return false;
|
|
24947
|
+
return pad.sourcePortIds.includes(sourcePortId);
|
|
24948
|
+
};
|
|
24949
|
+
var isBreakoutPadIgnoredForLayer = ({
|
|
24950
|
+
pad,
|
|
24951
|
+
layer
|
|
24952
|
+
}) => {
|
|
24953
|
+
if (!pad.layer || !layer) return false;
|
|
24954
|
+
return pad.layer !== layer;
|
|
24955
|
+
};
|
|
24956
|
+
var doesBreakoutSegmentIntersectPad = ({
|
|
24957
|
+
from,
|
|
24958
|
+
to,
|
|
24959
|
+
pad
|
|
24960
|
+
}) => doesSegmentIntersectRect(
|
|
24961
|
+
getLocalPadPoint(from, pad),
|
|
24962
|
+
getLocalPadPoint(to, pad),
|
|
24963
|
+
getInflatedPadRect(pad)
|
|
24964
|
+
);
|
|
24965
|
+
var doesBreakoutSegmentIntersectNonIgnoredPads = ({
|
|
24966
|
+
from,
|
|
24967
|
+
to,
|
|
24968
|
+
pads,
|
|
24969
|
+
ignoredSourcePortIds,
|
|
24970
|
+
layer
|
|
24971
|
+
}) => {
|
|
24972
|
+
for (const pad of pads) {
|
|
24973
|
+
if (ignoredSourcePortIds.some(
|
|
24974
|
+
(sourcePortId) => isBreakoutPadIgnoredForSourcePort({
|
|
24975
|
+
pad,
|
|
24976
|
+
sourcePortId
|
|
24977
|
+
})
|
|
24978
|
+
) || isBreakoutPadIgnoredForLayer({
|
|
24979
|
+
pad,
|
|
24980
|
+
layer
|
|
24981
|
+
})) {
|
|
24982
|
+
continue;
|
|
24983
|
+
}
|
|
24984
|
+
if (doesBreakoutSegmentIntersectPad({ from, to, pad })) {
|
|
24985
|
+
return true;
|
|
24986
|
+
}
|
|
24987
|
+
}
|
|
24988
|
+
return false;
|
|
24989
|
+
};
|
|
24990
|
+
var doesBreakoutSegmentIntersectPads = ({
|
|
24991
|
+
from,
|
|
24992
|
+
to,
|
|
24993
|
+
pads,
|
|
24994
|
+
sourcePortId,
|
|
24995
|
+
layer
|
|
24996
|
+
}) => doesBreakoutSegmentIntersectNonIgnoredPads({
|
|
24997
|
+
from,
|
|
24998
|
+
to,
|
|
24999
|
+
pads,
|
|
25000
|
+
ignoredSourcePortIds: [sourcePortId],
|
|
25001
|
+
layer
|
|
25002
|
+
});
|
|
25003
|
+
|
|
25004
|
+
// node_modules/@tscircuit/breakout-point-solver/lib/boundary/get-available-breakout-boundary-point.ts
|
|
25005
|
+
var BOUNDARY_POINT_DISTANCE_TOLERANCE = 1e-6;
|
|
25006
|
+
var isInsideRequiredSpacing = ({
|
|
25007
|
+
candidate,
|
|
25008
|
+
usedPoint,
|
|
25009
|
+
boundaryPointSpacing
|
|
25010
|
+
}) => distance15(usedPoint, candidate) < boundaryPointSpacing - BOUNDARY_POINT_DISTANCE_TOLERANCE;
|
|
25011
|
+
var getBoundsEdge = (point6, bounds) => {
|
|
25012
|
+
if (Math.abs(point6.x - bounds.minX) < BOUNDARY_POINT_DISTANCE_TOLERANCE)
|
|
25013
|
+
return "left";
|
|
25014
|
+
if (Math.abs(point6.x - bounds.maxX) < BOUNDARY_POINT_DISTANCE_TOLERANCE)
|
|
25015
|
+
return "right";
|
|
25016
|
+
if (Math.abs(point6.y - bounds.minY) < BOUNDARY_POINT_DISTANCE_TOLERANCE)
|
|
25017
|
+
return "bottom";
|
|
25018
|
+
if (Math.abs(point6.y - bounds.maxY) < BOUNDARY_POINT_DISTANCE_TOLERANCE)
|
|
25019
|
+
return "top";
|
|
25020
|
+
return null;
|
|
25021
|
+
};
|
|
25022
|
+
var getBoundsEdgeCandidates = ({
|
|
25023
|
+
edge,
|
|
25024
|
+
bounds,
|
|
25025
|
+
step
|
|
25026
|
+
}) => {
|
|
25027
|
+
const candidates = [];
|
|
25028
|
+
if (edge === "left" || edge === "right") {
|
|
25029
|
+
const x = edge === "left" ? bounds.minX : bounds.maxX;
|
|
25030
|
+
for (let y = bounds.minY; y <= bounds.maxY + step / 2; y += step) {
|
|
25031
|
+
candidates.push({ x, y: Math.min(y, bounds.maxY) });
|
|
25032
|
+
}
|
|
25033
|
+
} else {
|
|
25034
|
+
const y = edge === "bottom" ? bounds.minY : bounds.maxY;
|
|
25035
|
+
for (let x = bounds.minX; x <= bounds.maxX + step / 2; x += step) {
|
|
25036
|
+
candidates.push({ x: Math.min(x, bounds.maxX), y });
|
|
25037
|
+
}
|
|
25038
|
+
}
|
|
25039
|
+
return candidates;
|
|
25040
|
+
};
|
|
25041
|
+
var getAllBoundsCandidates = ({
|
|
25042
|
+
bounds,
|
|
25043
|
+
step
|
|
25044
|
+
}) => {
|
|
25045
|
+
const candidatesByCoordinate = /* @__PURE__ */ new Map();
|
|
25046
|
+
for (const edge of ["left", "right", "bottom", "top"]) {
|
|
25047
|
+
for (const candidate of getBoundsEdgeCandidates({ edge, bounds, step })) {
|
|
25048
|
+
candidatesByCoordinate.set(`${candidate.x}:${candidate.y}`, candidate);
|
|
25049
|
+
}
|
|
25050
|
+
}
|
|
25051
|
+
return [...candidatesByCoordinate.values()];
|
|
25052
|
+
};
|
|
25053
|
+
var getBoundaryCandidateSearchStep = ({
|
|
25054
|
+
bounds,
|
|
25055
|
+
boundaryPointSpacing
|
|
25056
|
+
}) => {
|
|
25057
|
+
if (boundaryPointSpacing > 0) return boundaryPointSpacing;
|
|
25058
|
+
return Math.min(bounds.maxX - bounds.minX, bounds.maxY - bounds.minY) / 40;
|
|
25059
|
+
};
|
|
25060
|
+
var hasBoundarySpacingConflict = ({
|
|
25061
|
+
candidate,
|
|
25062
|
+
usedBoundaryPoints,
|
|
25063
|
+
boundaryPointSpacing
|
|
25064
|
+
}) => {
|
|
25065
|
+
for (const usedPoint of usedBoundaryPoints) {
|
|
25066
|
+
if (isInsideRequiredSpacing({
|
|
25067
|
+
candidate,
|
|
25068
|
+
usedPoint,
|
|
25069
|
+
boundaryPointSpacing
|
|
25070
|
+
})) {
|
|
25071
|
+
return true;
|
|
25072
|
+
}
|
|
25073
|
+
}
|
|
25074
|
+
return false;
|
|
25075
|
+
};
|
|
25076
|
+
var isBoundaryCandidateBlocked = ({
|
|
25077
|
+
candidate,
|
|
25078
|
+
routeFrom,
|
|
25079
|
+
pads,
|
|
25080
|
+
sourcePortId,
|
|
25081
|
+
layer
|
|
25082
|
+
}) => {
|
|
25083
|
+
if (!routeFrom || !pads || !sourcePortId) return false;
|
|
25084
|
+
return doesBreakoutSegmentIntersectPads({
|
|
25085
|
+
from: routeFrom,
|
|
25086
|
+
to: candidate,
|
|
25087
|
+
pads,
|
|
25088
|
+
sourcePortId,
|
|
25089
|
+
layer
|
|
25090
|
+
});
|
|
25091
|
+
};
|
|
25092
|
+
var isCandidateAvailable = ({
|
|
25093
|
+
candidate,
|
|
25094
|
+
usedBoundaryPoints,
|
|
25095
|
+
boundaryPointSpacing,
|
|
25096
|
+
routeFrom,
|
|
25097
|
+
pads,
|
|
25098
|
+
sourcePortId,
|
|
25099
|
+
layer
|
|
25100
|
+
}) => {
|
|
25101
|
+
if (hasBoundarySpacingConflict({
|
|
25102
|
+
candidate,
|
|
25103
|
+
usedBoundaryPoints,
|
|
25104
|
+
boundaryPointSpacing
|
|
25105
|
+
})) {
|
|
25106
|
+
return false;
|
|
25107
|
+
}
|
|
25108
|
+
return !isBoundaryCandidateBlocked({
|
|
25109
|
+
candidate,
|
|
25110
|
+
routeFrom,
|
|
25111
|
+
pads,
|
|
25112
|
+
sourcePortId,
|
|
25113
|
+
layer
|
|
25114
|
+
});
|
|
25115
|
+
};
|
|
25116
|
+
var hasOutsideAccessConflict = ({
|
|
25117
|
+
candidate,
|
|
25118
|
+
outsidePorts,
|
|
25119
|
+
pads,
|
|
25120
|
+
sourcePortId,
|
|
25121
|
+
layer
|
|
25122
|
+
}) => {
|
|
25123
|
+
if (!outsidePorts || !pads || !sourcePortId) return false;
|
|
25124
|
+
for (const outsidePort of outsidePorts) {
|
|
25125
|
+
if (doesBreakoutSegmentIntersectNonIgnoredPads({
|
|
25126
|
+
from: candidate,
|
|
25127
|
+
to: outsidePort.position,
|
|
25128
|
+
pads,
|
|
25129
|
+
ignoredSourcePortIds: [sourcePortId, outsidePort.sourcePortId],
|
|
25130
|
+
layer
|
|
25131
|
+
})) {
|
|
25132
|
+
return true;
|
|
25133
|
+
}
|
|
25134
|
+
}
|
|
25135
|
+
return false;
|
|
25136
|
+
};
|
|
25137
|
+
var isCandidateAvailableForOutsidePorts = ({
|
|
25138
|
+
candidate,
|
|
25139
|
+
bounds,
|
|
25140
|
+
usedBoundaryPoints,
|
|
25141
|
+
boundaryPointSpacing,
|
|
25142
|
+
routeFrom,
|
|
25143
|
+
pads,
|
|
25144
|
+
sourcePortId,
|
|
25145
|
+
outsidePorts,
|
|
25146
|
+
layer
|
|
25147
|
+
}) => {
|
|
25148
|
+
if (!isCandidateAvailable({
|
|
25149
|
+
candidate,
|
|
25150
|
+
usedBoundaryPoints,
|
|
25151
|
+
boundaryPointSpacing,
|
|
25152
|
+
routeFrom,
|
|
25153
|
+
pads,
|
|
25154
|
+
sourcePortId,
|
|
25155
|
+
layer
|
|
25156
|
+
})) {
|
|
25157
|
+
return false;
|
|
25158
|
+
}
|
|
25159
|
+
return !hasOutsideAccessConflict({
|
|
25160
|
+
candidate,
|
|
25161
|
+
outsidePorts,
|
|
25162
|
+
pads,
|
|
25163
|
+
sourcePortId,
|
|
25164
|
+
layer
|
|
25165
|
+
});
|
|
25166
|
+
};
|
|
25167
|
+
var getAvailableBreakoutBoundaryPoint = ({
|
|
25168
|
+
idealPoint,
|
|
25169
|
+
bounds,
|
|
25170
|
+
usedBoundaryPoints,
|
|
25171
|
+
boundaryPointSpacing,
|
|
25172
|
+
routeFrom,
|
|
25173
|
+
pads,
|
|
25174
|
+
sourcePortId,
|
|
25175
|
+
layer
|
|
25176
|
+
}) => {
|
|
25177
|
+
if (isCandidateAvailable({
|
|
25178
|
+
candidate: idealPoint,
|
|
25179
|
+
usedBoundaryPoints,
|
|
25180
|
+
boundaryPointSpacing,
|
|
25181
|
+
routeFrom,
|
|
25182
|
+
pads,
|
|
25183
|
+
sourcePortId,
|
|
25184
|
+
layer
|
|
25185
|
+
})) {
|
|
25186
|
+
return idealPoint;
|
|
25187
|
+
}
|
|
25188
|
+
const edge = getBoundsEdge(idealPoint, bounds);
|
|
25189
|
+
if (!edge) return null;
|
|
25190
|
+
const step = getBoundaryCandidateSearchStep({
|
|
25191
|
+
bounds,
|
|
25192
|
+
boundaryPointSpacing
|
|
25193
|
+
});
|
|
25194
|
+
if (step <= 0) return null;
|
|
25195
|
+
const edgeCandidates = getBoundsEdgeCandidates({
|
|
25196
|
+
edge,
|
|
25197
|
+
bounds,
|
|
25198
|
+
step
|
|
25199
|
+
});
|
|
25200
|
+
edgeCandidates.sort(
|
|
25201
|
+
(a, b) => distance15(a, idealPoint) - distance15(b, idealPoint)
|
|
25202
|
+
);
|
|
25203
|
+
for (const candidate of edgeCandidates) {
|
|
25204
|
+
if (isCandidateAvailable({
|
|
25205
|
+
candidate,
|
|
25206
|
+
usedBoundaryPoints,
|
|
25207
|
+
boundaryPointSpacing,
|
|
25208
|
+
routeFrom,
|
|
25209
|
+
pads,
|
|
25210
|
+
sourcePortId,
|
|
25211
|
+
layer
|
|
25212
|
+
})) {
|
|
25213
|
+
return candidate;
|
|
25214
|
+
}
|
|
25215
|
+
}
|
|
25216
|
+
const candidates = getAllBoundsCandidates({ bounds, step });
|
|
25217
|
+
candidates.sort((a, b) => distance15(a, idealPoint) - distance15(b, idealPoint));
|
|
25218
|
+
for (const candidate of candidates) {
|
|
25219
|
+
if (isCandidateAvailable({
|
|
25220
|
+
candidate,
|
|
25221
|
+
usedBoundaryPoints,
|
|
25222
|
+
boundaryPointSpacing,
|
|
25223
|
+
routeFrom,
|
|
25224
|
+
pads,
|
|
25225
|
+
sourcePortId,
|
|
25226
|
+
layer
|
|
25227
|
+
})) {
|
|
25228
|
+
return candidate;
|
|
25229
|
+
}
|
|
25230
|
+
}
|
|
25231
|
+
return null;
|
|
25232
|
+
};
|
|
25233
|
+
var getAvailableBreakoutBoundaryPointForOutsidePorts = ({
|
|
25234
|
+
idealPoints,
|
|
25235
|
+
bounds,
|
|
25236
|
+
usedBoundaryPoints,
|
|
25237
|
+
boundaryPointSpacing,
|
|
25238
|
+
routeFrom,
|
|
25239
|
+
pads,
|
|
25240
|
+
sourcePortId,
|
|
25241
|
+
outsidePorts,
|
|
25242
|
+
layer
|
|
25243
|
+
}) => {
|
|
25244
|
+
const step = getBoundaryCandidateSearchStep({
|
|
25245
|
+
bounds,
|
|
25246
|
+
boundaryPointSpacing
|
|
25247
|
+
});
|
|
25248
|
+
if (step <= 0) return null;
|
|
25249
|
+
for (const idealPoint of idealPoints) {
|
|
25250
|
+
if (isCandidateAvailableForOutsidePorts({
|
|
25251
|
+
candidate: idealPoint,
|
|
25252
|
+
bounds,
|
|
25253
|
+
usedBoundaryPoints,
|
|
25254
|
+
boundaryPointSpacing,
|
|
25255
|
+
routeFrom,
|
|
25256
|
+
pads,
|
|
25257
|
+
sourcePortId,
|
|
25258
|
+
outsidePorts,
|
|
25259
|
+
layer
|
|
25260
|
+
})) {
|
|
25261
|
+
return idealPoint;
|
|
25262
|
+
}
|
|
25263
|
+
const edge = getBoundsEdge(idealPoint, bounds);
|
|
25264
|
+
if (!edge) continue;
|
|
25265
|
+
const edgeCandidates = getBoundsEdgeCandidates({ edge, bounds, step });
|
|
25266
|
+
edgeCandidates.sort(
|
|
25267
|
+
(a, b) => distance15(a, idealPoint) - distance15(b, idealPoint)
|
|
25268
|
+
);
|
|
25269
|
+
for (const candidate of edgeCandidates) {
|
|
25270
|
+
if (isCandidateAvailableForOutsidePorts({
|
|
25271
|
+
candidate,
|
|
25272
|
+
bounds,
|
|
25273
|
+
usedBoundaryPoints,
|
|
25274
|
+
boundaryPointSpacing,
|
|
25275
|
+
routeFrom,
|
|
25276
|
+
pads,
|
|
25277
|
+
sourcePortId,
|
|
25278
|
+
outsidePorts,
|
|
25279
|
+
layer
|
|
25280
|
+
})) {
|
|
25281
|
+
return candidate;
|
|
25282
|
+
}
|
|
25283
|
+
}
|
|
25284
|
+
}
|
|
25285
|
+
for (const idealPoint of idealPoints) {
|
|
25286
|
+
const candidates = getAllBoundsCandidates({ bounds, step });
|
|
25287
|
+
candidates.sort((a, b) => distance15(a, idealPoint) - distance15(b, idealPoint));
|
|
25288
|
+
for (const candidate of candidates) {
|
|
25289
|
+
if (isCandidateAvailableForOutsidePorts({
|
|
25290
|
+
candidate,
|
|
25291
|
+
bounds,
|
|
25292
|
+
usedBoundaryPoints,
|
|
25293
|
+
boundaryPointSpacing,
|
|
25294
|
+
routeFrom,
|
|
25295
|
+
pads,
|
|
25296
|
+
sourcePortId,
|
|
25297
|
+
outsidePorts,
|
|
25298
|
+
layer
|
|
25299
|
+
})) {
|
|
25300
|
+
return candidate;
|
|
25301
|
+
}
|
|
25302
|
+
}
|
|
25303
|
+
}
|
|
25304
|
+
return null;
|
|
25305
|
+
};
|
|
25306
|
+
|
|
25307
|
+
// node_modules/@tscircuit/breakout-point-solver/lib/BreakoutPointSolver.ts
|
|
25308
|
+
var getLayerVisualStyle = (layer) => {
|
|
25309
|
+
if (layer === "bottom") {
|
|
25310
|
+
return {
|
|
25311
|
+
insidePadFill: "rgba(2, 132, 199, 0.28)",
|
|
25312
|
+
insidePadStroke: "#0369a1",
|
|
25313
|
+
insidePointColor: "#0369a1",
|
|
25314
|
+
outsidePadFill: "rgba(30, 64, 175, 0.2)",
|
|
25315
|
+
outsidePadStroke: "#1e40af",
|
|
25316
|
+
outsidePointColor: "#1e40af",
|
|
25317
|
+
padFill: "rgba(37, 99, 235, 0.18)",
|
|
25318
|
+
padStroke: "#1d4ed8",
|
|
25319
|
+
componentFill: "rgba(245, 158, 11, 0.1)",
|
|
25320
|
+
componentStroke: "#b45309",
|
|
25321
|
+
traceStroke: "#2563eb",
|
|
25322
|
+
breakoutPointColor: "#0f766e"
|
|
25323
|
+
};
|
|
25324
|
+
}
|
|
25325
|
+
return {
|
|
25326
|
+
insidePadFill: "rgba(46, 125, 50, 0.28)",
|
|
25327
|
+
insidePadStroke: "#1b5e20",
|
|
25328
|
+
insidePointColor: "#1b5e20",
|
|
25329
|
+
outsidePadFill: "rgba(106, 27, 154, 0.2)",
|
|
25330
|
+
outsidePadStroke: "#6a1b9a",
|
|
25331
|
+
outsidePointColor: "#6a1b9a",
|
|
25332
|
+
padFill: "rgba(220, 38, 38, 0.22)",
|
|
25333
|
+
padStroke: "#b91c1c",
|
|
25334
|
+
componentFill: "rgba(245, 158, 11, 0.1)",
|
|
25335
|
+
componentStroke: "#b45309",
|
|
25336
|
+
traceStroke: "#7e8794",
|
|
25337
|
+
breakoutPointColor: "#0d47a1"
|
|
25338
|
+
};
|
|
25339
|
+
};
|
|
25340
|
+
var getPortPadRect = ({
|
|
25341
|
+
port,
|
|
25342
|
+
fill,
|
|
25343
|
+
stroke,
|
|
25344
|
+
fallbackLabel
|
|
25345
|
+
}) => {
|
|
25346
|
+
if (port.width === void 0 || port.height === void 0) return null;
|
|
25347
|
+
return {
|
|
25348
|
+
center: port.position,
|
|
25349
|
+
width: port.width,
|
|
25350
|
+
height: port.height,
|
|
25351
|
+
ccwRotationDegrees: port.ccwRotationDegrees,
|
|
25352
|
+
fill,
|
|
25353
|
+
stroke,
|
|
25354
|
+
label: port.label ?? fallbackLabel
|
|
25355
|
+
};
|
|
25356
|
+
};
|
|
25357
|
+
var getAveragePortPosition = (ports) => {
|
|
25358
|
+
if (ports.length === 0) return null;
|
|
25359
|
+
const total = ports.reduce(
|
|
25360
|
+
(sum, port) => ({
|
|
25361
|
+
x: sum.x + port.position.x,
|
|
25362
|
+
y: sum.y + port.position.y
|
|
25363
|
+
}),
|
|
25364
|
+
{ x: 0, y: 0 }
|
|
25365
|
+
);
|
|
25366
|
+
return {
|
|
25367
|
+
x: total.x / ports.length,
|
|
25368
|
+
y: total.y / ports.length
|
|
25369
|
+
};
|
|
25370
|
+
};
|
|
25371
|
+
var getOutsideTarget = (trace) => getAveragePortPosition(trace.outsidePorts);
|
|
25372
|
+
var getInsidePortKey = (port) => `${port.sourcePortId}:${port.layer ?? "top"}`;
|
|
25373
|
+
var getOutsidePortsForInsidePort = ({
|
|
25374
|
+
traces,
|
|
25375
|
+
insidePort
|
|
25376
|
+
}) => {
|
|
25377
|
+
const outsidePorts = [];
|
|
25378
|
+
const insidePortKey = getInsidePortKey(insidePort);
|
|
25379
|
+
for (const trace of traces) {
|
|
25380
|
+
const hasMatchingInsidePort = trace.insidePorts.some(
|
|
25381
|
+
(port) => getInsidePortKey(port) === insidePortKey
|
|
25382
|
+
);
|
|
25383
|
+
if (!hasMatchingInsidePort) continue;
|
|
25384
|
+
outsidePorts.push(...trace.outsidePorts);
|
|
25385
|
+
}
|
|
25386
|
+
return outsidePorts;
|
|
25387
|
+
};
|
|
25388
|
+
var getIdealBoundaryPoints = ({
|
|
25389
|
+
insidePort,
|
|
25390
|
+
outsidePorts,
|
|
25391
|
+
bounds
|
|
25392
|
+
}) => {
|
|
25393
|
+
const idealBoundaryPoints = [];
|
|
25394
|
+
for (const outsidePort of outsidePorts) {
|
|
25395
|
+
const idealBoundaryPoint = getBreakoutBoundaryIntersection({
|
|
25396
|
+
from: insidePort.position,
|
|
25397
|
+
to: outsidePort.position,
|
|
25398
|
+
bounds
|
|
25399
|
+
});
|
|
25400
|
+
if (idealBoundaryPoint) idealBoundaryPoints.push(idealBoundaryPoint);
|
|
25401
|
+
}
|
|
25402
|
+
return idealBoundaryPoints;
|
|
25403
|
+
};
|
|
25404
|
+
var BreakoutPointSolver = class extends BaseSolver {
|
|
25405
|
+
input;
|
|
25406
|
+
output = { breakoutPoints: [] };
|
|
25407
|
+
constructor(input) {
|
|
25408
|
+
super();
|
|
25409
|
+
this.input = input;
|
|
25410
|
+
}
|
|
25411
|
+
_step() {
|
|
25412
|
+
const breakoutPoints = [];
|
|
25413
|
+
const boundaryPointsByInsidePort = /* @__PURE__ */ new Map();
|
|
25414
|
+
for (const trace of this.input.traces) {
|
|
25415
|
+
for (const insidePort of trace.insidePorts) {
|
|
25416
|
+
const insidePortKey = getInsidePortKey(insidePort);
|
|
25417
|
+
let boundaryPoint = boundaryPointsByInsidePort.get(insidePortKey) ?? null;
|
|
25418
|
+
if (!boundaryPoint) {
|
|
25419
|
+
const outsidePorts = getOutsidePortsForInsidePort({
|
|
25420
|
+
traces: this.input.traces,
|
|
25421
|
+
insidePort
|
|
25422
|
+
});
|
|
25423
|
+
const idealBoundaryPoints = getIdealBoundaryPoints({
|
|
25424
|
+
insidePort,
|
|
25425
|
+
outsidePorts,
|
|
25426
|
+
bounds: this.input.bounds
|
|
25427
|
+
});
|
|
25428
|
+
if (idealBoundaryPoints.length === 0) continue;
|
|
25429
|
+
const usedBoundaryPoints = [
|
|
25430
|
+
...this.input.usedBoundaryPoints ?? [],
|
|
25431
|
+
...boundaryPointsByInsidePort.values()
|
|
25432
|
+
];
|
|
25433
|
+
if (outsidePorts.length > 1) {
|
|
25434
|
+
boundaryPoint = getAvailableBreakoutBoundaryPointForOutsidePorts({
|
|
25435
|
+
idealPoints: idealBoundaryPoints,
|
|
25436
|
+
bounds: this.input.bounds,
|
|
25437
|
+
usedBoundaryPoints,
|
|
25438
|
+
boundaryPointSpacing: this.input.boundaryPointSpacing ?? 0,
|
|
25439
|
+
routeFrom: insidePort.position,
|
|
25440
|
+
pads: this.input.pads,
|
|
25441
|
+
sourcePortId: insidePort.sourcePortId,
|
|
25442
|
+
outsidePorts,
|
|
25443
|
+
layer: insidePort.layer
|
|
25444
|
+
});
|
|
25445
|
+
}
|
|
25446
|
+
boundaryPoint ??= getAvailableBreakoutBoundaryPoint({
|
|
25447
|
+
idealPoint: idealBoundaryPoints[0],
|
|
25448
|
+
bounds: this.input.bounds,
|
|
25449
|
+
usedBoundaryPoints,
|
|
25450
|
+
boundaryPointSpacing: this.input.boundaryPointSpacing ?? 0,
|
|
25451
|
+
routeFrom: insidePort.position,
|
|
25452
|
+
pads: this.input.pads,
|
|
25453
|
+
sourcePortId: insidePort.sourcePortId,
|
|
25454
|
+
layer: insidePort.layer
|
|
25455
|
+
});
|
|
25456
|
+
if (!boundaryPoint) continue;
|
|
25457
|
+
boundaryPointsByInsidePort.set(insidePortKey, boundaryPoint);
|
|
25458
|
+
}
|
|
25459
|
+
breakoutPoints.push({
|
|
25460
|
+
sourcePortId: insidePort.sourcePortId,
|
|
25461
|
+
sourceTraceId: trace.sourceTraceId,
|
|
25462
|
+
x: boundaryPoint.x,
|
|
25463
|
+
y: boundaryPoint.y,
|
|
25464
|
+
...insidePort.layer ? { layer: insidePort.layer } : {}
|
|
25465
|
+
});
|
|
25466
|
+
}
|
|
25467
|
+
}
|
|
25468
|
+
this.output = { breakoutPoints };
|
|
25469
|
+
this.solved = true;
|
|
25470
|
+
}
|
|
25471
|
+
getConstructorParams() {
|
|
25472
|
+
return [this.input];
|
|
25473
|
+
}
|
|
25474
|
+
getOutput() {
|
|
25475
|
+
return this.output;
|
|
25476
|
+
}
|
|
25477
|
+
visualize() {
|
|
25478
|
+
const { bounds } = this.input;
|
|
25479
|
+
const width = bounds.maxX - bounds.minX;
|
|
25480
|
+
const height = bounds.maxY - bounds.minY;
|
|
25481
|
+
const center = {
|
|
25482
|
+
x: bounds.minX + width / 2,
|
|
25483
|
+
y: bounds.minY + height / 2
|
|
25484
|
+
};
|
|
25485
|
+
return {
|
|
25486
|
+
title: "BreakoutPointSolver - generated breakout points",
|
|
25487
|
+
rects: [
|
|
25488
|
+
{
|
|
25489
|
+
center,
|
|
25490
|
+
width,
|
|
25491
|
+
height,
|
|
25492
|
+
fill: "rgba(210, 225, 255, 0.25)",
|
|
25493
|
+
stroke: "#315fba",
|
|
25494
|
+
label: "breakout bounds"
|
|
25495
|
+
},
|
|
25496
|
+
...(this.input.components ?? []).map((component) => ({
|
|
25497
|
+
center: component.center,
|
|
25498
|
+
width: component.width,
|
|
25499
|
+
height: component.height,
|
|
25500
|
+
ccwRotationDegrees: component.ccwRotationDegrees,
|
|
25501
|
+
fill: getLayerVisualStyle(component.layer).componentFill,
|
|
25502
|
+
stroke: getLayerVisualStyle(component.layer).componentStroke,
|
|
25503
|
+
label: component.label ?? "component"
|
|
25504
|
+
})),
|
|
25505
|
+
...(this.input.pads ?? []).map((pad) => ({
|
|
25506
|
+
center: pad.center,
|
|
25507
|
+
width: pad.width + (pad.clearance ?? 0) * 2,
|
|
25508
|
+
height: pad.height + (pad.clearance ?? 0) * 2,
|
|
25509
|
+
ccwRotationDegrees: pad.ccwRotationDegrees,
|
|
25510
|
+
fill: getLayerVisualStyle(pad.layer).padFill,
|
|
25511
|
+
stroke: getLayerVisualStyle(pad.layer).padStroke,
|
|
25512
|
+
label: pad.label ?? "pad"
|
|
25513
|
+
})),
|
|
25514
|
+
...this.input.traces.flatMap(
|
|
25515
|
+
(trace) => trace.insidePorts.flatMap((port) => {
|
|
25516
|
+
const rect = getPortPadRect({
|
|
25517
|
+
port,
|
|
25518
|
+
fill: getLayerVisualStyle(port.layer).insidePadFill,
|
|
25519
|
+
stroke: getLayerVisualStyle(port.layer).insidePadStroke,
|
|
25520
|
+
fallbackLabel: `inside pad ${port.sourcePortId}`
|
|
25521
|
+
});
|
|
25522
|
+
return rect ? [rect] : [];
|
|
25523
|
+
})
|
|
25524
|
+
),
|
|
25525
|
+
...this.input.traces.flatMap(
|
|
25526
|
+
(trace) => trace.outsidePorts.flatMap((port) => {
|
|
25527
|
+
const rect = getPortPadRect({
|
|
25528
|
+
port,
|
|
25529
|
+
fill: getLayerVisualStyle(port.layer).outsidePadFill,
|
|
25530
|
+
stroke: getLayerVisualStyle(port.layer).outsidePadStroke,
|
|
25531
|
+
fallbackLabel: `outside pad ${port.sourcePortId}`
|
|
25532
|
+
});
|
|
25533
|
+
return rect ? [rect] : [];
|
|
25534
|
+
})
|
|
25535
|
+
)
|
|
25536
|
+
],
|
|
25537
|
+
lines: this.input.traces.flatMap(
|
|
25538
|
+
(trace) => trace.insidePorts.flatMap((insidePort) => {
|
|
25539
|
+
const outsideTarget = getOutsideTarget(trace);
|
|
25540
|
+
if (!outsideTarget) return [];
|
|
25541
|
+
const breakoutPoint = this.output.breakoutPoints.find(
|
|
25542
|
+
(point6) => point6.sourceTraceId === trace.sourceTraceId && point6.sourcePortId === insidePort.sourcePortId
|
|
25543
|
+
);
|
|
25544
|
+
if (!breakoutPoint) return [];
|
|
25545
|
+
return [
|
|
25546
|
+
{
|
|
25547
|
+
points: [
|
|
25548
|
+
insidePort.position,
|
|
25549
|
+
{ x: breakoutPoint.x, y: breakoutPoint.y }
|
|
25550
|
+
],
|
|
25551
|
+
strokeColor: getLayerVisualStyle(insidePort.layer).traceStroke,
|
|
25552
|
+
label: `breakout segment ${trace.sourceTraceId}`
|
|
25553
|
+
},
|
|
25554
|
+
{
|
|
25555
|
+
points: [
|
|
25556
|
+
{ x: breakoutPoint.x, y: breakoutPoint.y },
|
|
25557
|
+
outsideTarget
|
|
25558
|
+
],
|
|
25559
|
+
strokeColor: getLayerVisualStyle(insidePort.layer).traceStroke,
|
|
25560
|
+
strokeDash: "0.15 0.15",
|
|
25561
|
+
label: `target guide ${trace.sourceTraceId}`
|
|
25562
|
+
}
|
|
25563
|
+
];
|
|
25564
|
+
})
|
|
25565
|
+
),
|
|
25566
|
+
points: [
|
|
25567
|
+
...this.input.traces.flatMap(
|
|
25568
|
+
(trace) => trace.insidePorts.map((port) => ({
|
|
25569
|
+
...port.position,
|
|
25570
|
+
color: getLayerVisualStyle(port.layer).insidePointColor,
|
|
25571
|
+
label: `inside pad ${port.sourcePortId}`
|
|
25572
|
+
}))
|
|
25573
|
+
),
|
|
25574
|
+
...this.input.traces.flatMap(
|
|
25575
|
+
(trace) => trace.outsidePorts.map((port) => ({
|
|
25576
|
+
...port.position,
|
|
25577
|
+
color: getLayerVisualStyle(port.layer).outsidePointColor,
|
|
25578
|
+
label: `outside target ${port.sourcePortId}`
|
|
25579
|
+
}))
|
|
25580
|
+
),
|
|
25581
|
+
...this.output.breakoutPoints.map((point6) => ({
|
|
25582
|
+
x: point6.x,
|
|
25583
|
+
y: point6.y,
|
|
25584
|
+
color: getLayerVisualStyle(point6.layer).breakoutPointColor,
|
|
25585
|
+
label: `selected breakout ${point6.sourcePortId}`
|
|
25586
|
+
})),
|
|
25587
|
+
...(this.input.usedBoundaryPoints ?? []).map((point6) => ({
|
|
25588
|
+
...point6,
|
|
25589
|
+
color: "#ef6c00",
|
|
25590
|
+
label: "pre-existing breakout point"
|
|
25591
|
+
}))
|
|
25592
|
+
]
|
|
25593
|
+
};
|
|
25594
|
+
}
|
|
25595
|
+
};
|
|
24870
25596
|
|
|
24871
25597
|
// lib/components/primitive-components/BaseBreakoutPoint.ts
|
|
24872
25598
|
import { pcbLayoutProps } from "@tscircuit/props";
|
|
@@ -25380,7 +26106,7 @@ var NetLabel = class extends PrimitiveComponent2 {
|
|
|
25380
26106
|
|
|
25381
26107
|
// lib/components/primitive-components/Fiducial.ts
|
|
25382
26108
|
import "zod";
|
|
25383
|
-
import { distance as
|
|
26109
|
+
import { distance as distance16 } from "circuit-json";
|
|
25384
26110
|
import { fiducialProps } from "@tscircuit/props";
|
|
25385
26111
|
var Fiducial = class extends PrimitiveComponent2 {
|
|
25386
26112
|
pcb_smtpad_id = null;
|
|
@@ -25405,15 +26131,15 @@ var Fiducial = class extends PrimitiveComponent2 {
|
|
|
25405
26131
|
shape: "circle",
|
|
25406
26132
|
x: position.x,
|
|
25407
26133
|
y: position.y,
|
|
25408
|
-
radius:
|
|
25409
|
-
soldermask_margin: props.soldermaskPullback ?
|
|
26134
|
+
radius: distance16.parse(props.padDiameter) / 2,
|
|
26135
|
+
soldermask_margin: props.soldermaskPullback ? distance16.parse(props.soldermaskPullback) : distance16.parse(props.padDiameter) / 2,
|
|
25410
26136
|
is_covered_with_solder_mask: true
|
|
25411
26137
|
});
|
|
25412
26138
|
this.pcb_smtpad_id = pcb_smtpad.pcb_smtpad_id;
|
|
25413
26139
|
}
|
|
25414
26140
|
getPcbSize() {
|
|
25415
26141
|
const { _parsedProps: props } = this;
|
|
25416
|
-
const d =
|
|
26142
|
+
const d = distance16.parse(props.padDiameter);
|
|
25417
26143
|
return { width: d, height: d };
|
|
25418
26144
|
}
|
|
25419
26145
|
_setPositionFromLayout(newCenter) {
|